summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/CONTRIBUTING.md3
-rw-r--r--Documentation/CodingGuidelines7
-rw-r--r--Documentation/Makefile1
-rw-r--r--Documentation/MyFirstContribution.txt4
-rw-r--r--Documentation/RelNotes/2.28.0.txt236
-rw-r--r--Documentation/RelNotes/2.29.0.txt91
-rw-r--r--Documentation/SubmittingPatches15
-rw-r--r--Documentation/config/diff.txt4
-rw-r--r--Documentation/config/feature.txt10
-rw-r--r--Documentation/config/fetch.txt3
-rw-r--r--Documentation/config/fmt-merge-msg.txt12
-rw-r--r--Documentation/config/init.txt4
-rw-r--r--Documentation/config/protocol.txt3
-rw-r--r--Documentation/diff-options.txt5
-rw-r--r--Documentation/git-branch.txt2
-rw-r--r--Documentation/git-bugreport.txt1
-rw-r--r--Documentation/git-cat-file.txt2
-rw-r--r--Documentation/git-clone.txt2
-rw-r--r--Documentation/git-commit-graph.txt11
-rw-r--r--Documentation/git-diff.txt23
-rw-r--r--Documentation/git-fast-export.txt29
-rw-r--r--Documentation/git-fast-import.txt9
-rw-r--r--Documentation/git-fetch.txt8
-rw-r--r--Documentation/git-for-each-ref.txt27
-rw-r--r--Documentation/git-help.txt4
-rw-r--r--Documentation/git-http-fetch.txt9
-rw-r--r--Documentation/git-index-pack.txt12
-rw-r--r--Documentation/git-init.txt9
-rw-r--r--Documentation/git-log.txt7
-rw-r--r--Documentation/git-ls-remote.txt4
-rw-r--r--Documentation/git-rebase.txt2
-rw-r--r--Documentation/git-rev-list.txt40
-rw-r--r--Documentation/git-show-index.txt11
-rw-r--r--Documentation/git-sparse-checkout.txt30
-rw-r--r--Documentation/git-submodule.txt12
-rw-r--r--Documentation/git-worktree.txt4
-rw-r--r--Documentation/git.txt11
-rw-r--r--Documentation/giteveryday.txt10
-rw-r--r--Documentation/githooks.txt29
-rw-r--r--Documentation/gitmodules.txt6
-rw-r--r--Documentation/gitremote-helpers.txt37
-rw-r--r--Documentation/gitworkflows.txt18
-rw-r--r--Documentation/howto/maintain-git.txt52
-rw-r--r--Documentation/howto/rebase-from-internal-branch.txt32
-rw-r--r--Documentation/howto/revert-branch-rebase.txt32
-rw-r--r--Documentation/howto/update-hook-example.txt6
-rw-r--r--Documentation/pretty-formats.txt4
-rw-r--r--Documentation/rev-list-description.txt61
-rw-r--r--Documentation/revisions.txt3
-rw-r--r--Documentation/technical/commit-graph-format.txt2
-rw-r--r--Documentation/technical/http-protocol.txt2
-rw-r--r--Documentation/technical/pack-protocol.txt6
-rw-r--r--Documentation/technical/packfile-uri.txt78
-rw-r--r--Documentation/technical/protocol-capabilities.txt15
-rw-r--r--Documentation/technical/protocol-v2.txt59
-rw-r--r--Documentation/technical/reftable.txt1083
-rw-r--r--Documentation/user-manual.txt2
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--Makefile2
l---------RelNotes2
-rw-r--r--add-patch.c32
-rw-r--r--alloc.c18
-rw-r--r--alloc.h2
-rw-r--r--blame.c2
-rw-r--r--blob.c2
-rw-r--r--bloom.c26
-rw-r--r--bloom.h1
-rw-r--r--branch.c2
-rw-r--r--bugreport.c10
-rw-r--r--builtin/bisect--helper.c16
-rw-r--r--builtin/branch.c4
-rw-r--r--builtin/cat-file.c2
-rw-r--r--builtin/checkout.c6
-rw-r--r--builtin/clean.c49
-rw-r--r--builtin/clone.c47
-rw-r--r--builtin/commit-graph.c78
-rw-r--r--builtin/config.c2
-rw-r--r--builtin/diff-files.c7
-rw-r--r--builtin/diff.c147
-rw-r--r--builtin/fast-export.c162
-rw-r--r--builtin/fetch-pack.c19
-rw-r--r--builtin/fetch.c12
-rw-r--r--builtin/fsck.c4
-rw-r--r--builtin/grep.c2
-rw-r--r--builtin/index-pack.c14
-rw-r--r--builtin/init-db.c33
-rw-r--r--builtin/ls-remote.c4
-rw-r--r--builtin/merge.c2
-rw-r--r--builtin/mv.c7
-rw-r--r--builtin/pack-objects.c116
-rw-r--r--builtin/pull.c4
-rw-r--r--builtin/receive-pack.c10
-rw-r--r--builtin/reflog.c2
-rw-r--r--builtin/show-index.c29
-rw-r--r--builtin/sparse-checkout.c6
-rw-r--r--builtin/submodule--helper.c46
-rw-r--r--builtin/worktree.c158
-rw-r--r--bundle.c22
-rw-r--r--bundle.h1
-rw-r--r--cache.h4
-rwxr-xr-xci/lib.sh4
-rw-r--r--column.c2
-rw-r--r--command-list.txt2
-rw-r--r--commit-graph.c472
-rw-r--r--commit-graph.h23
-rw-r--r--commit-reach.c93
-rw-r--r--commit-reach.h4
-rw-r--r--commit-slab-decl.h1
-rw-r--r--commit-slab-impl.h13
-rw-r--r--commit-slab.h10
-rw-r--r--commit.c14
-rw-r--r--commit.h2
-rwxr-xr-xcompat/vcbuild/scripts/clink.pl4
-rw-r--r--connect.c156
-rw-r--r--connect.h7
-rw-r--r--connected.c8
-rw-r--r--contrib/coccinelle/commit.cocci18
-rw-r--r--contrib/completion/git-completion.bash278
-rw-r--r--contrib/completion/git-prompt.sh26
-rwxr-xr-xcontrib/subtree/t/t7900-subtree.sh6
-rw-r--r--diff-lib.c3
-rw-r--r--diff.c16
-rw-r--r--diff.h10
-rw-r--r--dir.c69
-rw-r--r--entry.c3
-rw-r--r--fast-import.c25
-rw-r--r--fetch-pack.c164
-rw-r--r--fetch-pack.h2
-rw-r--r--fmt-merge-msg.c38
-rw-r--r--fsck.c4
-rw-r--r--fsmonitor.c2
-rw-r--r--fuzz-commit-graph.c2
-rwxr-xr-xgit-add--interactive.perl21
-rwxr-xr-xgit-bisect.sh4
-rw-r--r--git-compat-util.h6
-rwxr-xr-xgit-cvsexportcommit.perl14
-rwxr-xr-xgit-cvsimport.perl8
-rwxr-xr-xgit-cvsserver.perl37
-rw-r--r--git-gui/lib/choose_repository.tcl27
-rwxr-xr-xgit-p4.py9
-rwxr-xr-xgit-send-email.perl8
-rwxr-xr-xgit-submodule.sh32
-rwxr-xr-xgit-svn.perl25
-rw-r--r--git.c6
-rw-r--r--grep.c2
-rw-r--r--hashmap.h2
-rw-r--r--help.c1
-rw-r--r--http-fetch.c126
-rw-r--r--http-push.c16
-rw-r--r--http-walker.c5
-rw-r--r--http.c125
-rw-r--r--http.h31
-rw-r--r--imap-send.c2
-rw-r--r--line-log.c43
-rw-r--r--line-log.h5
-rw-r--r--list-objects-filter-options.c3
-rw-r--r--object-store.h1
-rw-r--r--object.c4
-rw-r--r--object.h10
-rw-r--r--pack-write.c5
-rw-r--r--packfile.c1
-rw-r--r--perl/Git/IndexInfo.pm6
-rw-r--r--perl/Git/SVN.pm83
-rw-r--r--perl/Git/SVN/Editor.pm8
-rw-r--r--perl/Git/SVN/Fetcher.pm6
-rw-r--r--perl/Git/SVN/Log.pm2
-rw-r--r--perl/Git/SVN/Ra.pm4
-rw-r--r--pkt-line.c18
-rw-r--r--pkt-line.h14
-rw-r--r--po/ca.po854
-rw-r--r--po/de.po2586
-rw-r--r--po/es.po2728
-rw-r--r--po/fr.po2552
-rw-r--r--po/git.pot2452
-rw-r--r--po/it.po2536
-rw-r--r--po/sv.po2526
-rw-r--r--po/tr.po2505
-rw-r--r--po/vi.po2548
-rw-r--r--po/zh_CN.po2490
-rw-r--r--po/zh_TW.po2540
-rw-r--r--protocol.c4
-rw-r--r--read-cache.c14
-rw-r--r--ref-filter.c11
-rw-r--r--refs.c159
-rw-r--r--refs.h27
-rw-r--r--refs/files-backend.c6
-rw-r--r--refs/refs-internal.h24
-rw-r--r--remote-curl.c122
-rw-r--r--remote-testsvn.c10
-rw-r--r--remote.c14
-rw-r--r--remote.h3
-rw-r--r--repo-settings.c8
-rw-r--r--repository.h6
-rw-r--r--revision.c142
-rw-r--r--revision.h13
-rw-r--r--run-command.c1
-rw-r--r--run-command.h1
-rw-r--r--send-pack.c8
-rw-r--r--serve.c29
-rw-r--r--setup.c128
-rw-r--r--sha1-file.c3
-rw-r--r--shallow.c14
-rw-r--r--strbuf.c5
-rw-r--r--strbuf.h1
-rw-r--r--t/README14
-rw-r--r--t/helper/test-oid-array.c3
-rw-r--r--t/helper/test-pkt-line.c4
-rw-r--r--t/helper/test-reach.c4
-rw-r--r--t/helper/test-ref-store.c2
-rw-r--r--t/helper/test-regex.c94
-rw-r--r--t/lib-git-svn.sh17
-rw-r--r--t/lib-httpd.sh2
-rw-r--r--t/lib-httpd/apache.conf8
-rw-r--r--t/lib-httpd/incomplete-body-upload-pack-v2-http.sh3
-rw-r--r--t/lib-httpd/incomplete-length-upload-pack-v2-http.sh3
-rw-r--r--t/lib-submodule-update.sh75
-rw-r--r--t/lib-t6000.sh5
-rwxr-xr-xt/perf/p1400-update-ref.sh32
-rwxr-xr-xt/t0000-basic.sh18
-rwxr-xr-xt/t0001-init.sh26
-rwxr-xr-xt/t0002-gitfile.sh2
-rwxr-xr-xt/t0410-partial-clone.sh34
-rwxr-xr-xt/t1013-read-tree-submodule.sh4
-rwxr-xr-xt/t1050-large.sh6
-rwxr-xr-xt/t1090-sparse-checkout-scope.sh1
-rwxr-xr-xt/t1091-sparse-checkout-builtin.sh22
-rwxr-xr-xt/t1302-repo-version.sh9
-rwxr-xr-xt/t1400-update-ref.sh32
-rwxr-xr-xt/t1416-ref-transaction-hooks.sh109
-rwxr-xr-xt/t1450-fsck.sh43
-rwxr-xr-xt/t1506-rev-parse-diagnosis.sh2
-rwxr-xr-xt/t2013-checkout-submodule.sh4
-rwxr-xr-xt/t2018-checkout-branch.sh10
-rwxr-xr-xt/t2027-checkout-track.sh24
-rwxr-xr-xt/t2060-switch.sh8
-rwxr-xr-xt/t2203-add-intent.sh52
-rwxr-xr-xt/t2401-worktree-prune.sh24
-rwxr-xr-xt/t2403-worktree-move.sh21
-rwxr-xr-xt/t2404-worktree-config.sh4
-rwxr-xr-xt/t3200-branch.sh69
-rwxr-xr-xt/t3426-rebase-submodule.sh10
-rwxr-xr-xt/t3430-rebase-merges.sh2
-rwxr-xr-xt/t3432-rebase-fast-forward.sh7
-rwxr-xr-xt/t3512-cherry-pick-submodule.sh2
-rwxr-xr-xt/t3513-revert-submodule.sh9
-rwxr-xr-xt/t3701-add-interactive.sh32
-rwxr-xr-xt/t3906-stash-submodule.sh9
-rwxr-xr-xt/t4010-diff-pathspec.sh4
-rwxr-xr-xt/t4014-format-patch.sh21
-rwxr-xr-xt/t4045-diff-relative.sh82
-rwxr-xr-xt/t4068-diff-symmetric.sh91
-rwxr-xr-xt/t4137-apply-submodule.sh12
-rwxr-xr-xt/t4210-log-i18n.sh77
-rwxr-xr-xt/t4211-line-log.sh76
-rwxr-xr-xt/t4216-log-bloom.sh45
-rwxr-xr-xt/t4255-am-submodule.sh12
-rwxr-xr-xt/t5300-pack-object.sh45
-rwxr-xr-xt/t5302-pack-index.sh356
-rwxr-xr-xt/t5318-commit-graph.sh61
-rwxr-xr-xt/t5324-split-commit-graph.sh2
-rwxr-xr-xt/t5500-fetch-pack.sh6
-rwxr-xr-xt/t5505-remote.sh8
-rwxr-xr-xt/t5510-fetch.sh2
-rwxr-xr-xt/t5516-fetch-push.sh16
-rwxr-xr-xt/t5528-push-default.sh6
-rwxr-xr-xt/t5537-fetch-shallow.sh14
-rwxr-xr-xt/t5539-fetch-http-shallow.sh4
-rwxr-xr-xt/t5540-http-push-webdav.sh16
-rwxr-xr-xt/t5541-http-push-smart.sh30
-rwxr-xr-xt/t5550-http-fetch-dumb.sh48
-rwxr-xr-xt/t5551-http-fetch-smart.sh56
-rwxr-xr-xt/t5562-http-backend-content-length.sh5
-rwxr-xr-xt/t5572-pull-submodule.sh20
-rwxr-xr-xt/t5581-http-curl-verbose.sh2
-rwxr-xr-xt/t5601-clone.sh4
-rwxr-xr-xt/t5606-clone-options.sh24
-rwxr-xr-xt/t5608-clone-2gb.sh11
-rwxr-xr-xt/t5616-partial-clone.sh38
-rwxr-xr-xt/t5701-git-serve.sh25
-rwxr-xr-xt/t5702-protocol-v2.sh138
-rwxr-xr-xt/t5703-upload-pack-ref-in-want.sh19
-rwxr-xr-xt/t5704-protocol-violations.sh2
-rwxr-xr-xt/t5801/git-remote-testgit6
-rwxr-xr-xt/t6000-rev-list-misc.sh7
-rwxr-xr-xt/t6030-bisect-porcelain.sh2
-rwxr-xr-xt/t6041-bisect-submodule.sh9
-rwxr-xr-xt/t6046-merge-skip-unneeded-updates.sh2
-rwxr-xr-xt/t6050-replace.sh2
-rwxr-xr-xt/t6132-pathspec-exclude.sh33
-rwxr-xr-xt/t6200-fmt-merge-msg.sh20
-rwxr-xr-xt/t6300-for-each-ref.sh38
-rwxr-xr-xt/t7001-mv.sh17
-rwxr-xr-xt/t7061-wtstatus-ignore.sh25
-rwxr-xr-xt/t7107-reset-pathspec-file.sh9
-rwxr-xr-xt/t7112-reset-submodule.sh6
-rwxr-xr-xt/t7406-submodule-update.sh16
-rwxr-xr-xt/t7419-submodule-set-branch.sh7
-rwxr-xr-xt/t7613-merge-submodule.sh8
-rwxr-xr-xt/t7800-difftool.sh8
-rwxr-xr-xt/t8002-blame.sh11
-rwxr-xr-xt/t8014-blame-ignore-fuzzy.sh2
-rwxr-xr-xt/t9001-send-email.sh14
-rwxr-xr-xt/t9020-remote-svn.sh10
-rwxr-xr-xt/t9100-git-svn-basic.sh24
-rwxr-xr-xt/t9101-git-svn-props.sh12
-rwxr-xr-xt/t9104-git-svn-follow-parent.sh3
-rwxr-xr-xt/t9108-git-svn-glob.sh4
-rwxr-xr-xt/t9109-git-svn-multi-glob.sh6
-rwxr-xr-xt/t9168-git-svn-partially-globbed-names.sh8
-rwxr-xr-xt/t9300-fast-import.sh28
-rwxr-xr-xt/t9351-fast-export-anonymize.sh54
-rwxr-xr-xt/t9400-git-cvsserver-server.sh2
-rwxr-xr-xt/t9700/test.pl6
-rwxr-xr-xt/t9834-git-p4-file-dir-bug.sh2
-rwxr-xr-xt/t9902-completion.sh459
-rw-r--r--t/test-lib-functions.sh47
-rw-r--r--t/test-lib.sh10
-rw-r--r--tag.c2
-rw-r--r--trace.c20
-rw-r--r--trace.h6
-rw-r--r--transport-helper.c31
-rw-r--r--transport.c56
-rw-r--r--transport.h14
-rw-r--r--tree-diff.c30
-rw-r--r--tree-walk.c9
-rw-r--r--tree.c2
-rw-r--r--upload-pack.c869
-rw-r--r--worktree.c26
-rw-r--r--worktree.h11
-rw-r--r--wrapper.c8
-rw-r--r--wt-status.c43
-rw-r--r--wt-status.h2
332 files changed, 22780 insertions, 14096 deletions
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index e7b4e2f..c8755e3 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -16,4 +16,7 @@ If you prefer video, then [this talk](https://www.youtube.com/watch?v=Q7i_qQW__q
might be useful to you as the presenter walks you through the contribution
process by example.
+Or, you can follow the ["My First Contribution"](https://git-scm.com/docs/MyFirstContribution)
+tutorial for another example of the contribution process.
+
Your friendly Git community!
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index 227f46a..45465bc 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -489,16 +489,11 @@ For Python scripts:
- We follow PEP-8 (http://www.python.org/dev/peps/pep-0008/).
- - As a minimum, we aim to be compatible with Python 2.6 and 2.7.
+ - As a minimum, we aim to be compatible with Python 2.7.
- Where required libraries do not restrict us to Python 2, we try to
also be compatible with Python 3.1 and later.
- - When you must differentiate between Unicode literals and byte string
- literals, it is OK to use the 'b' prefix. Even though the Python
- documentation for version 2.6 does not mention this prefix, it has
- been supported since version 2.6.0.
-
Error Messages
- Do not end error messages with a full stop.
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 15d9d04..ecd0b34 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -93,6 +93,7 @@ TECH_DOCS += technical/protocol-capabilities
TECH_DOCS += technical/protocol-common
TECH_DOCS += technical/protocol-v2
TECH_DOCS += technical/racy-git
+TECH_DOCS += technical/reftable
TECH_DOCS += technical/send-pack-pipeline
TECH_DOCS += technical/shallow
TECH_DOCS += technical/signature-format
diff --git a/Documentation/MyFirstContribution.txt b/Documentation/MyFirstContribution.txt
index 427274d..d85c9b5 100644
--- a/Documentation/MyFirstContribution.txt
+++ b/Documentation/MyFirstContribution.txt
@@ -1179,8 +1179,8 @@ look at the section below this one for some context.)
[[after-approval]]
=== After Review Approval
-The Git project has four integration branches: `pu`, `next`, `master`, and
-`maint`. Your change will be placed into `pu` fairly early on by the maintainer
+The Git project has four integration branches: `seen`, `next`, `master`, and
+`maint`. Your change will be placed into `seen` fairly early on by the maintainer
while it is still in the review process; from there, when it is ready for wider
testing, it will be merged into `next`. Plenty of early testers use `next` and
may report issues. Eventually, changes in `next` will make it to `master`,
diff --git a/Documentation/RelNotes/2.28.0.txt b/Documentation/RelNotes/2.28.0.txt
new file mode 100644
index 0000000..6baf781
--- /dev/null
+++ b/Documentation/RelNotes/2.28.0.txt
@@ -0,0 +1,236 @@
+Git 2.28 Release Notes
+======================
+
+Updates since v2.27
+-------------------
+
+Backward compatibility notes
+
+ * "fetch.writeCommitGraph" is deemed to be still a bit too risky and
+ is no longer part of the "feature.experimental" set.
+
+
+UI, Workflows & Features
+
+ * The commands in the "diff" family learned to honor "diff.relative"
+ configuration variable.
+
+ * The check in "git fsck" to ensure that the tree objects are sorted
+ still had corner cases it missed unsorted entries.
+
+ * The interface to redact sensitive information in the trace output
+ has been simplified.
+
+ * The command line completion (in contrib/) learned to complete
+ options that the "git switch" command takes.
+
+ * "git diff" used to take arguments in random and nonsense range
+ notation, e.g. "git diff A..B C", "git diff A..B C...D", etc.,
+ which has been cleaned up.
+
+ * "git diff-files" has been taught to say paths that are marked as
+ intent-to-add are new files, not modified from an empty blob.
+
+ * "git status" learned to report the status of sparse checkout.
+
+ * "git difftool" has trouble dealing with paths added to the index
+ with the intent-to-add bit.
+
+ * "git fast-export --anonymize" learned to take customized mapping to
+ allow its users to tweak its output more usable for debugging.
+
+ * The command line completion support (in contrib/) used to be
+ prepared to work with "set -u" but recent changes got a bit more
+ sloppy. This has been corrected.
+
+ * "git gui" now allows opening work trees from the start-up dialog.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Code optimization for a common case.
+ (merge 8777616e4d an/merge-single-strategy-optim later to maint).
+
+ * We've adopted a convention that any on-stack structure can be
+ initialized to have zero values in all fields with "= { 0 }",
+ even when the first field happens to be a pointer, but sparse
+ complained that a null pointer should be spelled NULL for a long
+ time. Start using -Wno-universal-initializer option to squelch
+ it (the latest sparse has it on by default).
+
+ * "git log -L..." now takes advantage of the "which paths are touched
+ by this commit?" info stored in the commit-graph system.
+
+ * As FreeBSD is not the only platform whose regexp library reports
+ a REG_ILLSEQ error when fed invalid UTF-8, add logic to detect that
+ automatically and skip the affected tests.
+
+ * "git bugreport" learns to report what shell is in use.
+
+ * Support for GIT_CURL_VERBOSE has been rewritten in terms of
+ GIT_TRACE_CURL.
+
+ * Preliminary clean-ups around refs API, plus file format
+ specification documentation for the reftable backend.
+
+ * Workaround breakage in MSVC build, where "curl-config --cflags"
+ gives settings appropriate for GCC build.
+
+ * Code clean-up of "git clean" resulted in a fix of recent
+ performance regression.
+
+ * Code clean-up in the codepath that serves "git fetch" continues.
+
+ * "git merge-base --is-ancestor" is taught to take advantage of the
+ commit graph.
+
+ * Rewrite of parts of the scripted "git submodule" Porcelain command
+ continues; this time it is "git submodule set-branch" subcommand's
+ turn.
+
+ * The "fetch/clone" protocol has been updated to allow the server to
+ instruct the clients to grab pre-packaged packfile(s) in addition
+ to the packed object data coming over the wire.
+
+ * A misdesigned strbuf_write_fd() function has been retired.
+
+ * SHA-256 migration work continues, including CVS/SVN interface.
+
+ * A few fields in "struct commit" that do not have to always be
+ present have been moved to commit slabs.
+
+ * API cleanup for get_worktrees()
+
+ * By renumbering object flag bits, "struct object" managed to lose
+ bloated inter-field padding.
+
+ * The name of the primary branch in existing repositories, and the
+ default name used for the first branch in newly created
+ repositories, is made configurable, so that we can eventually wean
+ ourselves off of the hardcoded 'master'.
+
+ * The effort to avoid using test_must_fail on non-git command continues.
+
+ * In 2.28-rc0, we corrected a bug that some repository extensions are
+ honored by mistake even in a version 0 repositories (these
+ configuration variables in extensions.* namespace were supposed to
+ have special meaning in repositories whose version numbers are 1 or
+ higher), but this was a bit too big a change. The behaviour in
+ recent versions of Git where certain extensions.* were honored by
+ mistake even in version 0 repositories has been restored.
+
+
+Fixes since v2.27
+-----------------
+
+ * The "--prepare-p4-only" option of "git p4" is supposed to stop
+ after replaying one changeset, but kept going (by mistake?)
+
+ * The error message from "git checkout -b foo -t bar baz" was
+ confusing.
+
+ * Some repositories in the wild have commits that record nonsense
+ committer timezone (e.g. rails.git); "git fast-import" learned an
+ option to pass these nonsense timestamps intact to allow recreating
+ existing repositories as-is.
+ (merge d42a2fb72f en/fast-import-looser-date later to maint).
+
+ * The command line completion script (in contrib/) tried to complete
+ "git stash -p" as if it were "git stash push -p", but it was too
+ aggressive and also affected "git stash show -p", which has been
+ corrected.
+ (merge fffd0cf520 vs/complete-stash-show-p-fix later to maint).
+
+ * On-the-wire protocol v2 easily falls into a deadlock between the
+ remote-curl helper and the fetch-pack process when the server side
+ prematurely throws an error and disconnects. The communication has
+ been updated to make it more robust.
+
+ * "git checkout -p" did not handle a newly added path at all.
+ (merge 2c8bd8471a js/checkout-p-new-file later to maint).
+
+ * The code to parse "git bisect start" command line was lax in
+ validating the arguments.
+ (merge 4d9005ff5d cb/bisect-helper-parser-fix later to maint).
+
+ * Reduce memory usage during "diff --quiet" in a worktree with too
+ many stat-unmatched paths.
+ (merge d2d7fbe129 jk/diff-memuse-optim-with-stat-unmatch later to maint).
+
+ * The reflog entries for "git clone" and "git fetch" did not
+ anonymize the URL they operated on.
+ (merge 46da295a77 js/reflog-anonymize-for-clone-and-fetch later to maint).
+
+ * The behaviour of "sparse-checkout" in the state "git clone
+ --no-checkout" left was changed accidentally in 2.27, which has
+ been corrected.
+
+ * Use of negative pathspec, while collecting paths including
+ untracked ones in the working tree, was broken.
+
+ * The same worktree directory must be registered only once, but
+ "git worktree move" allowed this invariant to be violated, which
+ has been corrected.
+ (merge 810382ed37 es/worktree-duplicate-paths later to maint).
+
+ * The effect of sparse checkout settings on submodules is documented.
+ (merge e7d7c73249 en/sparse-with-submodule-doc later to maint).
+
+ * Code clean-up around "git branch" with a minor bugfix.
+ (merge dc44639904 dl/branch-cleanup later to maint).
+
+ * A branch name used in a test has been clarified to match what is
+ going on.
+ (merge 08dc26061f pb/t4014-unslave later to maint).
+
+ * An in-code comment in "git diff" has been updated.
+ (merge c592fd4c83 dl/diff-usage-comment-update later to maint).
+
+ * The documentation and some tests have been adjusted for the recent
+ renaming of "pu" branch to "seen".
+ (merge 6dca5dbf93 js/pu-to-seen later to maint).
+
+ * The code to push changes over "dumb" HTTP had a bad interaction
+ with the commit reachability code due to incorrect allocation of
+ object flag bits, which has been corrected.
+ (merge 64472d15e9 bc/http-push-flagsfix later to maint).
+
+ * "git send-email --in-reply-to=<msg>" did not use the In-Reply-To:
+ header with the value given from the command line, and let it be
+ overridden by the value on In-Reply-To: header in the messages
+ being sent out (if exists).
+ (merge f9f60d7066 ra/send-email-in-reply-to-from-command-line-wins later to maint).
+
+ * "git log -Lx,y:path --before=date" lost track of where the range
+ should be because it didn't take the changes made by the youngest
+ commits that are omitted from the output into account.
+
+ * When "fetch.writeCommitGraph" configuration is set in a shallow
+ repository and a fetch moves the shallow boundary, we wrote out
+ broken commit-graph files that do not match the reality, which has
+ been corrected.
+
+ * "git checkout" failed to catch an error from fstat() after updating
+ a path in the working tree.
+ (merge 35e6e212fd mt/entry-fstat-fallback-fix later to maint).
+
+ * When an aliased command, whose output is piped to a pager by git,
+ gets killed by a signal, the pager got into a funny state, which
+ has been corrected (again).
+ (merge c0d73a59c9 ta/wait-on-aliased-commands-upon-signal later to maint).
+
+ * The code to produce progress output from "git commit-graph --write"
+ had a few breakages, which have been fixed.
+
+ * Other code cleanup, docfix, build fix, etc.
+ (merge 2c31a7aa44 jx/pkt-line-doc-count-fix later to maint).
+ (merge d63ae31962 cb/t5608-cleanup later to maint).
+ (merge 788db145c7 dl/t-readme-spell-git-correctly later to maint).
+ (merge 45a87a83bb dl/python-2.7-is-the-floor-version later to maint).
+ (merge b75a219904 es/advertise-contribution-doc later to maint).
+ (merge 0c9a4f638a rs/pull-leakfix later to maint).
+ (merge d546fe2874 rs/commit-reach-leakfix later to maint).
+ (merge 087bf5409c mk/pb-pretty-email-without-domain-part-fix later to maint).
+ (merge 5f4ee57ad9 es/worktree-code-cleanup later to maint).
+ (merge 0172f7834a cc/cat-file-usage-update later to maint).
+ (merge 81de0c01cf ma/rebase-doc-typofix later to maint).
diff --git a/Documentation/RelNotes/2.29.0.txt b/Documentation/RelNotes/2.29.0.txt
new file mode 100644
index 0000000..41a2348
--- /dev/null
+++ b/Documentation/RelNotes/2.29.0.txt
@@ -0,0 +1,91 @@
+Git 2.29 Release Notes
+======================
+
+Updates since v2.28
+-------------------
+
+UI, Workflows & Features
+
+ * "git help log" has been enhanced by sharing more material from the
+ documentation for the underlying "git rev-list" command.
+
+ * "git for-each-ref --format=<>" learned %(contents:size).
+
+ * "git merge" learned to selectively omit " into <branch>" at the end
+ of the title of default merge message with merge.suppressDest
+ configuration.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * The changed-path Bloom filter is improved using ideas from an
+ independent implementation.
+
+ * Updates to the changed-paths bloom filter.
+
+ * The test framework has been updated so that most tests will run
+ with predictable (artificial) timestamps.
+
+ * Preliminary clean-up of the refs API in preparation for adding a
+ new refs backend "reftable".
+
+ * Dev support to limit the use of test_must_fail to only git commands.
+
+ * While packing many objects in a repository with a promissor remote,
+ lazily fetching missing objects from the promissor remote one by
+ one may be inefficient---the code now attempts to fetch all the
+ missing objects in batch (obviously this won't work for a lazy
+ clone that lazily fetches tree objects as you cannot even enumerate
+ what blobs are missing until you learn which trees are missing).
+
+ * The pretend-object mechanism checks if the given object already
+ exists in the object store before deciding to keep the data
+ in-core, but the check would have triggered lazy fetching of such
+ an object from a promissor remote.
+
+
+Fixes since v2.28
+-----------------
+
+ * "git clone --separate-git-dir=$elsewhere" used to stomp on the
+ contents of the existing directory $elsewhere, which has been
+ taught to fail when $elsewhere is not an empty directory.
+ (merge dfaa209a79 bw/fail-cloning-into-non-empty later to maint).
+
+ * With the base fix to 2.27 regresion, any new extensions in a v0
+ repository would still be silently honored, which is not quite
+ right. Instead, complain and die loudly.
+ (merge ec91ffca04 jk/reject-newer-extensions-in-v0 later to maint).
+
+ * Fetching from a lazily cloned repository resulted at the server
+ side in attempts to lazy fetch objects that the client side has,
+ many of which will not be available from the third-party anyway.
+ (merge 77aa0941ce jt/avoid-lazy-fetching-upon-have-check later to maint).
+
+ * Fix to an ancient bug caused by an over-eager attempt for
+ optimization.
+ (merge a98f7fb366 rs/add-index-entry-optim-fix later to maint).
+
+ * Pushing a ref whose name contains non-ASCII character with the
+ "--force-with-lease" option did not work over smart HTTP protocol,
+ which has been corrected.
+ (merge cd85b447bf bc/push-cas-cquoted-refname later to maint).
+
+ * "git mv src dst", when src is an unmerged path, errored out
+ correctly but with an incorrect error message to claim that src is
+ not tracked, which has been clarified.
+ (merge 9b906af657 ct/mv-unmerged-path-error later to maint).
+
+ * Fix to a regression introduced during 2.27 cycle.
+ (merge cada7308ad en/fill-directory-exponential later to maint).
+
+ * Command line completion (in contrib/) update.
+ (merge 688b87c81b mp/complete-show-color-moved later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+ (merge 84544f2ea3 sk/typofixes later to maint).
+ (merge b17f411ab5 ar/help-guides-doc later to maint).
+ (merge 98c6871fad rs/grep-simpler-parse-object-or-die-call later to maint).
+ (merge 861c4ce141 en/typofixes later to maint).
+ (merge 60e47f6773 sg/ci-git-path-fix-with-pyenv later to maint).
+ (merge e2bfa50ac3 jb/doc-packfile-name later to maint).
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index 4515cab..291b61e 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -3,8 +3,9 @@ Submitting Patches
== Guidelines
-Here are some guidelines for people who want to contribute their code
-to this software.
+Here are some guidelines for people who want to contribute their code to this
+software. There is also a link:MyFirstContribution.html[step-by-step tutorial]
+available which covers many of these same guidelines.
[[base-branch]]
=== Decide what to base your work on.
@@ -18,7 +19,7 @@ change is relevant to.
base your work on the tip of the topic.
* A new feature should be based on `master` in general. If the new
- feature depends on a topic that is in `pu`, but not in `master`,
+ feature depends on a topic that is in `seen`, but not in `master`,
base your work on the tip of that topic.
* Corrections and enhancements to a topic not yet in `master` should
@@ -27,7 +28,7 @@ change is relevant to.
into the series.
* In the exceptional case that a new feature depends on several topics
- not in `master`, start working on `next` or `pu` privately and send
+ not in `master`, start working on `next` or `seen` privately and send
out patches for discussion. Before the final merge, you may have to
wait until some of the dependent topics graduate to `master`, and
rebase your work.
@@ -37,7 +38,7 @@ change is relevant to.
these parts should be based on their trees.
To find the tip of a topic branch, run `git log --first-parent
-master..pu` and look for the merge commit. The second parent of this
+master..seen` and look for the merge commit. The second parent of this
commit is the tip of the topic branch.
[[separate-commits]]
@@ -423,7 +424,7 @@ help you find out who they are.
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 `pu`, in order to make it easier for
+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.
@@ -434,7 +435,7 @@ their trees themselves.
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 pu if you rebase on top of
+ tell you if your patch is merged in `seen` if you rebase on top of
master).
* Read the Git mailing list, the maintainer regularly posts messages
diff --git a/Documentation/config/diff.txt b/Documentation/config/diff.txt
index ff09f1c..c3ae136 100644
--- a/Documentation/config/diff.txt
+++ b/Documentation/config/diff.txt
@@ -105,6 +105,10 @@ diff.mnemonicPrefix::
diff.noprefix::
If set, 'git diff' does not show any source or destination prefix.
+diff.relative::
+ If set to 'true', 'git diff' does not show changes outside of the directory
+ and show pathnames relative to the current directory.
+
diff.orderFile::
File indicating how to order files within a diff.
See the '-O' option to linkgit:git-diff[1] for details.
diff --git a/Documentation/config/feature.txt b/Documentation/config/feature.txt
index 4e3a5c0..c0cbf2b 100644
--- a/Documentation/config/feature.txt
+++ b/Documentation/config/feature.txt
@@ -15,13 +15,9 @@ feature.experimental::
* `fetch.negotiationAlgorithm=skipping` may improve fetch negotiation times by
skipping more commits at a time, reducing the number of round trips.
+
-* `fetch.writeCommitGraph=true` writes a commit-graph after every `git fetch`
-command that downloads a pack-file from a remote. Using the `--split` option,
-most executions will create a very small commit-graph file on top of the
-existing commit-graph file(s). Occasionally, these files will merge and the
-write may take longer. Having an updated commit-graph file helps performance
-of many Git commands, including `git merge-base`, `git push -f`, and
-`git log --graph`.
+* `protocol.version=2` speeds up fetches from repositories with many refs by
+allowing the client to specify which refs to list before the server lists
+them.
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 b1a9b14..b203940 100644
--- a/Documentation/config/fetch.txt
+++ b/Documentation/config/fetch.txt
@@ -90,5 +90,4 @@ fetch.writeCommitGraph::
the existing commit-graph file(s). Occasionally, these files will
merge and the write may take longer. Having an updated commit-graph
file helps performance of many Git commands, including `git merge-base`,
- `git push -f`, and `git log --graph`. Defaults to false, unless
- `feature.experimental` is true.
+ `git push -f`, and `git log --graph`. Defaults to false.
diff --git a/Documentation/config/fmt-merge-msg.txt b/Documentation/config/fmt-merge-msg.txt
index c73cfa9..a8e8f74 100644
--- a/Documentation/config/fmt-merge-msg.txt
+++ b/Documentation/config/fmt-merge-msg.txt
@@ -8,3 +8,15 @@ merge.log::
most the specified number of one-line descriptions from the
actual commits that are being merged. Defaults to false, and
true is a synonym for 20.
+
+merge.suppressDest::
+ By adding a glob that matches the names of integration
+ branches to this multi-valued configuration variable, the
+ default merge message computed for merges into these
+ integration branches will omit " into <branch name>" from
+ its title.
++
+An element with an empty value can be used to clear the list
+of globs accumulated from previous configuration entries.
+When there is no `merge.suppressDest` variable defined, the
+default value of `master` is used for backward compatibility.
diff --git a/Documentation/config/init.txt b/Documentation/config/init.txt
index 46fa8c6..dc77f8c 100644
--- a/Documentation/config/init.txt
+++ b/Documentation/config/init.txt
@@ -1,3 +1,7 @@
init.templateDir::
Specify the directory from which templates will be copied.
(See the "TEMPLATE DIRECTORY" section of linkgit:git-init[1].)
+
+init.defaultBranch::
+ Allows overriding the default branch name e.g. when initializing
+ a new repository or when cloning an empty repository.
diff --git a/Documentation/config/protocol.txt b/Documentation/config/protocol.txt
index 0b40141..c46e9b3 100644
--- a/Documentation/config/protocol.txt
+++ b/Documentation/config/protocol.txt
@@ -48,7 +48,8 @@ protocol.version::
If set, clients will attempt to communicate with a server
using the specified protocol version. If the server does
not support it, communication falls back to version 0.
- If unset, the default is `0`.
+ If unset, the default is `0`, unless `feature.experimental`
+ is enabled, in which case the default is `2`.
Supported versions:
+
--
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index bb31f0c..7987d72 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -643,15 +643,18 @@ ifndef::git-format-patch[]
-R::
Swap two inputs; that is, show differences from index or
on-disk file to tree contents.
+endif::git-format-patch[]
--relative[=<path>]::
+--no-relative::
When run from a subdirectory of the project, it can be
told to exclude changes outside the directory and show
pathnames relative to it with this option. When you are
not in a subdirectory (e.g. in a bare repository), you
can name which subdirectory to make the output relative
to by giving a <path> as an argument.
-endif::git-format-patch[]
+ `--no-relative` can be used to countermand both `diff.relative` config
+ option and previous `--relative`.
-a::
--text::
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 135206f..03c0824 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -12,7 +12,7 @@ SYNOPSIS
[-v [--abbrev=<length> | --no-abbrev]]
[--column[=<options>] | --no-column] [--sort=<key>]
[(--merged | --no-merged) [<commit>]]
- [--contains [<commit]] [--no-contains [<commit>]]
+ [--contains [<commit>]] [--no-contains [<commit>]]
[--points-at <object>] [--format=<format>]
[(-r | --remotes) | (-a | --all)]
[--list] [<pattern>...]
diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
index 9edad66..66e88c2 100644
--- a/Documentation/git-bugreport.txt
+++ b/Documentation/git-bugreport.txt
@@ -29,6 +29,7 @@ The following information is captured automatically:
- uname sysname, release, version, and machine strings
- Compiler-specific info string
- A list of enabled hooks
+ - $SHELL
This tool is invoked via the typical Git setup process, which means that in some
cases, it might not be able to launch - for example, if a relevant config file
diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt
index 8eca671..8e192d8 100644
--- a/Documentation/git-cat-file.txt
+++ b/Documentation/git-cat-file.txt
@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git cat-file' (-t [--allow-unknown-type]| -s [--allow-unknown-type]| -e | -p | <type> | --textconv | --filters ) [--path=<path>] <object>
-'git cat-file' (--batch | --batch-check) [ --textconv | --filters ] [--follow-symlinks]
+'git cat-file' (--batch[=<format>] | --batch-check[=<format>]) [ --textconv | --filters ] [--follow-symlinks]
DESCRIPTION
-----------
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 08d6045..c898310 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -259,7 +259,7 @@ 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
provided, all submodules are initialized and cloned.
diff --git a/Documentation/git-commit-graph.txt b/Documentation/git-commit-graph.txt
index a3d9967..17405c7 100644
--- a/Documentation/git-commit-graph.txt
+++ b/Documentation/git-commit-graph.txt
@@ -47,8 +47,10 @@ with `--stdin-commits` or `--reachable`.)
+
With the `--stdin-commits` option, generate the new commit graph by
walking commits starting at the commits specified in stdin as a list
-of OIDs in hex, one OID per line. (Cannot be combined with
-`--stdin-packs` or `--reachable`.)
+of OIDs in hex, one OID per line. OIDs that resolve to non-commits
+(either directly, or by peeling tags) are silently ignored. OIDs that
+are malformed, or do not exist generate an error. (Cannot be combined
+with `--stdin-packs` or `--reachable`.)
+
With the `--reachable` option, generate the new commit graph by walking
commits starting at all refs. (Cannot be combined with `--stdin-commits`
@@ -60,7 +62,10 @@ existing commit-graph file.
With the `--changed-paths` option, compute and write information about the
paths changed between a commit and its first parent. This operation can
take a while on large repositories. It provides significant performance gains
-for getting history of a directory or a file with `git log -- <path>`.
+for getting history of a directory or a file with `git log -- <path>`. If
+this option is given, future commit-graph writes will automatically assume
+that this option was intended. Use `--no-changed-paths` to stop storing this
+data.
+
With the `--split[=<strategy>]` option, write the commit-graph as a
chain of multiple commit-graph files stored in
diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt
index 37781cf..727f24d 100644
--- a/Documentation/git-diff.txt
+++ b/Documentation/git-diff.txt
@@ -11,15 +11,17 @@ SYNOPSIS
[verse]
'git diff' [<options>] [<commit>] [--] [<path>...]
'git diff' [<options>] --cached [<commit>] [--] [<path>...]
-'git diff' [<options>] <commit> <commit> [--] [<path>...]
+'git diff' [<options>] <commit> [<commit>...] <commit> [--] [<path>...]
+'git diff' [<options>] <commit>...<commit> [--] [<path>...]
'git diff' [<options>] <blob> <blob>
'git diff' [<options>] --no-index [--] <path> <path>
DESCRIPTION
-----------
Show changes between the working tree and the index or a tree, changes
-between the index and a tree, changes between two trees, changes between
-two blob objects, or changes between two files on disk.
+between the index and a tree, changes between two trees, changes resulting
+from a merge, changes between two blob objects, or changes between two
+files on disk.
'git diff' [<options>] [--] [<path>...]::
@@ -61,9 +63,19 @@ two blob objects, or changes between two files on disk.
This is to view the changes between two arbitrary
<commit>.
+'git diff' [<options>] <commit> <commit>... <commit> [--] [<path>...]::
+
+ This form is to view the results of a merge commit. The first
+ listed <commit> must be the merge itself; the remaining two or
+ more commits should be its parents. A convenient way to produce
+ the desired set of revisions is to use the {caret}@ suffix.
+ For instance, if `master` names a merge commit, `git diff master
+ master^@` gives the same combined diff as `git show master`.
+
'git diff' [<options>] <commit>..<commit> [--] [<path>...]::
- This is synonymous to the previous form. If <commit> on
+ This is synonymous to the earlier form (without the "..") for
+ viewing the changes between two arbitrary <commit>. If <commit> on
one side is omitted, it will have the same effect as
using HEAD instead.
@@ -196,7 +208,8 @@ linkgit:git-difftool[1],
linkgit:git-log[1],
linkgit:gitdiffcore[7],
linkgit:git-format-patch[1],
-linkgit:git-apply[1]
+linkgit:git-apply[1],
+linkgit:git-show[1]
GIT
---
diff --git a/Documentation/git-fast-export.txt b/Documentation/git-fast-export.txt
index e8950de..1978dbd 100644
--- a/Documentation/git-fast-export.txt
+++ b/Documentation/git-fast-export.txt
@@ -119,6 +119,11 @@ by keeping the marks the same across runs.
the shape of the history and stored tree. See the section on
`ANONYMIZING` below.
+--anonymize-map=<from>[:<to>]::
+ Convert token `<from>` to `<to>` in the anonymized output. If
+ `<to>` is omitted, map `<from>` to itself (i.e., do not
+ anonymize it). See the section on `ANONYMIZING` below.
+
--reference-excluded-parents::
By default, running a command such as `git fast-export
master~5..master` will not include the commit master{tilde}5
@@ -238,6 +243,30 @@ collapse "User 0", "User 1", etc into "User X"). This produces a much
smaller output, and it is usually easy to quickly confirm that there is
no private data in the stream.
+Reproducing some bugs may require referencing particular commits or
+paths, which becomes challenging after refnames and paths have been
+anonymized. You can ask for a particular token to be left as-is or
+mapped to a new value. For example, if you have a bug which reproduces
+with `git rev-list sensitive -- secret.c`, you can run:
+
+---------------------------------------------------
+$ git fast-export --anonymize --all \
+ --anonymize-map=sensitive:foo \
+ --anonymize-map=secret.c:bar.c \
+ >stream
+---------------------------------------------------
+
+After importing the stream, you can then run `git rev-list foo -- bar.c`
+in the anonymized repository.
+
+Note that paths and refnames are split into tokens at slash boundaries.
+The command above would anonymize `subdir/secret.c` as something like
+`path123/bar.c`; you could then search for `bar.c` in the anonymized
+repository to determine the final pathname.
+
+To make referencing the final pathname simpler, you can map each path
+component; so if you also anonymize `subdir` to `publicdir`, then the
+final pathname would be `publicdir/bar.c`.
LIMITATIONS
-----------
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index 77c6b3d..7d9aad2 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -293,7 +293,14 @@ by users who are located in the same location and time zone. In this
case a reasonable offset from UTC could be assumed.
+
Unlike the `rfc2822` format, this format is very strict. Any
-variation in formatting will cause fast-import to reject the value.
+variation in formatting will cause fast-import to reject the value,
+and some sanity checks on the numeric values may also be performed.
+
+`raw-permissive`::
+ This is the same as `raw` except that no sanity checks on
+ the numeric epoch and local offset are performed. This can
+ be useful when trying to filter or import an existing history
+ with e.g. bogus timezone values.
`rfc2822`::
This is the standard email format as described by RFC 2822.
diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt
index 5b1909f..45b6d8e 100644
--- a/Documentation/git-fetch.txt
+++ b/Documentation/git-fetch.txt
@@ -255,14 +255,14 @@ refspec.
* Using refspecs explicitly:
+
------------------------------------------------
-$ git fetch origin +pu:pu maint:tmp
+$ git fetch origin +seen:seen maint:tmp
------------------------------------------------
+
-This updates (or creates, as necessary) branches `pu` and `tmp` in
+This updates (or creates, as necessary) branches `seen` and `tmp` in
the local repository by fetching from the branches (respectively)
-`pu` and `maint` from the remote repository.
+`seen` and `maint` from the remote repository.
+
-The `pu` branch will be updated even if it does not fast-forward,
+The `seen` branch will be updated even if it does not fast-forward,
because it is prefixed with a plus sign; `tmp` will not be.
* Peek at a remote's branch, without configuring the remote in your local
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 6dcd39f..2ea71c5 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -232,12 +232,27 @@ 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.
-The complete message in a commit and tag object is `contents`.
-Its first line is `contents:subject`, where subject is the concatenation
-of all lines of the commit message up to the first blank line. The next
-line is `contents:body`, where body is all of the lines after the first
-blank line. The optional GPG signature is `contents:signature`. The
-first `N` lines of the message is obtained using `contents:lines=N`.
+The message in a commit or a tag object is `contents`, from which
+`contents:<part>` can be used to extract various parts out of:
+
+contents:size::
+ The size in bytes of the commit or tag message.
+
+contents:subject::
+ The first paragraph of the message, which typically is a
+ single line, is taken as the "subject" of the commit or the
+ tag message.
+
+contents:body::
+ The remainder of the commit or the tag message that follows
+ the "subject".
+
+contents:signature::
+ The optional GPG signature of the tag.
+
+contents:lines=N::
+ The first `N` lines of the message.
+
Additionally, the trailers as interpreted by linkgit:git-interpret-trailers[1]
are obtained as `trailers` (or by using the historical alias
`contents:trailers`). Non-trailer lines from the trailer block can be omitted
diff --git a/Documentation/git-help.txt b/Documentation/git-help.txt
index f71db0d..69c0c5c 100644
--- a/Documentation/git-help.txt
+++ b/Documentation/git-help.txt
@@ -8,7 +8,7 @@ git-help - Display help information about Git
SYNOPSIS
--------
[verse]
-'git help' [-a|--all [--[no-]verbose]] [-g|--guide]
+'git help' [-a|--all [--[no-]verbose]] [-g|--guides]
[-i|--info|-m|--man|-w|--web] [COMMAND|GUIDE]
DESCRIPTION
@@ -21,7 +21,7 @@ on the standard output.
If the option `--all` or `-a` is given, all available commands are
printed on the standard output.
-If the option `--guide` or `-g` is given, a list of the useful
+If the option `--guides` or `-g` is given, a list of the useful
Git guides is also printed on the standard output.
If a command, or a guide, is given, a manual page for that command or
diff --git a/Documentation/git-http-fetch.txt b/Documentation/git-http-fetch.txt
index 666b042..4deb489 100644
--- a/Documentation/git-http-fetch.txt
+++ b/Documentation/git-http-fetch.txt
@@ -9,7 +9,7 @@ git-http-fetch - Download from a remote Git repository via HTTP
SYNOPSIS
--------
[verse]
-'git http-fetch' [-c] [-t] [-a] [-d] [-v] [-w filename] [--recover] [--stdin] <commit> <url>
+'git http-fetch' [-c] [-t] [-a] [-d] [-v] [-w filename] [--recover] [--stdin | --packfile=<hash> | <commit>] <url>
DESCRIPTION
-----------
@@ -40,6 +40,13 @@ commit-id::
<commit-id>['\t'<filename-as-in--w>]
+--packfile=<hash>::
+ Instead of a commit id on the command line (which is not expected in
+ this case), 'git http-fetch' fetches the packfile directly at the given
+ URL and uses index-pack to generate corresponding .idx and .keep files.
+ The hash is used to determine the name of the temporary file and is
+ arbitrary. The output of index-pack is printed to stdout.
+
--recover::
Verify that everything reachable from target is fetched. Used after
an earlier fetch is interrupted.
diff --git a/Documentation/git-index-pack.txt b/Documentation/git-index-pack.txt
index d5b7560..ac74d05 100644
--- a/Documentation/git-index-pack.txt
+++ b/Documentation/git-index-pack.txt
@@ -93,11 +93,19 @@ OPTIONS
--max-input-size=<size>::
Die, if the pack is larger than <size>.
+--object-format=<hash-algorithm>::
+ Specify the given object format (hash algorithm) for the pack. The valid
+ values are 'sha1' and (if enabled) 'sha256'. The default is the algorithm for
+ the current repository (set by `extensions.objectFormat`), or 'sha1' if no
+ value is set or outside a repository.
++
+This option cannot be used with --stdin.
+
NOTES
-----
-Once the index has been created, the list of object names is sorted
-and the SHA-1 hash of that list is printed to stdout. If --stdin was
+Once the index has been created, the hash that goes into the name of
+the pack/idx file is printed to stdout. If --stdin was
also used then this is prefixed by either "pack\t", or "keep\t" if a
new .keep file was successfully created. This is useful to remove a
.keep file used as a lock to prevent the race with 'git repack'
diff --git a/Documentation/git-init.txt b/Documentation/git-init.txt
index adc6adf..ddfe265 100644
--- a/Documentation/git-init.txt
+++ b/Documentation/git-init.txt
@@ -10,7 +10,8 @@ SYNOPSIS
--------
[verse]
'git init' [-q | --quiet] [--bare] [--template=<template_directory>]
- [--separate-git-dir <git dir>] [--object-format=<format]
+ [--separate-git-dir <git dir>] [--object-format=<format>]
+ [-b <branch-name> | --initial-branch=<branch-name>]
[--shared[=<permissions>]] [directory]
@@ -67,6 +68,12 @@ repository.
+
If this is 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 repository.
+If not specified, fall back to the default name: `master`.
+
--shared[=(false|true|umask|group|all|world|everybody|0xxx)]::
Specify that the Git repository is to be shared amongst several users. This
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index 20e6d21..3fd26d5 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -15,9 +15,12 @@ DESCRIPTION
-----------
Shows the commit logs.
-The command takes options applicable to the `git rev-list`
+:git-log: 1
+include::rev-list-description.txt[]
+
+The command takes options applicable to the linkgit:git-rev-list[1]
command to control what is shown and how, and options applicable to
-the `git diff-*` commands to control how the changes
+the linkgit:git-diff[1] command to control how the changes
each commit introduces are shown.
diff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt
index 0a5c8b7..492e573 100644
--- a/Documentation/git-ls-remote.txt
+++ b/Documentation/git-ls-remote.txt
@@ -101,9 +101,9 @@ f25a265a342aed6041ab0cc484224d9ca54b6f41 refs/tags/v0.99.1
7ceca275d047c90c0c7d5afb13ab97efdf51bd6e refs/tags/v0.99.3
c5db5456ae3b0873fc659c19fafdde22313cc441 refs/tags/v0.99.2
0918385dbd9656cab0d1d81ba7453d49bbc16250 refs/tags/junio-gpg-pub
-$ git ls-remote http://www.kernel.org/pub/scm/git/git.git master pu rc
+$ git ls-remote http://www.kernel.org/pub/scm/git/git.git master seen rc
5fe978a5381f1fbad26a80e682ddd2a401966740 refs/heads/master
-c781a84b5204fb294c9ccc79f8b3baceeb32c061 refs/heads/pu
+c781a84b5204fb294c9ccc79f8b3baceeb32c061 refs/heads/seen
$ git remote add korg http://www.kernel.org/pub/scm/git/git.git
$ git ls-remote --tags korg v\*
d6602ec5194c87b0fc87103ca4d67251c76f233a refs/tags/v0.99
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 4624cfd..374d248 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -259,7 +259,7 @@ See also INCOMPATIBLE OPTIONS below.
unchanged as a result. If a temporary stash entry was created
using --autostash, it will be saved to the stash list.
---apply:
+--apply::
Use applying strategies to rebase (calling `git-am`
internally). This option may become a no-op in the future
once the merge backend handles everything the apply one does.
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
index 025c911..5da6623 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -14,44 +14,8 @@ SYNOPSIS
DESCRIPTION
-----------
-List commits that are reachable by following the `parent` links from the
-given commit(s), but exclude commits that are reachable from the one(s)
-given with a '{caret}' in front of them. The output is given in reverse
-chronological order by default.
-
-You can think of this as a set operation. Commits given on the command
-line form a set of commits that are reachable from any of them, and then
-commits reachable from any of the ones given with '{caret}' in front are
-subtracted from that set. The remaining commits are what comes out in the
-command's output. Various other options and paths parameters can be used
-to further limit the result.
-
-Thus, the following command:
-
------------------------------------------------------------------------
- $ git rev-list foo bar ^baz
------------------------------------------------------------------------
-
-means "list all the commits which are reachable from 'foo' or 'bar', but
-not from 'baz'".
-
-A special notation "'<commit1>'..'<commit2>'" can be used as a
-short-hand for "{caret}'<commit1>' '<commit2>'". For example, either of
-the following may be used interchangeably:
-
------------------------------------------------------------------------
- $ git rev-list origin..HEAD
- $ git rev-list HEAD ^origin
------------------------------------------------------------------------
-
-Another special notation is "'<commit1>'...'<commit2>'" which is useful
-for merges. The resulting set of commits is the symmetric difference
-between the two operands. The following two commands are equivalent:
-
------------------------------------------------------------------------
- $ git rev-list A B --not $(git merge-base --all A B)
- $ git rev-list A...B
------------------------------------------------------------------------
+:git-rev-list: 1
+include::rev-list-description.txt[]
'rev-list' is a very essential Git command, since it
provides the ability to build and traverse commit ancestry graphs. For
diff --git a/Documentation/git-show-index.txt b/Documentation/git-show-index.txt
index 424e4ba..39b1d8e 100644
--- a/Documentation/git-show-index.txt
+++ b/Documentation/git-show-index.txt
@@ -9,7 +9,7 @@ git-show-index - Show packed archive index
SYNOPSIS
--------
[verse]
-'git show-index'
+'git show-index' [--object-format=<hash-algorithm>]
DESCRIPTION
@@ -36,6 +36,15 @@ Note that you can get more information on a packfile by calling
linkgit:git-verify-pack[1]. However, as this command considers only the
index file itself, it's both faster and more flexible.
+OPTIONS
+-------
+
+--object-format=<hash-algorithm>::
+ Specify the given object format (hash algorithm) for the index file. The
+ valid values are 'sha1' and (if enabled) 'sha256'. The default is the
+ algorithm for the current repository (set by `extensions.objectFormat`), or
+ 'sha1' if no value is set or outside a repository..
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-sparse-checkout.txt b/Documentation/git-sparse-checkout.txt
index 7c8943a..a0eeaeb 100644
--- a/Documentation/git-sparse-checkout.txt
+++ b/Documentation/git-sparse-checkout.txt
@@ -200,10 +200,32 @@ directory.
SUBMODULES
----------
-If your repository contains one or more submodules, then those submodules will
-appear based on which you initialized with the `git submodule` command. If
-your sparse-checkout patterns exclude an initialized submodule, then that
-submodule will still appear in your working directory.
+If your repository contains one or more submodules, then submodules
+are populated based on interactions with the `git submodule` command.
+Specifically, `git submodule init -- <path>` will ensure the submodule
+at `<path>` is present, while `git submodule deinit [-f] -- <path>`
+will remove the files for the submodule at `<path>` (including any
+untracked files, uncommitted changes, and unpushed history). Similar
+to how sparse-checkout removes files from the working tree but still
+leaves entries in the index, deinitialized submodules are removed from
+the working directory but still have an entry in the index.
+
+Since submodules may have unpushed changes or untracked files,
+removing them could result in data loss. Thus, changing sparse
+inclusion/exclusion rules will not cause an already checked out
+submodule to be removed from the working copy. Said another way, just
+as `checkout` will not cause submodules to be automatically removed or
+initialized even when switching between branches that remove or add
+submodules, using `sparse-checkout` to reduce or expand the scope of
+"interesting" files will not cause submodules to be automatically
+deinitialized or initialized either.
+
+Further, the above facts mean that there are multiple reasons that
+"tracked" files might not be present in the working copy: sparsity
+pattern application from sparse-checkout, and submodule initialization
+state. Thus, commands like `git grep` that work on tracked files in
+the working copy may return results that are limited by either or both
+of these restrictions.
SEE ALSO
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index c9ed2bf..7e5f995 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -183,7 +183,7 @@ set-branch (-d|--default) [--] <path>::
Sets the default remote tracking branch for the submodule. The
`--branch` option allows the remote branch to be specified. The
`--default` option removes the submodule.<name>.branch configuration
- key, which causes the tracking branch to default to 'master'.
+ key, which causes the tracking branch to default to the remote 'HEAD'.
set-url [--] <path> <newurl>::
Sets the URL of the specified submodule to <newurl>. Then, it will
@@ -284,7 +284,7 @@ OPTIONS
`.gitmodules` for `update --remote`. A special value of `.` is used to
indicate that the name of the branch in the submodule should be the
same name as the current branch in the current repository. If the
- option is not specified, it defaults to 'master'.
+ option is not specified, it defaults to the remote 'HEAD'.
-f::
--force::
@@ -322,10 +322,10 @@ OPTIONS
the superproject's recorded SHA-1 to update the submodule, use the
status of the submodule's remote-tracking branch. The remote used
is branch's remote (`branch.<name>.remote`), defaulting to `origin`.
- The remote branch used defaults to `master`, but the branch name may
- be overridden by setting the `submodule.<name>.branch` option in
- either `.gitmodules` or `.git/config` (with `.git/config` taking
- precedence).
+ The remote branch used defaults to the remote `HEAD`, but the branch
+ name may be overridden by setting the `submodule.<name>.branch`
+ option in either `.gitmodules` or `.git/config` (with `.git/config`
+ taking precedence).
+
This works for any of the supported update procedures (`--checkout`,
`--rebase`, etc.). The only change is the source of the target SHA-1.
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 85d92c9..4796c3c 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -126,7 +126,9 @@ OPTIONS
locked working tree path, specify `--force` twice.
+
`move` refuses to move a locked working tree unless `--force` is specified
-twice.
+twice. If the destination is already assigned to some other working tree but is
+missing (for instance, if `<new-path>` was deleted manually), then `--force`
+allows the move to proceed; use --force twice if the destination is locked.
+
`remove` refuses to remove an unclean working tree unless `--force` is used.
To remove a locked working tree, specify `--force` twice.
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 1289084..3e50065 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -721,8 +721,6 @@ of clones and fetches.
Enables a curl full trace dump of all incoming and outgoing data,
including descriptive information, of the git transport protocol.
This is similar to doing curl `--trace-ascii` on the command line.
- This option overrides setting the `GIT_CURL_VERBOSE` environment
- variable.
See `GIT_TRACE` for available trace output options.
`GIT_TRACE_CURL_NO_DATA`::
@@ -777,11 +775,10 @@ for full details.
See `GIT_TRACE2` for available trace output options and
link:technical/api-trace2.html[Trace2 documentation] for full details.
-`GIT_REDACT_COOKIES`::
- This can be set to a comma-separated list of strings. When a curl trace
- is enabled (see `GIT_TRACE_CURL` above), whenever a "Cookies:" header
- sent by the client is dumped, values of cookies whose key is in that
- list (case-sensitive) are redacted.
+`GIT_TRACE_REDACT`::
+ By default, when tracing is activated, Git redacts the values of
+ cookies, the "Authorization:" header, and the "Proxy-Authorization:"
+ header. Set this variable to `0` to prevent this redaction.
`GIT_LITERAL_PATHSPECS`::
Setting this variable to `1` will cause Git to treat all
diff --git a/Documentation/giteveryday.txt b/Documentation/giteveryday.txt
index 1bd919f..faba2ef 100644
--- a/Documentation/giteveryday.txt
+++ b/Documentation/giteveryday.txt
@@ -278,13 +278,13 @@ $ git am -3 -i -s ./+to-apply <4>
$ compile/test
$ git switch -c hold/linus && git am -3 -i -s ./+hold-linus <5>
$ git switch topic/one && git rebase master <6>
-$ git switch -C pu next <7>
+$ git switch -C seen next <7>
$ git merge topic/one topic/two && git merge hold/linus <8>
$ git switch maint
$ git cherry-pick master~4 <9>
$ compile/test
$ git tag -s -m "GIT 0.99.9x" v0.99.9x <10>
-$ git fetch ko && for branch in master maint next pu <11>
+$ git fetch ko && for branch in master maint next seen <11>
do
git show-branch ko/$branch $branch <12>
done
@@ -294,14 +294,14 @@ $ git push --follow-tags ko <13>
<1> see what you were in the middle of doing, if anything.
<2> see which branches haven't been merged into `master` yet.
Likewise for any other integration branches e.g. `maint`, `next`
-and `pu` (potential updates).
+and `seen`.
<3> read mails, save ones that are applicable, and save others
that are not quite ready (other mail readers are available).
<4> apply them, interactively, with your sign-offs.
<5> create topic branch as needed and apply, again with sign-offs.
<6> rebase internal topic branch that has not been merged to the
master or exposed as a part of a stable branch.
-<7> restart `pu` every time from the next.
+<7> restart `seen` every time from the next.
<8> and bundle topic branches still cooking.
<9> backport a critical fix.
<10> create a signed tag.
@@ -323,7 +323,7 @@ repository at kernel.org, and looks like this:
fetch = refs/heads/*:refs/remotes/ko/*
push = refs/heads/master
push = refs/heads/next
- push = +refs/heads/pu
+ push = +refs/heads/seen
push = refs/heads/maint
------------
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index 81f2a87..31b601e 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -404,6 +404,35 @@ Both standard output and standard error output are forwarded to
`git send-pack` on the other end, so you can simply `echo` messages
for the user.
+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 takes exactly one argument, which is the current state the
+given reference transaction is in:
+
+ - "prepared": All reference updates have been queued to the
+ transaction and references were locked on disk.
+
+ - "committed": The reference transaction was committed and all
+ references now have their respective new value.
+
+ - "aborted": The reference transaction was aborted, no changes
+ were performed and the locks have been released.
+
+For each reference update that was added to the transaction, the hook
+receives on standard input a line of the format:
+
+ <old-value> SP <new-value> SP <ref-name> LF
+
+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
+"aborted" state in that case.
+
push-to-checkout
~~~~~~~~~~~~~~~~
diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt
index 67275fd..539b4e1 100644
--- a/Documentation/gitmodules.txt
+++ b/Documentation/gitmodules.txt
@@ -49,9 +49,9 @@ submodule.<name>.update::
submodule.<name>.branch::
A remote branch name for tracking updates in the upstream submodule.
- If the option is not specified, it defaults to 'master'. A special
- value of `.` is used to indicate that the name of the branch in the
- submodule should be the same name as the current branch in the
+ If the option is not specified, it defaults to the remote 'HEAD'.
+ A special value of `.` is used to indicate that the name of the branch
+ in the submodule should be the same name as the current branch in the
current repository. See the `--remote` documentation in
linkgit:git-submodule[1] for details.
diff --git a/Documentation/gitremote-helpers.txt b/Documentation/gitremote-helpers.txt
index f48a031..6f1e269 100644
--- a/Documentation/gitremote-helpers.txt
+++ b/Documentation/gitremote-helpers.txt
@@ -238,6 +238,9 @@ the remote repository.
`--signed-tags=verbatim` to linkgit:git-fast-export[1]. In the
absence of this capability, Git will use `--signed-tags=warn-strip`.
+'object-format'::
+ This indicates that the helper is able to interact with the remote
+ side using an explicit hash algorithm extension.
COMMANDS
@@ -257,12 +260,14 @@ Support for this command is mandatory.
'list'::
Lists the refs, one per line, in the format "<value> <name>
[<attr> ...]". The value may be a hex sha1 hash, "@<dest>" for
- a symref, or "?" to indicate that the helper could not get the
- value of the ref. A space-separated list of attributes follows
- the name; unrecognized attributes are ignored. The list ends
- with a blank line.
+ a symref, ":<keyword> <value>" for a key-value pair, or
+ "?" to indicate that the helper could not get the value of the
+ ref. A space-separated list of attributes follows the name;
+ unrecognized attributes are ignored. The list ends with a
+ blank line.
+
See REF LIST ATTRIBUTES for a list of currently defined attributes.
+See REF LIST KEYWORDS for a list of currently defined keywords.
+
Supported if the helper has the "fetch" or "import" capability.
@@ -405,7 +410,9 @@ Supported if the helper has the "connect" capability.
trying to fall back). After line feed terminating the positive
(empty) response, the output of the service starts. Messages
(both request and response) must consist of zero or more
- PKT-LINEs, terminating in a flush packet. The client must not
+ PKT-LINEs, terminating in a flush packet. Response messages will
+ then have a response end packet after the flush packet to
+ indicate the end of a response. The client must not
expect the server to store any state in between request-response
pairs. After the connection ends, the remote helper exits.
+
@@ -430,6 +437,18 @@ attributes are defined.
This ref is unchanged since the last import or fetch, although
the helper cannot necessarily determine what value that produced.
+REF LIST KEYWORDS
+-----------------
+
+The 'list' command may produce a list of key-value pairs.
+The following keys are defined.
+
+'object-format'::
+ The refs are using the given hash algorithm. This keyword is only
+ used if the server and client both support the object-format
+ extension.
+
+
OPTIONS
-------
@@ -514,6 +533,14 @@ 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
+ 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
--------
linkgit:git-remote[1]
diff --git a/Documentation/gitworkflows.txt b/Documentation/gitworkflows.txt
index abc0dc6..47cf97f 100644
--- a/Documentation/gitworkflows.txt
+++ b/Documentation/gitworkflows.txt
@@ -85,15 +85,15 @@ As a given feature goes from experimental to stable, it also
There is a fourth official branch that is used slightly differently:
-* 'pu' (proposed updates) is an integration branch for things that are
- not quite ready for inclusion yet (see "Integration Branches"
- below).
+* 'seen' (patches seen by the maintainer) is an integration branch for
+ things that are not quite ready for inclusion yet (see "Integration
+ Branches" below).
Each of the four branches is usually a direct descendant of the one
above it.
Conceptually, the feature enters at an unstable branch (usually 'next'
-or 'pu'), and "graduates" to 'master' for the next release once it is
+or 'seen'), and "graduates" to 'master' for the next release once it is
considered stable enough.
@@ -207,7 +207,7 @@ If you make it (very) clear that this branch is going to be deleted
right after the testing, you can even publish this branch, for example
to give the testers a chance to work with it, or other developers a
chance to see if their in-progress work will be compatible. `git.git`
-has such an official throw-away integration branch called 'pu'.
+has such an official throw-away integration branch called 'seen'.
Branch management for a release
@@ -291,8 +291,8 @@ This will not happen if the content of the branches was verified as
described in the previous section.
-Branch management for next and pu after a feature release
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Branch management for next and seen after a feature release
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
After a feature release, the integration branch 'next' may optionally be
rewound and rebuilt from the tip of 'master' using the surviving
@@ -319,8 +319,8 @@ so.
If you do this, then you should make a public announcement indicating
that 'next' was rewound and rebuilt.
-The same rewind and rebuild process may be followed for 'pu'. A public
-announcement is not necessary since 'pu' is a throw-away branch, as
+The same rewind and rebuild process may be followed for 'seen'. A public
+announcement is not necessary since 'seen' is a throw-away branch, as
described above.
diff --git a/Documentation/howto/maintain-git.txt b/Documentation/howto/maintain-git.txt
index 73be8b4..a67130d 100644
--- a/Documentation/howto/maintain-git.txt
+++ b/Documentation/howto/maintain-git.txt
@@ -66,7 +66,7 @@ this mailing list after each feature release is made.
demonstrated to be regression free. New changes are tested
in 'next' before merged to 'master'.
- - 'pu' branch is used to publish other proposed changes that do
+ - 'seen' branch is used to publish other proposed changes that do
not yet pass the criteria set for 'next'.
- The tips of 'master' and 'maint' branches will not be rewound to
@@ -76,7 +76,7 @@ this mailing list after each feature release is made.
of the cycle.
- Usually 'master' contains all of 'maint' and 'next' contains all
- of 'master'. 'pu' contains all the topics merged to 'next', but
+ of 'master'. 'seen' contains all the topics merged to 'next', but
is rebuilt directly on 'master'.
- The tip of 'master' is meant to be more stable than any
@@ -229,12 +229,12 @@ by doing the following:
series?)
- Prepare 'jch' branch, which is used to represent somewhere
- between 'master' and 'pu' and often is slightly ahead of 'next'.
+ between 'master' and 'seen' and often is slightly ahead of 'next'.
- $ Meta/Reintegrate master..pu >Meta/redo-jch.sh
+ $ Meta/Reintegrate master..seen >Meta/redo-jch.sh
The result is a script that lists topics to be merged in order to
- rebuild 'pu' as the input to Meta/Reintegrate script. Remove
+ 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.
@@ -291,29 +291,29 @@ by doing the following:
merged to 'master'. This may lose '### match next' marker;
add it again to the appropriate place when it happens.
- - Rebuild 'pu'.
+ - Rebuild 'seen'.
- $ Meta/Reintegrate master..pu >Meta/redo-pu.sh
+ $ Meta/Reintegrate master..seen >Meta/redo-seen.sh
- Edit the result by adding new topics that are not still in 'pu'
+ Edit the result by adding new topics that are not still in 'seen'
in the script. Then
- $ git checkout -B pu jch
- $ sh Meta/redo-pu.sh
+ $ git checkout -B seen jch
+ $ sh Meta/redo-seen.sh
- When all is well, clean up the redo-pu.sh script with
+ When all is well, clean up the redo-seen.sh script with
- $ sh Meta/redo-pu.sh -u
+ $ sh Meta/redo-seen.sh -u
Double check by running
- $ git branch --no-merged pu
+ $ git branch --no-merged seen
to see there is no unexpected leftover topics.
At this point, build-test the result for semantic conflicts, and
if there are, prepare an appropriate merge-fix first (see
- appendix), and rebuild the 'pu' branch from scratch, starting at
+ appendix), and rebuild the 'seen' branch from scratch, starting at
the tip of 'jch'.
- Update "What's cooking" message to review the updates to
@@ -323,14 +323,14 @@ by doing the following:
$ Meta/cook
- This script inspects the history between master..pu, finds tips
+ This script inspects the history between master..seen, finds tips
of topic branches, compares what it found with the current
contents in Meta/whats-cooking.txt, and updates that file.
- Topics not listed in the file but are found in master..pu are
+ Topics not listed in the file but are found in master..seen are
added to the "New topics" section, topics listed in the file that
- are no longer found in master..pu are moved to the "Graduated to
+ are no longer found in master..seen are moved to the "Graduated to
master" section, and topics whose commits changed their states
- (e.g. used to be only in 'pu', now merged to 'next') are updated
+ (e.g. used to be only in 'seen', now merged to 'next') are updated
with change markers "<<" and ">>".
Look for lines enclosed in "<<" and ">>"; they hold contents from
@@ -360,7 +360,7 @@ Observations
Some observations to be made.
* Each topic is tested individually, and also together with other
- topics cooking first in 'pu', then in 'jch' and then in 'next'.
+ topics cooking first in 'seen', then in 'jch' and then in 'next'.
Until it matures, no part of it is merged to 'master'.
* A topic already in 'next' can get fixes while still in
@@ -411,7 +411,7 @@ 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-pu
+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.
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
@@ -431,14 +431,14 @@ commit that can be squashed into a result of mechanical merge to
correct semantic conflicts.
After finding that the result of merging branch "ai/topic" to an
-integration branch had such a semantic conflict, say pu~4, check the
+integration branch had such a semantic conflict, say seen~4, check the
problematic merge out on a detached HEAD, edit the working tree to
fix the semantic conflict, and make a separate commit to record the
fix-up:
- $ git checkout pu~4
+ $ git checkout seen~4
$ git show -s --pretty=%s ;# double check
- Merge branch 'ai/topic' to pu
+ Merge branch 'ai/topic' to seen
$ edit
$ git commit -m 'merge-fix/ai/topic' -a
@@ -450,9 +450,9 @@ result:
Then double check the result by asking Meta/Reintegrate to redo the
merge:
- $ git checkout pu~5 ;# the parent of the problem merge
+ $ git checkout seen~5 ;# the parent of the problem merge
$ echo ai/topic | Meta/Reintegrate
- $ git diff pu~4
+ $ git diff seen~4
This time, because you prepared refs/merge-fix/ai/topic, the
resulting merge should have been tweaked to include the fix for the
@@ -464,7 +464,7 @@ branch needs this merge-fix is because another branch merged earlier
to the integration branch changed the underlying assumption ai/topic
branch made (e.g. ai/topic branch added a site to refer to a
variable, while the other branch renamed that variable and adjusted
-existing use sites), and if you changed redo-jch (or redo-pu) script
+existing use sites), and if you changed redo-jch (or redo-seen) script
to merge ai/topic branch before the other branch, then the above
merge-fix should not be applied while merging ai/topic, but should
instead be applied while merging the other branch. You would need
diff --git a/Documentation/howto/rebase-from-internal-branch.txt b/Documentation/howto/rebase-from-internal-branch.txt
index 02cb5f7..f2e10a7 100644
--- a/Documentation/howto/rebase-from-internal-branch.txt
+++ b/Documentation/howto/rebase-from-internal-branch.txt
@@ -4,7 +4,7 @@ Cc: Petr Baudis <pasky@suse.cz>, Linus Torvalds <torvalds@osdl.org>
Subject: Re: sending changesets from the middle of a git tree
Date: Sun, 14 Aug 2005 18:37:39 -0700
Abstract: In this article, JC talks about how he rebases the
- public "pu" branch using the core Git tools when he updates
+ public "seen" branch using the core Git tools when he updates
the "master" branch, and how "rebase" works. Also discussed
is how this applies to individual developers who sends patches
upstream.
@@ -20,8 +20,8 @@ Petr Baudis <pasky@suse.cz> writes:
> where Junio C Hamano <junkio@cox.net> told me that...
>> Linus Torvalds <torvalds@osdl.org> writes:
>>
->> > Junio, maybe you want to talk about how you move patches from your "pu"
->> > branch to the real branches.
+>> > Junio, maybe you want to talk about how you move patches from your
+>> > "seen" branch to the real branches.
>>
> Actually, wouldn't this be also precisely for what StGIT is intended to?
--------------------------------------
@@ -33,12 +33,12 @@ the kind of task StGIT is designed to do.
I just have done a simpler one, this time using only the core
Git tools.
-I had a handful of commits that were ahead of master in pu, and I
+I had a handful of commits that were ahead of master in 'seen', and I
wanted to add some documentation bypassing my usual habit of
-placing new things in pu first. At the beginning, the commit
+placing new things in 'seen' first. At the beginning, the commit
ancestry graph looked like this:
- *"pu" head
+ *"seen" head
master --> #1 --> #2 --> #3
So I started from master, made a bunch of edits, and committed:
@@ -50,7 +50,7 @@ So I started from master, made a bunch of edits, and committed:
After the commit, the ancestry graph would look like this:
- *"pu" head
+ *"seen" head
master^ --> #1 --> #2 --> #3
\
\---> master
@@ -58,31 +58,31 @@ After the commit, the ancestry graph would look like this:
The old master is now master^ (the first parent of the master).
The new master commit holds my documentation updates.
-Now I have to deal with "pu" branch.
+Now I have to deal with "seen" branch.
This is the kind of situation I used to have all the time when
Linus was the maintainer and I was a contributor, when you look
-at "master" branch being the "maintainer" branch, and "pu"
+at "master" branch being the "maintainer" branch, and "seen"
branch being the "contributor" branch. Your work started at the
tip of the "maintainer" branch some time ago, you made a lot of
progress in the meantime, and now the maintainer branch has some
other commits you do not have yet. And "git rebase" was written
with the explicit purpose of helping to maintain branches like
-"pu". You _could_ merge master to pu and keep going, but if you
+"seen". You _could_ merge master to 'seen' and keep going, but if you
eventually want to cherrypick and merge some but not necessarily
all changes back to the master branch, it often makes later
operations for _you_ easier if you rebase (i.e. carry forward
-your changes) "pu" rather than merge. So I ran "git rebase":
+your changes) "seen" rather than merge. So I ran "git rebase":
- $ git checkout pu
- $ git rebase master pu
+ $ git checkout seen
+ $ git rebase master seen
What this does is to pick all the commits since the current
-branch (note that I now am on "pu" branch) forked from the
+branch (note that I now am on "seen" branch) forked from the
master branch, and forward port these changes.
master^ --> #1 --> #2 --> #3
- \ *"pu" head
+ \ *"seen" head
\---> master --> #1' --> #2' --> #3'
The diff between master^ and #1 is applied to master and
@@ -92,7 +92,7 @@ commits are made similarly out of #2 and #3 commits.
Old #3 is not recorded in any of the .git/refs/heads/ file
anymore, so after doing this you will have dangling commit if
-you ran fsck-cache, which is normal. After testing "pu", you
+you ran fsck-cache, which is normal. After testing "seen", you
can run "git prune" to get rid of those original three commits.
While I am talking about "git rebase", I should talk about how
diff --git a/Documentation/howto/revert-branch-rebase.txt b/Documentation/howto/revert-branch-rebase.txt
index 149508e..a3e5595 100644
--- a/Documentation/howto/revert-branch-rebase.txt
+++ b/Documentation/howto/revert-branch-rebase.txt
@@ -15,7 +15,7 @@ One of the changes I pulled into the 'master' branch turns out to
break building Git with GCC 2.95. While they were well-intentioned
portability fixes, keeping things working with gcc-2.95 was also
important. Here is what I did to revert the change in the 'master'
-branch and to adjust the 'pu' branch, using core Git tools and
+branch and to adjust the 'seen' branch, using core Git tools and
barebone Porcelain.
First, prepare a throw-away branch in case I screw things up.
@@ -104,11 +104,11 @@ $ git diff master..revert-c99
says nothing.
-Then we rebase the 'pu' branch as usual.
+Then we rebase the 'seen' branch as usual.
------------------------------------------------
-$ git checkout pu
-$ git tag pu-anchor pu
+$ git checkout seen
+$ git tag seen-anchor seen
$ git rebase master
* Applying: Redo "revert" using three-way merge machinery.
First trying simple merge strategy to cherry-pick.
@@ -127,11 +127,11 @@ First trying simple merge strategy to cherry-pick.
First trying simple merge strategy to cherry-pick.
------------------------------------------------
-The temporary tag 'pu-anchor' is me just being careful, in case 'git
+The temporary tag 'seen-anchor' is me just being careful, in case 'git
rebase' screws up. After this, I can do these for sanity check:
------------------------------------------------
-$ git diff pu-anchor..pu ;# make sure we got the master fix.
+$ git diff seen-anchor..seen ;# make sure we got the master fix.
$ make CC=gcc-2.95 clean test ;# make sure it fixed the breakage.
$ make clean test ;# make sure it did not cause other breakage.
------------------------------------------------
@@ -140,7 +140,7 @@ Everything is in the good order. I do not need the temporary branch
or tag anymore, so remove them:
------------------------------------------------
-$ rm -f .git/refs/tags/pu-anchor
+$ rm -f .git/refs/tags/seen-anchor
$ git branch -d revert-c99
------------------------------------------------
@@ -168,18 +168,18 @@ Committed merge 7fb9b7262a1d1e0a47bbfdcbbcf50ce0635d3f8f
And the final repository status looks like this:
------------------------------------------------
-$ git show-branch --more=1 master pu rc
+$ git show-branch --more=1 master seen rc
! [master] Revert "Replace zero-length array decls with []."
- ! [pu] git-repack: Add option to repack all objects.
+ ! [seen] git-repack: Add option to repack all objects.
* [rc] Merge refs/heads/master from .
---
- + [pu] git-repack: Add option to repack all objects.
- + [pu~1] More documentation updates.
- + [pu~2] Show commits in topo order and name all commits.
- + [pu~3] mailinfo and applymbox updates
- + [pu~4] Document "git cherry-pick" and "git revert"
- + [pu~5] Remove git-apply-patch-script.
- + [pu~6] Redo "revert" using three-way merge machinery.
+ + [seen] git-repack: Add option to repack all objects.
+ + [seen~1] More documentation updates.
+ + [seen~2] Show commits in topo order and name all commits.
+ + [seen~3] mailinfo and applymbox updates
+ + [seen~4] Document "git cherry-pick" and "git revert"
+ + [seen~5] Remove git-apply-patch-script.
+ + [seen~6] Redo "revert" using three-way merge machinery.
- [rc] Merge refs/heads/master from .
++* [master] Revert "Replace zero-length array decls with []."
- [rc~1] Merge refs/heads/master from .
diff --git a/Documentation/howto/update-hook-example.txt b/Documentation/howto/update-hook-example.txt
index 89821ec..151ee84 100644
--- a/Documentation/howto/update-hook-example.txt
+++ b/Documentation/howto/update-hook-example.txt
@@ -179,7 +179,7 @@ allowed-groups, to describe which heads can be pushed into by
whom. The format of each file would look like this:
refs/heads/master junio
- +refs/heads/pu junio
+ +refs/heads/seen junio
refs/heads/cogito$ pasky
refs/heads/bw/.* linus
refs/heads/tmp/.* .*
@@ -187,6 +187,6 @@ whom. The format of each file would look like this:
With this, Linus can push or create "bw/penguin" or "bw/zebra"
or "bw/panda" branches, Pasky can do only "cogito", and JC can
-do master and pu branches and make versioned tags. And anybody
-can do tmp/blah branches. The '+' sign at the pu record means
+do master and "seen" branches and make versioned tags. And anybody
+can do tmp/blah branches. The '+' sign at the "seen" record means
that JC can make non-fast-forward pushes on it.
diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 547a552..84bbc74 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -196,8 +196,8 @@ The placeholders are:
'%ce':: committer email
'%cE':: committer email (respecting .mailmap, see
linkgit:git-shortlog[1] or linkgit:git-blame[1])
-'%cl':: author email local-part (the part before the '@' sign)
-'%cL':: author local-part (see '%cl') respecting .mailmap, see
+'%cl':: committer email local-part (the part before the '@' sign)
+'%cL':: committer local-part (see '%cl') respecting .mailmap, see
linkgit:git-shortlog[1] or linkgit:git-blame[1])
'%cd':: committer date (format respects --date= option)
'%cD':: committer date, RFC2822 style
diff --git a/Documentation/rev-list-description.txt b/Documentation/rev-list-description.txt
new file mode 100644
index 0000000..a9efa7f
--- /dev/null
+++ b/Documentation/rev-list-description.txt
@@ -0,0 +1,61 @@
+List commits that are reachable by following the `parent` links from the
+given commit(s), but exclude commits that are reachable from the one(s)
+given with a '{caret}' in front of them. The output is given in reverse
+chronological order by default.
+
+You can think of this as a set operation. Commits reachable from any of
+the commits given on the command line form a set, and then commits reachable
+from any of the ones given with '{caret}' in front are subtracted from that
+set. The remaining commits are what comes out in the command's output.
+Various other options and paths parameters can be used to further limit the
+result.
+
+Thus, the following command:
+
+ifdef::git-rev-list[]
+-----------------------------------------------------------------------
+$ git rev-list foo bar ^baz
+-----------------------------------------------------------------------
+endif::git-rev-list[]
+ifdef::git-log[]
+-----------------------------------------------------------------------
+$ git log foo bar ^baz
+-----------------------------------------------------------------------
+endif::git-log[]
+
+means "list all the commits which are reachable from 'foo' or 'bar', but
+not from 'baz'".
+
+A special notation "'<commit1>'..'<commit2>'" can be used as a
+short-hand for "^'<commit1>' '<commit2>'". For example, either of
+the following may be used interchangeably:
+
+ifdef::git-rev-list[]
+-----------------------------------------------------------------------
+$ git rev-list origin..HEAD
+$ git rev-list HEAD ^origin
+-----------------------------------------------------------------------
+endif::git-rev-list[]
+ifdef::git-log[]
+-----------------------------------------------------------------------
+$ git log origin..HEAD
+$ git log HEAD ^origin
+-----------------------------------------------------------------------
+endif::git-log[]
+
+Another special notation is "'<commit1>'...'<commit2>'" which is useful
+for merges. The resulting set of commits is the symmetric difference
+between the two operands. The following two commands are equivalent:
+
+ifdef::git-rev-list[]
+-----------------------------------------------------------------------
+$ git rev-list A B --not $(git merge-base --all A B)
+$ git rev-list A...B
+-----------------------------------------------------------------------
+endif::git-rev-list[]
+ifdef::git-log[]
+-----------------------------------------------------------------------
+$ git log A B --not $(git merge-base --all A B)
+$ git log A...B
+-----------------------------------------------------------------------
+endif::git-log[]
diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt
index 1ad9506..d9169c0 100644
--- a/Documentation/revisions.txt
+++ b/Documentation/revisions.txt
@@ -254,6 +254,9 @@ specifying a single revision, using the notation described in the
previous section, means the set of commits `reachable` from the given
commit.
+Specifying several revisions means the set of commits reachable from
+any of the given commits.
+
A commit's reachable set is the commit itself and the commits in
its ancestry chain.
diff --git a/Documentation/technical/commit-graph-format.txt b/Documentation/technical/commit-graph-format.txt
index 1beef17..4405410 100644
--- a/Documentation/technical/commit-graph-format.txt
+++ b/Documentation/technical/commit-graph-format.txt
@@ -32,7 +32,7 @@ the body into "chunks" and provide a binary lookup table at the beginning
of the body. The header includes certain values, such as number of chunks
and hash type.
-All 4-byte numbers are in network order.
+All multi-byte numbers are in network byte order.
HEADER:
diff --git a/Documentation/technical/http-protocol.txt b/Documentation/technical/http-protocol.txt
index 9c5b6f0..51a79e6 100644
--- a/Documentation/technical/http-protocol.txt
+++ b/Documentation/technical/http-protocol.txt
@@ -216,7 +216,7 @@ smart server reply:
S: 001e# service=git-upload-pack\n
S: 0000
S: 004895dcfa3633004da0049d3d0fa03f80589cbcaf31 refs/heads/maint\0multi_ack\n
- S: 0042d049f6c27a2244e12041955e262a404c7faba355 refs/heads/master\n
+ S: 003fd049f6c27a2244e12041955e262a404c7faba355 refs/heads/master\n
S: 003c2cb58b79488a98d2721cea644875a8dd0026b115 refs/tags/v1.0\n
S: 003fa3c2e2402b99163d1d59756e5f207ae21cccba4c refs/tags/v1.0^{}\n
S: 0000
diff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt
index d5ce4ee..a4573d1 100644
--- a/Documentation/technical/pack-protocol.txt
+++ b/Documentation/technical/pack-protocol.txt
@@ -96,7 +96,7 @@ Basically what the Git client is doing to connect to an 'upload-pack'
process on the server side over the Git protocol is this:
$ echo -e -n \
- "0039git-upload-pack /schacon/gitbook.git\0host=example.com\0" |
+ "003agit-upload-pack /schacon/gitbook.git\0host=example.com\0" |
nc -v example.com 9418
@@ -171,9 +171,9 @@ with a version number (if "version=1" is sent as an Extra Parameter),
and a listing of each reference it has (all branches and tags) along
with the object name that each reference currently points to.
- $ echo -e -n "0044git-upload-pack /schacon/gitbook.git\0host=example.com\0\0version=1\0" |
+ $ echo -e -n "0045git-upload-pack /schacon/gitbook.git\0host=example.com\0\0version=1\0" |
nc -v example.com 9418
- 000aversion 1
+ 000eversion 1
00887217a7c7e582c46cec22a130adf4b9d7d950fba0 HEAD\0multi_ack thin-pack
side-band side-band-64k ofs-delta shallow no-progress include-tag
00441d3fcd5ced445d1abc402225c0b8a1299641f497 refs/heads/integration
diff --git a/Documentation/technical/packfile-uri.txt b/Documentation/technical/packfile-uri.txt
new file mode 100644
index 0000000..318713a
--- /dev/null
+++ b/Documentation/technical/packfile-uri.txt
@@ -0,0 +1,78 @@
+Packfile URIs
+=============
+
+This feature allows servers to serve part of their packfile response as URIs.
+This allows server designs that improve scalability in bandwidth and CPU usage
+(for example, by serving some data through a CDN), and (in the future) provides
+some measure of resumability to clients.
+
+This feature is available only in protocol version 2.
+
+Protocol
+--------
+
+The server advertises the `packfile-uris` capability.
+
+If the client then communicates which protocols (HTTPS, etc.) it supports with
+a `packfile-uris` argument, the server MAY send a `packfile-uris` section
+directly before the `packfile` section (right after `wanted-refs` if it is
+sent) containing URIs of any of the given protocols. The URIs point to
+packfiles that use only features that the client has declared that it supports
+(e.g. ofs-delta and thin-pack). See protocol-v2.txt for the documentation of
+this section.
+
+Clients should then download and index all the given URIs (in addition to
+downloading and indexing the packfile given in the `packfile` section of the
+response) before performing the connectivity check.
+
+Server design
+-------------
+
+The server can be trivially made compatible with the proposed protocol by
+having it advertise `packfile-uris`, tolerating the client sending
+`packfile-uris`, and never sending any `packfile-uris` section. But we should
+include some sort of non-trivial implementation in the Minimum Viable Product,
+at least so that we can test the client.
+
+This is the implementation: a feature, marked experimental, that allows the
+server to be configured by one or more `uploadpack.blobPackfileUri=<sha1>
+<uri>` entries. Whenever the list of objects to be sent is assembled, all such
+blobs are excluded, replaced with URIs. The client will download those URIs,
+expecting them to each point to packfiles containing single blobs.
+
+Client design
+-------------
+
+The client has a config variable `fetch.uriprotocols` that determines which
+protocols the end user is willing to use. By default, this is empty.
+
+When the client downloads the given URIs, it should store them with "keep"
+files, just like it does with the packfile in the `packfile` section. These
+additional "keep" files can only be removed after the refs have been updated -
+just like the "keep" file for the packfile in the `packfile` section.
+
+The division of work (initial fetch + additional URIs) introduces convenient
+points for resumption of an interrupted clone - such resumption can be done
+after the Minimum Viable Product (see "Future work").
+
+Future work
+-----------
+
+The protocol design allows some evolution of the server and client without any
+need for protocol changes, so only a small-scoped design is included here to
+form the MVP. For example, the following can be done:
+
+ * On the server, more sophisticated means of excluding objects (e.g. by
+ specifying a commit to represent that commit and all objects that it
+ references).
+ * On the client, resumption of clone. If a clone is interrupted, information
+ could be recorded in the repository's config and a "clone-resume" command
+ can resume the clone in progress. (Resumption of subsequent fetches is more
+ difficult because that must deal with the user wanting to use the repository
+ even after the fetch was interrupted.)
+
+There are some possible features that will require a change in protocol:
+
+ * Additional HTTP headers (e.g. authentication)
+ * Byte range support
+ * Different file formats referenced by URIs (e.g. raw object)
diff --git a/Documentation/technical/protocol-capabilities.txt b/Documentation/technical/protocol-capabilities.txt
index 2b267c0..36ccd14 100644
--- a/Documentation/technical/protocol-capabilities.txt
+++ b/Documentation/technical/protocol-capabilities.txt
@@ -176,6 +176,21 @@ agent strings are purely informative for statistics and debugging
purposes, and MUST NOT be used to programmatically assume the presence
or absence of particular features.
+object-format
+-------------
+
+This capability, which takes a hash algorithm as an argument, indicates
+that the server supports the given hash algorithms. It may be sent
+multiple times; if so, the first one given is the one used in the ref
+advertisement.
+
+When provided by the client, this indicates that it intends to use the
+given hash algorithm to communicate. The algorithm provided must be one
+that the server supports.
+
+If this capability is not provided, it is assumed that the only
+supported algorithm is SHA-1.
+
symref
------
diff --git a/Documentation/technical/protocol-v2.txt b/Documentation/technical/protocol-v2.txt
index 7e3766c..e597b74 100644
--- a/Documentation/technical/protocol-v2.txt
+++ b/Documentation/technical/protocol-v2.txt
@@ -33,6 +33,8 @@ In protocol v2 these special packets will have the following semantics:
* '0000' Flush Packet (flush-pkt) - indicates the end of a message
* '0001' Delimiter Packet (delim-pkt) - separates sections of a message
+ * '0002' Message Packet (response-end-pkt) - indicates the end of a response
+ for stateless connections
Initial Client Request
----------------------
@@ -323,13 +325,26 @@ included in the client's request:
indicating its sideband (1, 2, or 3), and the server may send "0005\2"
(a PKT-LINE of sideband 2 with no payload) as a keepalive packet.
+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.
+
+ 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
+ client should download from all given URIs. Currently, the
+ protocols supported are "http" and "https".
+
The response of `fetch` is broken into a number of sections separated by
delimiter packets (0001), with each section beginning with its section
-header.
+header. Most sections are sent only when the packfile is sent.
- output = *section
- section = (acknowledgments | shallow-info | wanted-refs | packfile)
- (flush-pkt | delim-pkt)
+ output = acknowledgements flush-pkt |
+ [acknowledgments delim-pkt] [shallow-info delim-pkt]
+ [wanted-refs delim-pkt] [packfile-uris delim-pkt]
+ packfile flush-pkt
acknowledgments = PKT-LINE("acknowledgments" LF)
(nak | *ack)
@@ -347,13 +362,17 @@ header.
*PKT-LINE(wanted-ref LF)
wanted-ref = obj-id SP refname
+ packfile-uris = PKT-LINE("packfile-uris" LF) *packfile-uri
+ packfile-uri = PKT-LINE(40*(HEXDIGIT) SP *%x20-ff LF)
+
packfile = PKT-LINE("packfile" LF)
*PKT-LINE(%x01-03 *%x00-ff)
acknowledgments section
- * If the client determines that it is finished with negotiations
- by sending a "done" line, the acknowledgments sections MUST be
- omitted from the server's response.
+ * If the client determines that it is finished with negotiations by
+ sending a "done" line (thus requiring the server to send a packfile),
+ the acknowledgments sections MUST be omitted from the server's
+ response.
* Always begins with the section header "acknowledgments"
@@ -404,9 +423,6 @@ header.
which the client has not indicated was shallow as a part of
its request.
- * This section is only included if a packfile section is also
- included in the response.
-
wanted-refs section
* This section is only included if the client has requested a
ref using a 'want-ref' line and if a packfile section is also
@@ -420,6 +436,20 @@ header.
* The server MUST NOT send any refs which were not requested
using 'want-ref' lines.
+ packfile-uris section
+ * This section is only included if the client sent
+ 'packfile-uris' and the server has at least one such URI to
+ send.
+
+ * Always begins with the section header "packfile-uris".
+
+ * For each URI the server sends, it sends a hash of the pack's
+ contents (as output by git index-pack) followed by the URI.
+
+ * The hashes are 40 hex characters long. When Git upgrades to a new
+ hash algorithm, this might need to be updated. (It should match
+ whatever index-pack outputs after "pack\t" or "keep\t".
+
packfile section
* This section is only included if the client has sent 'want'
lines in its request and either requested that no more
@@ -453,3 +483,12 @@ included in a request. This is done by sending each option as a
a request.
The provided options must not contain a NUL or LF character.
+
+ 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
+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.
diff --git a/Documentation/technical/reftable.txt b/Documentation/technical/reftable.txt
new file mode 100644
index 0000000..2951840
--- /dev/null
+++ b/Documentation/technical/reftable.txt
@@ -0,0 +1,1083 @@
+reftable
+--------
+
+Overview
+~~~~~~~~
+
+Problem statement
+^^^^^^^^^^^^^^^^^
+
+Some repositories contain a lot of references (e.g. android at 866k,
+rails at 31k). The existing packed-refs format takes up a lot of space
+(e.g. 62M), and does not scale with additional references. Lookup of a
+single reference requires linearly scanning the file.
+
+Atomic pushes modifying multiple references require copying the entire
+packed-refs file, which can be a considerable amount of data moved
+(e.g. 62M in, 62M out) for even small transactions (2 refs modified).
+
+Repositories with many loose references occupy a large number of disk
+blocks from the local file system, as each reference is its own file
+storing 41 bytes (and another file for the corresponding reflog). This
+negatively affects the number of inodes available when a large number of
+repositories are stored on the same filesystem. Readers can be penalized
+due to the larger number of syscalls required to traverse and read the
+`$GIT_DIR/refs` directory.
+
+
+Objectives
+^^^^^^^^^^
+
+* Near constant time lookup for any single reference, even when the
+repository is cold and not in process or kernel cache.
+* Near constant time verification if an object name is referred to by at least
+one reference (for allow-tip-sha1-in-want).
+* Efficient enumeration of an entire namespace, such as `refs/tags/`.
+* Support atomic push with `O(size_of_update)` operations.
+* Combine reflog storage with ref storage for small transactions.
+* Separate reflog storage for base refs and historical logs.
+
+Description
+^^^^^^^^^^^
+
+A reftable file is a portable binary file format customized for
+reference storage. References are sorted, enabling linear scans, binary
+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.
+
+Performance
+^^^^^^^^^^^
+
+Space used, packed-refs vs. reftable:
+
+[cols=",>,>,>,>,>",options="header",]
+|===============================================================
+|repository |packed-refs |reftable |% original |avg ref |avg obj
+|android |62.2 M |36.1 M |58.0% |33 bytes |5 bytes
+|rails |1.8 M |1.1 M |57.7% |29 bytes |4 bytes
+|git |78.7 K |48.1 K |61.0% |50 bytes |4 bytes
+|git (heads) |332 b |269 b |81.0% |33 bytes |0 bytes
+|===============================================================
+
+Scan (read 866k refs), by reference name lookup (single ref from 866k
+refs), and by SHA-1 lookup (refs with that SHA-1, from 866k refs):
+
+[cols=",>,>,>,>",options="header",]
+|=========================================================
+|format |cache |scan |by name |by SHA-1
+|packed-refs |cold |402 ms |409,660.1 usec |412,535.8 usec
+|packed-refs |hot | |6,844.6 usec |20,110.1 usec
+|reftable |cold |112 ms |33.9 usec |323.2 usec
+|reftable |hot | |20.2 usec |320.8 usec
+|=========================================================
+
+Space used for 149,932 log entries for 43,061 refs, reflog vs. reftable:
+
+[cols=",>,>",options="header",]
+|================================
+|format |size |avg entry
+|$GIT_DIR/logs |173 M |1209 bytes
+|reftable |5 M |37 bytes
+|================================
+
+Details
+~~~~~~~
+
+Peeling
+^^^^^^^
+
+References stored in a reftable are peeled, a record for an annotated
+(or signed) tag records both the tag object, and the object it refers
+to. This is analogous to storage in the packed-refs format.
+
+Reference name encoding
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Reference names are an uninterpreted sequence of bytes that must pass
+linkgit:git-check-ref-format[1] as a valid reference name.
+
+Key unicity
+^^^^^^^^^^^
+
+Each entry must have a unique key; repeated keys are disallowed.
+
+Network byte order
+^^^^^^^^^^^^^^^^^^
+
+All multi-byte, fixed width fields are in network byte order.
+
+Varint encoding
+^^^^^^^^^^^^^^^
+
+Varint encoding is identical to the ofs-delta encoding method used
+within pack files.
+
+Decoder works such as:
+
+....
+val = buf[ptr] & 0x7f
+while (buf[ptr] & 0x80) {
+ ptr++
+ val = ((val + 1) << 7) | (buf[ptr] & 0x7f)
+}
+....
+
+Ordering
+^^^^^^^^
+
+Blocks are lexicographically ordered by their first reference.
+
+Directory/file conflicts
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+The reftable format accepts both `refs/heads/foo` and
+`refs/heads/foo/bar` as distinct references.
+
+This property is useful for retaining log records in reftable, but may
+confuse versions of Git using `$GIT_DIR/refs` directory tree to maintain
+references. Users of reftable may choose to continue to reject `foo` and
+`foo/bar` type conflicts to prevent problems for peers.
+
+File format
+~~~~~~~~~~~
+
+Structure
+^^^^^^^^^
+
+A reftable file has the following high-level structure:
+
+....
+first_block {
+ header
+ first_ref_block
+}
+ref_block*
+ref_index*
+obj_block*
+obj_index*
+log_block*
+log_index*
+footer
+....
+
+A log-only file omits the `ref_block`, `ref_index`, `obj_block` and
+`obj_index` sections, containing only the file header and log block:
+
+....
+first_block {
+ header
+}
+log_block*
+log_index*
+footer
+....
+
+in a log-only file the first log block immediately follows the file
+header, without padding to block alignment.
+
+Block size
+^^^^^^^^^^
+
+The file's block size is arbitrarily 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 4k or 8k) are recommended. Larger sizes (64k) can
+yield better compression, with a possible increased cost incurred by
+readers during access.
+
+The largest block size is `16777215` bytes (15.99 MiB).
+
+Block alignment
+^^^^^^^^^^^^^^^
+
+Writers may choose to align blocks at multiples of the block size by
+including `padding` filled with NUL bytes at the end of a block to round
+out to the chosen alignment. When alignment is used, writers must
+specify the alignment with the file header's `block_size` field.
+
+Block alignment is not required by the file format. Unaligned files must
+set `block_size = 0` in the file header, and omit `padding`. Unaligned
+files with more than one ref block must include the link:#Ref-index[ref
+index] to support fast lookup. Readers must be able to read both aligned
+and non-aligned files.
+
+Very small files (e.g. a single ref block) may omit `padding` and the ref
+index to reduce total file size.
+
+Header (version 1)
+^^^^^^^^^^^^^^^^^^
+
+A 24-byte header appears at the beginning of the file:
+
+....
+'REFT'
+uint8( version_number = 1 )
+uint24( block_size )
+uint64( min_update_index )
+uint64( max_update_index )
+....
+
+Aligned files must specify `block_size` to configure readers with the
+expected block alignment. Unaligned files must set `block_size = 0`.
+
+The `min_update_index` and `max_update_index` describe bounds for the
+`update_index` field of all log records in this file. When reftables are
+used in a stack for link:#Update-transactions[transactions], these
+fields can order the files such that the prior file's
+`max_update_index + 1` is the next file's `min_update_index`.
+
+Header (version 2)
+^^^^^^^^^^^^^^^^^^
+
+A 28-byte header appears at the beginning of the file:
+
+....
+'REFT'
+uint8( version_number = 2 )
+uint24( block_size )
+uint64( min_update_index )
+uint64( max_update_index )
+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.
+
+For maximum backward compatibility, it is recommended to use version 1 when
+writing SHA1 reftables.
+
+First ref block
+^^^^^^^^^^^^^^^
+
+The first ref block shares the same block as the file header, and is 24
+bytes smaller than all other blocks in the file. The first block
+immediately begins after the file header, at position 24.
+
+If the first block is a log block (a log-only file), its block header
+begins immediately at position 24.
+
+Ref block format
+^^^^^^^^^^^^^^^^
+
+A ref block is written as:
+
+....
+'r'
+uint24( block_len )
+ref_record+
+uint24( restart_offset )+
+uint16( restart_count )
+
+padding?
+....
+
+Blocks begin with `block_type = 'r'` and a 3-byte `block_len` which
+encodes the number of bytes in the block up to, but not including the
+optional `padding`. This is always less than or equal to the file's
+block size. In the first ref block, `block_len` includes 24 bytes for
+the file header.
+
+The 2-byte `restart_count` stores the number of entries in the
+`restart_offset` list, which must not be empty. Readers can use
+`restart_count` to binary search between restarts before starting a
+linear scan.
+
+Exactly `restart_count` 3-byte `restart_offset` values precedes 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,
+ascending. Readers can start linear scans from any of these records.
+
+A variable number of `ref_record` fill the middle of the block,
+describing reference names and values. The format is described below.
+
+As the first ref block shares the first file block with the file header,
+all `restart_offset` in the first block are relative to the start of the
+file (position 0), and include the file header. This forces the first
+`restart_offset` to be `28`.
+
+ref record
+++++++++++
+
+A `ref_record` describes a single reference, storing both the name and
+its value(s). Records are formatted as:
+
+....
+varint( prefix_length )
+varint( (suffix_length << 3) | value_type )
+suffix
+varint( update_index_delta )
+value?
+....
+
+The `prefix_length` field specifies how many leading bytes of the prior
+reference record's name should be copied to obtain this reference's
+name. This must be 0 for the first reference in any block, and also must
+be 0 for any `ref_record` whose offset is listed in the `restart_offset`
+table at the end of the block.
+
+Recovering a reference name from any `ref_record` is a simple concat:
+
+....
+this_name = prior_name[0..prefix_length] + suffix
+....
+
+The `suffix_length` value provides the number of bytes available in
+`suffix` to copy from `suffix` to complete the reference name.
+
+The `update_index` that last modified the reference can be obtained by
+adding `update_index_delta` to the `min_update_index` from the file
+header: `min_update_index + update_index_delta`.
+
+The `value` follows. Its format is determined by `value_type`, one of
+the following:
+
+* `0x0`: deletion; no value data (see transactions, below)
+* `0x1`: one object name; value of the ref
+* `0x2`: two object names; value of the ref, peeled target
+* `0x3`: symbolic reference: `varint( target_len ) target`
+
+Symbolic references use `0x3`, followed by the complete name of the
+reference target. No compression is applied to the target name.
+
+Types `0x4..0x7` are reserved for future use.
+
+Ref index
+^^^^^^^^^
+
+The ref index stores the name of the last reference from every ref block
+in the file, enabling reduced disk seeks for lookups. Any reference can
+be found by searching the index, identifying the containing block, and
+searching within that block.
+
+The index may be organized into a multi-level index, where the 1st level
+index block points to additional ref index blocks (2nd level), which may
+in turn point to either additional index blocks (e.g. 3rd level) or ref
+blocks (leaf level). Disk reads required to access a ref go up with
+higher index levels. Multi-level indexes may be required to ensure no
+single index block exceeds the file format's max block size of
+`16777215` bytes (15.99 MiB). To achieve constant O(1) disk seeks for
+lookups the index must be a single level, which is permitted to exceed
+the file's configured block size, but not the format's max block size of
+15.99 MiB.
+
+If present, the ref index block(s) appears after the last ref block.
+
+If there are at least 4 ref blocks, a ref index block should be written
+to improve lookup times. Cold reads using the index require 2 disk reads
+(read index, read block), and binary searching < 4 blocks also requires
+<= 2 reads. Omitting the index block from smaller files saves space.
+
+If the file is unaligned and contains more than one ref block, the ref
+index must be written.
+
+Index block format:
+
+....
+'i'
+uint24( block_len )
+index_record+
+uint24( restart_offset )+
+uint16( restart_count )
+
+padding?
+....
+
+The index blocks begin with `block_type = 'i'` and a 3-byte `block_len`
+which encodes the number of bytes in the block, up to but not including
+the optional `padding`.
+
+The `restart_offset` and `restart_count` fields are identical in format,
+meaning and usage as in ref blocks.
+
+To reduce the number of reads required for random access in very large
+files the index block may be larger than other blocks. However, readers
+must hold the entire index in memory to benefit from this, so it's a
+time-space tradeoff in both file size and reader memory.
+
+Increasing the file's block size decreases the index size. Alternatively
+a multi-level index may be used, keeping index blocks within the file's
+block size, but increasing the number of blocks that need to be
+accessed.
+
+index record
+++++++++++++
+
+An index record describes the last entry in another block. Index records
+are written as:
+
+....
+varint( prefix_length )
+varint( (suffix_length << 3) | 0 )
+suffix
+varint( block_position )
+....
+
+Index records use prefix compression exactly like `ref_record`.
+
+Index records store `block_position` after the suffix, specifying the
+absolute position in bytes (from the start of the file) of the block
+that ends with this reference. Readers can seek to `block_position` to
+begin reading the block header.
+
+Readers must examine the block header at `block_position` to determine
+if the next block is another level index block, or the leaf-level ref
+block.
+
+Reading the index
++++++++++++++++++
+
+Readers loading the ref index must first read the footer (below) to
+obtain `ref_index_position`. If not present, the position will be 0. The
+`ref_index_position` is for the 1st level root of the ref index.
+
+Obj block format
+^^^^^^^^^^^^^^^^
+
+Object blocks are optional. Writers may choose to omit object blocks,
+especially if readers will not use the object name to ref mapping.
+
+Object blocks use unique, abbreviated 2-32 object name keys, mapping to
+ref blocks containing references pointing to that object directly, or as
+the peeled value of an annotated tag. Like ref blocks, object blocks use
+the file's standard block size. The abbrevation length is available in
+the footer as `obj_id_len`.
+
+To save space in small files, object blocks may be omitted if the ref
+index is not present, as brute force search will only need to read a few
+ref blocks. When missing, readers should brute force a linear search of
+all references to lookup by object name.
+
+An object block is written as:
+
+....
+'o'
+uint24( block_len )
+obj_record+
+uint24( restart_offset )+
+uint16( restart_count )
+
+padding?
+....
+
+Fields are identical to ref block. Binary search using the restart table
+works the same as in reference blocks.
+
+Because object names are abbreviated by writers to the shortest unique
+abbreviation within the reftable, obj key lengths have a variable length. Their
+length must be at least 2 bytes. Readers must compare only for common prefix
+match within an obj block or obj index.
+
+obj record
+++++++++++
+
+An `obj_record` describes a single object abbreviation, and the blocks
+containing references using that unique abbreviation:
+
+....
+varint( prefix_length )
+varint( (suffix_length << 3) | cnt_3 )
+suffix
+varint( cnt_large )?
+varint( position_delta )*
+....
+
+Like in reference blocks, abbreviations are prefix compressed within an
+obj block. On large reftables with many unique objects, higher block
+sizes (64k), and higher restart interval (128), a `prefix_length` of 2
+or 3 and `suffix_length` of 3 may be common in obj records (unique
+abbreviation of 5-6 raw bytes, 10-12 hex digits).
+
+Each record contains `position_count` number of positions for matching
+ref blocks. For 1-7 positions the count is stored in `cnt_3`. When
+`cnt_3 = 0` the actual count follows in a varint, `cnt_large`.
+
+The use of `cnt_3` bets most objects are pointed to by only a single
+reference, some may be pointed to by a couple of references, and very
+few (if any) are pointed to by more than 7 references.
+
+A special case exists when `cnt_3 = 0` and `cnt_large = 0`: there are no
+`position_delta`, but at least one reference starts with this
+abbreviation. A reader that needs exact reference names must scan all
+references to find which specific references have the desired object.
+Writers should use this format when the `position_delta` list would have
+overflowed the file's block size due to a high number of references
+pointing to the same object.
+
+The first `position_delta` is the position from the start of the file.
+Additional `position_delta` entries are sorted ascending and relative to
+the prior entry, e.g. a reader would perform:
+
+....
+pos = position_delta[0]
+prior = pos
+for (j = 1; j < position_count; j++) {
+ pos = prior + position_delta[j]
+ prior = pos
+}
+....
+
+With a position in hand, a reader must linearly scan the ref block,
+starting from the first `ref_record`, testing each reference's object names
+(for `value_type = 0x1` or `0x2`) for full equality. Faster searching by
+object name within a single ref block is not supported by the reftable format.
+Smaller block sizes reduce the number of candidates this step must
+consider.
+
+Obj index
+^^^^^^^^^
+
+The obj index stores the abbreviation from the last entry for every obj
+block in the file, enabling reduced disk seeks for all lookups. It is
+formatted exactly the same as the ref index, but refers to obj blocks.
+
+The obj index should be present if obj blocks are present, as obj blocks
+should only be written in larger files.
+
+Readers loading the obj index must first read the footer (below) to
+obtain `obj_index_position`. If not present, the position will be 0.
+
+Log block format
+^^^^^^^^^^^^^^^^
+
+Unlike ref and obj blocks, log blocks are always unaligned.
+
+Log blocks are variable in size, and do not match the `block_size`
+specified in the file header or footer. Writers should choose an
+appropriate buffer size to prepare a log block for deflation, such as
+`2 * block_size`.
+
+A log block is written as:
+
+....
+'g'
+uint24( block_len )
+zlib_deflate {
+ log_record+
+ uint24( restart_offset )+
+ uint16( restart_count )
+}
+....
+
+Log blocks look similar to ref blocks, except `block_type = 'g'`.
+
+The 4-byte block header is followed by the deflated block contents using
+zlib deflate. The `block_len` in the header is the inflated size
+(including 4-byte block header), and should be used by readers to
+preallocate the inflation output buffer. A log block's `block_len` may
+exceed the file's block size.
+
+Offsets within the log block (e.g. `restart_offset`) still include the
+4-byte header. Readers may prefer prefixing the inflation output buffer
+with the 4-byte header.
+
+Within the deflate container, a variable number of `log_record` describe
+reference changes. The log record format is described below. See ref
+block format (above) for a description of `restart_offset` and
+`restart_count`.
+
+Because log blocks have no alignment or padding between blocks, readers
+must keep track of the bytes consumed by the inflater to know where the
+next log block begins.
+
+log record
+++++++++++
+
+Log record keys are structured as:
+
+....
+ref_name '\0' reverse_int64( update_index )
+....
+
+where `update_index` is the unique transaction identifier. The
+`update_index` field must be unique within the scope of a `ref_name`.
+See the update transactions section below for further details.
+
+The `reverse_int64` function inverses the value so lexicographical
+ordering the network byte order encoding sorts the more recent records
+with higher `update_index` values first:
+
+....
+reverse_int64(int64 t) {
+ return 0xffffffffffffffff - t;
+}
+....
+
+Log records have a similar starting structure to ref and index records,
+utilizing the same prefix compression scheme applied to the log record
+key described above.
+
+....
+ varint( prefix_length )
+ varint( (suffix_length << 3) | log_type )
+ suffix
+ log_data {
+ old_id
+ new_id
+ varint( name_length ) name
+ varint( email_length ) email
+ varint( time_seconds )
+ sint16( tz_offset )
+ varint( message_length ) message
+ }?
+....
+
+Log record entries use `log_type` to indicate what follows:
+
+* `0x0`: deletion; no log data.
+* `0x1`: standard git reflog data using `log_data` above.
+
+The `log_type = 0x0` is mostly useful for `git stash drop`, removing an
+entry from the reflog of `refs/stash` in a transaction file (below),
+without needing to rewrite larger files. Readers reading a stack of
+reflogs must treat this as a deletion.
+
+For `log_type = 0x1`, the `log_data` section follows
+linkgit:git-update-ref[1] logging and includes:
+
+* two object names (old id, new id)
+* varint string of committer's name
+* varint string of committer's email
+* varint time in seconds since epoch (Jan 1, 1970)
+* 2-byte timezone offset in minutes (signed)
+* varint string of message
+
+`tz_offset` is the absolute number of minutes from GMT the committer was
+at the time of the update. For example `GMT-0800` is encoded in reftable
+as `sint16(-480)` and `GMT+0230` is `sint16(150)`.
+
+The committer email does not contain `<` or `>`, it's the value normally
+found between the `<>` in a git commit object header.
+
+The `message_length` may be 0, in which case there was no message
+supplied for the update.
+
+Contrary to traditional reflog (which is a file), renames are encoded as
+a combination of ref deletion and ref creation. A deletion is a log
+record with a zero new_id, and a creation is a log record with a zero old_id.
+
+Reading the log
++++++++++++++++
+
+Readers accessing the log must first read the footer (below) to
+determine the `log_position`. The first block of the log begins at
+`log_position` bytes since the start of the file. The `log_position` is
+not block aligned.
+
+Importing logs
+++++++++++++++
+
+When importing from `$GIT_DIR/logs` writers should globally order all
+log records roughly by timestamp while preserving file order, and assign
+unique, increasing `update_index` values for each log line. Newer log
+records get higher `update_index` values.
+
+Although an import may write only a single reftable file, the reftable
+file must span many unique `update_index`, as each log line requires its
+own `update_index` to preserve semantics.
+
+Log index
+^^^^^^^^^
+
+The log index stores the log key
+(`refname \0 reverse_int64(update_index)`) for the last log record of
+every log block in the file, supporting bounded-time lookup.
+
+A log index block must be written if 2 or more log blocks are written to
+the file. If present, the log index appears after the last log block.
+There is no padding used to align the log index to block alignment.
+
+Log index format is identical to ref index, except the keys are 9 bytes
+longer to include `'\0'` and the 8-byte `reverse_int64(update_index)`.
+Records use `block_position` to refer to the start of a log block.
+
+Reading the index
++++++++++++++++++
+
+Readers loading the log index must first read the footer (below) to
+obtain `log_index_position`. If not present, the position will be 0.
+
+Footer
+^^^^^^
+
+After the last block of the file, a file footer is written. It begins
+like the file header, but is extended with additional data.
+
+....
+ HEADER
+
+ uint64( ref_index_position )
+ uint64( (obj_position << 5) | obj_id_len )
+ uint64( obj_index_position )
+
+ uint64( log_position )
+ uint64( log_index_position )
+
+ uint32( CRC-32 of above )
+....
+
+If a section is missing (e.g. ref index) the corresponding position
+field (e.g. `ref_index_position`) will be 0.
+
+* `obj_position`: byte position for the first obj block.
+* `obj_id_len`: number of bytes used to abbreviate object names in
+obj blocks.
+* `log_position`: byte position for the first log block.
+* `ref_index_position`: byte position for the start of the ref index.
+* `obj_index_position`: byte position for the start of the obj index.
+* `log_index_position`: byte position for the start of the log index.
+
+The size of the footer is 68 bytes for version 1, and 72 bytes for
+version 2.
+
+Reading the footer
+++++++++++++++++++
+
+Readers must first read the file start to determine the version
+number. Then they seek to `file_length - FOOTER_LENGTH` to access the
+footer. A trusted external source (such as `stat(2)`) is necessary to
+obtain `file_length`. When reading the footer, readers must verify:
+
+* 4-byte magic is correct
+* 1-byte version number is recognized
+* 4-byte CRC-32 matches the other 64 bytes (including magic, and
+version)
+
+Once verified, the other fields of the footer can be accessed.
+
+Empty tables
+++++++++++++
+
+A reftable may be empty. In this case, the file starts with a header
+and is immediately followed by a footer.
+
+Binary search
+^^^^^^^^^^^^^
+
+Binary search within a block is supported by the `restart_offset` fields
+at the end of the block. Readers can binary search through the restart
+table to locate between which two restart points the sought reference or
+key should appear.
+
+Each record identified by a `restart_offset` stores the complete key in
+the `suffix` field of the record, making the compare operation during
+binary search straightforward.
+
+Once a restart point lexicographically before the sought reference has
+been identified, readers can linearly scan through the following record
+entries to locate the sought record, terminating if the current record
+sorts after (and therefore the sought key is not present).
+
+Restart point selection
++++++++++++++++++++++++
+
+Writers determine the restart points at file creation. The process is
+arbitrary, but every 16 or 64 records is recommended. 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.
+
+Considerations
+~~~~~~~~~~~~~~
+
+Lightweight refs dominate
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The reftable format assumes the vast majority of references are single
+object names valued with common prefixes, such as Gerrit Code Review's
+`refs/changes/` namespace, GitHub's `refs/pulls/` namespace, or many
+lightweight tags in the `refs/tags/` namespace.
+
+Annotated tags storing the peeled object cost an additional object name per
+reference.
+
+Low overhead
+^^^^^^^^^^^^
+
+A reftable with very few references (e.g. git.git with 5 heads) is 269
+bytes for reftable, vs. 332 bytes for packed-refs. This supports
+reftable scaling down for transaction logs (below).
+
+Block size
+^^^^^^^^^^
+
+For a Gerrit Code Review type repository with many change refs, larger
+block sizes (64 KiB) and less frequent restart points (every 64) yield
+better compression due to more references within the block compressing
+against the prior reference.
+
+Larger block sizes reduce the index size, as the reftable will require
+fewer blocks to store the same number of references.
+
+Minimal disk seeks
+^^^^^^^^^^^^^^^^^^
+
+Assuming the index block has been loaded into memory, binary searching
+for any single reference requires exactly 1 disk seek to load the
+containing block.
+
+Scans and lookups dominate
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Scanning all references and lookup by name (or namespace such as
+`refs/heads/`) are the most common activities performed on repositories.
+Object names are stored directly with references to optimize this use case.
+
+Logs are infrequently read
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Logs are infrequently accessed, but can be large. Deflating log blocks
+saves disk space, with some increased penalty at read time.
+
+Logs are stored in an isolated section from refs, reducing the burden on
+reference readers that want to ignore logs. Further, historical logs can
+be isolated into log-only files.
+
+Logs are read backwards
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Logs are frequently accessed backwards (most recent N records for master
+to answer `master@{4}`), so log records are grouped by reference, and
+sorted descending by update index.
+
+Repository format
+~~~~~~~~~~~~~~~~~
+
+Version 1
+^^^^^^^^^
+
+A repository must set its `$GIT_DIR/config` to configure reftable:
+
+....
+[core]
+ repositoryformatversion = 1
+[extensions]
+ refStorage = reftable
+....
+
+Layout
+^^^^^^
+
+A collection of reftable files are stored in the `$GIT_DIR/reftable/`
+directory:
+
+....
+00000001-00000001.log
+00000002-00000002.ref
+00000003-00000003.ref
+....
+
+where reftable files are named by a unique name such as produced by the
+function `${min_update_index}-${max_update_index}.ref`.
+
+Log-only files use the `.log` extension, while ref-only and mixed ref
+and log files use `.ref`. extension.
+
+The stack ordering file is `$GIT_DIR/reftable/tables.list` and lists the
+current files, one per line, in order, from oldest (base) to newest
+(most recent):
+
+....
+$ cat .git/reftable/tables.list
+00000001-00000001.log
+00000002-00000002.ref
+00000003-00000003.ref
+....
+
+Readers must read `$GIT_DIR/reftable/tables.list` to determine which
+files are relevant right now, and search through the stack in reverse
+order (last reftable is examined first).
+
+Reftable files not listed in `tables.list` may be new (and about to be
+added to the stack by the active writer), or ancient and ready to be
+pruned.
+
+Backward compatibility
+^^^^^^^^^^^^^^^^^^^^^^
+
+Older clients should continue to recognize the directory as a git
+repository so they don't look for an enclosing repository in parent
+directories. To this end, a reftable-enabled repository must contain the
+following dummy files
+
+* `.git/HEAD`, a regular file containing `ref: refs/heads/.invalid`.
+* `.git/refs/`, a directory
+* `.git/refs/heads`, a regular file
+
+Readers
+^^^^^^^
+
+Readers can obtain a consistent snapshot of the reference space by
+following:
+
+1. Open and read the `tables.list` file.
+2. Open each of the reftable files that it mentions.
+3. If any of the files is missing, goto 1.
+4. Read from the now-open files as long as necessary.
+
+Update transactions
+^^^^^^^^^^^^^^^^^^^
+
+Although reftables are immutable, mutations are supported by writing a
+new reftable and atomically appending it to the stack:
+
+1. Acquire `tables.list.lock`.
+2. Read `tables.list` to determine current reftables.
+3. Select `update_index` to be most recent file's
+`max_update_index + 1`.
+4. Prepare temp reftable `tmp_XXXXXX`, including log entries.
+5. Rename `tmp_XXXXXX` to `${update_index}-${update_index}.ref`.
+6. Copy `tables.list` to `tables.list.lock`, appending file from (5).
+7. Rename `tables.list.lock` to `tables.list`.
+
+During step 4 the new file's `min_update_index` and `max_update_index`
+are both set to the `update_index` selected by step 3. All log records
+for the transaction use the same `update_index` in their keys. This
+enables later correlation of which references were updated by the same
+transaction.
+
+Because a single `tables.list.lock` file is used to manage locking, the
+repository is single-threaded for writers. Writers may have to busy-spin
+(with backoff) around creating `tables.list.lock`, for up to an
+acceptable wait period, aborting if the repository is too busy to
+mutate. Application servers wrapped around repositories (e.g. Gerrit
+Code Review) can layer their own lock/wait queue to improve fairness to
+writers.
+
+Reference deletions
+^^^^^^^^^^^^^^^^^^^
+
+Deletion of any reference can be explicitly stored by setting the `type`
+to `0x0` and omitting the `value` field of the `ref_record`. This serves
+as a tombstone, overriding any assertions about the existence of the
+reference from earlier files in the stack.
+
+Compaction
+^^^^^^^^^^
+
+A partial stack of reftables can be compacted by merging references
+using a straightforward merge join across reftables, selecting the most
+recent value for output, and omitting deleted references that do not
+appear in remaining, lower reftables.
+
+A compacted reftable should set its `min_update_index` to the smallest
+of the input files' `min_update_index`, and its `max_update_index`
+likewise to the largest input `max_update_index`.
+
+For sake of illustration, assume the stack currently consists of
+reftable files (from oldest to newest): A, B, C, and D. The compactor is
+going to compact B and C, leaving A and D alone.
+
+1. Obtain lock `tables.list.lock` and read the `tables.list` file.
+2. Obtain locks `B.lock` and `C.lock`. Ownership of these locks
+prevents other processes from trying to compact these files.
+3. Release `tables.list.lock`.
+4. Compact `B` and `C` into a temp file
+`${min_update_index}-${max_update_index}_XXXXXX`.
+5. Reacquire lock `tables.list.lock`.
+6. Verify that `B` and `C` are still in the stack, in that order. This
+should always be the case, assuming that other processes are adhering to
+the locking protocol.
+7. Rename `${min_update_index}-${max_update_index}_XXXXXX` to
+`${min_update_index}-${max_update_index}.ref`.
+8. Write the new stack to `tables.list.lock`, replacing `B` and `C`
+with the file from (4).
+9. Rename `tables.list.lock` to `tables.list`.
+10. Delete `B` and `C`, perhaps after a short sleep to avoid forcing
+readers to backtrack.
+
+This strategy permits compactions to proceed independently of updates.
+
+Each reftable (compacted or not) is uniquely identified by its name, so
+open reftables can be cached by their name.
+
+Alternatives considered
+~~~~~~~~~~~~~~~~~~~~~~~
+
+bzip packed-refs
+^^^^^^^^^^^^^^^^
+
+`bzip2` can significantly shrink a large packed-refs file (e.g. 62 MiB
+compresses to 23 MiB, 37%). However the bzip format does not support
+random access to a single reference. Readers must inflate and discard
+while performing a linear scan.
+
+Breaking packed-refs into chunks (individually compressing each chunk)
+would reduce the amount of data a reader must inflate, but still leaves
+the problem of indexing chunks to support readers efficiently locating
+the correct chunk.
+
+Given the compression achieved by reftable's encoding, it does not seem
+necessary to add the complexity of bzip/gzip/zlib.
+
+Michael Haggerty's alternate format
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Michael Haggerty proposed
+link:https://lore.kernel.org/git/CAMy9T_HCnyc1g8XWOOWhe7nN0aEFyyBskV2aOMb_fe%2BwGvEJ7A%40mail.gmail.com/[an
+alternate] format to reftable on the Git mailing list. This format uses
+smaller chunks, without the restart table, and avoids block alignment
+with padding. Reflog entries immediately follow each ref, and are thus
+interleaved between refs.
+
+Performance testing indicates reftable is faster for lookups (51%
+faster, 11.2 usec vs. 5.4 usec), although reftable produces a slightly
+larger file (+ ~3.2%, 28.3M vs 29.2M):
+
+[cols=">,>,>,>",options="header",]
+|=====================================
+|format |size |seek cold |seek hot
+|mh-alt |28.3 M |23.4 usec |11.2 usec
+|reftable |29.2 M |19.9 usec |5.4 usec
+|=====================================
+
+JGit Ketch RefTree
+^^^^^^^^^^^^^^^^^^
+
+https://dev.eclipse.org/mhonarc/lists/jgit-dev/msg03073.html[JGit Ketch]
+proposed
+link:https://lore.kernel.org/git/CAJo%3DhJvnAPNAdDcAAwAvU9C4RVeQdoS3Ev9WTguHx4fD0V_nOg%40mail.gmail.com/[RefTree],
+an encoding of references inside Git tree objects stored as part of the
+repository's object database.
+
+The RefTree format adds additional load on the object database storage
+layer (more loose objects, more objects in packs), and relies heavily on
+the packer's delta compression to save space. Namespaces which are flat
+(e.g. thousands of tags in refs/tags) initially create very large loose
+objects, and so RefTree does not address the problem of copying many
+references to modify a handful.
+
+Flat namespaces are not efficiently searchable in RefTree, as tree
+objects in canonical formatting cannot be binary searched. This fails
+the need to handle a large number of references in a single namespace,
+such as GitHub's `refs/pulls`, or a project with many tags.
+
+LMDB
+^^^^
+
+David Turner proposed
+https://lore.kernel.org/git/1455772670-21142-26-git-send-email-dturner@twopensource.com/[using
+LMDB], as LMDB is lightweight (64k of runtime code) and GPL-compatible
+license.
+
+A downside of LMDB is its reliance on a single C implementation. This
+makes embedding inside JGit (a popular reimplementation of Git)
+difficult, and hoisting onto virtual storage (for JGit DFS) virtually
+impossible.
+
+A common format that can be supported by all major Git implementations
+(git-core, JGit, libgit2) is strongly preferred.
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index 8336529..fd480b8 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -347,7 +347,7 @@ $ git branch -r
origin/man
origin/master
origin/next
- origin/pu
+ origin/seen
origin/todo
------------------------------------------------
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index c30d71a..9db2f4f 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.27.0-rc2
+DEF_VER=v2.28.0
LF='
'
diff --git a/Makefile b/Makefile
index 90aa329..372139f 100644
--- a/Makefile
+++ b/Makefile
@@ -1186,7 +1186,7 @@ PTHREAD_CFLAGS =
# For the 'sparse' target
SPARSE_FLAGS ?=
-SP_EXTRA_FLAGS =
+SP_EXTRA_FLAGS = -Wno-universal-initializer
# For the 'coccicheck' target; setting SPATCH_BATCH_SIZE higher will
# usually result in less CPU usage at the cost of higher peak memory.
diff --git a/RelNotes b/RelNotes
index f3d8527..9143650 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.27.0.txt \ No newline at end of file
+Documentation/RelNotes/2.29.0.txt \ No newline at end of file
diff --git a/add-patch.c b/add-patch.c
index d8bfe37..a1d66c1 100644
--- a/add-patch.c
+++ b/add-patch.c
@@ -10,7 +10,7 @@
#include "prompt.h"
enum prompt_mode_type {
- PROMPT_MODE_CHANGE = 0, PROMPT_DELETION, PROMPT_HUNK,
+ PROMPT_MODE_CHANGE = 0, PROMPT_DELETION, PROMPT_ADDITION, PROMPT_HUNK,
PROMPT_MODE_MAX, /* must be last */
};
@@ -33,6 +33,7 @@ static struct patch_mode patch_mode_add = {
.prompt_mode = {
N_("Stage mode change [y,n,q,a,d%s,?]? "),
N_("Stage deletion [y,n,q,a,d%s,?]? "),
+ N_("Stage addition [y,n,q,a,d%s,?]? "),
N_("Stage this hunk [y,n,q,a,d%s,?]? ")
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -54,6 +55,7 @@ static struct patch_mode patch_mode_stash = {
.prompt_mode = {
N_("Stash mode change [y,n,q,a,d%s,?]? "),
N_("Stash deletion [y,n,q,a,d%s,?]? "),
+ N_("Stash addition [y,n,q,a,d%s,?]? "),
N_("Stash this hunk [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -77,6 +79,7 @@ static struct patch_mode patch_mode_reset_head = {
.prompt_mode = {
N_("Unstage mode change [y,n,q,a,d%s,?]? "),
N_("Unstage deletion [y,n,q,a,d%s,?]? "),
+ N_("Unstage addition [y,n,q,a,d%s,?]? "),
N_("Unstage this hunk [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -99,6 +102,7 @@ static struct patch_mode patch_mode_reset_nothead = {
.prompt_mode = {
N_("Apply mode change to index [y,n,q,a,d%s,?]? "),
N_("Apply deletion to index [y,n,q,a,d%s,?]? "),
+ N_("Apply addition to index [y,n,q,a,d%s,?]? "),
N_("Apply this hunk to index [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -121,6 +125,7 @@ static struct patch_mode patch_mode_checkout_index = {
.prompt_mode = {
N_("Discard mode change from worktree [y,n,q,a,d%s,?]? "),
N_("Discard deletion from worktree [y,n,q,a,d%s,?]? "),
+ N_("Discard addition from worktree [y,n,q,a,d%s,?]? "),
N_("Discard this hunk from worktree [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -143,6 +148,7 @@ static struct patch_mode patch_mode_checkout_head = {
.prompt_mode = {
N_("Discard mode change from index and worktree [y,n,q,a,d%s,?]? "),
N_("Discard deletion from index and worktree [y,n,q,a,d%s,?]? "),
+ N_("Discard addition from index and worktree [y,n,q,a,d%s,?]? "),
N_("Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -164,6 +170,7 @@ static struct patch_mode patch_mode_checkout_nothead = {
.prompt_mode = {
N_("Apply mode change to index and worktree [y,n,q,a,d%s,?]? "),
N_("Apply deletion to index and worktree [y,n,q,a,d%s,?]? "),
+ N_("Apply addition to index and worktree [y,n,q,a,d%s,?]? "),
N_("Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -186,6 +193,7 @@ static struct patch_mode patch_mode_worktree_head = {
.prompt_mode = {
N_("Discard mode change from index and worktree [y,n,q,a,d%s,?]? "),
N_("Discard deletion from index and worktree [y,n,q,a,d%s,?]? "),
+ N_("Discard addition from index and worktree [y,n,q,a,d%s,?]? "),
N_("Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -207,6 +215,7 @@ static struct patch_mode patch_mode_worktree_nothead = {
.prompt_mode = {
N_("Apply mode change to index and worktree [y,n,q,a,d%s,?]? "),
N_("Apply deletion to index and worktree [y,n,q,a,d%s,?]? "),
+ N_("Apply addition to index and worktree [y,n,q,a,d%s,?]? "),
N_("Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
@@ -248,7 +257,7 @@ struct add_p_state {
struct hunk head;
struct hunk *hunk;
size_t hunk_nr, hunk_alloc;
- unsigned deleted:1, mode_change:1,binary:1;
+ unsigned deleted:1, added:1, mode_change:1,binary:1;
} *file_diff;
size_t file_diff_nr;
@@ -442,7 +451,7 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
pend = p + plain->len;
while (p != pend) {
char *eol = memchr(p, '\n', pend - p);
- const char *deleted = NULL, *mode_change = NULL;
+ const char *deleted = NULL, *added = NULL, *mode_change = NULL;
if (!eol)
eol = pend;
@@ -461,11 +470,12 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
} else if (p == plain->buf)
BUG("diff starts with unexpected line:\n"
"%.*s\n", (int)(eol - p), p);
- else if (file_diff->deleted)
+ else if (file_diff->deleted || file_diff->added)
; /* keep the rest of the file in a single "hunk" */
else if (starts_with(p, "@@ ") ||
(hunk == &file_diff->head &&
- skip_prefix(p, "deleted file", &deleted))) {
+ (skip_prefix(p, "deleted file", &deleted) ||
+ skip_prefix(p, "new file", &added)))) {
if (marker == '-' || marker == '+')
/*
* Should not happen; previous hunk did not end
@@ -485,6 +495,8 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
if (deleted)
file_diff->deleted = 1;
+ else if (added)
+ file_diff->added = 1;
else if (parse_hunk_header(s, hunk) < 0)
return -1;
@@ -537,8 +549,10 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
starts_with(p, "Binary files "))
file_diff->binary = 1;
- if (file_diff->deleted && file_diff->mode_change)
- BUG("diff contains delete *and* a mode change?!?\n%.*s",
+ if (!!file_diff->deleted + !!file_diff->added +
+ !!file_diff->mode_change > 1)
+ BUG("diff can only contain delete *or* add *or* a "
+ "mode change?!?\n%.*s",
(int)(eol - (plain->buf + file_diff->head.start)),
plain->buf + file_diff->head.start);
@@ -1189,7 +1203,7 @@ static int edit_hunk_loop(struct add_p_state *s,
for (;;) {
int res = edit_hunk_manually(s, hunk);
if (res == 0) {
- /* abandonded */
+ /* abandoned */
*hunk = backup;
return -1;
}
@@ -1397,6 +1411,8 @@ static int patch_update_file(struct add_p_state *s,
if (file_diff->deleted)
prompt_mode_type = PROMPT_DELETION;
+ else if (file_diff->added)
+ prompt_mode_type = PROMPT_ADDITION;
else if (file_diff->mode_change && !hunk_index)
prompt_mode_type = PROMPT_MODE_CHANGE;
else
diff --git a/alloc.c b/alloc.c
index 1c64c4d..957a0af 100644
--- a/alloc.c
+++ b/alloc.c
@@ -99,23 +99,27 @@ void *alloc_object_node(struct repository *r)
return obj;
}
-static unsigned int alloc_commit_index(struct repository *r)
+/*
+ * The returned count is to be used as an index into commit slabs,
+ * that are *NOT* maintained per repository, and that is why a single
+ * global counter is used.
+ */
+static unsigned int alloc_commit_index(void)
{
- return r->parsed_objects->commit_count++;
+ static unsigned int parsed_commits_count;
+ return parsed_commits_count++;
}
-void init_commit_node(struct repository *r, struct commit *c)
+void init_commit_node(struct commit *c)
{
c->object.type = OBJ_COMMIT;
- c->index = alloc_commit_index(r);
- c->graph_pos = COMMIT_NOT_FROM_GRAPH;
- c->generation = GENERATION_NUMBER_INFINITY;
+ c->index = alloc_commit_index();
}
void *alloc_commit_node(struct repository *r)
{
struct commit *c = alloc_node(r->parsed_objects->commit_state, sizeof(struct commit));
- init_commit_node(r, c);
+ init_commit_node(c);
return c;
}
diff --git a/alloc.h b/alloc.h
index ed1071c..371d388 100644
--- a/alloc.h
+++ b/alloc.h
@@ -9,7 +9,7 @@ struct repository;
void *alloc_blob_node(struct repository *r);
void *alloc_tree_node(struct repository *r);
-void init_commit_node(struct repository *r, struct commit *c);
+void init_commit_node(struct commit *c);
void *alloc_commit_node(struct repository *r);
void *alloc_tag_node(struct repository *r);
void *alloc_object_node(struct repository *r);
diff --git a/blame.c b/blame.c
index da7e288..82fa16d 100644
--- a/blame.c
+++ b/blame.c
@@ -1272,7 +1272,7 @@ static int maybe_changed_path(struct repository *r,
if (!bd)
return 1;
- if (origin->commit->generation == GENERATION_NUMBER_INFINITY)
+ if (commit_graph_generation(origin->commit) == GENERATION_NUMBER_INFINITY)
return 1;
filter = get_bloom_filter(r, origin->commit, 0);
diff --git a/blob.c b/blob.c
index 36f9abd..182718a 100644
--- a/blob.c
+++ b/blob.c
@@ -10,7 +10,7 @@ struct blob *lookup_blob(struct repository *r, const struct object_id *oid)
struct object *obj = lookup_object(r, oid);
if (!obj)
return create_object(r, oid, alloc_blob_node(r));
- return object_as_type(r, obj, OBJ_BLOB, 0);
+ return object_as_type(obj, OBJ_BLOB, 0);
}
int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size)
diff --git a/bloom.c b/bloom.c
index 9b86aa3..1a57322 100644
--- a/bloom.c
+++ b/bloom.c
@@ -33,15 +33,16 @@ static int load_bloom_filter_from_graph(struct commit_graph *g,
struct commit *c)
{
uint32_t lex_pos, start_index, end_index;
+ uint32_t graph_pos = commit_graph_position(c);
- while (c->graph_pos < g->num_commits_in_base)
+ while (graph_pos < g->num_commits_in_base)
g = g->base_graph;
/* The commit graph commit 'c' lives in doesn't carry bloom filters. */
if (!g->chunk_bloom_indexes)
return 0;
- lex_pos = c->graph_pos - g->num_commits_in_base;
+ lex_pos = graph_pos - g->num_commits_in_base;
end_index = get_be32(g->chunk_bloom_indexes + 4 * lex_pos);
@@ -138,6 +139,11 @@ void fill_bloom_key(const char *data,
key->hashes[i] = hash0 + i * hash1;
}
+void clear_bloom_key(struct bloom_key *key)
+{
+ FREE_AND_NULL(key->hashes);
+}
+
void add_key_to_filter(const struct bloom_key *key,
struct bloom_filter *filter,
const struct bloom_filter_settings *settings)
@@ -181,24 +187,22 @@ struct bloom_filter *get_bloom_filter(struct repository *r,
struct diff_options diffopt;
int max_changes = 512;
- if (bloom_filters.slab_size == 0)
+ if (!bloom_filters.slab_size)
return NULL;
filter = bloom_filter_slab_at(&bloom_filters, c);
if (!filter->data) {
load_commit_graph_info(r, c);
- if (c->graph_pos != COMMIT_NOT_FROM_GRAPH &&
- r->objects->commit_graph->chunk_bloom_indexes) {
- if (load_bloom_filter_from_graph(r->objects->commit_graph, filter, c))
- return filter;
- else
- return NULL;
- }
+ if (commit_graph_position(c) != COMMIT_NOT_FROM_GRAPH &&
+ r->objects->commit_graph->chunk_bloom_indexes)
+ load_bloom_filter_from_graph(r->objects->commit_graph, filter, c);
}
- if (filter->data || !compute_if_not_present)
+ if (filter->data)
return filter;
+ if (!compute_if_not_present)
+ return NULL;
repo_diff_setup(r, &diffopt);
diffopt.flags.recursive = 1;
diff --git a/bloom.h b/bloom.h
index b2a8379..d8fbb0f 100644
--- a/bloom.h
+++ b/bloom.h
@@ -72,6 +72,7 @@ void fill_bloom_key(const char *data,
size_t len,
struct bloom_key *key,
const struct bloom_filter_settings *settings);
+void clear_bloom_key(struct bloom_key *key);
void add_key_to_filter(const struct bloom_key *key,
struct bloom_filter *filter,
diff --git a/branch.c b/branch.c
index 2d9e767..7095f78 100644
--- a/branch.c
+++ b/branch.c
@@ -370,7 +370,7 @@ int replace_each_worktree_head_symref(const char *oldref, const char *newref,
const char *logmsg)
{
int ret = 0;
- struct worktree **worktrees = get_worktrees(0);
+ struct worktree **worktrees = get_worktrees();
int i;
for (i = 0; worktrees[i]; i++) {
diff --git a/bugreport.c b/bugreport.c
index aa8a489..09579e2 100644
--- a/bugreport.c
+++ b/bugreport.c
@@ -9,6 +9,7 @@
static void get_system_info(struct strbuf *sys_info)
{
struct utsname uname_info;
+ char *shell = NULL;
/* get git version from native cmd */
strbuf_addstr(sys_info, _("git version:\n"));
@@ -29,8 +30,13 @@ static void get_system_info(struct strbuf *sys_info)
strbuf_addstr(sys_info, _("compiler info: "));
get_compiler_info(sys_info);
+
strbuf_addstr(sys_info, _("libc info: "));
get_libc_info(sys_info);
+
+ shell = getenv("SHELL");
+ strbuf_addf(sys_info, "$SHELL (typically, interactive shell): %s\n",
+ shell ? shell : "<unset>");
}
static void get_populated_hooks(struct strbuf *hook_info, int nongit)
@@ -174,7 +180,9 @@ int cmd_main(int argc, const char **argv)
die(_("couldn't create a new file at '%s'"), report_path.buf);
}
- strbuf_write_fd(&buffer, report);
+ if (write_in_full(report, buffer.buf, buffer.len) < 0)
+ die_errno(_("unable to write to %s"), report_path.buf);
+
close(report);
/*
diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index c1c40b5..73f9324 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -13,7 +13,6 @@ 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_head, "BISECT_HEAD")
static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
static GIT_PATH_FUNC(git_path_head_name, "head-name")
static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
@@ -164,7 +163,7 @@ static int bisect_reset(const char *commit)
strbuf_addstr(&branch, commit);
}
- if (!file_exists(git_path_bisect_head())) {
+ if (!ref_exists("BISECT_HEAD")) {
struct argv_array argv = ARGV_ARRAY_INIT;
argv_array_pushl(&argv, "checkout", branch.buf, "--", NULL);
@@ -455,9 +454,12 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout,
no_checkout = 1;
} else if (!strcmp(arg, "--term-good") ||
!strcmp(arg, "--term-old")) {
+ i++;
+ if (argc <= i)
+ return error(_("'' is not a valid term"));
must_write_terms = 1;
free((void *) terms->term_good);
- terms->term_good = xstrdup(argv[++i]);
+ terms->term_good = xstrdup(argv[i]);
} else if (skip_prefix(arg, "--term-good=", &arg) ||
skip_prefix(arg, "--term-old=", &arg)) {
must_write_terms = 1;
@@ -465,16 +467,18 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout,
terms->term_good = xstrdup(arg);
} else if (!strcmp(arg, "--term-bad") ||
!strcmp(arg, "--term-new")) {
+ i++;
+ if (argc <= i)
+ return error(_("'' is not a valid term"));
must_write_terms = 1;
free((void *) terms->term_bad);
- terms->term_bad = xstrdup(argv[++i]);
+ terms->term_bad = xstrdup(argv[i]);
} else if (skip_prefix(arg, "--term-bad=", &arg) ||
skip_prefix(arg, "--term-new=", &arg)) {
must_write_terms = 1;
free((void *) terms->term_bad);
terms->term_bad = xstrdup(arg);
- } else if (starts_with(arg, "--") &&
- !one_of(arg, "--term-good", "--term-bad", NULL)) {
+ } else if (starts_with(arg, "--")) {
return error(_("unrecognized option: '%s'"), arg);
} else {
char *commit_id = xstrfmt("%s^{commit}", arg);
diff --git a/builtin/branch.c b/builtin/branch.c
index accb61b..e82301f 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -468,7 +468,7 @@ static void print_current_branch_name(void)
static void reject_rebase_or_bisect_branch(const char *target)
{
- struct worktree **worktrees = get_worktrees(0);
+ struct worktree **worktrees = get_worktrees();
int i;
for (i = 0; worktrees[i]; i++) {
@@ -693,7 +693,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
list = 1;
if (!!delete + !!rename + !!copy + !!new_upstream + !!show_current +
- list + unset_upstream > 1)
+ list + edit_description + unset_upstream > 1)
usage_with_options(builtin_branch_usage, options);
if (filter.abbrev == -1)
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index ae18e20..5ebf133 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -596,7 +596,7 @@ static int batch_objects(struct batch_options *opt)
static const char * const cat_file_usage[] = {
N_("git cat-file (-t [--allow-unknown-type] | -s [--allow-unknown-type] | -e | -p | <type> | --textconv | --filters) [--path=<path>] <object>"),
- N_("git cat-file (--batch | --batch-check) [--follow-symlinks] [--textconv | --filters]"),
+ N_("git cat-file (--batch[=<format>] | --batch-check[=<format>]) [--follow-symlinks] [--textconv | --filters]"),
NULL
};
diff --git a/builtin/checkout.c b/builtin/checkout.c
index e9d111b..af849c6 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -621,9 +621,7 @@ static int reset_tree(struct tree *tree, const struct checkout_opts *o,
opts.src_index = &the_index;
opts.dst_index = &the_index;
init_checkout_metadata(&opts.meta, info->refname,
- info->commit ? &info->commit->object.oid :
- is_null_oid(&info->oid) ? &tree->object.oid :
- &info->oid,
+ info->commit ? &info->commit->object.oid : &null_oid,
NULL);
parse_tree(tree);
init_tree_desc(&tree_desc, tree->buffer, tree->size);
@@ -1689,7 +1687,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)
+ 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);
diff --git a/builtin/clean.c b/builtin/clean.c
index 4ca12bc..5a9c29a 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -924,12 +924,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
0);
memset(&dir, 0, sizeof(dir));
- if (ignored_only)
- dir.flags |= DIR_SHOW_IGNORED;
-
- if (ignored && ignored_only)
- die(_("-x and -X cannot be used together"));
-
if (!interactive && !dry_run && !force) {
if (config_set)
die(_("clean.requireForce set to true and neither -i, -n, nor -f given; "
@@ -946,6 +940,13 @@ 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"));
+ if (!ignored)
+ setup_standard_excludes(&dir);
+ if (ignored_only)
+ dir.flags |= DIR_SHOW_IGNORED;
+
if (argc) {
/*
* Remaining args implies pathspecs specified, and we should
@@ -954,15 +955,41 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
remove_directories = 1;
}
- if (remove_directories)
- dir.flags |= DIR_SHOW_IGNORED_TOO | DIR_KEEP_UNTRACKED_CONTENTS;
+ if (remove_directories && !ignored_only) {
+ /*
+ * We need to know about ignored files too:
+ *
+ * If (ignored), then we will delete ignored files as well.
+ *
+ * If (!ignored), then even though we not are doing
+ * anything with ignored files, we need to know about them
+ * so that we can avoid deleting a directory of untracked
+ * files that also contains an ignored file within it.
+ *
+ * For the (!ignored) case, since we only need to avoid
+ * deleting ignored files, we can set
+ * DIR_SHOW_IGNORED_TOO_MODE_MATCHING in order to avoid
+ * recursing into a directory which is itself ignored.
+ */
+ dir.flags |= DIR_SHOW_IGNORED_TOO;
+ if (!ignored)
+ dir.flags |= DIR_SHOW_IGNORED_TOO_MODE_MATCHING;
+
+ /*
+ * Let the fill_directory() machinery know that we aren't
+ * just recursing to collect the ignored files; we want all
+ * the untracked ones so that we can delete them. (Note:
+ * we could also set DIR_KEEP_UNTRACKED_CONTENTS when
+ * ignored_only is true, since DIR_KEEP_UNTRACKED_CONTENTS
+ * only has effect in combination with DIR_SHOW_IGNORED_TOO. It makes
+ * the code clearer to exclude it, though.
+ */
+ dir.flags |= DIR_KEEP_UNTRACKED_CONTENTS;
+ }
if (read_cache() < 0)
die(_("index file corrupt"));
- if (!ignored)
- setup_standard_excludes(&dir);
-
pl = add_pattern_list(&dir, EXC_CMDL, "--exclude option");
for (i = 0; i < exclude_list.nr; i++)
add_pattern(exclude_list.items[i].string, "", 0, pl, -(i+1));
diff --git a/builtin/clone.c b/builtin/clone.c
index cb48a29..a9f3312 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -945,8 +945,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
{
int is_bundle = 0, is_local;
const char *repo_name, *repo, *work_tree, *git_dir;
- char *path, *dir;
- int dest_exists;
+ char *path, *dir, *display_repo = NULL;
+ int dest_exists, real_dest_exists = 0;
const struct ref *refs, *remote_head;
const struct ref *remote_head_points_at;
const struct ref *our_head_points_at;
@@ -1000,10 +1000,11 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
path = get_repo_path(repo_name, &is_bundle);
if (path)
repo = absolute_pathdup(repo_name);
- else if (!strchr(repo_name, ':'))
- die(_("repository '%s' does not exist"), repo_name);
- else
+ else if (strchr(repo_name, ':')) {
repo = repo_name;
+ display_repo = transport_anonymize_url(repo);
+ } else
+ die(_("repository '%s' does not exist"), repo_name);
/* no need to be strict, transport_set_option() will validate it again */
if (option_depth && atoi(option_depth) < 1)
@@ -1020,7 +1021,17 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
die(_("destination path '%s' already exists and is not "
"an empty directory."), dir);
- strbuf_addf(&reflog_msg, "clone: from %s", repo);
+ if (real_git_dir) {
+ real_dest_exists = path_exists(real_git_dir);
+ if (real_dest_exists && !is_empty_dir(real_git_dir))
+ die(_("repository path '%s' already exists and is not "
+ "an empty directory."), real_git_dir);
+ }
+
+
+ strbuf_addf(&reflog_msg, "clone: from %s",
+ display_repo ? display_repo : repo);
+ free(display_repo);
if (option_bare)
work_tree = NULL;
@@ -1054,7 +1065,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
if (real_git_dir) {
- if (path_exists(real_git_dir))
+ if (real_dest_exists)
junk_git_dir_flags |= REMOVE_DIR_KEEP_TOPLEVEL;
junk_git_dir = real_git_dir;
} else {
@@ -1108,7 +1119,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
}
- init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN, INIT_DB_QUIET);
+ init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN, NULL,
+ INIT_DB_QUIET);
if (real_git_dir)
git_dir = real_git_dir;
@@ -1217,6 +1229,15 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
refs = transport_get_remote_refs(transport, &ref_prefixes);
if (refs) {
+ int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
+
+ /*
+ * Now that we know what algorithm the remote side is using,
+ * let's set ours to the same thing.
+ */
+ initialize_repository_version(hash_algo);
+ repo_set_hash_algo(the_repository, hash_algo);
+
mapped_refs = wanted_peer_refs(refs, &remote->fetch);
/*
* transport_get_remote_refs() may return refs with null sha-1
@@ -1263,9 +1284,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
remote_head_points_at = NULL;
remote_head = NULL;
option_no_checkout = 1;
- if (!option_bare)
- install_branch_config(0, "master", option_origin,
- "refs/heads/master");
+ if (!option_bare) {
+ const char *branch = git_default_branch_name();
+ char *ref = xstrfmt("refs/heads/%s", branch);
+
+ install_branch_config(0, branch, option_origin, ref);
+ free(ref);
+ }
}
write_refspec_config(src_ref_prefix, our_head_points_at,
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 15fe603..523501f 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -6,6 +6,8 @@
#include "repository.h"
#include "commit-graph.h"
#include "object-store.h"
+#include "progress.h"
+#include "tag.h"
static char const * const builtin_commit_graph_usage[] = {
N_("git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]"),
@@ -138,14 +140,37 @@ static int write_option_parse_split(const struct option *opt, const char *arg,
return 0;
}
+static int read_one_commit(struct oidset *commits, struct progress *progress,
+ const char *hash)
+{
+ struct object *result;
+ struct object_id oid;
+ const char *end;
+
+ if (parse_oid_hex(hash, &oid, &end))
+ return error(_("unexpected non-hex object ID: %s"), hash);
+
+ result = deref_tag(the_repository, parse_object(the_repository, &oid),
+ NULL, 0);
+ if (!result)
+ return error(_("invalid object: %s"), hash);
+ else if (object_as_type(result, OBJ_COMMIT, 1))
+ oidset_insert(commits, &result->oid);
+
+ display_progress(progress, oidset_size(commits));
+
+ return 0;
+}
+
static int graph_write(int argc, const char **argv)
{
- struct string_list *pack_indexes = NULL;
+ struct string_list pack_indexes = STRING_LIST_INIT_NODUP;
+ struct strbuf buf = STRBUF_INIT;
struct oidset commits = OIDSET_INIT;
struct object_directory *odb = NULL;
- struct string_list lines;
int result = 0;
enum commit_graph_write_flags flags = 0;
+ struct progress *progress = NULL;
static struct option builtin_commit_graph_write_options[] = {
OPT_STRING(0, "object-dir", &opts.obj_dir,
@@ -176,6 +201,7 @@ static int graph_write(int argc, const char **argv)
};
opts.progress = isatty(2);
+ opts.enable_changed_paths = -1;
split_opts.size_multiple = 2;
split_opts.max_commits = 0;
split_opts.expire_time = 0;
@@ -196,7 +222,9 @@ static int graph_write(int argc, const char **argv)
flags |= COMMIT_GRAPH_WRITE_SPLIT;
if (opts.progress)
flags |= COMMIT_GRAPH_WRITE_PROGRESS;
- if (opts.enable_changed_paths ||
+ if (!opts.enable_changed_paths)
+ flags |= COMMIT_GRAPH_NO_WRITE_BLOOM_FILTERS;
+ if (opts.enable_changed_paths == 1 ||
git_env_bool(GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS, 0))
flags |= COMMIT_GRAPH_WRITE_BLOOM_FILTERS;
@@ -209,44 +237,36 @@ static int graph_write(int argc, const char **argv)
return 0;
}
- string_list_init(&lines, 0);
- if (opts.stdin_packs || opts.stdin_commits) {
- struct strbuf buf = STRBUF_INIT;
-
+ if (opts.stdin_packs) {
while (strbuf_getline(&buf, stdin) != EOF)
- string_list_append(&lines, strbuf_detach(&buf, NULL));
-
- if (opts.stdin_packs)
- pack_indexes = &lines;
- if (opts.stdin_commits) {
- struct string_list_item *item;
- oidset_init(&commits, lines.nr);
- for_each_string_list_item(item, &lines) {
- struct object_id oid;
- const char *end;
-
- if (parse_oid_hex(item->string, &oid, &end)) {
- error(_("unexpected non-hex object ID: "
- "%s"), item->string);
- return 1;
- }
-
- oidset_insert(&commits, &oid);
+ string_list_append(&pack_indexes,
+ strbuf_detach(&buf, NULL));
+ } else if (opts.stdin_commits) {
+ oidset_init(&commits, 0);
+ if (opts.progress)
+ progress = start_delayed_progress(
+ _("Collecting commits from input"), 0);
+
+ while (strbuf_getline(&buf, stdin) != EOF) {
+ if (read_one_commit(&commits, progress, buf.buf)) {
+ result = 1;
+ goto cleanup;
}
- flags |= COMMIT_GRAPH_WRITE_CHECK_OIDS;
}
- UNLEAK(buf);
+ stop_progress(&progress);
}
if (write_commit_graph(odb,
- pack_indexes,
+ opts.stdin_packs ? &pack_indexes : NULL,
opts.stdin_commits ? &commits : NULL,
flags,
&split_opts))
result = 1;
- UNLEAK(lines);
+cleanup:
+ string_list_clear(&pack_indexes, 0);
+ strbuf_release(&buf);
return result;
}
diff --git a/builtin/config.c b/builtin/config.c
index ee4aef6..5e39f61 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -672,7 +672,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
given_config_source.file = git_pathdup("config");
given_config_source.scope = CONFIG_SCOPE_LOCAL;
} else if (use_worktree_config) {
- struct worktree **worktrees = get_worktrees(0);
+ struct worktree **worktrees = get_worktrees();
if (repository_format_worktree_config)
given_config_source.file = git_pathdup("config.worktree");
else if (worktrees[0] && worktrees[1])
diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index 86ae474..1e352dd 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -28,6 +28,13 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
repo_init_revisions(the_repository, &rev, prefix);
rev.abbrev = 0;
+
+ /*
+ * Consider "intent-to-add" files as new by default, unless
+ * explicitly specified in the command line or anywhere else.
+ */
+ rev.diffopt.ita_invisible_in_index = 1;
+
precompose_argv(argc, argv);
argc = setup_revisions(argc, argv, &rev, NULL);
diff --git a/builtin/diff.c b/builtin/diff.c
index 8537b17..cb98811 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -6,6 +6,7 @@
#define USE_THE_INDEX_COMPATIBILITY_MACROS
#include "cache.h"
#include "config.h"
+#include "ewah/ewok.h"
#include "lockfile.h"
#include "color.h"
#include "commit.h"
@@ -23,7 +24,13 @@
#define DIFF_NO_INDEX_IMPLICIT 2
static const char builtin_diff_usage[] =
-"git diff [<options>] [<commit> [<commit>]] [--] [<path>...]";
+"git diff [<options>] [<commit>] [--] [<path>...]\n"
+" or: git diff [<options>] --cached [<commit>] [--] [<path>...]\n"
+" or: git diff [<options>] <commit> [<commit>...] <commit> [--] [<path>...]\n"
+" or: git diff [<options>] <commit>...<commit>] [--] [<path>...]\n"
+" or: git diff [<options>] <blob> <blob>]\n"
+" or: git diff [<options>] --no-index [--] <path> <path>]\n"
+COMMON_DIFF_OPTIONS_HELP;
static const char *blob_path(struct object_array_entry *entry)
{
@@ -254,6 +261,108 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
return run_diff_files(revs, options);
}
+struct symdiff {
+ struct bitmap *skip;
+ int warn;
+ const char *base, *left, *right;
+};
+
+/*
+ * Check for symmetric-difference arguments, and if present, arrange
+ * everything we need to know to handle them correctly. As a bonus,
+ * weed out all bogus range-based revision specifications, e.g.,
+ * "git diff A..B C..D" or "git diff A..B C" get rejected.
+ *
+ * For an actual symmetric diff, *symdiff is set this way:
+ *
+ * - its skip is non-NULL and marks *all* rev->pending.objects[i]
+ * indices that the caller should ignore (extra merge bases, of
+ * which there might be many, and A in A...B). Note that the
+ * chosen merge base and right side are NOT marked.
+ * - warn is set if there are multiple merge bases.
+ * - base, left, and right point to the names to use in a
+ * warning about multiple merge bases.
+ *
+ * If there is no symmetric diff argument, sym->skip is NULL and
+ * sym->warn is cleared. The remaining fields are not set.
+ */
+static void symdiff_prepare(struct rev_info *rev, struct symdiff *sym)
+{
+ int i, is_symdiff = 0, basecount = 0, othercount = 0;
+ int lpos = -1, rpos = -1, basepos = -1;
+ struct bitmap *map = NULL;
+
+ /*
+ * Use the whence fields to find merge bases and left and
+ * right parts of symmetric difference, so that we do not
+ * depend on the order that revisions are parsed. If there
+ * are any revs that aren't from these sources, we have a
+ * "git diff C A...B" or "git diff A...B C" case. Or we
+ * could even get "git diff A...B C...E", for instance.
+ *
+ * If we don't have just one merge base, we pick one
+ * at random.
+ *
+ * NB: REV_CMD_LEFT, REV_CMD_RIGHT are also used for A..B,
+ * so we must check for SYMMETRIC_LEFT too. The two arrays
+ * rev->pending.objects and rev->cmdline.rev are parallel.
+ */
+ for (i = 0; i < rev->cmdline.nr; i++) {
+ struct object *obj = rev->pending.objects[i].item;
+ switch (rev->cmdline.rev[i].whence) {
+ case REV_CMD_MERGE_BASE:
+ if (basepos < 0)
+ basepos = i;
+ basecount++;
+ break; /* do mark all bases */
+ case REV_CMD_LEFT:
+ if (lpos >= 0)
+ usage(builtin_diff_usage);
+ lpos = i;
+ if (obj->flags & SYMMETRIC_LEFT) {
+ is_symdiff = 1;
+ break; /* do mark A */
+ }
+ continue;
+ case REV_CMD_RIGHT:
+ if (rpos >= 0)
+ usage(builtin_diff_usage);
+ rpos = i;
+ continue; /* don't mark B */
+ case REV_CMD_PARENTS_ONLY:
+ case REV_CMD_REF:
+ case REV_CMD_REV:
+ othercount++;
+ continue;
+ }
+ if (map == NULL)
+ map = bitmap_new();
+ bitmap_set(map, i);
+ }
+
+ /*
+ * Forbid any additional revs for both A...B and A..B.
+ */
+ if (lpos >= 0 && othercount > 0)
+ usage(builtin_diff_usage);
+
+ if (!is_symdiff) {
+ bitmap_free(map);
+ sym->warn = 0;
+ sym->skip = NULL;
+ return;
+ }
+
+ sym->left = rev->pending.objects[lpos].name;
+ sym->right = rev->pending.objects[rpos].name;
+ if (basecount == 0)
+ die(_("%s...%s: no merge base"), sym->left, sym->right);
+ sym->base = rev->pending.objects[basepos].name;
+ bitmap_unset(map, basepos); /* unmark the base we want */
+ sym->warn = basecount > 1;
+ sym->skip = map;
+}
+
int cmd_diff(int argc, const char **argv, const char *prefix)
{
int i;
@@ -263,19 +372,29 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
struct object_array_entry *blob[2];
int nongit = 0, no_index = 0;
int result = 0;
+ struct symdiff sdiff;
/*
* We could get N tree-ish in the rev.pending_objects list.
- * Also there could be M blobs there, and P pathspecs.
+ * Also there could be M blobs there, and P pathspecs. --cached may
+ * also be present.
*
* N=0, M=0:
- * cache vs files (diff-files)
+ * cache vs files (diff-files)
+ *
+ * N=0, M=0, --cached:
+ * HEAD vs cache (diff-index --cached)
+ *
* N=0, M=2:
* compare two random blobs. P must be zero.
+ *
* N=0, M=1, P=1:
- * compare a blob with a working tree file.
+ * compare a blob with a working tree file.
*
* N=1, M=0:
+ * tree vs files (diff-index)
+ *
+ * N=1, M=0, --cached:
* tree vs cache (diff-index --cached)
*
* N=2, M=0:
@@ -382,6 +501,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
}
}
+ symdiff_prepare(&rev, &sdiff);
for (i = 0; i < rev.pending.nr; i++) {
struct object_array_entry *entry = &rev.pending.objects[i];
struct object *obj = entry->item;
@@ -396,6 +516,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
obj = &get_commit_tree(((struct commit *)obj))->object;
if (obj->type == OBJ_TREE) {
+ if (sdiff.skip && bitmap_get(sdiff.skip, i))
+ continue;
obj->flags |= flags;
add_object_array(obj, name, &ent);
} else if (obj->type == OBJ_BLOB) {
@@ -437,21 +559,12 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
usage(builtin_diff_usage);
else if (ent.nr == 1)
result = builtin_diff_index(&rev, argc, argv);
- else if (ent.nr == 2)
+ else if (ent.nr == 2) {
+ if (sdiff.warn)
+ warning(_("%s...%s: multiple merge bases, using %s"),
+ sdiff.left, sdiff.right, sdiff.base);
result = builtin_diff_tree(&rev, argc, argv,
&ent.objects[0], &ent.objects[1]);
- else if (ent.objects[0].item->flags & UNINTERESTING) {
- /*
- * diff A...B where there is at least one merge base
- * between A and B. We have ent.objects[0] ==
- * merge-base, ent.objects[ents-2] == A, and
- * ent.objects[ents-1] == B. Show diff between the
- * base and B. Note that we pick one merge base at
- * random if there are more than one.
- */
- result = builtin_diff_tree(&rev, argc, argv,
- &ent.objects[0],
- &ent.objects[ent.nr-1]);
} else
result = builtin_diff_combined(&rev, argc, argv,
ent.objects, ent.nr);
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 8586816..9f37895 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -45,6 +45,7 @@ static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
static struct string_list tag_refs = STRING_LIST_INIT_NODUP;
static struct refspec refspecs = REFSPEC_INIT_FETCH;
static int anonymize;
+static struct hashmap anonymized_seeds;
static struct revision_sources revision_sources;
static int parse_opt_signed_tag_mode(const struct option *opt,
@@ -120,24 +121,33 @@ static int has_unshown_parent(struct commit *commit)
struct anonymized_entry {
struct hashmap_entry hash;
+ const char *anon;
+ const char orig[FLEX_ARRAY];
+};
+
+struct anonymized_entry_key {
+ struct hashmap_entry hash;
const char *orig;
size_t orig_len;
- const char *anon;
- size_t anon_len;
};
static int anonymized_entry_cmp(const void *unused_cmp_data,
const struct hashmap_entry *eptr,
const struct hashmap_entry *entry_or_key,
- const void *unused_keydata)
+ const void *keydata)
{
const struct anonymized_entry *a, *b;
a = container_of(eptr, const struct anonymized_entry, hash);
- b = container_of(entry_or_key, 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];
+ return !equal;
+ }
- return a->orig_len != b->orig_len ||
- memcmp(a->orig, b->orig, a->orig_len);
+ b = container_of(entry_or_key, const struct anonymized_entry, hash);
+ return strcmp(a->orig, b->orig);
}
/*
@@ -145,31 +155,39 @@ static int anonymized_entry_cmp(const void *unused_cmp_data,
* the same anonymized string with another. The actual generation
* is farmed out to the generate function.
*/
-static const void *anonymize_mem(struct hashmap *map,
- void *(*generate)(const void *, size_t *),
- const void *orig, size_t *len)
+static const char *anonymize_str(struct hashmap *map,
+ char *(*generate)(void *),
+ const char *orig, size_t len,
+ void *data)
{
- struct anonymized_entry key, *ret;
+ struct anonymized_entry_key key;
+ struct anonymized_entry *ret;
if (!map->cmpfn)
hashmap_init(map, anonymized_entry_cmp, NULL, 0);
- hashmap_entry_init(&key.hash, memhash(orig, *len));
+ hashmap_entry_init(&key.hash, memhash(orig, len));
key.orig = orig;
- key.orig_len = *len;
- ret = hashmap_get_entry(map, &key, hash, NULL);
+ key.orig_len = len;
+
+ /* First check if it's a token the user configured manually... */
+ if (anonymized_seeds.cmpfn)
+ ret = hashmap_get_entry(&anonymized_seeds, &key, hash, &key);
+ else
+ ret = NULL;
+
+ /* ...otherwise check if we've already seen it in this context... */
+ if (!ret)
+ ret = hashmap_get_entry(map, &key, hash, &key);
+ /* ...and finally generate a new mapping if necessary */
if (!ret) {
- ret = xmalloc(sizeof(*ret));
+ FLEX_ALLOC_MEM(ret, orig, orig, len);
hashmap_entry_init(&ret->hash, key.hash.hash);
- ret->orig = xstrdup(orig);
- ret->orig_len = *len;
- ret->anon = generate(orig, len);
- ret->anon_len = *len;
+ ret->anon = generate(data);
hashmap_put(map, &ret->hash);
}
- *len = ret->anon_len;
return ret->anon;
}
@@ -181,13 +199,13 @@ static const void *anonymize_mem(struct hashmap *map,
*/
static void anonymize_path(struct strbuf *out, const char *path,
struct hashmap *map,
- void *(*generate)(const void *, size_t *))
+ char *(*generate)(void *))
{
while (*path) {
const char *end_of_component = strchrnul(path, '/');
size_t len = end_of_component - path;
- const char *c = anonymize_mem(map, generate, path, &len);
- strbuf_add(out, c, len);
+ const char *c = anonymize_str(map, generate, path, len, NULL);
+ strbuf_addstr(out, c);
path = end_of_component;
if (*path)
strbuf_addch(out, *path++);
@@ -361,12 +379,12 @@ static void print_path_1(const char *path)
printf("%s", path);
}
-static void *anonymize_path_component(const void *path, size_t *len)
+static char *anonymize_path_component(void *data)
{
static int counter;
struct strbuf out = STRBUF_INIT;
strbuf_addf(&out, "path%d", counter++);
- return strbuf_detach(&out, len);
+ return strbuf_detach(&out, NULL);
}
static void print_path(const char *path)
@@ -383,20 +401,23 @@ static void print_path(const char *path)
}
}
-static void *generate_fake_oid(const void *old, size_t *len)
+static char *generate_fake_oid(void *data)
{
static uint32_t counter = 1; /* avoid null oid */
const unsigned hashsz = the_hash_algo->rawsz;
- unsigned char *out = xcalloc(hashsz, 1);
+ unsigned char out[GIT_MAX_RAWSZ];
+ char *hex = xmallocz(GIT_MAX_HEXSZ);
+
+ hashclr(out);
put_be32(out + hashsz - 4, counter++);
- return out;
+ return hash_to_hex_algop_r(hex, out, the_hash_algo);
}
-static const struct object_id *anonymize_oid(const struct object_id *oid)
+static const char *anonymize_oid(const char *oid_hex)
{
static struct hashmap objs;
- size_t len = the_hash_algo->rawsz;
- return anonymize_mem(&objs, generate_fake_oid, oid, &len);
+ size_t len = strlen(oid_hex);
+ return anonymize_str(&objs, generate_fake_oid, oid_hex, len, NULL);
}
static void show_filemodify(struct diff_queue_struct *q,
@@ -455,9 +476,9 @@ static void show_filemodify(struct diff_queue_struct *q,
*/
if (no_data || S_ISGITLINK(spec->mode))
printf("M %06o %s ", spec->mode,
- oid_to_hex(anonymize ?
- anonymize_oid(&spec->oid) :
- &spec->oid));
+ anonymize ?
+ anonymize_oid(oid_to_hex(&spec->oid)) :
+ oid_to_hex(&spec->oid));
else {
struct object *object = lookup_object(the_repository,
&spec->oid);
@@ -493,12 +514,12 @@ static const char *find_encoding(const char *begin, const char *end)
return bol;
}
-static void *anonymize_ref_component(const void *old, size_t *len)
+static char *anonymize_ref_component(void *data)
{
static int counter;
struct strbuf out = STRBUF_INIT;
strbuf_addf(&out, "ref%d", counter++);
- return strbuf_detach(&out, len);
+ return strbuf_detach(&out, NULL);
}
static const char *anonymize_refname(const char *refname)
@@ -517,13 +538,6 @@ static const char *anonymize_refname(const char *refname)
static struct strbuf anon = STRBUF_INIT;
int i;
- /*
- * We also leave "master" as a special case, since it does not reveal
- * anything interesting.
- */
- if (!strcmp(refname, "refs/heads/master"))
- return refname;
-
strbuf_reset(&anon);
for (i = 0; i < ARRAY_SIZE(prefixes); i++) {
if (skip_prefix(refname, prefixes[i], &refname)) {
@@ -546,14 +560,13 @@ static char *anonymize_commit_message(const char *old)
return xstrfmt("subject %d\n\nbody\n", counter++);
}
-static struct hashmap idents;
-static void *anonymize_ident(const void *old, size_t *len)
+static char *anonymize_ident(void *data)
{
static int counter;
struct strbuf out = STRBUF_INIT;
strbuf_addf(&out, "User %d <user%d@example.com>", counter, counter);
counter++;
- return strbuf_detach(&out, len);
+ return strbuf_detach(&out, NULL);
}
/*
@@ -563,6 +576,7 @@ static void *anonymize_ident(const void *old, size_t *len)
*/
static void anonymize_ident_line(const char **beg, const char **end)
{
+ static struct hashmap idents;
static struct strbuf buffers[] = { STRBUF_INIT, STRBUF_INIT };
static unsigned which_buffer;
@@ -588,9 +602,9 @@ static void anonymize_ident_line(const char **beg, const char **end)
size_t len;
len = split.mail_end - split.name_begin;
- ident = anonymize_mem(&idents, anonymize_ident,
- split.name_begin, &len);
- strbuf_add(out, ident, len);
+ ident = anonymize_str(&idents, anonymize_ident,
+ split.name_begin, len, NULL);
+ strbuf_addstr(out, ident);
strbuf_addch(out, ' ');
strbuf_add(out, split.date_begin, split.tz_end - split.date_begin);
} else {
@@ -712,9 +726,10 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
if (mark)
printf(":%d\n", mark);
else
- printf("%s\n", oid_to_hex(anonymize ?
- anonymize_oid(&obj->oid) :
- &obj->oid));
+ printf("%s\n",
+ anonymize ?
+ anonymize_oid(oid_to_hex(&obj->oid)) :
+ oid_to_hex(&obj->oid));
i++;
}
@@ -729,12 +744,12 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
show_progress();
}
-static void *anonymize_tag(const void *old, size_t *len)
+static char *anonymize_tag(void *data)
{
static int counter;
struct strbuf out = STRBUF_INIT;
strbuf_addf(&out, "tag message %d", counter++);
- return strbuf_detach(&out, len);
+ return strbuf_detach(&out, NULL);
}
static void handle_tail(struct object_array *commits, struct rev_info *revs,
@@ -804,8 +819,8 @@ static void handle_tag(const char *name, struct tag *tag)
name = anonymize_refname(name);
if (message) {
static struct hashmap tags;
- message = anonymize_mem(&tags, anonymize_tag,
- message, &message_size);
+ message = anonymize_str(&tags, anonymize_tag,
+ message, message_size, NULL);
}
}
@@ -1136,6 +1151,37 @@ static void handle_deletes(void)
}
}
+static char *anonymize_seed(void *data)
+{
+ return xstrdup(data);
+}
+
+static int parse_opt_anonymize_map(const struct option *opt,
+ const char *arg, int unset)
+{
+ struct hashmap *map = opt->value;
+ const char *delim, *value;
+ size_t keylen;
+
+ BUG_ON_OPT_NEG(unset);
+
+ delim = strchr(arg, ':');
+ if (delim) {
+ keylen = delim - arg;
+ value = delim + 1;
+ } else {
+ keylen = strlen(arg);
+ value = arg;
+ }
+
+ if (!keylen || !*value)
+ return error(_("--anonymize-map token cannot be empty"));
+
+ anonymize_str(map, anonymize_seed, arg, keylen, (void *)value);
+
+ return 0;
+}
+
int cmd_fast_export(int argc, const char **argv, const char *prefix)
{
struct rev_info revs;
@@ -1177,6 +1223,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
OPT_STRING_LIST(0, "refspec", &refspecs_list, N_("refspec"),
N_("Apply refspec to exported refs")),
OPT_BOOL(0, "anonymize", &anonymize, N_("anonymize output")),
+ OPT_CALLBACK_F(0, "anonymize-map", &anonymized_seeds, N_("from:to"),
+ N_("convert <from> to <to> in anonymized output"),
+ PARSE_OPT_NONEG, parse_opt_anonymize_map),
OPT_BOOL(0, "reference-excluded-parents",
&reference_excluded_commits, N_("Reference parents which are not in fast-export stream by object id")),
OPT_BOOL(0, "show-original-ids", &show_original_ids,
@@ -1204,6 +1253,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
if (argc > 1)
usage_with_options (fast_export_usage, options);
+ if (anonymized_seeds.cmpfn && !anonymize)
+ die(_("--anonymize-map without --anonymize does not make sense"));
+
if (refspecs_list.nr) {
int i;
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index 4771100..bbb5c96 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -48,8 +48,8 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
struct ref **sought = NULL;
int nr_sought = 0, alloc_sought = 0;
int fd[2];
- char *pack_lockfile = NULL;
- char **pack_lockfile_ptr = NULL;
+ struct string_list pack_lockfiles = STRING_LIST_INIT_DUP;
+ struct string_list *pack_lockfiles_ptr = NULL;
struct child_process *conn;
struct fetch_pack_args args;
struct oid_array shallow = OID_ARRAY_INIT;
@@ -134,7 +134,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
}
if (!strcmp("--lock-pack", arg)) {
args.lock_pack = 1;
- pack_lockfile_ptr = &pack_lockfile;
+ pack_lockfiles_ptr = &pack_lockfiles;
continue;
}
if (!strcmp("--check-self-contained-and-connected", arg)) {
@@ -224,7 +224,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
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, &ref, 0, NULL, NULL, args.stateless_rpc);
break;
case protocol_v1:
case protocol_v0:
@@ -235,10 +235,15 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
}
ref = fetch_pack(&args, fd, ref, sought, nr_sought,
- &shallow, pack_lockfile_ptr, version);
- if (pack_lockfile) {
- printf("lock %s\n", pack_lockfile);
+ &shallow, pack_lockfiles_ptr, version);
+ if (pack_lockfiles.nr) {
+ int i;
+
+ printf("lock %s\n", pack_lockfiles.items[0].string);
fflush(stdout);
+ for (i = 1; i < pack_lockfiles.nr; i++)
+ warning(_("Lockfile created but not reported: %s"),
+ pack_lockfiles.items[i].string);
}
if (args.check_self_contained_and_connected &&
args.self_contained_and_connected) {
diff --git a/builtin/fetch.c b/builtin/fetch.c
index b5788c1..82ac4be 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1758,8 +1758,13 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
/* Record the command line for the reflog */
strbuf_addstr(&default_rla, "fetch");
- for (i = 1; i < argc; i++)
- strbuf_addf(&default_rla, " %s", argv[i]);
+ for (i = 1; i < argc; i++) {
+ /* This handles non-URLs gracefully */
+ char *anon = transport_anonymize_url(argv[i]);
+
+ strbuf_addf(&default_rla, " %s", anon);
+ free(anon);
+ }
fetch_config_from_gitmodules(&submodule_fetch_jobs_config,
&recurse_submodules);
@@ -1790,9 +1795,6 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
if (depth || deepen_since || deepen_not.nr)
deepen = 1;
- if (filter_options.choice && !has_promisor_remote())
- die("--filter can only be used when extensions.partialClone is set");
-
if (all) {
if (argc == 1)
die(_("fetch --all does not take a repository argument"));
diff --git a/builtin/fsck.c b/builtin/fsck.c
index f02cbdb..37aa07d 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -241,7 +241,7 @@ static void mark_unreachable_referents(const struct object_id *oid)
enum object_type type = oid_object_info(the_repository,
&obj->oid, NULL);
if (type > 0)
- object_as_type(the_repository, obj, type, 0);
+ object_as_type(obj, type, 0);
}
options.walk = mark_used;
@@ -577,7 +577,7 @@ static void get_default_heads(void)
for_each_rawref(fsck_handle_ref, NULL);
- worktrees = get_worktrees(0);
+ worktrees = get_worktrees();
for (p = worktrees; *p; p++) {
struct worktree *wt = *p;
struct strbuf ref = STRBUF_INIT;
diff --git a/builtin/grep.c b/builtin/grep.c
index a5056f3..5975cf5 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -466,7 +466,7 @@ static int grep_submodule(struct grep_opt *opt,
struct strbuf base = STRBUF_INIT;
obj_read_lock();
- object = parse_object_or_die(oid, oid_to_hex(oid));
+ object = parse_object_or_die(oid, NULL);
obj_read_unlock();
data = read_object_with_reference(&subrepo,
&object->oid, tree_type,
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index f176dd2..f865666 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1555,13 +1555,9 @@ static void read_v2_anomalous_offsets(struct packed_git *p,
{
const uint32_t *idx1, *idx2;
uint32_t i;
- const uint32_t hashwords = the_hash_algo->rawsz / sizeof(uint32_t);
/* The address of the 4-byte offset table */
- idx1 = (((const uint32_t *)p->index_data)
- + 2 /* 8-byte header */
- + 256 /* fan out */
- + hashwords * p->num_objects /* object ID table */
+ idx1 = (((const uint32_t *)((const uint8_t *)p->index_data + p->crc_offset))
+ p->num_objects /* CRC32 table */
);
@@ -1671,6 +1667,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
unsigned char pack_hash[GIT_MAX_RAWSZ];
unsigned foreign_nr = 1; /* zero is a "good" value, assume bad */
int report_end_of_input = 0;
+ int hash_algo = 0;
/*
* index-pack never needs to fetch missing objects except when
@@ -1764,6 +1761,11 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
die(_("bad %s"), arg);
} else if (skip_prefix(arg, "--max-input-size=", &arg)) {
max_input_size = strtoumax(arg, NULL, 10);
+ } else if (skip_prefix(arg, "--object-format=", &arg)) {
+ hash_algo = hash_algo_by_name(arg);
+ if (hash_algo == GIT_HASH_UNKNOWN)
+ die(_("unknown hash algorithm '%s'"), arg);
+ repo_set_hash_algo(the_repository, hash_algo);
} else
usage(index_pack_usage);
continue;
@@ -1780,6 +1782,8 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
die(_("--fix-thin cannot be used without --stdin"));
if (from_stdin && !startup_info->have_repository)
die(_("--stdin requires a git repository"));
+ if (from_stdin && hash_algo)
+ die(_("--object-format cannot be used with --stdin"));
if (!index_name && pack_name)
index_name = derive_filename(pack_name, "idx", &index_name_buf);
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 0b7222e..cee6482 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -203,6 +203,7 @@ void initialize_repository_version(int hash_algo)
static int create_default_files(const char *template_path,
const char *original_git_dir,
+ const char *initial_branch,
const struct repository_format *fmt)
{
struct stat st1;
@@ -258,15 +259,26 @@ static int create_default_files(const char *template_path,
die("failed to set up refs db: %s", err.buf);
/*
- * Create the default symlink from ".git/HEAD" to the "master"
- * branch, if it does not exist yet.
+ * 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) {
- if (create_symref("HEAD", "refs/heads/master", NULL) < 0)
+ char *ref;
+
+ if (!initial_branch)
+ initial_branch = git_default_branch_name();
+
+ ref = xstrfmt("refs/heads/%s", initial_branch);
+ if (check_refname_format(ref, 0) < 0)
+ die(_("invalid initial branch name: '%s'"),
+ initial_branch);
+
+ if (create_symref("HEAD", ref, NULL) < 0)
exit(1);
+ free(ref);
}
initialize_repository_version(fmt->hash_algo);
@@ -383,7 +395,8 @@ static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash
}
int init_db(const char *git_dir, const char *real_git_dir,
- const char *template_dir, int hash, unsigned int flags)
+ const char *template_dir, int hash, const char *initial_branch,
+ unsigned int flags)
{
int reinit;
int exist_ok = flags & INIT_DB_EXIST_OK;
@@ -425,7 +438,11 @@ int init_db(const char *git_dir, const char *real_git_dir,
validate_hash_algorithm(&repo_fmt, hash);
- reinit = create_default_files(template_dir, original_git_dir, &repo_fmt);
+ reinit = create_default_files(template_dir, original_git_dir,
+ initial_branch, &repo_fmt);
+ if (reinit && initial_branch)
+ warning(_("re-init: ignored --initial-branch=%s"),
+ initial_branch);
create_object_directory();
@@ -528,6 +545,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
const char *template_dir = NULL;
unsigned int flags = 0;
const char *object_format = NULL;
+ const char *initial_branch = NULL;
int hash_algo = GIT_HASH_UNKNOWN;
const struct option init_db_options[] = {
OPT_STRING(0, "template", &template_dir, N_("template-directory"),
@@ -541,6 +559,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
OPT_BIT('q', "quiet", &flags, N_("be quiet"), INIT_DB_QUIET),
OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
N_("separate git dir from working tree")),
+ OPT_STRING('b', "initial-branch", &initial_branch, N_("name"),
+ 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_END()
@@ -652,5 +672,6 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
UNLEAK(work_tree);
flags |= INIT_DB_EXIST_OK;
- return init_db(git_dir, real_git_dir, template_dir, hash_algo, flags);
+ return init_db(git_dir, real_git_dir, template_dir, hash_algo,
+ initial_branch, flags);
}
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index 6ef5195..3a4dd12 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -118,6 +118,10 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
transport->server_options = &server_options;
ref = transport_get_remote_refs(transport, &ref_prefixes);
+ if (ref) {
+ int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
+ repo_set_hash_algo(the_repository, hash_algo);
+ }
if (transport_disconnect(transport)) {
UNLEAK(sorting);
return 1;
diff --git a/builtin/merge.c b/builtin/merge.c
index ca6a5dc..7da707b 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -1656,7 +1656,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
}
merge_was_ok = 1;
}
- cnt = evaluate_result();
+ cnt = (use_strategies_nr > 1) ? evaluate_result() : 0;
if (best_cnt <= 0 || cnt <= best_cnt) {
best_strategy = use_strategies[i]->name;
best_cnt = cnt;
diff --git a/builtin/mv.c b/builtin/mv.c
index be15ba7..7dac714 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -132,6 +132,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
struct stat st;
struct string_list src_for_dst = STRING_LIST_INIT_NODUP;
struct lock_file lock_file = LOCK_INIT;
+ struct cache_entry *ce;
git_config(git_default_config, NULL);
@@ -220,9 +221,11 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
}
argc += last - first;
}
- } else if (cache_name_pos(src, length) < 0)
+ } else if (!(ce = cache_file_exists(src, length, ignore_case))) {
bad = _("not under version control");
- else if (lstat(dst, &st) == 0 &&
+ } else if (ce_stage(ce)) {
+ bad = _("conflicted");
+ } else if (lstat(dst, &st) == 0 &&
(!ignore_case || strcasecmp(src, dst))) {
bad = _("destination exists");
if (force) {
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index c5b433a..ecef5cd 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -35,6 +35,7 @@
#include "midx.h"
#include "trace2.h"
#include "shallow.h"
+#include "promisor-remote.h"
#define IN_PACK(obj) oe_in_pack(&to_pack, obj)
#define SIZE(obj) oe_size(&to_pack, obj)
@@ -117,6 +118,8 @@ static unsigned long window_memory_limit = 0;
static struct list_objects_filter_options filter_options;
+static struct string_list uri_protocols = STRING_LIST_INIT_NODUP;
+
enum missing_action {
MA_ERROR = 0, /* fail if any missing objects are encountered */
MA_ALLOW_ANY, /* silently allow ALL missing objects */
@@ -125,6 +128,15 @@ enum missing_action {
static enum missing_action arg_missing_action;
static show_object_fn fn_show_object;
+struct configured_exclusion {
+ struct oidmap_entry e;
+ char *pack_hash_hex;
+ char *uri;
+};
+static struct oidmap configured_exclusions;
+
+static struct oidset excluded_by_config;
+
/*
* stats
*/
@@ -969,6 +981,25 @@ static void write_reused_pack(struct hashfile *f)
unuse_pack(&w_curs);
}
+static void write_excluded_by_configs(void)
+{
+ struct oidset_iter iter;
+ const struct object_id *oid;
+
+ oidset_iter_init(&excluded_by_config, &iter);
+ while ((oid = oidset_iter_next(&iter))) {
+ struct configured_exclusion *ex =
+ oidmap_get(&configured_exclusions, oid);
+
+ if (!ex)
+ BUG("configured exclusion wasn't configured");
+ write_in_full(1, ex->pack_hash_hex, strlen(ex->pack_hash_hex));
+ write_in_full(1, " ", 1);
+ write_in_full(1, ex->uri, strlen(ex->uri));
+ write_in_full(1, "\n", 1);
+ }
+}
+
static const char no_split_warning[] = N_(
"disabling bitmap writing, packs are split due to pack.packSizeLimit"
);
@@ -1266,6 +1297,25 @@ static int want_object_in_pack(const struct object_id *oid,
}
}
+ if (uri_protocols.nr) {
+ struct configured_exclusion *ex =
+ oidmap_get(&configured_exclusions, oid);
+ int i;
+ const char *p;
+
+ if (ex) {
+ for (i = 0; i < uri_protocols.nr; i++) {
+ if (skip_prefix(ex->uri,
+ uri_protocols.items[i].string,
+ &p) &&
+ *p == ':') {
+ oidset_insert(&excluded_by_config, oid);
+ return 0;
+ }
+ }
+ }
+ }
+
return 1;
}
@@ -1655,9 +1705,30 @@ static int can_reuse_delta(const struct object_id *base_oid,
return 0;
}
-static void check_object(struct object_entry *entry)
+static void prefetch_to_pack(uint32_t object_index_start) {
+ struct oid_array to_fetch = OID_ARRAY_INIT;
+ uint32_t i;
+
+ for (i = object_index_start; i < to_pack.nr_objects; i++) {
+ struct object_entry *entry = to_pack.objects + i;
+
+ if (!oid_object_info_extended(the_repository,
+ &entry->idx.oid,
+ NULL,
+ OBJECT_INFO_FOR_PREFETCH))
+ continue;
+ oid_array_append(&to_fetch, &entry->idx.oid);
+ }
+ promisor_remote_get_direct(the_repository,
+ to_fetch.oid, to_fetch.nr);
+ oid_array_clear(&to_fetch);
+}
+
+static void check_object(struct object_entry *entry, uint32_t object_index)
{
unsigned long canonical_size;
+ enum object_type type;
+ struct object_info oi = {.typep = &type, .sizep = &canonical_size};
if (IN_PACK(entry)) {
struct packed_git *p = IN_PACK(entry);
@@ -1791,8 +1862,18 @@ static void check_object(struct object_entry *entry)
unuse_pack(&w_curs);
}
- oe_set_type(entry,
- oid_object_info(the_repository, &entry->idx.oid, &canonical_size));
+ if (oid_object_info_extended(the_repository, &entry->idx.oid, &oi,
+ OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_LOOKUP_REPLACE) < 0) {
+ if (has_promisor_remote()) {
+ prefetch_to_pack(object_index);
+ if (oid_object_info_extended(the_repository, &entry->idx.oid, &oi,
+ OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_LOOKUP_REPLACE) < 0)
+ type = -1;
+ } else {
+ type = -1;
+ }
+ }
+ oe_set_type(entry, type);
if (entry->type_valid) {
SET_SIZE(entry, canonical_size);
} else {
@@ -2012,7 +2093,7 @@ static void get_object_details(void)
for (i = 0; i < to_pack.nr_objects; i++) {
struct object_entry *entry = sorted_by_offset[i];
- check_object(entry);
+ check_object(entry, i);
if (entry->type_valid &&
oe_size_greater_than(&to_pack, entry, big_file_threshold))
entry->no_try_delta = 1;
@@ -2864,6 +2945,29 @@ static int git_pack_config(const char *k, const char *v, void *cb)
pack_idx_opts.version);
return 0;
}
+ if (!strcmp(k, "uploadpack.blobpackfileuri")) {
+ struct configured_exclusion *ex = xmalloc(sizeof(*ex));
+ const char *oid_end, *pack_end;
+ /*
+ * Stores the pack hash. This is not a true object ID, but is
+ * of the same form.
+ */
+ struct object_id pack_hash;
+
+ if (parse_oid_hex(v, &ex->e.oid, &oid_end) ||
+ *oid_end != ' ' ||
+ parse_oid_hex(oid_end + 1, &pack_hash, &pack_end) ||
+ *pack_end != ' ')
+ die(_("value of uploadpack.blobpackfileuri must be "
+ "of the form '<object-hash> <pack-hash> <uri>' (got '%s')"), v);
+ if (oidmap_get(&configured_exclusions, &ex->e.oid))
+ die(_("object already configured in another "
+ "uploadpack.blobpackfileuri (got '%s')"), v);
+ ex->pack_hash_hex = xcalloc(1, pack_end - oid_end);
+ memcpy(ex->pack_hash_hex, oid_end + 1, pack_end - oid_end - 1);
+ ex->uri = xstrdup(pack_end + 1);
+ oidmap_put(&configured_exclusions, ex);
+ }
return git_default_config(k, v, cb);
}
@@ -3462,6 +3566,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
N_("do not pack objects in promisor packfiles")),
OPT_BOOL(0, "delta-islands", &use_delta_islands,
N_("respect islands during delta compression")),
+ OPT_STRING_LIST(0, "uri-protocol", &uri_protocols,
+ N_("protocol"),
+ N_("exclude any configured uploadpack.blobpackfileuri with this protocol")),
OPT_END(),
};
@@ -3650,6 +3757,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
}
trace2_region_enter("pack-objects", "write-pack-file", the_repository);
+ write_excluded_by_configs();
write_pack_file();
trace2_region_leave("pack-objects", "write-pack-file", the_repository);
diff --git a/builtin/pull.c b/builtin/pull.c
index 00e5857..8159c5d 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -1025,12 +1025,14 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
commit_list_insert(head, &list);
merge_head = lookup_commit_reference(the_repository,
&merge_heads.oid[0]);
- if (is_descendant_of(merge_head, list)) {
+ if (repo_is_descendant_of(the_repository,
+ merge_head, list)) {
/* we can fast-forward this without invoking rebase */
opt_ff = "--ff-only";
ran_ff = 1;
ret = run_merge();
}
+ free_commit_list(list);
}
if (!ran_ff)
ret = run_rebase(&curr_head, merge_heads.oid, &rebase_fork_point);
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index ea3d0f0..d43663b 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -249,6 +249,7 @@ static void show_ref(const char *path, const struct object_id *oid)
strbuf_addf(&cap, " push-cert=%s", push_cert_nonce);
if (advertise_push_options)
strbuf_addstr(&cap, " push-options");
+ strbuf_addf(&cap, " object-format=%s", the_hash_algo->name);
strbuf_addf(&cap, " agent=%s", git_user_agent_sanitized());
packet_write_fmt(1, "%s %s%c%s\n",
oid_to_hex(oid), path, 0, cap.buf);
@@ -1624,6 +1625,8 @@ static struct command *read_head_info(struct packet_reader *reader,
linelen = strlen(reader->line);
if (linelen < reader->pktlen) {
const char *feature_list = reader->line + linelen + 1;
+ const char *hash = NULL;
+ int len = 0;
if (parse_feature_request(feature_list, "report-status"))
report_status = 1;
if (parse_feature_request(feature_list, "side-band-64k"))
@@ -1636,6 +1639,13 @@ static struct command *read_head_info(struct packet_reader *reader,
if (advertise_push_options
&& parse_feature_request(feature_list, "push-options"))
use_push_options = 1;
+ hash = parse_feature_value(feature_list, "object-format", &len, NULL);
+ if (!hash) {
+ hash = hash_algos[GIT_HASH_SHA1].name;
+ len = strlen(hash);
+ }
+ if (xstrncmpz(the_hash_algo->name, hash, len))
+ die("error: unsupported object format '%s'", hash);
}
if (!strcmp(reader->line, "push-cert")) {
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 52ecf6d..ca1d807 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -615,7 +615,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
int i;
memset(&collected, 0, sizeof(collected));
- worktrees = get_worktrees(0);
+ worktrees = get_worktrees();
for (p = worktrees; *p; p++) {
if (!all_worktrees && !(*p)->is_current)
continue;
diff --git a/builtin/show-index.c b/builtin/show-index.c
index 0826f6a..8106b03 100644
--- a/builtin/show-index.c
+++ b/builtin/show-index.c
@@ -1,9 +1,12 @@
#include "builtin.h"
#include "cache.h"
#include "pack.h"
+#include "parse-options.h"
-static const char show_index_usage[] =
-"git show-index";
+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)
{
@@ -11,10 +14,26 @@ int cmd_show_index(int argc, const char **argv, const char *prefix)
unsigned nr;
unsigned int version;
static unsigned int top_index[256];
- const unsigned hashsz = the_hash_algo->rawsz;
+ unsigned hashsz;
+ const char *hash_name = NULL;
+ int hash_algo;
+ const struct option show_index_options[] = {
+ OPT_STRING(0, "object-format", &hash_name, N_("hash-algorithm"),
+ N_("specify the hash algorithm to use")),
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, prefix, show_index_options, show_index_usage, 0);
+
+ if (hash_name) {
+ hash_algo = hash_algo_by_name(hash_name);
+ if (hash_algo == GIT_HASH_UNKNOWN)
+ die(_("Unknown hash algorithm"));
+ repo_set_hash_algo(the_repository, hash_algo);
+ }
+
+ hashsz = the_hash_algo->rawsz;
- if (argc != 1)
- usage(show_index_usage);
if (fread(top_index, 2 * 4, 1, stdin) != 1)
die("unable to read header");
if (top_index[0] == htonl(PACK_IDX_SIGNATURE)) {
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index 95d0882..4003f4d 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -99,6 +99,10 @@ static int update_working_directory(struct pattern_list *pl)
struct lock_file lock_file = LOCK_INIT;
struct repository *r = the_repository;
+ /* If no branch has been checked out, there are no updates to make. */
+ if (is_index_unborn(r->index))
+ return UPDATE_SPARSITY_SUCCESS;
+
memset(&o, 0, sizeof(o));
o.verbose_update = isatty(2);
o.update = 1;
@@ -249,6 +253,8 @@ static int set_config(enum sparse_checkout_mode mode)
{
const char *config_path;
+ if (upgrade_repository_format(1) < 0)
+ die(_("unable to upgrade repository format to enable worktreeConfig"));
if (git_config_set_gently("extensions.worktreeConfig", "true")) {
error(_("failed to set extensions.worktreeConfig setting"));
return 1;
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 46c03d2..a1c7560 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1981,7 +1981,7 @@ static const char *remote_submodule_branch(const char *path)
free(key);
if (!branch)
- return "master";
+ return "HEAD";
if (!strcmp(branch, ".")) {
const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
@@ -2277,6 +2277,49 @@ static int module_set_url(int argc, const char **argv, const char *prefix)
return 0;
}
+static int module_set_branch(int argc, const char **argv, const char *prefix)
+{
+ int opt_default = 0, ret;
+ const char *opt_branch = NULL;
+ const char *path;
+ char *config_name;
+
+ /*
+ * We accept the `quiet` option for uniformity across subcommands,
+ * though there is nothing to make less verbose in this subcommand.
+ */
+ struct option options[] = {
+ OPT_NOOP_NOARG('q', "quiet"),
+ OPT_BOOL('d', "default", &opt_default,
+ N_("set the default tracking branch to master")),
+ OPT_STRING('b', "branch", &opt_branch, N_("branch"),
+ N_("set the default tracking branch")),
+ OPT_END()
+ };
+ const char *const usage[] = {
+ N_("git submodule--helper set-branch [-q|--quiet] (-d|--default) <path>"),
+ N_("git submodule--helper set-branch [-q|--quiet] (-b|--branch) <branch> <path>"),
+ NULL
+ };
+
+ argc = parse_options(argc, argv, prefix, options, usage, 0);
+
+ if (!opt_branch && !opt_default)
+ die(_("--branch or --default required"));
+
+ if (opt_branch && opt_default)
+ die(_("--branch and --default are mutually exclusive"));
+
+ if (argc != 1 || !(path = argv[0]))
+ usage_with_options(usage, options);
+
+ config_name = xstrfmt("submodule.%s.branch", path);
+ ret = config_set_in_gitmodules_file_gently(config_name, opt_branch);
+
+ free(config_name);
+ return !!ret;
+}
+
#define SUPPORT_SUPER_PREFIX (1<<0)
struct cmd_struct {
@@ -2308,6 +2351,7 @@ static struct cmd_struct commands[] = {
{"check-name", check_name, 0},
{"config", module_config, 0},
{"set-url", module_set_url, 0},
+ {"set-branch", module_set_branch, 0},
};
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/builtin/worktree.c b/builtin/worktree.c
index d99db35..f0cbdef 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -67,7 +67,12 @@ static void delete_worktrees_dir_if_empty(void)
rmdir(git_path("worktrees")); /* ignore failed removal */
}
-static int prune_worktree(const char *id, struct strbuf *reason)
+/*
+ * Return true if worktree entry should be pruned, along with the reason for
+ * pruning. Otherwise, return false and the worktree's path, or NULL if it
+ * cannot be determined. Caller is responsible for freeing returned path.
+ */
+static int should_prune_worktree(const char *id, struct strbuf *reason, char **wtpath)
{
struct stat st;
char *path;
@@ -75,20 +80,21 @@ static int prune_worktree(const char *id, struct strbuf *reason)
size_t len;
ssize_t read_result;
+ *wtpath = NULL;
if (!is_directory(git_path("worktrees/%s", id))) {
- strbuf_addf(reason, _("Removing worktrees/%s: not a valid directory"), id);
+ strbuf_addstr(reason, _("not a valid directory"));
return 1;
}
if (file_exists(git_path("worktrees/%s/locked", id)))
return 0;
if (stat(git_path("worktrees/%s/gitdir", id), &st)) {
- strbuf_addf(reason, _("Removing worktrees/%s: gitdir file does not exist"), id);
+ strbuf_addstr(reason, _("gitdir file does not exist"));
return 1;
}
fd = open(git_path("worktrees/%s/gitdir", id), O_RDONLY);
if (fd < 0) {
- strbuf_addf(reason, _("Removing worktrees/%s: unable to read gitdir file (%s)"),
- id, strerror(errno));
+ strbuf_addf(reason, _("unable to read gitdir file (%s)"),
+ strerror(errno));
return 1;
}
len = xsize_t(st.st_size);
@@ -96,8 +102,8 @@ static int prune_worktree(const char *id, struct strbuf *reason)
read_result = read_in_full(fd, path, len);
if (read_result < 0) {
- strbuf_addf(reason, _("Removing worktrees/%s: unable to read gitdir file (%s)"),
- id, strerror(errno));
+ strbuf_addf(reason, _("unable to read gitdir file (%s)"),
+ strerror(errno));
close(fd);
free(path);
return 1;
@@ -106,53 +112,103 @@ static int prune_worktree(const char *id, struct strbuf *reason)
if (read_result != len) {
strbuf_addf(reason,
- _("Removing worktrees/%s: short read (expected %"PRIuMAX" bytes, read %"PRIuMAX")"),
- id, (uintmax_t)len, (uintmax_t)read_result);
+ _("short read (expected %"PRIuMAX" bytes, read %"PRIuMAX")"),
+ (uintmax_t)len, (uintmax_t)read_result);
free(path);
return 1;
}
while (len && (path[len - 1] == '\n' || path[len - 1] == '\r'))
len--;
if (!len) {
- strbuf_addf(reason, _("Removing worktrees/%s: invalid gitdir file"), id);
+ strbuf_addstr(reason, _("invalid gitdir file"));
free(path);
return 1;
}
path[len] = '\0';
if (!file_exists(path)) {
- free(path);
if (stat(git_path("worktrees/%s/index", id), &st) ||
st.st_mtime <= expire) {
- strbuf_addf(reason, _("Removing worktrees/%s: gitdir file points to non-existent location"), id);
+ strbuf_addstr(reason, _("gitdir file points to non-existent location"));
+ free(path);
return 1;
} else {
+ *wtpath = path;
return 0;
}
}
- free(path);
+ *wtpath = path;
return 0;
}
+static void prune_worktree(const char *id, const char *reason)
+{
+ if (show_only || verbose)
+ printf_ln(_("Removing %s/%s: %s"), "worktrees", id, reason);
+ if (!show_only)
+ delete_git_dir(id);
+}
+
+static int prune_cmp(const void *a, const void *b)
+{
+ const struct string_list_item *x = a;
+ const struct string_list_item *y = b;
+ int c;
+
+ if ((c = fspathcmp(x->string, y->string)))
+ return c;
+ /*
+ * paths same; prune_dupes() removes all but the first worktree entry
+ * having the same path, so sort main worktree ('util' is NULL) above
+ * linked worktrees ('util' not NULL) since main worktree can't be
+ * removed
+ */
+ if (!x->util)
+ return -1;
+ if (!y->util)
+ return 1;
+ /* paths same; sort by .git/worktrees/<id> */
+ return strcmp(x->util, y->util);
+}
+
+static void prune_dups(struct string_list *l)
+{
+ int i;
+
+ QSORT(l->items, l->nr, prune_cmp);
+ for (i = 1; i < l->nr; i++) {
+ if (!fspathcmp(l->items[i].string, l->items[i - 1].string))
+ prune_worktree(l->items[i].util, "duplicate entry");
+ }
+}
+
static void prune_worktrees(void)
{
struct strbuf reason = STRBUF_INIT;
+ struct strbuf main_path = STRBUF_INIT;
+ struct string_list kept = STRING_LIST_INIT_NODUP;
DIR *dir = opendir(git_path("worktrees"));
struct dirent *d;
if (!dir)
return;
while ((d = readdir(dir)) != NULL) {
+ char *path;
if (is_dot_or_dotdot(d->d_name))
continue;
strbuf_reset(&reason);
- if (!prune_worktree(d->d_name, &reason))
- continue;
- if (show_only || verbose)
- printf("%s\n", reason.buf);
- if (show_only)
- continue;
- delete_git_dir(d->d_name);
+ if (should_prune_worktree(d->d_name, &reason, &path))
+ prune_worktree(d->d_name, reason.buf);
+ else if (path)
+ string_list_append(&kept, path)->util = xstrdup(d->d_name);
}
closedir(dir);
+
+ strbuf_add_absolute_path(&main_path, get_git_common_dir());
+ /* massage main worktree absolute path to match 'gitdir' content */
+ strbuf_strip_suffix(&main_path, "/.");
+ string_list_append(&kept, strbuf_detach(&main_path, NULL));
+ prune_dups(&kept);
+ string_list_clear(&kept, 1);
+
if (!show_only)
delete_worktrees_dir_if_empty();
strbuf_release(&reason);
@@ -224,34 +280,33 @@ static const char *worktree_basename(const char *path, int *olen)
return name;
}
-static void validate_worktree_add(const char *path, const struct add_opts *opts)
+/* check that path is viable location for worktree */
+static void check_candidate_path(const char *path,
+ int force,
+ struct worktree **worktrees,
+ const char *cmd)
{
- struct worktree **worktrees;
struct worktree *wt;
int locked;
if (file_exists(path) && !is_empty_dir(path))
die(_("'%s' already exists"), path);
- worktrees = get_worktrees(0);
wt = find_worktree_by_path(worktrees, path);
if (!wt)
- goto done;
+ return;
locked = !!worktree_lock_reason(wt);
- if ((!locked && opts->force) || (locked && opts->force > 1)) {
+ if ((!locked && force) || (locked && force > 1)) {
if (delete_git_dir(wt->id))
- die(_("unable to re-add worktree '%s'"), path);
- goto done;
+ die(_("unusable worktree destination '%s'"), path);
+ return;
}
if (locked)
- die(_("'%s' is a missing but locked worktree;\nuse 'add -f -f' to override, or 'unlock' and 'prune' or 'remove' to clear"), path);
+ die(_("'%s' is a missing but locked worktree;\nuse '%s -f -f' to override, or 'unlock' and 'prune' or 'remove' to clear"), cmd, path);
else
- die(_("'%s' is a missing but already registered worktree;\nuse 'add -f' to override, or 'prune' or 'remove' to clear"), path);
-
-done:
- free_worktrees(worktrees);
+ die(_("'%s' is a missing but already registered worktree;\nuse '%s -f' to override, or 'prune' or 'remove' to clear"), cmd, path);
}
static int add_worktree(const char *path, const char *refname,
@@ -268,8 +323,12 @@ 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;
- validate_worktree_add(path, opts);
+ worktrees = get_worktrees();
+ check_candidate_path(path, opts->force, worktrees, "add");
+ free_worktrees(worktrees);
+ worktrees = NULL;
/* is 'refname' a branch or commit? */
if (!opts->detach && !strbuf_check_branch_ref(&symref, refname) &&
@@ -638,6 +697,23 @@ static void measure_widths(struct worktree **wt, int *abbrev, int *maxlen)
}
}
+static int pathcmp(const void *a_, const void *b_)
+{
+ const struct worktree *const *a = a_;
+ const struct worktree *const *b = b_;
+ return fspathcmp((*a)->path, (*b)->path);
+}
+
+static void pathsort(struct worktree **wt)
+{
+ int n = 0;
+ struct worktree **p = wt;
+
+ while (*p++)
+ n++;
+ QSORT(wt, n, pathcmp);
+}
+
static int list(int ac, const char **av, const char *prefix)
{
int porcelain = 0;
@@ -651,9 +727,12 @@ static int list(int ac, const char **av, const char *prefix)
if (ac)
usage_with_options(worktree_usage, options);
else {
- struct worktree **worktrees = get_worktrees(GWT_SORT_LINKED);
+ struct worktree **worktrees = get_worktrees();
int path_maxlen = 0, abbrev = DEFAULT_ABBREV, i;
+ /* sort worktrees by path but keep main worktree at top */
+ pathsort(worktrees + 1);
+
if (!porcelain)
measure_widths(worktrees, &abbrev, &path_maxlen);
@@ -682,7 +761,7 @@ static int lock_worktree(int ac, const char **av, const char *prefix)
if (ac != 1)
usage_with_options(worktree_usage, options);
- worktrees = get_worktrees(0);
+ worktrees = get_worktrees();
wt = find_worktree(worktrees, prefix, av[0]);
if (!wt)
die(_("'%s' is not a working tree"), av[0]);
@@ -715,7 +794,7 @@ static int unlock_worktree(int ac, const char **av, const char *prefix)
if (ac != 1)
usage_with_options(worktree_usage, options);
- worktrees = get_worktrees(0);
+ worktrees = get_worktrees();
wt = find_worktree(worktrees, prefix, av[0]);
if (!wt)
die(_("'%s' is not a working tree"), av[0]);
@@ -789,7 +868,7 @@ static int move_worktree(int ac, const char **av, const char *prefix)
strbuf_addstr(&dst, path);
free(path);
- worktrees = get_worktrees(0);
+ worktrees = get_worktrees();
wt = find_worktree(worktrees, prefix, av[0]);
if (!wt)
die(_("'%s' is not a working tree"), av[0]);
@@ -804,8 +883,7 @@ static int move_worktree(int ac, const char **av, const char *prefix)
strbuf_trim_trailing_dir_sep(&dst);
strbuf_addstr(&dst, sep);
}
- if (file_exists(dst.buf))
- die(_("target '%s' already exists"), dst.buf);
+ check_candidate_path(dst.buf, force, worktrees, "move");
validate_no_submodules(wt);
@@ -916,7 +994,7 @@ static int remove_worktree(int ac, const char **av, const char *prefix)
if (ac != 1)
usage_with_options(worktree_usage, options);
- worktrees = get_worktrees(0);
+ worktrees = get_worktrees();
wt = find_worktree(worktrees, prefix, av[0]);
if (!wt)
die(_("'%s' is not a working tree"), av[0]);
diff --git a/bundle.c b/bundle.c
index 99439e0..2a0d744 100644
--- a/bundle.c
+++ b/bundle.c
@@ -23,6 +23,17 @@ static void add_to_ref_list(const struct object_id *oid, const char *name,
list->nr++;
}
+static const struct git_hash_algo *detect_hash_algo(struct strbuf *buf)
+{
+ size_t len = strcspn(buf->buf, " \n");
+ int algo;
+
+ algo = hash_algo_by_length(len / 2);
+ if (algo == GIT_HASH_UNKNOWN)
+ return NULL;
+ return &hash_algos[algo];
+}
+
static int parse_bundle_header(int fd, struct bundle_header *header,
const char *report_path)
{
@@ -52,12 +63,21 @@ static int parse_bundle_header(int fd, struct bundle_header *header,
}
strbuf_rtrim(&buf);
+ if (!header->hash_algo) {
+ header->hash_algo = detect_hash_algo(&buf);
+ if (!header->hash_algo) {
+ error(_("unknown hash algorithm length"));
+ status = -1;
+ break;
+ }
+ }
+
/*
* Tip lines have object name, SP, and refname.
* Prerequisites have object name that is optionally
* followed by SP and subject line.
*/
- if (parse_oid_hex(buf.buf, &oid, &p) ||
+ if (parse_oid_hex_algop(buf.buf, &oid, &p, header->hash_algo) ||
(*p && !isspace(*p)) ||
(!is_prereq && !*p)) {
if (report_path)
diff --git a/bundle.h b/bundle.h
index ceab0c7..2dc9442 100644
--- a/bundle.h
+++ b/bundle.h
@@ -15,6 +15,7 @@ struct ref_list {
struct bundle_header {
struct ref_list prerequisites;
struct ref_list references;
+ const struct git_hash_algo *hash_algo;
};
int is_bundle(const char *path, int quiet);
diff --git a/cache.h b/cache.h
index 0f0485e..0290849 100644
--- a/cache.h
+++ b/cache.h
@@ -628,7 +628,7 @@ int path_inside_repo(const char *prefix, const char *path);
int init_db(const char *git_dir, const char *real_git_dir,
const char *template_dir, int hash_algo,
- unsigned int flags);
+ const char *initial_branch, unsigned int flags);
void initialize_repository_version(int hash_algo);
void sanitize_stdfds(void);
@@ -1044,6 +1044,7 @@ struct repository_format {
int hash_algo;
char *work_tree;
struct string_list unknown_extensions;
+ struct string_list v1_only_extensions;
};
/*
@@ -1057,6 +1058,7 @@ struct repository_format {
.is_bare = -1, \
.hash_algo = GIT_HASH_SHA1, \
.unknown_extensions = STRING_LIST_INIT_DUP, \
+ .v1_only_extensions = STRING_LIST_INIT_DUP, \
}
/*
diff --git a/ci/lib.sh b/ci/lib.sh
index ff24c54..3eefec5 100755
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -184,9 +184,9 @@ linux-clang|linux-gcc)
if [ "$jobname" = linux-gcc ]
then
export CC=gcc-8
- MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=$(which python3)"
+ MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=/usr/bin/python3"
else
- MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=$(which python2)"
+ MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=/usr/bin/python2"
fi
export GIT_TEST_HTTPD=true
diff --git a/column.c b/column.c
index 4a38eed..a58969b 100644
--- a/column.c
+++ b/column.c
@@ -107,7 +107,7 @@ static void display_plain(const struct string_list *list,
printf("%s%s%s", indent, list->items[i].string, nl);
}
-/* Print a cell to stdout with all necessary leading/traling space */
+/* Print a cell to stdout with all necessary leading/trailing space */
static int display_cell(struct column_data *data, int initial_width,
const char *empty_cell, int x, int y)
{
diff --git a/command-list.txt b/command-list.txt
index cbb960c..89aa60c 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -136,7 +136,7 @@ git-pack-redundant plumbinginterrogators
git-pack-refs ancillarymanipulators
git-parse-remote synchelpers
git-patch-id purehelpers
-git-prune ancillarymanipulators
+git-prune ancillarymanipulators complete
git-prune-packed plumbingmanipulators
git-pull mainporcelain remote
git-push mainporcelain remote
diff --git a/commit-graph.c b/commit-graph.c
index e3420dd..e51c91d 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -1,7 +1,5 @@
-#include "cache.h"
-#include "config.h"
-#include "dir.h"
#include "git-compat-util.h"
+#include "config.h"
#include "lockfile.h"
#include "pack.h"
#include "packfile.h"
@@ -19,6 +17,8 @@
#include "bloom.h"
#include "commit-slab.h"
#include "shallow.h"
+#include "json-writer.h"
+#include "trace2.h"
void git_test_write_commit_graph_or_die(void)
{
@@ -87,15 +87,69 @@ static int commit_pos_cmp(const void *va, const void *vb)
commit_pos_at(&commit_pos, b);
}
+define_commit_slab(commit_graph_data_slab, struct commit_graph_data);
+static struct commit_graph_data_slab commit_graph_data_slab =
+ COMMIT_SLAB_INIT(1, commit_graph_data_slab);
+
+uint32_t commit_graph_position(const struct commit *c)
+{
+ struct commit_graph_data *data =
+ commit_graph_data_slab_peek(&commit_graph_data_slab, c);
+
+ return data ? data->graph_pos : COMMIT_NOT_FROM_GRAPH;
+}
+
+uint32_t commit_graph_generation(const struct commit *c)
+{
+ struct commit_graph_data *data =
+ commit_graph_data_slab_peek(&commit_graph_data_slab, c);
+
+ if (!data)
+ return GENERATION_NUMBER_INFINITY;
+ else if (data->graph_pos == COMMIT_NOT_FROM_GRAPH)
+ return GENERATION_NUMBER_INFINITY;
+
+ return data->generation;
+}
+
+static struct commit_graph_data *commit_graph_data_at(const struct commit *c)
+{
+ unsigned int i, nth_slab;
+ struct commit_graph_data *data =
+ commit_graph_data_slab_peek(&commit_graph_data_slab, c);
+
+ if (data)
+ return data;
+
+ nth_slab = c->index / commit_graph_data_slab.slab_size;
+ data = commit_graph_data_slab_at(&commit_graph_data_slab, c);
+
+ /*
+ * commit-slab initializes elements with zero, overwrite this with
+ * COMMIT_NOT_FROM_GRAPH for graph_pos.
+ *
+ * We avoid initializing generation with checking if graph position
+ * is not COMMIT_NOT_FROM_GRAPH.
+ */
+ for (i = 0; i < commit_graph_data_slab.slab_size; i++) {
+ commit_graph_data_slab.slab[nth_slab][i].graph_pos =
+ COMMIT_NOT_FROM_GRAPH;
+ }
+
+ return data;
+}
+
static int commit_gen_cmp(const void *va, const void *vb)
{
const struct commit *a = *(const struct commit **)va;
const struct commit *b = *(const struct commit **)vb;
+ uint32_t generation_a = commit_graph_generation(a);
+ uint32_t generation_b = commit_graph_generation(b);
/* lower generation commits first */
- if (a->generation < b->generation)
+ if (generation_a < generation_b)
return -1;
- else if (a->generation > b->generation)
+ else if (generation_a > generation_b)
return 1;
/* use date as a heuristic when generations are equal */
@@ -149,7 +203,8 @@ static int commit_graph_compatible(struct repository *r)
}
prepare_commit_graft(r);
- if (r->parsed_objects && r->parsed_objects->grafts_nr)
+ if (r->parsed_objects &&
+ (r->parsed_objects->grafts_nr || r->parsed_objects->substituted_parent))
return 0;
if (is_repository_shallow(r))
return 0;
@@ -230,8 +285,7 @@ struct commit_graph *parse_commit_graph(void *graph_map, size_t graph_size)
const unsigned char *data, *chunk_lookup;
uint32_t i;
struct commit_graph *graph;
- uint64_t last_chunk_offset;
- uint32_t last_chunk_id;
+ uint64_t next_chunk_offset;
uint32_t graph_signature;
unsigned char graph_version, hash_version;
@@ -271,24 +325,26 @@ struct commit_graph *parse_commit_graph(void *graph_map, size_t graph_size)
graph->data = graph_map;
graph->data_len = graph_size;
- last_chunk_id = 0;
- last_chunk_offset = 8;
+ if (graph_size < GRAPH_HEADER_SIZE +
+ (graph->num_chunks + 1) * GRAPH_CHUNKLOOKUP_WIDTH +
+ GRAPH_FANOUT_SIZE + the_hash_algo->rawsz) {
+ error(_("commit-graph file is too small to hold %u chunks"),
+ graph->num_chunks);
+ free(graph);
+ return NULL;
+ }
+
chunk_lookup = data + 8;
+ next_chunk_offset = get_be64(chunk_lookup + 4);
for (i = 0; i < graph->num_chunks; i++) {
uint32_t chunk_id;
- uint64_t chunk_offset;
+ uint64_t chunk_offset = next_chunk_offset;
int chunk_repeated = 0;
- if (data + graph_size - chunk_lookup <
- GRAPH_CHUNKLOOKUP_WIDTH) {
- error(_("commit-graph chunk lookup table entry missing; file may be incomplete"));
- goto free_and_return;
- }
-
chunk_id = get_be32(chunk_lookup + 0);
- chunk_offset = get_be64(chunk_lookup + 4);
chunk_lookup += GRAPH_CHUNKLOOKUP_WIDTH;
+ next_chunk_offset = get_be64(chunk_lookup + 4);
if (chunk_offset > graph_size - the_hash_algo->rawsz) {
error(_("commit-graph improper chunk offset %08x%08x"), (uint32_t)(chunk_offset >> 32),
@@ -307,8 +363,11 @@ struct commit_graph *parse_commit_graph(void *graph_map, size_t graph_size)
case GRAPH_CHUNKID_OIDLOOKUP:
if (graph->chunk_oid_lookup)
chunk_repeated = 1;
- else
+ else {
graph->chunk_oid_lookup = data + chunk_offset;
+ graph->num_commits = (next_chunk_offset - chunk_offset)
+ / graph->hash_len;
+ }
break;
case GRAPH_CHUNKID_DATA:
@@ -362,15 +421,6 @@ struct commit_graph *parse_commit_graph(void *graph_map, size_t graph_size)
error(_("commit-graph chunk id %08x appears multiple times"), chunk_id);
goto free_and_return;
}
-
- if (last_chunk_id == GRAPH_CHUNKID_OIDLOOKUP)
- {
- graph->num_commits = (chunk_offset - last_chunk_offset)
- / graph->hash_len;
- }
-
- last_chunk_id = chunk_id;
- last_chunk_offset = chunk_offset;
}
if (graph->chunk_bloom_indexes && graph->chunk_bloom_data) {
@@ -569,10 +619,6 @@ static int prepare_commit_graph(struct repository *r)
return !!r->objects->commit_graph;
r->objects->commit_graph_attempted = 1;
- if (git_env_bool(GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD, 0))
- die("dying as requested by the '%s' variable on commit-graph load!",
- GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD);
-
prepare_repo_settings(r);
if (!git_env_bool(GIT_TEST_COMMIT_GRAPH, 0) &&
@@ -670,13 +716,14 @@ static struct commit_list **insert_parent_or_die(struct repository *r,
c = lookup_commit(r, &oid);
if (!c)
die(_("could not find commit %s"), oid_to_hex(&oid));
- c->graph_pos = pos;
+ commit_graph_data_at(c)->graph_pos = pos;
return &commit_list_insert(c, pptr)->next;
}
static void fill_commit_graph_info(struct commit *item, struct commit_graph *g, uint32_t pos)
{
const unsigned char *commit_data;
+ struct commit_graph_data *graph_data;
uint32_t lex_index;
while (pos < g->num_commits_in_base)
@@ -684,8 +731,10 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,
lex_index = pos - g->num_commits_in_base;
commit_data = g->chunk_commit_data + GRAPH_DATA_WIDTH * lex_index;
- item->graph_pos = pos;
- item->generation = get_be32(commit_data + g->hash_len + 8) >> 2;
+
+ graph_data = commit_graph_data_at(item);
+ graph_data->graph_pos = pos;
+ graph_data->generation = get_be32(commit_data + g->hash_len + 8) >> 2;
}
static inline void set_commit_tree(struct commit *c, struct tree *t)
@@ -701,6 +750,7 @@ static int fill_commit_in_graph(struct repository *r,
uint32_t *parent_data_ptr;
uint64_t date_low, date_high;
struct commit_list **pptr;
+ struct commit_graph_data *graph_data;
const unsigned char *commit_data;
uint32_t lex_index;
@@ -714,7 +764,8 @@ static int fill_commit_in_graph(struct repository *r,
* Store the "full" position, but then use the
* "local" position for the rest of the calculation.
*/
- item->graph_pos = pos;
+ graph_data = commit_graph_data_at(item);
+ graph_data->graph_pos = pos;
lex_index = pos - g->num_commits_in_base;
commit_data = g->chunk_commit_data + (g->hash_len + 16) * lex_index;
@@ -727,7 +778,7 @@ static int fill_commit_in_graph(struct repository *r,
date_low = get_be32(commit_data + g->hash_len + 12);
item->date = (timestamp_t)((date_high << 32) | date_low);
- item->generation = get_be32(commit_data + g->hash_len + 8) >> 2;
+ graph_data->generation = get_be32(commit_data + g->hash_len + 8) >> 2;
pptr = &item->parents;
@@ -759,8 +810,9 @@ static int fill_commit_in_graph(struct repository *r,
static int find_commit_in_graph(struct commit *item, struct commit_graph *g, uint32_t *pos)
{
- if (item->graph_pos != COMMIT_NOT_FROM_GRAPH) {
- *pos = item->graph_pos;
+ uint32_t graph_pos = commit_graph_position(item);
+ if (graph_pos != COMMIT_NOT_FROM_GRAPH) {
+ *pos = graph_pos;
return 1;
} else {
struct commit_graph *cur_g = g;
@@ -795,6 +847,14 @@ static int parse_commit_in_graph_one(struct repository *r,
int parse_commit_in_graph(struct repository *r, struct commit *item)
{
+ static int checked_env = 0;
+
+ if (!checked_env &&
+ git_env_bool(GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE, 0))
+ die("dying as requested by the '%s' variable on commit-graph parse!",
+ GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE);
+ checked_env = 1;
+
if (!prepare_commit_graph(r))
return 0;
return parse_commit_in_graph_one(r, r->objects->commit_graph, item);
@@ -815,12 +875,13 @@ static struct tree *load_tree_for_commit(struct repository *r,
{
struct object_id oid;
const unsigned char *commit_data;
+ uint32_t graph_pos = commit_graph_position(c);
- while (c->graph_pos < g->num_commits_in_base)
+ while (graph_pos < g->num_commits_in_base)
g = g->base_graph;
commit_data = g->chunk_commit_data +
- GRAPH_DATA_WIDTH * (c->graph_pos - g->num_commits_in_base);
+ GRAPH_DATA_WIDTH * (graph_pos - g->num_commits_in_base);
hashcpy(oid.hash, commit_data);
set_commit_tree(c, lookup_tree(r, &oid));
@@ -834,7 +895,7 @@ static struct tree *get_commit_tree_in_graph_one(struct repository *r,
{
if (c->maybe_tree)
return c->maybe_tree;
- if (c->graph_pos == COMMIT_NOT_FROM_GRAPH)
+ if (commit_graph_position(c) == COMMIT_NOT_FROM_GRAPH)
BUG("get_commit_tree_in_graph_one called from non-commit-graph commit");
return load_tree_for_commit(r, g, (struct commit *)c);
@@ -881,16 +942,16 @@ struct write_commit_graph_context {
unsigned append:1,
report_progress:1,
split:1,
- check_oids:1,
changed_paths:1,
order_by_pack:1;
const struct split_commit_graph_opts *split_opts;
size_t total_bloom_filter_data_size;
+ const struct bloom_filter_settings *bloom_settings;
};
-static void write_graph_chunk_fanout(struct hashfile *f,
- struct write_commit_graph_context *ctx)
+static int write_graph_chunk_fanout(struct hashfile *f,
+ struct write_commit_graph_context *ctx)
{
int i, count = 0;
struct commit **list = ctx->commits.list;
@@ -911,17 +972,21 @@ static void write_graph_chunk_fanout(struct hashfile *f,
hashwrite_be32(f, count);
}
+
+ return 0;
}
-static void write_graph_chunk_oids(struct hashfile *f, int hash_len,
- struct write_commit_graph_context *ctx)
+static int write_graph_chunk_oids(struct hashfile *f,
+ struct write_commit_graph_context *ctx)
{
struct commit **list = ctx->commits.list;
int count;
for (count = 0; count < ctx->commits.nr; count++, list++) {
display_progress(ctx->progress, ++ctx->progress_cnt);
- hashwrite(f, (*list)->object.oid.hash, (int)hash_len);
+ hashwrite(f, (*list)->object.oid.hash, the_hash_algo->rawsz);
}
+
+ return 0;
}
static const unsigned char *commit_to_sha1(size_t index, void *table)
@@ -930,8 +995,8 @@ static const unsigned char *commit_to_sha1(size_t index, void *table)
return commits[index]->object.oid.hash;
}
-static void write_graph_chunk_data(struct hashfile *f, int hash_len,
- struct write_commit_graph_context *ctx)
+static int write_graph_chunk_data(struct hashfile *f,
+ struct write_commit_graph_context *ctx)
{
struct commit **list = ctx->commits.list;
struct commit **last = ctx->commits.list + ctx->commits.nr;
@@ -948,7 +1013,7 @@ static void write_graph_chunk_data(struct hashfile *f, int hash_len,
die(_("unable to parse commit %s"),
oid_to_hex(&(*list)->object.oid));
tree = get_commit_tree_oid(*list);
- hashwrite(f, tree->hash, hash_len);
+ hashwrite(f, tree->hash, the_hash_algo->rawsz);
parent = (*list)->parents;
@@ -1021,17 +1086,19 @@ static void write_graph_chunk_data(struct hashfile *f, int hash_len,
else
packedDate[0] = 0;
- packedDate[0] |= htonl((*list)->generation << 2);
+ packedDate[0] |= htonl(commit_graph_data_at(*list)->generation << 2);
packedDate[1] = htonl((*list)->date);
hashwrite(f, packedDate, 8);
list++;
}
+
+ return 0;
}
-static void write_graph_chunk_extra_edges(struct hashfile *f,
- struct write_commit_graph_context *ctx)
+static int write_graph_chunk_extra_edges(struct hashfile *f,
+ struct write_commit_graph_context *ctx)
{
struct commit **list = ctx->commits.list;
struct commit **last = ctx->commits.list + ctx->commits.nr;
@@ -1080,59 +1147,67 @@ static void write_graph_chunk_extra_edges(struct hashfile *f,
list++;
}
+
+ return 0;
}
-static void write_graph_chunk_bloom_indexes(struct hashfile *f,
- struct write_commit_graph_context *ctx)
+static int write_graph_chunk_bloom_indexes(struct hashfile *f,
+ struct write_commit_graph_context *ctx)
{
struct commit **list = ctx->commits.list;
struct commit **last = ctx->commits.list + ctx->commits.nr;
uint32_t cur_pos = 0;
- struct progress *progress = NULL;
- int i = 0;
-
- if (ctx->report_progress)
- progress = start_delayed_progress(
- _("Writing changed paths Bloom filters index"),
- ctx->commits.nr);
while (list < last) {
struct bloom_filter *filter = get_bloom_filter(ctx->r, *list, 0);
- cur_pos += filter->len;
- display_progress(progress, ++i);
+ size_t len = filter ? filter->len : 0;
+ cur_pos += len;
+ display_progress(ctx->progress, ++ctx->progress_cnt);
hashwrite_be32(f, cur_pos);
list++;
}
- stop_progress(&progress);
+ return 0;
}
-static void write_graph_chunk_bloom_data(struct hashfile *f,
- struct write_commit_graph_context *ctx,
- const struct bloom_filter_settings *settings)
+static void trace2_bloom_filter_settings(struct write_commit_graph_context *ctx)
+{
+ struct json_writer jw = JSON_WRITER_INIT;
+
+ jw_object_begin(&jw, 0);
+ jw_object_intmax(&jw, "hash_version", ctx->bloom_settings->hash_version);
+ jw_object_intmax(&jw, "num_hashes", ctx->bloom_settings->num_hashes);
+ jw_object_intmax(&jw, "bits_per_entry", ctx->bloom_settings->bits_per_entry);
+ jw_end(&jw);
+
+ trace2_data_json("bloom", ctx->r, "settings", &jw);
+
+ jw_release(&jw);
+}
+
+static int write_graph_chunk_bloom_data(struct hashfile *f,
+ struct write_commit_graph_context *ctx)
{
struct commit **list = ctx->commits.list;
struct commit **last = ctx->commits.list + ctx->commits.nr;
- struct progress *progress = NULL;
- int i = 0;
- if (ctx->report_progress)
- progress = start_delayed_progress(
- _("Writing changed paths Bloom filters data"),
- ctx->commits.nr);
+ trace2_bloom_filter_settings(ctx);
- hashwrite_be32(f, settings->hash_version);
- hashwrite_be32(f, settings->num_hashes);
- hashwrite_be32(f, settings->bits_per_entry);
+ hashwrite_be32(f, ctx->bloom_settings->hash_version);
+ hashwrite_be32(f, ctx->bloom_settings->num_hashes);
+ hashwrite_be32(f, ctx->bloom_settings->bits_per_entry);
while (list < last) {
struct bloom_filter *filter = get_bloom_filter(ctx->r, *list, 0);
- display_progress(progress, ++i);
- hashwrite(f, filter->data, filter->len * sizeof(unsigned char));
+ size_t len = filter ? filter->len : 0;
+
+ display_progress(ctx->progress, ++ctx->progress_cnt);
+ if (len)
+ hashwrite(f, filter->data, len * sizeof(unsigned char));
list++;
}
- stop_progress(&progress);
+ return 0;
}
static int oid_compare(const void *_a, const void *_b)
@@ -1220,7 +1295,7 @@ static void close_reachable(struct write_commit_graph_context *ctx)
continue;
if (ctx->split) {
if ((!parse_commit(commit) &&
- commit->graph_pos == COMMIT_NOT_FROM_GRAPH) ||
+ commit_graph_position(commit) == COMMIT_NOT_FROM_GRAPH) ||
flags == COMMIT_GRAPH_SPLIT_REPLACE)
add_missing_parents(ctx, commit);
} else if (!parse_commit_no_graph(commit))
@@ -1252,9 +1327,11 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
_("Computing commit graph generation numbers"),
ctx->commits.nr);
for (i = 0; i < ctx->commits.nr; i++) {
+ uint32_t generation = commit_graph_data_at(ctx->commits.list[i])->generation;
+
display_progress(ctx->progress, i + 1);
- if (ctx->commits.list[i]->generation != GENERATION_NUMBER_INFINITY &&
- ctx->commits.list[i]->generation != GENERATION_NUMBER_ZERO)
+ if (generation != GENERATION_NUMBER_INFINITY &&
+ generation != GENERATION_NUMBER_ZERO)
continue;
commit_list_insert(ctx->commits.list[i], &list);
@@ -1265,22 +1342,26 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
uint32_t max_generation = 0;
for (parent = current->parents; parent; parent = parent->next) {
- if (parent->item->generation == GENERATION_NUMBER_INFINITY ||
- parent->item->generation == GENERATION_NUMBER_ZERO) {
+ generation = commit_graph_data_at(parent->item)->generation;
+
+ if (generation == GENERATION_NUMBER_INFINITY ||
+ generation == GENERATION_NUMBER_ZERO) {
all_parents_computed = 0;
commit_list_insert(parent->item, &list);
break;
- } else if (parent->item->generation > max_generation) {
- max_generation = parent->item->generation;
+ } else if (generation > max_generation) {
+ max_generation = generation;
}
}
if (all_parents_computed) {
- current->generation = max_generation + 1;
+ struct commit_graph_data *data = commit_graph_data_at(current);
+
+ data->generation = max_generation + 1;
pop_commit(&list);
- if (current->generation > GENERATION_NUMBER_MAX)
- current->generation = GENERATION_NUMBER_MAX;
+ if (data->generation > GENERATION_NUMBER_MAX)
+ data->generation = GENERATION_NUMBER_MAX;
}
}
}
@@ -1319,13 +1400,25 @@ static void compute_bloom_filters(struct write_commit_graph_context *ctx)
stop_progress(&progress);
}
+struct refs_cb_data {
+ struct oidset *commits;
+ struct progress *progress;
+};
+
static int add_ref_to_set(const char *refname,
const struct object_id *oid,
int flags, void *cb_data)
{
- struct oidset *commits = (struct oidset *)cb_data;
+ struct object_id peeled;
+ struct refs_cb_data *data = (struct refs_cb_data *)cb_data;
+
+ if (!peel_ref(refname, &peeled))
+ oid = &peeled;
+ if (oid_object_info(the_repository, oid, NULL) == OBJ_COMMIT)
+ oidset_insert(data->commits, oid);
+
+ display_progress(data->progress, oidset_size(data->commits));
- oidset_insert(commits, oid);
return 0;
}
@@ -1334,9 +1427,19 @@ int write_commit_graph_reachable(struct object_directory *odb,
const struct split_commit_graph_opts *split_opts)
{
struct oidset commits = OIDSET_INIT;
+ struct refs_cb_data data;
int result;
- for_each_ref(add_ref_to_set, &commits);
+ memset(&data, 0, sizeof(data));
+ data.commits = &commits;
+ if (flags & COMMIT_GRAPH_WRITE_PROGRESS)
+ data.progress = start_delayed_progress(
+ _("Collecting referenced commits"), 0);
+
+ for_each_ref(add_ref_to_set, &data);
+
+ stop_progress(&data.progress);
+
result = write_commit_graph(odb, NULL, &commits,
flags, split_opts);
@@ -1392,46 +1495,19 @@ static int fill_oids_from_packs(struct write_commit_graph_context *ctx,
static int fill_oids_from_commits(struct write_commit_graph_context *ctx,
struct oidset *commits)
{
- uint32_t i = 0;
- struct strbuf progress_title = STRBUF_INIT;
struct oidset_iter iter;
struct object_id *oid;
if (!oidset_size(commits))
return 0;
- if (ctx->report_progress) {
- strbuf_addf(&progress_title,
- Q_("Finding commits for commit graph from %d ref",
- "Finding commits for commit graph from %d refs",
- oidset_size(commits)),
- oidset_size(commits));
- ctx->progress = start_delayed_progress(
- progress_title.buf,
- oidset_size(commits));
- }
-
oidset_iter_init(commits, &iter);
while ((oid = oidset_iter_next(&iter))) {
- struct commit *result;
-
- display_progress(ctx->progress, ++i);
-
- result = lookup_commit_reference_gently(ctx->r, oid, 1);
- if (result) {
- ALLOC_GROW(ctx->oids.list, ctx->oids.nr + 1, ctx->oids.alloc);
- oidcpy(&ctx->oids.list[ctx->oids.nr], &(result->object.oid));
- ctx->oids.nr++;
- } else if (ctx->check_oids) {
- error(_("invalid commit object id: %s"),
- oid_to_hex(oid));
- return -1;
- }
+ ALLOC_GROW(ctx->oids.list, ctx->oids.nr + 1, ctx->oids.alloc);
+ oidcpy(&ctx->oids.list[ctx->oids.nr], oid);
+ ctx->oids.nr++;
}
- stop_progress(&ctx->progress);
- strbuf_release(&progress_title);
-
return 0;
}
@@ -1465,7 +1541,7 @@ static uint32_t count_distinct_commits(struct write_commit_graph_context *ctx)
if (ctx->split) {
struct commit *c = lookup_commit(ctx->r, &ctx->oids.list[i]);
- if (!c || c->graph_pos != COMMIT_NOT_FROM_GRAPH)
+ if (!c || commit_graph_position(c) != COMMIT_NOT_FROM_GRAPH)
continue;
}
@@ -1499,7 +1575,7 @@ static void copy_oids_to_commits(struct write_commit_graph_context *ctx)
ctx->commits.list[ctx->commits.nr] = lookup_commit(ctx->r, &ctx->oids.list[i]);
if (ctx->split && flags != COMMIT_GRAPH_SPLIT_REPLACE &&
- ctx->commits.list[ctx->commits.nr]->graph_pos != COMMIT_NOT_FROM_GRAPH)
+ commit_graph_position(ctx->commits.list[ctx->commits.nr]) != COMMIT_NOT_FROM_GRAPH)
continue;
if (ctx->split && flags == COMMIT_GRAPH_SPLIT_REPLACE)
@@ -1542,19 +1618,36 @@ static int write_graph_chunk_base(struct hashfile *f,
return 0;
}
+typedef int (*chunk_write_fn)(struct hashfile *f,
+ struct write_commit_graph_context *ctx);
+
+struct chunk_info {
+ uint32_t id;
+ uint64_t size;
+ chunk_write_fn write_fn;
+};
+
static int write_commit_graph_file(struct write_commit_graph_context *ctx)
{
uint32_t i;
int fd;
struct hashfile *f;
struct lock_file lk = LOCK_INIT;
- uint32_t chunk_ids[MAX_NUM_CHUNKS + 1];
- uint64_t chunk_offsets[MAX_NUM_CHUNKS + 1];
+ struct chunk_info chunks[MAX_NUM_CHUNKS + 1];
const unsigned hashsz = the_hash_algo->rawsz;
struct strbuf progress_title = STRBUF_INIT;
int num_chunks = 3;
+ uint64_t chunk_offset;
struct object_id file_hash;
- const struct bloom_filter_settings bloom_settings = DEFAULT_BLOOM_FILTER_SETTINGS;
+ struct bloom_filter_settings bloom_settings = DEFAULT_BLOOM_FILTER_SETTINGS;
+
+ if (!ctx->bloom_settings) {
+ 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",
+ bloom_settings.num_hashes);
+ ctx->bloom_settings = &bloom_settings;
+ }
if (ctx->split) {
struct strbuf tmp_file = STRBUF_INIT;
@@ -1600,51 +1693,41 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
f = hashfd(lk.tempfile->fd, lk.tempfile->filename.buf);
}
- chunk_ids[0] = GRAPH_CHUNKID_OIDFANOUT;
- chunk_ids[1] = GRAPH_CHUNKID_OIDLOOKUP;
- chunk_ids[2] = GRAPH_CHUNKID_DATA;
+ chunks[0].id = GRAPH_CHUNKID_OIDFANOUT;
+ chunks[0].size = GRAPH_FANOUT_SIZE;
+ chunks[0].write_fn = write_graph_chunk_fanout;
+ chunks[1].id = GRAPH_CHUNKID_OIDLOOKUP;
+ chunks[1].size = hashsz * ctx->commits.nr;
+ chunks[1].write_fn = write_graph_chunk_oids;
+ chunks[2].id = GRAPH_CHUNKID_DATA;
+ chunks[2].size = (hashsz + 16) * ctx->commits.nr;
+ chunks[2].write_fn = write_graph_chunk_data;
if (ctx->num_extra_edges) {
- chunk_ids[num_chunks] = GRAPH_CHUNKID_EXTRAEDGES;
+ chunks[num_chunks].id = GRAPH_CHUNKID_EXTRAEDGES;
+ chunks[num_chunks].size = 4 * ctx->num_extra_edges;
+ chunks[num_chunks].write_fn = write_graph_chunk_extra_edges;
num_chunks++;
}
if (ctx->changed_paths) {
- chunk_ids[num_chunks] = GRAPH_CHUNKID_BLOOMINDEXES;
+ chunks[num_chunks].id = GRAPH_CHUNKID_BLOOMINDEXES;
+ chunks[num_chunks].size = sizeof(uint32_t) * ctx->commits.nr;
+ chunks[num_chunks].write_fn = write_graph_chunk_bloom_indexes;
num_chunks++;
- chunk_ids[num_chunks] = GRAPH_CHUNKID_BLOOMDATA;
+ chunks[num_chunks].id = GRAPH_CHUNKID_BLOOMDATA;
+ chunks[num_chunks].size = sizeof(uint32_t) * 3
+ + ctx->total_bloom_filter_data_size;
+ chunks[num_chunks].write_fn = write_graph_chunk_bloom_data;
num_chunks++;
}
if (ctx->num_commit_graphs_after > 1) {
- chunk_ids[num_chunks] = GRAPH_CHUNKID_BASE;
+ chunks[num_chunks].id = GRAPH_CHUNKID_BASE;
+ chunks[num_chunks].size = hashsz * (ctx->num_commit_graphs_after - 1);
+ chunks[num_chunks].write_fn = write_graph_chunk_base;
num_chunks++;
}
- chunk_ids[num_chunks] = 0;
-
- chunk_offsets[0] = 8 + (num_chunks + 1) * GRAPH_CHUNKLOOKUP_WIDTH;
- chunk_offsets[1] = chunk_offsets[0] + GRAPH_FANOUT_SIZE;
- chunk_offsets[2] = chunk_offsets[1] + hashsz * ctx->commits.nr;
- chunk_offsets[3] = chunk_offsets[2] + (hashsz + 16) * ctx->commits.nr;
-
- num_chunks = 3;
- if (ctx->num_extra_edges) {
- chunk_offsets[num_chunks + 1] = chunk_offsets[num_chunks] +
- 4 * ctx->num_extra_edges;
- num_chunks++;
- }
- if (ctx->changed_paths) {
- chunk_offsets[num_chunks + 1] = chunk_offsets[num_chunks] +
- sizeof(uint32_t) * ctx->commits.nr;
- num_chunks++;
-
- chunk_offsets[num_chunks + 1] = chunk_offsets[num_chunks] +
- sizeof(uint32_t) * 3 + ctx->total_bloom_filter_data_size;
- num_chunks++;
- }
- if (ctx->num_commit_graphs_after > 1) {
- chunk_offsets[num_chunks + 1] = chunk_offsets[num_chunks] +
- hashsz * (ctx->num_commit_graphs_after - 1);
- num_chunks++;
- }
+ chunks[num_chunks].id = 0;
+ chunks[num_chunks].size = 0;
hashwrite_be32(f, GRAPH_SIGNATURE);
@@ -1653,13 +1736,16 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
hashwrite_u8(f, num_chunks);
hashwrite_u8(f, ctx->num_commit_graphs_after - 1);
+ chunk_offset = 8 + (num_chunks + 1) * GRAPH_CHUNKLOOKUP_WIDTH;
for (i = 0; i <= num_chunks; i++) {
uint32_t chunk_write[3];
- chunk_write[0] = htonl(chunk_ids[i]);
- chunk_write[1] = htonl(chunk_offsets[i] >> 32);
- chunk_write[2] = htonl(chunk_offsets[i] & 0xffffffff);
+ chunk_write[0] = htonl(chunks[i].id);
+ chunk_write[1] = htonl(chunk_offset >> 32);
+ chunk_write[2] = htonl(chunk_offset & 0xffffffff);
hashwrite(f, chunk_write, 12);
+
+ chunk_offset += chunks[i].size;
}
if (ctx->report_progress) {
@@ -1672,19 +1758,19 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
progress_title.buf,
num_chunks * ctx->commits.nr);
}
- write_graph_chunk_fanout(f, ctx);
- write_graph_chunk_oids(f, hashsz, ctx);
- write_graph_chunk_data(f, hashsz, ctx);
- if (ctx->num_extra_edges)
- write_graph_chunk_extra_edges(f, ctx);
- if (ctx->changed_paths) {
- write_graph_chunk_bloom_indexes(f, ctx);
- write_graph_chunk_bloom_data(f, ctx, &bloom_settings);
- }
- if (ctx->num_commit_graphs_after > 1 &&
- write_graph_chunk_base(f, ctx)) {
- return -1;
+
+ for (i = 0; i < num_chunks; i++) {
+ uint64_t start_offset = f->total + f->offset;
+
+ if (chunks[i].write_fn(f, ctx))
+ return -1;
+
+ if (f->total + f->offset != start_offset + chunks[i].size)
+ BUG("expected to write %"PRId64" bytes to chunk %"PRIx32", but wrote %"PRId64" instead",
+ chunks[i].size, chunks[i].id,
+ f->total + f->offset - start_offset);
}
+
stop_progress(&ctx->progress);
strbuf_release(&progress_title);
@@ -2017,11 +2103,24 @@ int write_commit_graph(struct object_directory *odb,
ctx->append = flags & COMMIT_GRAPH_WRITE_APPEND ? 1 : 0;
ctx->report_progress = flags & COMMIT_GRAPH_WRITE_PROGRESS ? 1 : 0;
ctx->split = flags & COMMIT_GRAPH_WRITE_SPLIT ? 1 : 0;
- ctx->check_oids = flags & COMMIT_GRAPH_WRITE_CHECK_OIDS ? 1 : 0;
ctx->split_opts = split_opts;
- ctx->changed_paths = flags & COMMIT_GRAPH_WRITE_BLOOM_FILTERS ? 1 : 0;
ctx->total_bloom_filter_data_size = 0;
+ if (flags & COMMIT_GRAPH_WRITE_BLOOM_FILTERS)
+ ctx->changed_paths = 1;
+ if (!(flags & COMMIT_GRAPH_NO_WRITE_BLOOM_FILTERS)) {
+ struct commit_graph *g;
+ prepare_commit_graph_one(ctx->r, ctx->odb);
+
+ g = ctx->r->objects->commit_graph;
+
+ /* We have changed-paths already. Keep them in the next graph */
+ if (g && g->chunk_bloom_data) {
+ ctx->changed_paths = 1;
+ ctx->bloom_settings = g->bloom_filter_settings;
+ }
+ }
+
if (ctx->split) {
struct commit_graph *g;
prepare_commit_graph(ctx->r);
@@ -2249,6 +2348,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)
struct commit *graph_commit, *odb_commit;
struct commit_list *graph_parents, *odb_parents;
uint32_t max_generation = 0;
+ uint32_t generation;
display_progress(progress, i + 1);
hashcpy(cur_oid.hash, g->chunk_oid_lookup + g->hash_len * i);
@@ -2287,8 +2387,9 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)
oid_to_hex(&graph_parents->item->object.oid),
oid_to_hex(&odb_parents->item->object.oid));
- if (graph_parents->item->generation > max_generation)
- max_generation = graph_parents->item->generation;
+ generation = commit_graph_generation(graph_parents->item);
+ if (generation > max_generation)
+ max_generation = generation;
graph_parents = graph_parents->next;
odb_parents = odb_parents->next;
@@ -2298,7 +2399,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)
graph_report(_("commit-graph parent list for commit %s terminates early"),
oid_to_hex(&cur_oid));
- if (!graph_commit->generation) {
+ if (!commit_graph_generation(graph_commit)) {
if (generation_zero == GENERATION_NUMBER_EXISTS)
graph_report(_("commit-graph has generation number zero for commit %s, but non-zero elsewhere"),
oid_to_hex(&cur_oid));
@@ -2318,10 +2419,11 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)
if (max_generation == GENERATION_NUMBER_MAX)
max_generation--;
- if (graph_commit->generation != max_generation + 1)
+ generation = commit_graph_generation(graph_commit);
+ if (generation != max_generation + 1)
graph_report(_("commit-graph generation for commit %s is %u != %u"),
oid_to_hex(&cur_oid),
- graph_commit->generation,
+ generation,
max_generation + 1);
if (graph_commit->date != odb_commit->date)
diff --git a/commit-graph.h b/commit-graph.h
index 4212766..09a9703 100644
--- a/commit-graph.h
+++ b/commit-graph.h
@@ -2,14 +2,11 @@
#define COMMIT_GRAPH_H
#include "git-compat-util.h"
-#include "repository.h"
-#include "string-list.h"
-#include "cache.h"
#include "object-store.h"
#include "oidset.h"
#define GIT_TEST_COMMIT_GRAPH "GIT_TEST_COMMIT_GRAPH"
-#define GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD "GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD"
+#define GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE "GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE"
#define GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS "GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS"
/*
@@ -23,6 +20,9 @@ void git_test_write_commit_graph_or_die(void);
struct commit;
struct bloom_filter_settings;
+struct repository;
+struct raw_object_store;
+struct string_list;
char *get_commit_graph_filename(struct object_directory *odb);
int open_commit_graph(const char *graph_file, int *fd, struct stat *st);
@@ -91,9 +91,8 @@ enum commit_graph_write_flags {
COMMIT_GRAPH_WRITE_APPEND = (1 << 0),
COMMIT_GRAPH_WRITE_PROGRESS = (1 << 1),
COMMIT_GRAPH_WRITE_SPLIT = (1 << 2),
- /* Make sure that each OID in the input is a valid commit OID. */
- COMMIT_GRAPH_WRITE_CHECK_OIDS = (1 << 3),
- COMMIT_GRAPH_WRITE_BLOOM_FILTERS = (1 << 4),
+ COMMIT_GRAPH_WRITE_BLOOM_FILTERS = (1 << 3),
+ COMMIT_GRAPH_NO_WRITE_BLOOM_FILTERS = (1 << 4),
};
enum commit_graph_split_flags {
@@ -137,4 +136,14 @@ void free_commit_graph(struct commit_graph *);
*/
void disable_commit_graph(struct repository *r);
+struct commit_graph_data {
+ uint32_t graph_pos;
+ uint32_t generation;
+};
+
+/*
+ * Commits should be parsed before accessing generation, graph positions.
+ */
+uint32_t commit_graph_generation(const struct commit *);
+uint32_t commit_graph_position(const struct commit *);
#endif
diff --git a/commit-reach.c b/commit-reach.c
index 4ca7e70..efd5925 100644
--- a/commit-reach.c
+++ b/commit-reach.c
@@ -58,14 +58,15 @@ static struct commit_list *paint_down_to_common(struct repository *r,
struct commit *commit = prio_queue_get(&queue);
struct commit_list *parents;
int flags;
+ uint32_t generation = commit_graph_generation(commit);
- if (min_generation && commit->generation > last_gen)
+ if (min_generation && generation > last_gen)
BUG("bad generation skip %8x > %8x at %s",
- commit->generation, last_gen,
+ generation, last_gen,
oid_to_hex(&commit->object.oid));
- last_gen = commit->generation;
+ last_gen = generation;
- if (commit->generation < min_generation)
+ if (generation < min_generation)
break;
flags = commit->object.flags & (PARENT1 | PARENT2 | STALE);
@@ -176,18 +177,20 @@ static int remove_redundant(struct repository *r, struct commit **array, int cnt
repo_parse_commit(r, array[i]);
for (i = 0; i < cnt; i++) {
struct commit_list *common;
- uint32_t min_generation = array[i]->generation;
+ uint32_t min_generation = commit_graph_generation(array[i]);
if (redundant[i])
continue;
for (j = filled = 0; j < cnt; j++) {
+ uint32_t curr_generation;
if (i == j || redundant[j])
continue;
filled_index[filled] = j;
work[filled++] = array[j];
- if (array[j]->generation < min_generation)
- min_generation = array[j]->generation;
+ curr_generation = commit_graph_generation(array[j]);
+ if (curr_generation < min_generation)
+ min_generation = curr_generation;
}
common = paint_down_to_common(r, array[i], filled,
work, min_generation);
@@ -283,7 +286,9 @@ struct commit_list *repo_get_merge_bases(struct repository *r,
/*
* Is "commit" a descendant of one of the elements on the "with_commit" list?
*/
-int is_descendant_of(struct commit *commit, struct commit_list *with_commit)
+int repo_is_descendant_of(struct repository *r,
+ struct commit *commit,
+ struct commit_list *with_commit)
{
if (!with_commit)
return 1;
@@ -301,7 +306,7 @@ int is_descendant_of(struct commit *commit, struct commit_list *with_commit)
other = with_commit->item;
with_commit = with_commit->next;
- if (in_merge_bases(other, commit))
+ if (repo_in_merge_bases_many(r, other, 1, &commit))
return 1;
}
return 0;
@@ -316,23 +321,26 @@ int repo_in_merge_bases_many(struct repository *r, struct commit *commit,
{
struct commit_list *bases;
int ret = 0, i;
- uint32_t min_generation = GENERATION_NUMBER_INFINITY;
+ uint32_t generation, min_generation = GENERATION_NUMBER_INFINITY;
if (repo_parse_commit(r, commit))
return ret;
for (i = 0; i < nr_reference; i++) {
if (repo_parse_commit(r, reference[i]))
return ret;
- if (reference[i]->generation < min_generation)
- min_generation = reference[i]->generation;
+
+ generation = commit_graph_generation(reference[i]);
+ if (generation < min_generation)
+ min_generation = generation;
}
- if (commit->generation > min_generation)
+ generation = commit_graph_generation(commit);
+ if (generation > min_generation)
return ret;
bases = paint_down_to_common(r, commit,
nr_reference, reference,
- commit->generation);
+ generation);
if (commit->object.flags & PARENT2)
ret = 1;
clear_commit_marks(commit, all_flags);
@@ -348,7 +356,15 @@ int repo_in_merge_bases(struct repository *r,
struct commit *commit,
struct commit *reference)
{
- return repo_in_merge_bases_many(r, commit, 1, &reference);
+ int res;
+ struct commit_list *list = NULL;
+ struct commit_list **next = &list;
+
+ next = commit_list_append(commit, next);
+ res = repo_is_descendant_of(r, reference, list);
+ free_commit_list(list);
+
+ return res;
}
struct commit_list *reduce_heads(struct commit_list *heads)
@@ -396,6 +412,7 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid)
struct object *o;
struct commit *old_commit, *new_commit;
struct commit_list *old_commit_list = NULL;
+ int ret;
/*
* Both new_commit and old_commit must be commit-ish and new_commit is descendant of
@@ -417,7 +434,10 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid)
return 0;
commit_list_insert(old_commit, &old_commit_list);
- return is_descendant_of(new_commit, old_commit_list);
+ ret = repo_is_descendant_of(the_repository,
+ new_commit, old_commit_list);
+ free_commit_list(old_commit_list);
+ return ret;
}
/*
@@ -467,7 +487,7 @@ static enum contains_result contains_test(struct commit *candidate,
/* Otherwise, we don't know; prepare to recurse */
parse_commit_or_die(candidate);
- if (candidate->generation < cutoff)
+ if (commit_graph_generation(candidate) < cutoff)
return CONTAINS_NO;
return CONTAINS_UNKNOWN;
@@ -490,10 +510,12 @@ static enum contains_result contains_tag_algo(struct commit *candidate,
const struct commit_list *p;
for (p = want; p; p = p->next) {
+ uint32_t generation;
struct commit *c = p->item;
load_commit_graph_info(the_repository, c);
- if (c->generation < cutoff)
- cutoff = c->generation;
+ generation = commit_graph_generation(c);
+ if (generation < cutoff)
+ cutoff = generation;
}
result = contains_test(candidate, want, cache, cutoff);
@@ -536,7 +558,7 @@ int commit_contains(struct ref_filter *filter, struct commit *commit,
{
if (filter->with_commit_tag_algo)
return contains_tag_algo(commit, list, cache) == CONTAINS_YES;
- return is_descendant_of(commit, list);
+ return repo_is_descendant_of(the_repository, commit, list);
}
static int compare_commits_by_gen(const void *_a, const void *_b)
@@ -544,9 +566,12 @@ static int compare_commits_by_gen(const void *_a, const void *_b)
const struct commit *a = *(const struct commit * const *)_a;
const struct commit *b = *(const struct commit * const *)_b;
- if (a->generation < b->generation)
+ uint32_t generation_a = commit_graph_generation(a);
+ uint32_t generation_b = commit_graph_generation(b);
+
+ if (generation_a < generation_b)
return -1;
- if (a->generation > b->generation)
+ if (generation_a > generation_b)
return 1;
return 0;
}
@@ -585,7 +610,7 @@ int can_all_from_reach_with_flag(struct object_array *from,
list[nr_commits] = (struct commit *)from_one;
if (parse_commit(list[nr_commits]) ||
- list[nr_commits]->generation < min_generation) {
+ commit_graph_generation(list[nr_commits]) < min_generation) {
result = 0;
goto cleanup;
}
@@ -621,7 +646,7 @@ int can_all_from_reach_with_flag(struct object_array *from,
if (parse_commit(parent->item) ||
parent->item->date < min_commit_date ||
- parent->item->generation < min_generation)
+ commit_graph_generation(parent->item) < min_generation)
continue;
commit_list_insert(parent->item, &stack);
@@ -662,11 +687,13 @@ int can_all_from_reach(struct commit_list *from, struct commit_list *to,
add_object_array(&from_iter->item->object, NULL, &from_objs);
if (!parse_commit(from_iter->item)) {
+ uint32_t generation;
if (from_iter->item->date < min_commit_date)
min_commit_date = from_iter->item->date;
- if (from_iter->item->generation < min_generation)
- min_generation = from_iter->item->generation;
+ generation = commit_graph_generation(from_iter->item);
+ if (generation < min_generation)
+ min_generation = generation;
}
from_iter = from_iter->next;
@@ -674,11 +701,13 @@ int can_all_from_reach(struct commit_list *from, struct commit_list *to,
while (to_iter) {
if (!parse_commit(to_iter->item)) {
+ uint32_t generation;
if (to_iter->item->date < min_commit_date)
min_commit_date = to_iter->item->date;
- if (to_iter->item->generation < min_generation)
- min_generation = to_iter->item->generation;
+ generation = commit_graph_generation(to_iter->item);
+ if (generation < min_generation)
+ min_generation = generation;
}
to_iter->item->object.flags |= PARENT2;
@@ -718,11 +747,13 @@ struct commit_list *get_reachable_subset(struct commit **from, int nr_from,
struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
for (item = to; item < to_last; item++) {
+ uint32_t generation;
struct commit *c = *item;
parse_commit(c);
- if (c->generation < min_generation)
- min_generation = c->generation;
+ generation = commit_graph_generation(c);
+ if (generation < min_generation)
+ min_generation = generation;
if (!(c->object.flags & PARENT1)) {
c->object.flags |= PARENT1;
@@ -755,7 +786,7 @@ struct commit_list *get_reachable_subset(struct commit **from, int nr_from,
parse_commit(p);
- if (p->generation < min_generation)
+ if (commit_graph_generation(p) < min_generation)
continue;
if (p->object.flags & PARENT2)
diff --git a/commit-reach.h b/commit-reach.h
index 99a43e8..b49ad71 100644
--- a/commit-reach.h
+++ b/commit-reach.h
@@ -27,7 +27,9 @@ struct commit_list *repo_get_merge_bases_many_dirty(struct repository *r,
struct commit_list *get_octopus_merge_bases(struct commit_list *in);
-int is_descendant_of(struct commit *commit, struct commit_list *with_commit);
+int repo_is_descendant_of(struct repository *r,
+ struct commit *commit,
+ struct commit_list *with_commit);
int repo_in_merge_bases(struct repository *r,
struct commit *commit,
struct commit *reference);
diff --git a/commit-slab-decl.h b/commit-slab-decl.h
index bfbed15..98de2c9 100644
--- a/commit-slab-decl.h
+++ b/commit-slab-decl.h
@@ -32,6 +32,7 @@ struct slabname { \
void init_ ##slabname## _with_stride(struct slabname *s, unsigned stride); \
void init_ ##slabname(struct slabname *s); \
void clear_ ##slabname(struct slabname *s); \
+void deep_clear_ ##slabname(struct slabname *s, void (*free_fn)(elemtype *ptr)); \
elemtype *slabname## _at_peek(struct slabname *s, const struct commit *c, int add_if_missing); \
elemtype *slabname## _at(struct slabname *s, const struct commit *c); \
elemtype *slabname## _peek(struct slabname *s, const struct commit *c)
diff --git a/commit-slab-impl.h b/commit-slab-impl.h
index 5c0eb91..557738d 100644
--- a/commit-slab-impl.h
+++ b/commit-slab-impl.h
@@ -38,6 +38,19 @@ scope void clear_ ##slabname(struct slabname *s) \
FREE_AND_NULL(s->slab); \
} \
\
+scope void deep_clear_ ##slabname(struct slabname *s, void (*free_fn)(elemtype *)) \
+{ \
+ unsigned int i; \
+ for (i = 0; i < s->slab_count; i++) { \
+ unsigned int j; \
+ if (!s->slab[i]) \
+ continue; \
+ for (j = 0; j < s->slab_size; j++) \
+ free_fn(&s->slab[i][j * s->stride]); \
+ } \
+ clear_ ##slabname(s); \
+} \
+ \
scope elemtype *slabname## _at_peek(struct slabname *s, \
const struct commit *c, \
int add_if_missing) \
diff --git a/commit-slab.h b/commit-slab.h
index 05b3f28..8e72a30 100644
--- a/commit-slab.h
+++ b/commit-slab.h
@@ -47,6 +47,16 @@
*
* Call this function before the slab falls out of scope to avoid
* leaking memory.
+ *
+ * - void deep_clear_indegree(struct indegree *, void (*free_fn)(int*))
+ *
+ * Empties the slab, similar to clear_indegree(), but in addition it
+ * calls the given 'free_fn' for each slab entry to release any
+ * additional memory that might be owned by the entry (but not the
+ * entry itself!).
+ * Note that 'free_fn' might be called even for entries for which no
+ * indegree_at() call has been made; in this case 'free_fn' is invoked
+ * with a pointer to a zero-initialized location.
*/
#define define_commit_slab(slabname, elemtype) \
diff --git a/commit.c b/commit.c
index 87686a7..7128895 100644
--- a/commit.c
+++ b/commit.c
@@ -37,7 +37,7 @@ struct commit *lookup_commit_reference_gently(struct repository *r,
if (!obj)
return NULL;
- return object_as_type(r, obj, OBJ_COMMIT, quiet);
+ return object_as_type(obj, OBJ_COMMIT, quiet);
}
struct commit *lookup_commit_reference(struct repository *r, const struct object_id *oid)
@@ -62,7 +62,7 @@ struct commit *lookup_commit(struct repository *r, const struct object_id *oid)
struct object *obj = lookup_object(r, oid);
if (!obj)
return create_object(r, oid, alloc_commit_node(r));
- return object_as_type(r, obj, OBJ_COMMIT, 0);
+ return object_as_type(obj, OBJ_COMMIT, 0);
}
struct commit *lookup_commit_reference_by_name(const char *name)
@@ -339,7 +339,7 @@ struct tree *repo_get_commit_tree(struct repository *r,
if (commit->maybe_tree || !commit->object.parsed)
return commit->maybe_tree;
- if (commit->graph_pos != COMMIT_NOT_FROM_GRAPH)
+ if (commit_graph_position(commit) != COMMIT_NOT_FROM_GRAPH)
return get_commit_tree_in_graph(r, commit);
return NULL;
@@ -423,6 +423,8 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
pptr = &item->parents;
graft = lookup_commit_graft(r, &item->object.oid);
+ if (graft)
+ r->parsed_objects->substituted_parent = 1;
while (bufptr + parent_entry_len < tail && !memcmp(bufptr, "parent ", 7)) {
struct commit *new_parent;
@@ -729,11 +731,13 @@ int compare_commits_by_author_date(const void *a_, const void *b_,
int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_, void *unused)
{
const struct commit *a = a_, *b = b_;
+ const uint32_t generation_a = commit_graph_generation(a),
+ generation_b = commit_graph_generation(b);
/* newer commits first */
- if (a->generation < b->generation)
+ if (generation_a < generation_b)
return 1;
- else if (a->generation > b->generation)
+ else if (generation_a > generation_b)
return -1;
/* use date as a heuristic when generations are equal */
diff --git a/commit.h b/commit.h
index 1b2dea5..e901538 100644
--- a/commit.h
+++ b/commit.h
@@ -36,8 +36,6 @@ struct commit {
* or get_commit_tree_oid().
*/
struct tree *maybe_tree;
- uint32_t graph_pos;
- uint32_t generation;
unsigned int index;
};
diff --git a/compat/vcbuild/scripts/clink.pl b/compat/vcbuild/scripts/clink.pl
index d9f71b7..61ad084 100755
--- a/compat/vcbuild/scripts/clink.pl
+++ b/compat/vcbuild/scripts/clink.pl
@@ -23,7 +23,9 @@ while (@ARGV) {
# before any "-l*" flags.
$is_debug = 1;
}
- if ("$arg" =~ /^-[DIMGOZ]/) {
+ if ("$arg" =~ /^-I\/mingw(32|64)/) {
+ # eat
+ } elsif ("$arg" =~ /^-[DIMGOZ]/) {
push(@cflags, $arg);
} elsif ("$arg" eq "-o") {
my $file_out = shift @ARGV;
diff --git a/connect.c b/connect.c
index 23013c6..e0d5b9f 100644
--- a/connect.c
+++ b/connect.c
@@ -18,7 +18,7 @@
static char *server_capabilities_v1;
static struct argv_array server_capabilities_v2 = ARGV_ARRAY_INIT;
-static const char *parse_feature_value(const char *, const char *, int *);
+static const char *next_server_feature_value(const char *feature, int *len, int *offset);
static int check_ref(const char *name, unsigned int flags)
{
@@ -83,6 +83,21 @@ int server_supports_v2(const char *c, int die_on_error)
return 0;
}
+int server_feature_v2(const char *c, const char **v)
+{
+ int i;
+
+ for (i = 0; i < server_capabilities_v2.argc; i++) {
+ const char *out;
+ if (skip_prefix(server_capabilities_v2.argv[i], c, &out) &&
+ (*out == '=')) {
+ *v = out + 1;
+ return 1;
+ }
+ }
+ return 0;
+}
+
int server_supports_feature(const char *c, const char *feature,
int die_on_error)
{
@@ -127,6 +142,7 @@ enum protocol_version discover_version(struct packet_reader *reader)
die_initial_contact(0);
case PACKET_READ_FLUSH:
case PACKET_READ_DELIM:
+ case PACKET_READ_RESPONSE_END:
version = protocol_v0;
break;
case PACKET_READ_NORMAL:
@@ -180,17 +196,16 @@ reject:
static void annotate_refs_with_symref_info(struct ref *ref)
{
struct string_list symref = STRING_LIST_INIT_DUP;
- const char *feature_list = server_capabilities_v1;
+ int offset = 0;
- while (feature_list) {
+ while (1) {
int len;
const char *val;
- val = parse_feature_value(feature_list, "symref", &len);
+ val = next_server_feature_value("symref", &len, &offset);
if (!val)
break;
parse_one_symref_info(&symref, val, len);
- feature_list = val + 1;
}
string_list_sort(&symref);
@@ -204,21 +219,36 @@ static void annotate_refs_with_symref_info(struct ref *ref)
string_list_clear(&symref, 0);
}
-static void process_capabilities(const char *line, int *len)
+static void process_capabilities(struct packet_reader *reader, int *linelen)
{
+ const char *feat_val;
+ int feat_len;
+ const char *line = reader->line;
int nul_location = strlen(line);
- if (nul_location == *len)
+ if (nul_location == *linelen)
return;
server_capabilities_v1 = xstrdup(line + nul_location + 1);
- *len = nul_location;
+ *linelen = nul_location;
+
+ feat_val = server_feature_value("object-format", &feat_len);
+ if (feat_val) {
+ char *hash_name = xstrndup(feat_val, feat_len);
+ int hash_algo = hash_algo_by_name(hash_name);
+ if (hash_algo != GIT_HASH_UNKNOWN)
+ reader->hash_algo = &hash_algos[hash_algo];
+ free(hash_name);
+ } else {
+ reader->hash_algo = &hash_algos[GIT_HASH_SHA1];
+ }
}
-static int process_dummy_ref(const char *line)
+static int process_dummy_ref(const struct packet_reader *reader)
{
+ const char *line = reader->line;
struct object_id oid;
const char *name;
- if (parse_oid_hex(line, &oid, &name))
+ if (parse_oid_hex_algop(line, &oid, &name, reader->hash_algo))
return 0;
if (*name != ' ')
return 0;
@@ -234,13 +264,15 @@ static void check_no_capabilities(const char *line, int len)
line + strlen(line));
}
-static int process_ref(const char *line, int len, struct ref ***list,
- unsigned int flags, struct oid_array *extra_have)
+static int process_ref(const struct packet_reader *reader, int len,
+ struct ref ***list, unsigned int flags,
+ struct oid_array *extra_have)
{
+ const char *line = reader->line;
struct object_id old_oid;
const char *name;
- if (parse_oid_hex(line, &old_oid, &name))
+ if (parse_oid_hex_algop(line, &old_oid, &name, reader->hash_algo))
return 0;
if (*name != ' ')
return 0;
@@ -260,16 +292,17 @@ static int process_ref(const char *line, int len, struct ref ***list,
return 1;
}
-static int process_shallow(const char *line, int len,
+static int process_shallow(const struct packet_reader *reader, int len,
struct oid_array *shallow_points)
{
+ const char *line = reader->line;
const char *arg;
struct object_id old_oid;
if (!skip_prefix(line, "shallow ", &arg))
return 0;
- if (get_oid_hex(arg, &old_oid))
+ if (get_oid_hex_algop(arg, &old_oid, reader->hash_algo))
die(_("protocol error: expected shallow sha-1, got '%s'"), arg);
if (!shallow_points)
die(_("repository on the other end cannot be shallow"));
@@ -310,25 +343,26 @@ struct ref **get_remote_heads(struct packet_reader *reader,
state = EXPECTING_DONE;
break;
case PACKET_READ_DELIM:
+ case PACKET_READ_RESPONSE_END:
die(_("invalid packet"));
}
switch (state) {
case EXPECTING_FIRST_REF:
- process_capabilities(reader->line, &len);
- if (process_dummy_ref(reader->line)) {
+ process_capabilities(reader, &len);
+ if (process_dummy_ref(reader)) {
state = EXPECTING_SHALLOW;
break;
}
state = EXPECTING_REF;
/* fallthrough */
case EXPECTING_REF:
- if (process_ref(reader->line, len, &list, flags, extra_have))
+ if (process_ref(reader, len, &list, flags, extra_have))
break;
state = EXPECTING_SHALLOW;
/* fallthrough */
case EXPECTING_SHALLOW:
- if (process_shallow(reader->line, len, shallow_points))
+ if (process_shallow(reader, len, shallow_points))
break;
die(_("protocol error: unexpected '%s'"), reader->line);
case EXPECTING_DONE:
@@ -342,7 +376,7 @@ struct ref **get_remote_heads(struct packet_reader *reader,
}
/* Returns 1 when a valid ref has been added to `list`, 0 otherwise */
-static int process_ref_v2(const char *line, struct ref ***list)
+static int process_ref_v2(struct packet_reader *reader, struct ref ***list)
{
int ret = 1;
int i = 0;
@@ -350,6 +384,7 @@ static int process_ref_v2(const char *line, struct ref ***list)
struct ref *ref;
struct string_list line_sections = STRING_LIST_INIT_DUP;
const char *end;
+ const char *line = reader->line;
/*
* Ref lines have a number of fields which are space deliminated. The
@@ -362,7 +397,7 @@ static int process_ref_v2(const char *line, struct ref ***list)
goto out;
}
- if (parse_oid_hex(line_sections.items[i++].string, &old_oid, &end) ||
+ if (parse_oid_hex_algop(line_sections.items[i++].string, &old_oid, &end, reader->hash_algo) ||
*end) {
ret = 0;
goto out;
@@ -370,7 +405,7 @@ static int process_ref_v2(const char *line, struct ref ***list)
ref = alloc_ref(line_sections.items[i++].string);
- oidcpy(&ref->old_oid, &old_oid);
+ memcpy(ref->old_oid.hash, old_oid.hash, reader->hash_algo->rawsz);
**list = ref;
*list = &ref->next;
@@ -383,7 +418,8 @@ static int process_ref_v2(const char *line, struct ref ***list)
struct object_id peeled_oid;
char *peeled_name;
struct ref *peeled;
- if (parse_oid_hex(arg, &peeled_oid, &end) || *end) {
+ if (parse_oid_hex_algop(arg, &peeled_oid, &end,
+ reader->hash_algo) || *end) {
ret = 0;
goto out;
}
@@ -391,7 +427,8 @@ static int process_ref_v2(const char *line, struct ref ***list)
peeled_name = xstrfmt("%s^{}", ref->name);
peeled = alloc_ref(peeled_name);
- oidcpy(&peeled->old_oid, &peeled_oid);
+ memcpy(peeled->old_oid.hash, peeled_oid.hash,
+ reader->hash_algo->rawsz);
**list = peeled;
*list = &peeled->next;
@@ -404,12 +441,24 @@ out:
return ret;
}
+void check_stateless_delimiter(int stateless_rpc,
+ struct packet_reader *reader,
+ const char *error)
+{
+ if (!stateless_rpc)
+ return; /* not in stateless mode, no delimiter expected */
+ if (packet_reader_read(reader) != PACKET_READ_RESPONSE_END)
+ die("%s", error);
+}
+
struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
struct ref **list, int for_push,
const struct argv_array *ref_prefixes,
- const struct string_list *server_options)
+ const struct string_list *server_options,
+ int stateless_rpc)
{
int i;
+ const char *hash_name;
*list = NULL;
if (server_supports_v2("ls-refs", 1))
@@ -418,6 +467,16 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
if (server_supports_v2("agent", 0))
packet_write_fmt(fd_out, "agent=%s", git_user_agent_sanitized());
+ if (server_feature_v2("object-format", &hash_name)) {
+ int hash_algo = hash_algo_by_name(hash_name);
+ if (hash_algo == GIT_HASH_UNKNOWN)
+ die(_("unknown object format '%s' specified by server"), hash_name);
+ reader->hash_algo = &hash_algos[hash_algo];
+ packet_write_fmt(fd_out, "object-format=%s", reader->hash_algo->name);
+ } else {
+ reader->hash_algo = &hash_algos[GIT_HASH_SHA1];
+ }
+
if (server_options && server_options->nr &&
server_supports_v2("server-option", 1))
for (i = 0; i < server_options->nr; i++)
@@ -437,17 +496,20 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
/* Process response from server */
while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
- if (!process_ref_v2(reader->line, &list))
+ if (!process_ref_v2(reader, &list))
die(_("invalid ls-refs response: %s"), reader->line);
}
if (reader->status != PACKET_READ_FLUSH)
die(_("expected flush after ref listing"));
+ check_stateless_delimiter(stateless_rpc, reader,
+ _("expected response end packet after ref listing"));
+
return list;
}
-static const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp)
+const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp, int *offset)
{
int len;
@@ -455,6 +517,8 @@ static const char *parse_feature_value(const char *feature_list, const char *fea
return NULL;
len = strlen(feature);
+ if (offset)
+ feature_list += *offset;
while (*feature_list) {
const char *found = strstr(feature_list, feature);
if (!found)
@@ -469,9 +533,14 @@ static const char *parse_feature_value(const char *feature_list, const char *fea
}
/* feature with a value (e.g., "agent=git/1.2.3") */
else if (*value == '=') {
+ int end;
+
value++;
+ end = strcspn(value, " \t\n");
if (lenp)
- *lenp = strcspn(value, " \t\n");
+ *lenp = end;
+ if (offset)
+ *offset = value + end - feature_list;
return value;
}
/*
@@ -484,14 +553,41 @@ static const char *parse_feature_value(const char *feature_list, const char *fea
return NULL;
}
+int server_supports_hash(const char *desired, int *feature_supported)
+{
+ int offset = 0;
+ int len;
+ const char *hash;
+
+ hash = next_server_feature_value("object-format", &len, &offset);
+ if (feature_supported)
+ *feature_supported = !!hash;
+ if (!hash) {
+ hash = hash_algos[GIT_HASH_SHA1].name;
+ len = strlen(hash);
+ }
+ while (hash) {
+ if (!xstrncmpz(desired, hash, len))
+ return 1;
+
+ hash = next_server_feature_value("object-format", &len, &offset);
+ }
+ return 0;
+}
+
int parse_feature_request(const char *feature_list, const char *feature)
{
- return !!parse_feature_value(feature_list, feature, NULL);
+ return !!parse_feature_value(feature_list, feature, NULL, NULL);
+}
+
+static const char *next_server_feature_value(const char *feature, int *len, int *offset)
+{
+ return parse_feature_value(server_capabilities_v1, feature, len, offset);
}
const char *server_feature_value(const char *feature, int *len)
{
- return parse_feature_value(server_capabilities_v1, feature, len);
+ return parse_feature_value(server_capabilities_v1, feature, len, NULL);
}
int server_supports(const char *feature)
diff --git a/connect.h b/connect.h
index 5f2382e..c53586e 100644
--- a/connect.h
+++ b/connect.h
@@ -18,8 +18,15 @@ int url_is_local_not_ssh(const char *url);
struct packet_reader;
enum protocol_version discover_version(struct packet_reader *reader);
+int server_supports_hash(const char *desired, int *feature_supported);
+const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp, int *offset);
int server_supports_v2(const char *c, int die_on_error);
+int server_feature_v2(const char *c, const char **v);
int server_supports_feature(const char *c, const char *feature,
int die_on_error);
+void check_stateless_delimiter(int stateless_rpc,
+ struct packet_reader *reader,
+ const char *error);
+
#endif
diff --git a/connected.c b/connected.c
index 3135b71..937b4ba 100644
--- a/connected.c
+++ b/connected.c
@@ -43,10 +43,12 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
if (transport && transport->smart_options &&
transport->smart_options->self_contained_and_connected &&
- transport->pack_lockfile &&
- strip_suffix(transport->pack_lockfile, ".keep", &base_len)) {
+ transport->pack_lockfiles.nr == 1 &&
+ strip_suffix(transport->pack_lockfiles.items[0].string,
+ ".keep", &base_len)) {
struct strbuf idx_file = STRBUF_INIT;
- strbuf_add(&idx_file, transport->pack_lockfile, base_len);
+ strbuf_add(&idx_file, transport->pack_lockfiles.items[0].string,
+ base_len);
strbuf_addstr(&idx_file, ".idx");
new_pack = add_packed_git(idx_file.buf, idx_file.len, 1);
strbuf_release(&idx_file);
diff --git a/contrib/coccinelle/commit.cocci b/contrib/coccinelle/commit.cocci
index 778e470..af6dd4c 100644
--- a/contrib/coccinelle/commit.cocci
+++ b/contrib/coccinelle/commit.cocci
@@ -32,3 +32,21 @@ expression c;
- c->maybe_tree
+ repo_get_commit_tree(specify_the_right_repo_here, c)
...>}
+
+@@
+struct commit *c;
+expression E;
+@@
+(
+- c->generation = E;
++ commit_graph_data_at(c)->generation = E;
+|
+- c->graph_pos = E;
++ commit_graph_data_at(c)->graph_pos = E;
+|
+- c->generation
++ commit_graph_generation(c)
+|
+- c->graph_pos
++ commit_graph_position(c)
+)
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 70ad04e..0fdb5da 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -50,7 +50,7 @@ esac
# variable.
__git_find_repo_path ()
{
- if [ -n "$__git_repo_path" ]; then
+ if [ -n "${__git_repo_path-}" ]; then
# we already know where it is
return
fi
@@ -301,6 +301,19 @@ __gitcomp_direct ()
COMPREPLY=($1)
}
+# Similar to __gitcomp_direct, but appends to COMPREPLY instead.
+# Callers must take care of providing only words that match the current word
+# to be completed and adding any prefix and/or suffix (trailing space!), if
+# necessary.
+# 1: List of newline-separated matching completion words, complete with
+# prefix and suffix.
+__gitcomp_direct_append ()
+{
+ local IFS=$'\n'
+
+ COMPREPLY+=($1)
+}
+
__gitcompappend ()
{
local x i=${#COMPREPLY[@]}
@@ -373,7 +386,7 @@ __gitcomp ()
# Clear the variables caching builtins' options when (re-)sourcing
# the completion script.
if [[ -n ${ZSH_VERSION-} ]]; then
- unset $(set |sed -ne 's/^\(__gitcomp_builtin_[a-zA-Z0-9_][a-zA-Z0-9_]*\)=.*/\1/p') 2>/dev/null
+ unset ${(M)${(k)parameters[@]}:#__gitcomp_builtin_*} 2>/dev/null
else
unset $(compgen -v __gitcomp_builtin_)
fi
@@ -391,12 +404,12 @@ __gitcomp_builtin ()
# 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"
+ local incl="${2-}"
+ local excl="${3-}"
local var=__gitcomp_builtin_"${cmd/-/_}"
local options
- eval "options=\$$var"
+ eval "options=\${$var-}"
if [ -z "$options" ]; then
# leading and trailing spaces are significant to make
@@ -611,6 +624,19 @@ __git_heads ()
"refs/heads/$cur_*" "refs/heads/$cur_*/**"
}
+# Lists branches from remote repositories.
+# 1: A prefix to be added to each listed branch (optional).
+# 2: List only branches matching this word (optional; list all branches if
+# unset or empty).
+# 3: A suffix to be appended to each listed branch (optional).
+__git_remote_heads ()
+{
+ local pfx="${1-}" cur_="${2-}" sfx="${3-}"
+
+ __git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+ "refs/remotes/$cur_*" "refs/remotes/$cur_*/**"
+}
+
# Lists tags from the local repository.
# Accepts the same positional parameters as __git_heads() above.
__git_tags ()
@@ -621,6 +647,26 @@ __git_tags ()
"refs/tags/$cur_*" "refs/tags/$cur_*/**"
}
+# List unique branches from refs/remotes used for 'git checkout' and 'git
+# switch' tracking DWIMery.
+# 1: A prefix to be added to each listed branch (optional)
+# 2: List only branches matching this word (optional; list all branches if
+# unset or empty).
+# 3: A suffix to be appended to each listed branch (optional).
+__git_dwim_remote_heads ()
+{
+ local pfx="${1-}" cur_="${2-}" sfx="${3-}"
+ local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers
+
+ # employ the heuristic used by git checkout and git switch
+ # Try to find a remote branch that cur_es the completion word
+ # but only output if the branch name is unique
+ __git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
+ --sort="refname:strip=3" \
+ "refs/remotes/*/$cur_*" "refs/remotes/*/$cur_*/**" | \
+ uniq -u
+}
+
# Lists refs from the local (by default) or from a remote repository.
# It accepts 0, 1 or 2 arguments:
# 1: The remote to list refs from (optional; ignored, if set but empty).
@@ -696,13 +742,7 @@ __git_refs ()
__git_dir="$dir" __git for-each-ref --format="$fer_pfx%($format)$sfx" \
"${refs[@]}"
if [ -n "$track" ]; then
- # employ the heuristic used by git checkout
- # Try to find a remote branch that matches the completion word
- # but only output if the branch name is unique
- __git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
- --sort="refname:strip=3" \
- "refs/remotes/*/$match*" "refs/remotes/*/$match*/**" | \
- uniq -u
+ __git_dwim_remote_heads "$pfx" "$match" "$sfx"
fi
return
fi
@@ -749,29 +789,51 @@ __git_refs ()
# Usage: __git_complete_refs [<option>]...
# --remote=<remote>: The remote to list refs from, can be the name of a
# configured remote, a path, or a URL.
-# --track: List unique remote branches for 'git checkout's tracking DWIMery.
+# --dwim: List unique remote branches for 'git switch's tracking DWIMery.
# --pfx=<prefix>: A prefix to be added to each ref.
# --cur=<word>: The current ref to be completed. Defaults to the current
# word to be completed.
# --sfx=<suffix>: A suffix to be appended to each ref instead of the default
# space.
+# --mode=<mode>: What set of refs to complete, one of 'refs' (the default) to
+# complete all refs, 'heads' to complete only branches, or
+# 'remote-heads' to complete only remote branches. Note that
+# --remote is only compatible with --mode=refs.
__git_complete_refs ()
{
- local remote track pfx cur_="$cur" sfx=" "
+ local remote= dwim= pfx= cur_="$cur" sfx=" " mode="refs"
while test $# != 0; do
case "$1" in
--remote=*) remote="${1##--remote=}" ;;
- --track) track="yes" ;;
+ --dwim) dwim="yes" ;;
+ # --track is an old spelling of --dwim
+ --track) dwim="yes" ;;
--pfx=*) pfx="${1##--pfx=}" ;;
--cur=*) cur_="${1##--cur=}" ;;
--sfx=*) sfx="${1##--sfx=}" ;;
+ --mode=*) mode="${1##--mode=}" ;;
*) return 1 ;;
esac
shift
done
- __gitcomp_direct "$(__git_refs "$remote" "$track" "$pfx" "$cur_" "$sfx")"
+ # complete references based on the specified mode
+ case "$mode" in
+ refs)
+ __gitcomp_direct "$(__git_refs "$remote" "" "$pfx" "$cur_" "$sfx")" ;;
+ heads)
+ __gitcomp_direct "$(__git_heads "$pfx" "$cur_" "$sfx")" ;;
+ remote-heads)
+ __gitcomp_direct "$(__git_remote_heads "$pfx" "$cur_" "$sfx")" ;;
+ *)
+ return 1 ;;
+ esac
+
+ # Append DWIM remote branch names if requested
+ if [ "$dwim" = "yes" ]; then
+ __gitcomp_direct_append "$(__git_dwim_remote_heads "$pfx" "$cur_" "$sfx")"
+ fi
}
# __git_refs2 requires 1 argument (to pass to __git_refs)
@@ -1090,7 +1152,7 @@ __git_find_on_cmdline ()
while [ $c -lt $cword ]; do
for word in $wordlist; do
if [ "$word" = "${words[c]}" ]; then
- if [ -n "$show_idx" ]; then
+ if [ -n "${show_idx-}" ]; then
echo "$c $word"
else
echo "$word"
@@ -1102,6 +1164,40 @@ __git_find_on_cmdline ()
done
}
+# Similar to __git_find_on_cmdline, except that it loops backwards and thus
+# prints the *last* word found. Useful for finding which of two options that
+# supersede each other came last, such as "--guess" and "--no-guess".
+#
+# Usage: __git_find_last_on_cmdline [<option>]... "<wordlist>"
+# --show-idx: Optionally show the index of the found word in the $words array.
+__git_find_last_on_cmdline ()
+{
+ local word c=$cword show_idx
+
+ while test $# -gt 1; do
+ case "$1" in
+ --show-idx) show_idx=y ;;
+ *) return 1 ;;
+ esac
+ shift
+ done
+ local wordlist="$1"
+
+ while [ $c -gt 1 ]; do
+ ((c--))
+ for word in $wordlist; do
+ if [ "$word" = "${words[c]}" ]; then
+ if [ -n "$show_idx" ]; then
+ echo "$c $word"
+ else
+ echo "$word"
+ fi
+ return
+ fi
+ done
+ done
+}
+
# Echo the value of an option set on the command line or config
#
# $1: short option name
@@ -1356,6 +1452,46 @@ _git_bundle ()
esac
}
+# Helper function to decide whether or not we should enable DWIM logic for
+# git-switch and git-checkout.
+#
+# To decide between the following rules in priority order
+# 1) the last provided of "--guess" or "--no-guess" explicitly enable or
+# disable completion of DWIM logic respectively.
+# 2) If the --no-track option is provided, take this as a hint to disable the
+# DWIM completion logic
+# 3) If GIT_COMPLETION_CHECKOUT_NO_GUESS is set, disable the DWIM completion
+# logic, as requested by the user.
+# 4) Enable DWIM logic otherwise.
+#
+__git_checkout_default_dwim_mode ()
+{
+ local last_option dwim_opt="--dwim"
+
+ if [ "${GIT_COMPLETION_CHECKOUT_NO_GUESS-}" = "1" ]; then
+ dwim_opt=""
+ fi
+
+ # --no-track disables DWIM, but with lower priority than
+ # --guess/--no-guess
+ if [ -n "$(__git_find_on_cmdline "--no-track")" ]; then
+ dwim_opt=""
+ fi
+
+ # Find the last provided --guess or --no-guess
+ last_option="$(__git_find_last_on_cmdline "--guess --no-guess")"
+ case "$last_option" in
+ --guess)
+ dwim_opt="--dwim"
+ ;;
+ --no-guess)
+ dwim_opt=""
+ ;;
+ esac
+
+ echo "$dwim_opt"
+}
+
_git_checkout ()
{
__git_has_doubledash && return
@@ -1368,14 +1504,38 @@ _git_checkout ()
__gitcomp_builtin checkout
;;
*)
- # check if --track, --no-track, or --no-guess was specified
- # if so, disable DWIM mode
- local flags="--track --no-track --no-guess" track_opt="--track"
- if [ "$GIT_COMPLETION_CHECKOUT_NO_GUESS" = "1" ] ||
- [ -n "$(__git_find_on_cmdline "$flags")" ]; then
- track_opt=''
+ local dwim_opt="$(__git_checkout_default_dwim_mode)"
+ local prevword prevword="${words[cword-1]}"
+
+ case "$prevword" in
+ -b|-B|--orphan)
+ # Complete local branches (and DWIM branch
+ # remote branch names) for an option argument
+ # specifying a new branch name. This is for
+ # convenience, assuming new branches are
+ # possibly based on pre-existing branch names.
+ __git_complete_refs $dwim_opt --mode="heads"
+ return
+ ;;
+ *)
+ ;;
+ esac
+
+ # At this point, we've already handled special completion for
+ # the arguments to -b/-B, and --orphan. There are 3 main
+ # things left we can possibly complete:
+ # 1) a start-point for -b/-B, -d/--detach, or --orphan
+ # 2) a remote head, for --track
+ # 3) an arbitrary reference, possibly including DWIM names
+ #
+
+ if [ -n "$(__git_find_on_cmdline "-b -B -d --detach --orphan")" ]; then
+ __git_complete_refs --mode="refs"
+ elif [ -n "$(__git_find_on_cmdline "--track")" ]; then
+ __git_complete_refs --mode="remote-heads"
+ else
+ __git_complete_refs $dwim_opt --mode="refs"
fi
- __git_complete_refs $track_opt
;;
esac
}
@@ -2224,29 +2384,43 @@ _git_switch ()
__gitcomp_builtin switch
;;
*)
- # check if --track, --no-track, or --no-guess was specified
- # if so, disable DWIM mode
- local track_opt="--track" only_local_ref=n
- if [ "$GIT_COMPLETION_CHECKOUT_NO_GUESS" = "1" ] ||
- [ -n "$(__git_find_on_cmdline "--track --no-track --no-guess")" ]; then
- track_opt=''
- fi
- # explicit --guess enables DWIM mode regardless of
- # $GIT_COMPLETION_CHECKOUT_NO_GUESS
- if [ -n "$(__git_find_on_cmdline "--guess")" ]; then
- track_opt='--track'
- fi
- if [ -z "$(__git_find_on_cmdline "-d --detach")" ]; then
- only_local_ref=y
- else
- # --guess --detach is invalid combination, no
- # dwim will be done when --detach is specified
- track_opt=
+ local dwim_opt="$(__git_checkout_default_dwim_mode)"
+ local prevword prevword="${words[cword-1]}"
+
+ case "$prevword" in
+ -c|-C|--orphan)
+ # Complete local branches (and DWIM branch
+ # remote branch names) for an option argument
+ # specifying a new branch name. This is for
+ # convenience, assuming new branches are
+ # possibly based on pre-existing branch names.
+ __git_complete_refs $dwim_opt --mode="heads"
+ return
+ ;;
+ *)
+ ;;
+ esac
+
+ # Unlike in git checkout, git switch --orphan does not take
+ # a start point. Thus we really have nothing to complete after
+ # the branch name.
+ if [ -n "$(__git_find_on_cmdline "--orphan")" ]; then
+ return
fi
- if [ $only_local_ref = y -a -z "$track_opt" ]; then
- __gitcomp_direct "$(__git_heads "" "$cur" " ")"
+
+ # At this point, we've already handled special completion for
+ # -c/-C, and --orphan. There are 3 main things left to
+ # complete:
+ # 1) a start-point for -c/-C or -d/--detach
+ # 2) a remote head, for --track
+ # 3) a branch name, possibly including DWIM remote branches
+
+ if [ -n "$(__git_find_on_cmdline "-c -C -d --detach")" ]; then
+ __git_complete_refs --mode="refs"
+ elif [ -n "$(__git_find_on_cmdline "--track")" ]; then
+ __git_complete_refs --mode="remote-heads"
else
- __git_complete_refs $track_opt
+ __git_complete_refs $dwim_opt --mode="heads"
fi
;;
esac
@@ -2733,6 +2907,14 @@ _git_show ()
__gitcomp "$__git_diff_submodule_formats" "" "${cur##--submodule=}"
return
;;
+ --color-moved=*)
+ __gitcomp "$__git_color_moved_opts" "" "${cur##--color-moved=}"
+ return
+ ;;
+ --color-moved-ws=*)
+ __gitcomp "$__git_color_moved_ws_opts" "" "${cur##--color-moved-ws=}"
+ return
+ ;;
--*)
__gitcomp "--pretty= --format= --abbrev-commit --no-abbrev-commit
--oneline --show-signature --patch
@@ -2782,7 +2964,7 @@ _git_stash ()
local save_opts='--all --keep-index --no-keep-index --quiet --patch --include-untracked'
local subcommands='push list show apply clear drop pop create branch'
local subcommand="$(__git_find_on_cmdline "$subcommands save")"
- if [ -n "$(__git_find_on_cmdline "-p")" ]; then
+ if [ -z "$subcommand" -a -n "$(__git_find_on_cmdline "-p")" ]; then
subcommand="push"
fi
if [ -z "$subcommand" ]; then
@@ -3176,7 +3358,7 @@ __git_main ()
((c++))
done
- if [ -z "$command" ]; then
+ if [ -z "${command-}" ]; then
case "$prev" in
--git-dir|-C|--work-tree)
# these need a path argument, let's fall back to
@@ -3211,7 +3393,7 @@ __git_main ()
"
;;
*)
- if test -n "$GIT_TESTING_PORCELAIN_COMMAND_LIST"
+ if test -n "${GIT_TESTING_PORCELAIN_COMMAND_LIST-}"
then
__gitcomp "$GIT_TESTING_PORCELAIN_COMMAND_LIST"
else
diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh
index 014cd7c..16260ba 100644
--- a/contrib/completion/git-prompt.sh
+++ b/contrib/completion/git-prompt.sh
@@ -70,6 +70,15 @@
# state symbols by setting GIT_PS1_STATESEPARATOR. The default separator
# is SP.
#
+# When there is an in-progress operation such as a merge, rebase,
+# revert, cherry-pick, or bisect, the prompt will include information
+# related to the operation, often in the form "|<OPERATION-NAME>".
+#
+# When the repository has a sparse-checkout, a notification of the form
+# "|SPARSE" will be included in the prompt. This can be shortened to a
+# single '?' character by setting GIT_PS1_COMPRESSSPARSESTATE, or omitted
+# by setting GIT_PS1_OMITSPARSESTATE.
+#
# By default, __git_ps1 will compare HEAD to your SVN upstream if it can
# find one, or @{upstream} otherwise. Once you have set
# GIT_PS1_SHOWUPSTREAM, you can override it on a per-repository basis by
@@ -421,6 +430,13 @@ __git_ps1 ()
return $exit
fi
+ local sparse=""
+ if [ -z "${GIT_PS1_COMPRESSSPARSESTATE}" ] &&
+ [ -z "${GIT_PS1_OMITSPARSESTATE}" ] &&
+ [ "$(git config --bool core.sparseCheckout)" = "true" ]; then
+ sparse="|SPARSE"
+ fi
+
local r=""
local b=""
local step=""
@@ -492,6 +508,7 @@ __git_ps1 ()
local i=""
local s=""
local u=""
+ local h=""
local c=""
local p=""
@@ -524,6 +541,11 @@ __git_ps1 ()
u="%${ZSH_VERSION+%}"
fi
+ if [ -n "${GIT_PS1_COMPRESSSPARSESTATE}" ] &&
+ [ "$(git config --bool core.sparseCheckout)" = "true" ]; then
+ h="?"
+ fi
+
if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
__git_ps1_show_upstream
fi
@@ -542,8 +564,8 @@ __git_ps1 ()
b="\${__git_ps1_branch_name}"
fi
- local f="$w$i$s$u"
- local gitstring="$c$b${f:+$z$f}$r$p"
+ local f="$h$w$i$s$u"
+ local gitstring="$c$b${f:+$z$f}${sparse}$r$p"
if [ $pcmode = yes ]; then
if [ "${__git_printf_supports_v-}" != yes ]; then
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 57ff4b2..53d7acc 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -196,7 +196,8 @@ test_expect_success 'merge new subproj history into sub dir/ with --prefix' '
cd "$subtree_test_count" &&
git fetch ./"sub proj" master &&
git subtree merge --prefix="sub dir" FETCH_HEAD &&
- check_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
+ check_equal "$(last_commit_message)" \
+ "Merge commit '\''$(git rev-parse FETCH_HEAD)'\'' into master"
)
'
@@ -273,7 +274,8 @@ test_expect_success 'merge new subproj history into subdir/ with a slash appende
cd "$test_count" &&
git fetch ./subproj master &&
git subtree merge --prefix=subdir/ FETCH_HEAD &&
- check_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
+ check_equal "$(last_commit_message)" \
+ "Merge commit '\''$(git rev-parse FETCH_HEAD)'\'' into master"
)
'
diff --git a/diff-lib.c b/diff-lib.c
index 61812f4..25fd2de 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -220,8 +220,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
} else if (revs->diffopt.ita_invisible_in_index &&
ce_intent_to_add(ce)) {
diff_addremove(&revs->diffopt, '+', ce->ce_mode,
- the_hash_algo->empty_tree, 0,
- ce->name, 0);
+ &null_oid, 0, ce->name, 0);
continue;
}
diff --git a/diff.c b/diff.c
index d1ad6a3..d24aaa3 100644
--- a/diff.c
+++ b/diff.c
@@ -48,6 +48,7 @@ static const char *diff_order_file_cfg;
int diff_auto_refresh_index = 1;
static int diff_mnemonic_prefix;
static int diff_no_prefix;
+static int diff_relative;
static int diff_stat_graph_width;
static int diff_dirstat_permille_default = 30;
static struct diff_options default_diff_options;
@@ -386,6 +387,10 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
diff_no_prefix = git_config_bool(var, value);
return 0;
}
+ if (!strcmp(var, "diff.relative")) {
+ diff_relative = git_config_bool(var, value);
+ return 0;
+ }
if (!strcmp(var, "diff.statgraphwidth")) {
diff_stat_graph_width = git_config_int(var, value);
return 0;
@@ -4538,6 +4543,7 @@ void repo_diff_setup(struct repository *r, struct diff_options *options)
options->interhunkcontext = diff_interhunk_context_default;
options->ws_error_highlight = ws_error_highlight_default;
options->flags.rename_empty = 1;
+ options->flags.relative_name = diff_relative;
options->objfind = NULL;
/* pathchange left =NULL by default */
@@ -5195,8 +5201,7 @@ static int diff_opt_relative(const struct option *opt,
{
struct diff_options *options = opt->value;
- BUG_ON_OPT_NEG(unset);
- options->flags.relative_name = 1;
+ options->flags.relative_name = !unset;
if (arg)
options->prefix = arg;
return 0;
@@ -5492,7 +5497,7 @@ static void prep_parse_options(struct diff_options *options)
OPT_GROUP(N_("Other diff options")),
OPT_CALLBACK_F(0, "relative", options, N_("<prefix>"),
N_("when run from subdir, exclude changes outside and show relative paths"),
- PARSE_OPT_NONEG | PARSE_OPT_OPTARG,
+ PARSE_OPT_OPTARG,
diff_opt_relative),
OPT_BOOL('a', "text", &options->flags.text,
N_("treat all files as text")),
@@ -6758,8 +6763,11 @@ void diff_change(struct diff_options *options,
return;
if (options->flags.quick && options->skip_stat_unmatch &&
- !diff_filespec_check_stat_unmatch(options->repo, p))
+ !diff_filespec_check_stat_unmatch(options->repo, p)) {
+ diff_free_filespec_data(p->one);
+ diff_free_filespec_data(p->two);
return;
+ }
options->flags.has_changes = 1;
}
diff --git a/diff.h b/diff.h
index 9443dc1..e0c0af6 100644
--- a/diff.h
+++ b/diff.h
@@ -431,11 +431,11 @@ struct combine_diff_path *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);
-int diff_tree_oid(const struct object_id *old_oid,
- const struct object_id *new_oid,
- const char *base, struct diff_options *opt);
-int diff_root_tree_oid(const struct object_id *new_oid, const char *base,
- struct diff_options *opt);
+void diff_tree_oid(const struct object_id *old_oid,
+ const struct object_id *new_oid,
+ const char *base, struct diff_options *opt);
+void diff_root_tree_oid(const struct object_id *new_oid, const char *base,
+ struct diff_options *opt);
struct combine_diff_path {
struct combine_diff_path *next;
diff --git a/dir.c b/dir.c
index d97e955..fe64be3 100644
--- a/dir.c
+++ b/dir.c
@@ -193,6 +193,10 @@ int fill_directory(struct dir_struct *dir,
const char *prefix;
size_t prefix_len;
+ unsigned exclusive_flags = DIR_SHOW_IGNORED | DIR_SHOW_IGNORED_TOO;
+ if ((dir->flags & exclusive_flags) == exclusive_flags)
+ BUG("DIR_SHOW_IGNORED and DIR_SHOW_IGNORED_TOO are exclusive");
+
/*
* Calculate common prefix for the pathspec, and
* use that to optimize the directory walk
@@ -364,7 +368,8 @@ static int match_pathspec_item(const struct index_state *istate,
return MATCHED_FNMATCH;
/* Perform checks to see if "name" is a leading string of the pathspec */
- if (flags & DO_MATCH_LEADING_PATHSPEC) {
+ if ( (flags & DO_MATCH_LEADING_PATHSPEC) &&
+ !(flags & DO_MATCH_EXCLUDE)) {
/* name is a literal prefix of the pathspec */
int offset = name[namelen-1] == '/' ? 1 : 0;
if ((namelen < matchlen) &&
@@ -401,6 +406,10 @@ static int match_pathspec_item(const struct index_state *istate,
}
/*
+ * do_match_pathspec() is meant to ONLY be called by
+ * match_pathspec_with_flags(); calling it directly risks pathspecs
+ * like ':!unwanted_path' being ignored.
+ *
* Given a name and a list of pathspecs, returns the nature of the
* closest (i.e. most specific) match of the name to any of the
* pathspecs.
@@ -486,13 +495,12 @@ static int do_match_pathspec(const struct index_state *istate,
return retval;
}
-int match_pathspec(const struct index_state *istate,
- const struct pathspec *ps,
- const char *name, int namelen,
- int prefix, char *seen, int is_dir)
+static int match_pathspec_with_flags(const struct index_state *istate,
+ const struct pathspec *ps,
+ const char *name, int namelen,
+ int prefix, char *seen, unsigned flags)
{
int positive, negative;
- unsigned flags = is_dir ? DO_MATCH_DIRECTORY : 0;
positive = do_match_pathspec(istate, ps, name, namelen,
prefix, seen, flags);
if (!(ps->magic & PATHSPEC_EXCLUDE) || !positive)
@@ -503,6 +511,16 @@ int match_pathspec(const struct index_state *istate,
return negative ? 0 : positive;
}
+int match_pathspec(const struct index_state *istate,
+ const struct pathspec *ps,
+ const char *name, int namelen,
+ int prefix, char *seen, int is_dir)
+{
+ unsigned flags = is_dir ? DO_MATCH_DIRECTORY : 0;
+ return match_pathspec_with_flags(istate, ps, name, namelen,
+ prefix, seen, flags);
+}
+
/**
* Check if a submodule is a superset of the pathspec
*/
@@ -511,11 +529,11 @@ int submodule_path_match(const struct index_state *istate,
const char *submodule_name,
char *seen)
{
- int matched = do_match_pathspec(istate, ps, submodule_name,
- strlen(submodule_name),
- 0, seen,
- DO_MATCH_DIRECTORY |
- DO_MATCH_LEADING_PATHSPEC);
+ int matched = match_pathspec_with_flags(istate, ps, submodule_name,
+ strlen(submodule_name),
+ 0, seen,
+ DO_MATCH_DIRECTORY |
+ DO_MATCH_LEADING_PATHSPEC);
return matched;
}
@@ -1757,9 +1775,11 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
* for matching patterns.
*/
if (pathspec && !excluded) {
- matches_how = do_match_pathspec(istate, pathspec, dirname, len,
- 0 /* prefix */, NULL /* seen */,
- DO_MATCH_LEADING_PATHSPEC);
+ matches_how = match_pathspec_with_flags(istate, pathspec,
+ dirname, len,
+ 0 /* prefix */,
+ NULL /* seen */,
+ DO_MATCH_LEADING_PATHSPEC);
if (!matches_how)
return path_none;
}
@@ -1820,7 +1840,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
* to recurse into untracked/ignored directories if either of the
* following bits is set:
* - DIR_SHOW_IGNORED_TOO (because then we need to determine if
- * there are ignored directories below)
+ * there are ignored entries below)
* - DIR_HIDE_EMPTY_DIRECTORIES (because we have to determine if
* the directory is empty)
*/
@@ -1838,10 +1858,11 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
return path_excluded;
/*
- * If we have we don't want to know the all the paths under an
- * untracked or ignored directory, we still need to go into the
- * directory to determine if it is empty (because an empty directory
- * should be path_none instead of path_excluded or path_untracked).
+ * Even if we don't want to know all the paths under an untracked or
+ * ignored directory, we may still need to go into the directory to
+ * determine if it is empty (because with DIR_HIDE_EMPTY_DIRECTORIES,
+ * an empty directory should be path_none instead of path_excluded or
+ * path_untracked).
*/
check_only = ((dir->flags & DIR_HIDE_EMPTY_DIRECTORIES) &&
!(dir->flags & DIR_SHOW_IGNORED_TOO));
@@ -2188,13 +2209,13 @@ static enum path_treatment treat_path(struct dir_struct *dir,
baselen, excluded, pathspec);
case DT_REG:
case DT_LNK:
- if (excluded)
- return path_excluded;
if (pathspec &&
- !do_match_pathspec(istate, pathspec, path->buf, path->len,
- 0 /* prefix */, NULL /* seen */,
- 0 /* flags */))
+ !match_pathspec(istate, pathspec, path->buf, path->len,
+ 0 /* prefix */, NULL /* seen */,
+ 0 /* is_dir */))
return path_none;
+ if (excluded)
+ return path_excluded;
return path_untracked;
}
}
diff --git a/entry.c b/entry.c
index 00b4903..449bd32 100644
--- a/entry.c
+++ b/entry.c
@@ -113,8 +113,7 @@ static int fstat_output(int fd, const struct checkout *state, struct stat *st)
/* use fstat() only when path == ce->name */
if (fstat_is_reliable() &&
state->refresh_cache && !state->base_dir_len) {
- fstat(fd, st);
- return 1;
+ return !fstat(fd, st);
}
return 0;
}
diff --git a/fast-import.c b/fast-import.c
index c989702..0dfa14d 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -139,6 +139,7 @@ struct hash_list {
typedef enum {
WHENSPEC_RAW = 1,
+ WHENSPEC_RAW_PERMISSIVE,
WHENSPEC_RFC2822,
WHENSPEC_NOW
} whenspec_type;
@@ -1911,7 +1912,7 @@ static int parse_data(struct strbuf *sb, uintmax_t limit, uintmax_t *len_res)
return 1;
}
-static int validate_raw_date(const char *src, struct strbuf *result)
+static int validate_raw_date(const char *src, struct strbuf *result, int strict)
{
const char *orig_src = src;
char *endp;
@@ -1920,7 +1921,11 @@ static int validate_raw_date(const char *src, struct strbuf *result)
errno = 0;
num = strtoul(src, &endp, 10);
- /* NEEDSWORK: perhaps check for reasonable values? */
+ /*
+ * NEEDSWORK: perhaps check for reasonable values? For example, we
+ * could error on values representing times more than a
+ * day in the future.
+ */
if (errno || endp == src || *endp != ' ')
return -1;
@@ -1929,7 +1934,13 @@ static int validate_raw_date(const char *src, struct strbuf *result)
return -1;
num = strtoul(src + 1, &endp, 10);
- if (errno || endp == src + 1 || *endp || 1400 < num)
+ /*
+ * NEEDSWORK: check for brokenness other than num > 1400, such as
+ * (num % 100) >= 60, or ((num % 100) % 15) != 0 ?
+ */
+ if (errno || endp == src + 1 || *endp || /* did not parse */
+ (strict && (1400 < num)) /* parsed a broken timezone */
+ )
return -1;
strbuf_addstr(result, orig_src);
@@ -1963,7 +1974,11 @@ static char *parse_ident(const char *buf)
switch (whenspec) {
case WHENSPEC_RAW:
- if (validate_raw_date(ltgt, &ident) < 0)
+ if (validate_raw_date(ltgt, &ident, 1) < 0)
+ die("Invalid raw date \"%s\" in ident: %s", ltgt, buf);
+ break;
+ case WHENSPEC_RAW_PERMISSIVE:
+ if (validate_raw_date(ltgt, &ident, 0) < 0)
die("Invalid raw date \"%s\" in ident: %s", ltgt, buf);
break;
case WHENSPEC_RFC2822:
@@ -3258,6 +3273,8 @@ static void option_date_format(const char *fmt)
{
if (!strcmp(fmt, "raw"))
whenspec = WHENSPEC_RAW;
+ else if (!strcmp(fmt, "raw-permissive"))
+ whenspec = WHENSPEC_RAW_PERMISSIVE;
else if (!strcmp(fmt, "rfc2822"))
whenspec = WHENSPEC_RFC2822;
else if (!strcmp(fmt, "now"))
diff --git a/fetch-pack.c b/fetch-pack.c
index 7eaa19d..80fb3bd 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -38,6 +38,7 @@ static int server_supports_filtering;
static struct shallow_lock shallow_lock;
static const char *alternate_shallow_file;
static struct strbuf fsck_msg_types = STRBUF_INIT;
+static struct string_list uri_protocols = STRING_LIST_INIT_DUP;
/* Remember to update object flag allocation in object.h */
#define COMPLETE (1U << 0)
@@ -794,7 +795,8 @@ static void write_promisor_file(const char *keep_name,
}
static int get_pack(struct fetch_pack_args *args,
- int xd[2], char **pack_lockfile,
+ int xd[2], struct string_list *pack_lockfiles,
+ int only_packfile,
struct ref **sought, int nr_sought)
{
struct async demux;
@@ -838,7 +840,7 @@ static int get_pack(struct fetch_pack_args *args,
}
if (do_keep || args->from_promisor) {
- if (pack_lockfile)
+ if (pack_lockfiles)
cmd.out = -1;
cmd_name = "index-pack";
argv_array_push(&cmd.args, cmd_name);
@@ -855,15 +857,22 @@ static int get_pack(struct fetch_pack_args *args,
"--keep=fetch-pack %"PRIuMAX " on %s",
(uintmax_t)getpid(), hostname);
}
- if (args->check_self_contained_and_connected)
+ if (only_packfile && args->check_self_contained_and_connected)
argv_array_push(&cmd.args, "--check-self-contained-and-connected");
+ else
+ /*
+ * We cannot perform any connectivity checks because
+ * not all packs have been downloaded; let the caller
+ * have this responsibility.
+ */
+ args->check_self_contained_and_connected = 0;
/*
* If we're obtaining the filename of a lockfile, we'll use
* that filename to write a .promisor file with more
* information below. If not, we need index-pack to do it for
* us.
*/
- if (!(do_keep && pack_lockfile) && args->from_promisor)
+ if (!(do_keep && pack_lockfiles) && args->from_promisor)
argv_array_push(&cmd.args, "--promisor");
}
else {
@@ -899,8 +908,9 @@ static int get_pack(struct fetch_pack_args *args,
cmd.git_cmd = 1;
if (start_command(&cmd))
die(_("fetch-pack: unable to fork off %s"), cmd_name);
- if (do_keep && pack_lockfile) {
- *pack_lockfile = index_pack_lockfile(cmd.out);
+ if (do_keep && pack_lockfiles) {
+ string_list_append_nodup(pack_lockfiles,
+ index_pack_lockfile(cmd.out));
close(cmd.out);
}
@@ -922,8 +932,8 @@ static int get_pack(struct fetch_pack_args *args,
* Now that index-pack has succeeded, write the promisor file using the
* obtained .keep filename if necessary
*/
- if (do_keep && pack_lockfile && args->from_promisor)
- write_promisor_file(*pack_lockfile, sought, nr_sought);
+ if (do_keep && pack_lockfiles && pack_lockfiles->nr && args->from_promisor)
+ write_promisor_file(pack_lockfiles->items[0].string, sought, nr_sought);
return 0;
}
@@ -940,7 +950,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
const struct ref *orig_ref,
struct ref **sought, int nr_sought,
struct shallow_info *si,
- char **pack_lockfile)
+ struct string_list *pack_lockfiles)
{
struct repository *r = the_repository;
struct ref *ref = copy_ref_list(orig_ref);
@@ -1040,6 +1050,8 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
print_verbose(args, _("Server supports %s"), "deepen-relative");
else if (args->deepen_relative)
die(_("Server does not support --deepen"));
+ if (!server_supports_hash(the_hash_algo->name, NULL))
+ die(_("Server does not support this repository's object format"));
if (!args->no_dependents) {
mark_complete_and_common_ref(negotiator, args, &ref);
@@ -1067,7 +1079,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
alternate_shallow_file = setup_temporary_shallow(si->shallow);
else
alternate_shallow_file = NULL;
- if (get_pack(args, fd, pack_lockfile, sought, nr_sought))
+ if (get_pack(args, fd, pack_lockfiles, 1, sought, nr_sought))
die(_("git fetch-pack: fetch failed."));
all_done:
@@ -1178,6 +1190,7 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
int sideband_all, int seen_ack)
{
int ret = 0;
+ const char *hash_name;
struct strbuf req_buf = STRBUF_INIT;
if (server_supports_v2("fetch", 1))
@@ -1192,6 +1205,17 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
args->server_options->items[i].string);
}
+ if (server_feature_v2("object-format", &hash_name)) {
+ int hash_algo = hash_algo_by_name(hash_name);
+ if (hash_algo_by_ptr(the_hash_algo) != hash_algo)
+ die(_("mismatched algorithms: client %s; server %s"),
+ the_hash_algo->name, hash_name);
+ packet_write_fmt(fd_out, "object-format=%s", the_hash_algo->name);
+ } else if (hash_algo_by_ptr(the_hash_algo) != GIT_HASH_SHA1) {
+ die(_("the server does not support algorithm '%s'"),
+ the_hash_algo->name);
+ }
+
packet_buf_delim(&req_buf);
if (args->use_thin_pack)
packet_buf_write(&req_buf, "thin-pack");
@@ -1221,6 +1245,26 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
warning("filtering not recognized by server, ignoring");
}
+ if (server_supports_feature("fetch", "packfile-uris", 0)) {
+ int i;
+ struct strbuf to_send = STRBUF_INIT;
+
+ for (i = 0; i < uri_protocols.nr; i++) {
+ const char *s = uri_protocols.items[i].string;
+
+ if (!strcmp(s, "https") || !strcmp(s, "http")) {
+ if (to_send.len)
+ strbuf_addch(&to_send, ',');
+ strbuf_addstr(&to_send, s);
+ }
+ }
+ if (to_send.len) {
+ packet_buf_write(&req_buf, "packfile-uris %s",
+ to_send.buf);
+ strbuf_release(&to_send);
+ }
+ }
+
/* add wants */
add_wants(args->no_dependents, wants, &req_buf);
@@ -1443,6 +1487,21 @@ static void receive_wanted_refs(struct packet_reader *reader,
die(_("error processing wanted refs: %d"), reader->status);
}
+static void receive_packfile_uris(struct packet_reader *reader,
+ struct string_list *uris)
+{
+ process_section_header(reader, "packfile-uris", 0);
+ 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);
+
+ string_list_append(uris, reader->line);
+ }
+ if (reader->status != PACKET_READ_DELIM)
+ die("expected DELIM");
+}
+
enum fetch_state {
FETCH_CHECK_LOCAL = 0,
FETCH_SEND_REQUEST,
@@ -1451,13 +1510,20 @@ enum fetch_state {
FETCH_DONE,
};
+static void do_check_stateless_delimiter(const struct fetch_pack_args *args,
+ struct packet_reader *reader)
+{
+ check_stateless_delimiter(args->stateless_rpc, reader,
+ _("git fetch-pack: expected response end packet"));
+}
+
static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
int fd[2],
const struct ref *orig_ref,
struct ref **sought, int nr_sought,
struct oid_array *shallows,
struct shallow_info *si,
- char **pack_lockfile)
+ struct string_list *pack_lockfiles)
{
struct repository *r = the_repository;
struct ref *ref = copy_ref_list(orig_ref);
@@ -1469,6 +1535,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
struct fetch_negotiator negotiator_alloc;
struct fetch_negotiator *negotiator;
int seen_ack = 0;
+ struct string_list packfile_uris = STRING_LIST_INIT_DUP;
+ int i;
if (args->no_dependents) {
negotiator = NULL;
@@ -1535,6 +1603,10 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
/* Process ACKs/NAKs */
switch (process_acks(negotiator, &reader, &common)) {
case READY:
+ /*
+ * Don't check for response delimiter; get_pack() will
+ * read the rest of this response.
+ */
state = FETCH_GET_PACK;
break;
case COMMON_FOUND:
@@ -1542,6 +1614,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
seen_ack = 1;
/* fallthrough */
case NO_COMMON_FOUND:
+ do_check_stateless_delimiter(args, &reader);
state = FETCH_SEND_REQUEST;
break;
}
@@ -1557,10 +1630,14 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
if (process_section_header(&reader, "wanted-refs", 1))
receive_wanted_refs(&reader, sought, nr_sought);
- /* get the pack */
+ /* get the pack(s) */
+ if (process_section_header(&reader, "packfile-uris", 1))
+ receive_packfile_uris(&reader, &packfile_uris);
process_section_header(&reader, "packfile", 0);
- if (get_pack(args, fd, pack_lockfile, sought, nr_sought))
+ if (get_pack(args, fd, pack_lockfiles,
+ !packfile_uris.nr, sought, nr_sought))
die(_("git fetch-pack: fetch failed."));
+ do_check_stateless_delimiter(args, &reader);
state = FETCH_DONE;
break;
@@ -1569,8 +1646,55 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
}
}
+ for (i = 0; i < packfile_uris.nr; i++) {
+ struct child_process cmd = CHILD_PROCESS_INIT;
+ char packname[GIT_MAX_HEXSZ + 1];
+ const char *uri = packfile_uris.items[i].string +
+ the_hash_algo->hexsz + 1;
+
+ argv_array_push(&cmd.args, "http-fetch");
+ argv_array_pushf(&cmd.args, "--packfile=%.*s",
+ (int) the_hash_algo->hexsz,
+ packfile_uris.items[i].string);
+ argv_array_push(&cmd.args, uri);
+ cmd.git_cmd = 1;
+ cmd.no_stdin = 1;
+ cmd.out = -1;
+ if (start_command(&cmd))
+ die("fetch-pack: unable to spawn http-fetch");
+
+ if (read_in_full(cmd.out, packname, 5) < 0 ||
+ memcmp(packname, "keep\t", 5))
+ die("fetch-pack: expected keep then TAB at start of http-fetch output");
+
+ if (read_in_full(cmd.out, packname,
+ the_hash_algo->hexsz + 1) < 0 ||
+ packname[the_hash_algo->hexsz] != '\n')
+ die("fetch-pack: expected hash then LF at end of http-fetch output");
+
+ packname[the_hash_algo->hexsz] = '\0';
+
+ close(cmd.out);
+
+ if (finish_command(&cmd))
+ die("fetch-pack: unable to finish http-fetch");
+
+ if (memcmp(packfile_uris.items[i].string, packname,
+ the_hash_algo->hexsz))
+ die("fetch-pack: pack downloaded from %s does not match expected hash %.*s",
+ uri, (int) the_hash_algo->hexsz,
+ packfile_uris.items[i].string);
+
+ string_list_append_nodup(pack_lockfiles,
+ xstrfmt("%s/pack/pack-%s.keep",
+ get_object_directory(),
+ packname));
+ }
+ string_list_clear(&packfile_uris, 0);
+
if (negotiator)
negotiator->release(negotiator);
+
oidset_clear(&common);
return ref;
}
@@ -1607,6 +1731,14 @@ static void fetch_pack_config(void)
git_config_get_bool("repack.usedeltabaseoffset", &prefer_ofs_delta);
git_config_get_bool("fetch.fsckobjects", &fetch_fsck_objects);
git_config_get_bool("transfer.fsckobjects", &transfer_fsck_objects);
+ if (!uri_protocols.nr) {
+ char *str;
+
+ if (!git_config_get_string("fetch.uriprotocols", &str) && str) {
+ string_list_split(&uri_protocols, str, ',', -1);
+ free(str);
+ }
+ }
git_config(fetch_pack_config_cb, NULL);
}
@@ -1759,7 +1891,7 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
const struct ref *ref,
struct ref **sought, int nr_sought,
struct oid_array *shallow,
- char **pack_lockfile,
+ struct string_list *pack_lockfiles,
enum protocol_version version)
{
struct ref *ref_cpy;
@@ -1794,11 +1926,11 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
memset(&si, 0, sizeof(si));
ref_cpy = do_fetch_pack_v2(args, fd, ref, sought, nr_sought,
&shallows_scratch, &si,
- pack_lockfile);
+ pack_lockfiles);
} else {
prepare_shallow_info(&si, shallow);
ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought,
- &si, pack_lockfile);
+ &si, pack_lockfiles);
}
reprepare_packed_git(the_repository);
diff --git a/fetch-pack.h b/fetch-pack.h
index 67f6842..85d1e39 100644
--- a/fetch-pack.h
+++ b/fetch-pack.h
@@ -83,7 +83,7 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
struct ref **sought,
int nr_sought,
struct oid_array *shallow,
- char **pack_lockfile,
+ struct string_list *pack_lockfiles,
enum protocol_version version);
/*
diff --git a/fmt-merge-msg.c b/fmt-merge-msg.c
index 72d32bd..bd22e1e 100644
--- a/fmt-merge-msg.c
+++ b/fmt-merge-msg.c
@@ -10,6 +10,8 @@
#include "commit-reach.h"
static int use_branch_desc;
+static int suppress_dest_pattern_seen;
+static struct string_list suppress_dest_patterns = STRING_LIST_INIT_DUP;
int fmt_merge_msg_config(const char *key, const char *value, void *cb)
{
@@ -22,6 +24,14 @@ int fmt_merge_msg_config(const char *key, const char *value, void *cb)
merge_log_config = DEFAULT_MERGE_LOG_LEN;
} else if (!strcmp(key, "merge.branchdesc")) {
use_branch_desc = git_config_bool(key, value);
+ } else if (!strcmp(key, "merge.suppressdest")) {
+ if (!value)
+ return config_error_nonbool(key);
+ if (!*value)
+ string_list_clear(&suppress_dest_patterns, 0);
+ else
+ string_list_append(&suppress_dest_patterns, value);
+ suppress_dest_pattern_seen = 1;
} else {
return git_default_config(key, value, cb);
}
@@ -403,6 +413,24 @@ static void shortlog(const char *name,
string_list_clear(&subjects, 0);
}
+/*
+ * See if dest_branch matches with any glob pattern on the
+ * suppress_dest_patterns list.
+ *
+ * We may want to also allow negative matches e.g. ":!glob" like we do
+ * for pathspec, but for now, let's keep it simple and stupid.
+ */
+static int dest_suppressed(const char *dest_branch)
+{
+ struct string_list_item *item;
+
+ for_each_string_list_item(item, &suppress_dest_patterns) {
+ if (!wildmatch(item->string, dest_branch, WM_PATHNAME))
+ return 1;
+ }
+ return 0;
+}
+
static void fmt_merge_msg_title(struct strbuf *out,
const char *current_branch)
{
@@ -451,10 +479,9 @@ static void fmt_merge_msg_title(struct strbuf *out,
strbuf_addf(out, " of %s", srcs.items[i].string);
}
- if (!strcmp("master", current_branch))
- strbuf_addch(out, '\n');
- else
- strbuf_addf(out, " into %s\n", current_branch);
+ if (!dest_suppressed(current_branch))
+ strbuf_addf(out, " into %s", current_branch);
+ strbuf_addch(out, '\n');
}
static void fmt_tag_signature(struct strbuf *tagbuf,
@@ -599,6 +626,9 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
void *current_branch_to_free;
struct merge_parents merge_parents;
+ if (!suppress_dest_pattern_seen)
+ string_list_append(&suppress_dest_patterns, "master");
+
memset(&merge_parents, 0, sizeof(merge_parents));
/* get current branch */
diff --git a/fsck.c b/fsck.c
index 8bb3ecf..f82e2fe 100644
--- a/fsck.c
+++ b/fsck.c
@@ -598,7 +598,7 @@ static int verify_ordered(unsigned mode1, const char *name1,
/*
* There can be non-consecutive duplicates due to the implicitly
- * add slash, e.g.:
+ * added slash, e.g.:
*
* foo
* foo.bar
@@ -620,7 +620,7 @@ static int verify_ordered(unsigned mode1, const char *name1,
if (!f_name)
break;
if (!skip_prefix(name2, f_name, &p))
- break;
+ continue;
if (!*p)
return TREE_HAS_DUPS;
if (is_less_than_slash(*p)) {
diff --git a/fsmonitor.c b/fsmonitor.c
index 932bd90..ed796e3 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -217,7 +217,7 @@ void refresh_fsmonitor(struct index_state *istate)
* Need to use a char * variable because static
* analysis was suggesting to use strbuf_addbuf
* but we don't want to copy the entire strbuf
- * only the the chars up to the first NUL
+ * only the chars up to the first NUL
*/
buf = query_result.buf;
strbuf_addstr(&last_update_token, buf);
diff --git a/fuzz-commit-graph.c b/fuzz-commit-graph.c
index 9fd1c04..4308172 100644
--- a/fuzz-commit-graph.c
+++ b/fuzz-commit-graph.c
@@ -12,7 +12,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
initialize_the_repository();
g = parse_commit_graph((void *)data, size);
repo_clear(the_repository);
- free(g);
+ free_commit_graph(g);
return 0;
}
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index 10fd30a..f36c007 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -754,16 +754,18 @@ sub parse_diff_header {
my $head = { TEXT => [], DISPLAY => [], TYPE => 'header' };
my $mode = { TEXT => [], DISPLAY => [], TYPE => 'mode' };
my $deletion = { TEXT => [], DISPLAY => [], TYPE => 'deletion' };
+ my $addition = { TEXT => [], DISPLAY => [], TYPE => 'addition' };
for (my $i = 0; $i < @{$src->{TEXT}}; $i++) {
my $dest =
$src->{TEXT}->[$i] =~ /^(old|new) mode (\d+)$/ ? $mode :
$src->{TEXT}->[$i] =~ /^deleted file/ ? $deletion :
+ $src->{TEXT}->[$i] =~ /^new file/ ? $addition :
$head;
push @{$dest->{TEXT}}, $src->{TEXT}->[$i];
push @{$dest->{DISPLAY}}, $src->{DISPLAY}->[$i];
}
- return ($head, $mode, $deletion);
+ return ($head, $mode, $deletion, $addition);
}
sub hunk_splittable {
@@ -1427,46 +1429,55 @@ my %patch_update_prompt_modes = (
stage => {
mode => N__("Stage mode change [y,n,q,a,d%s,?]? "),
deletion => N__("Stage deletion [y,n,q,a,d%s,?]? "),
+ addition => N__("Stage addition [y,n,q,a,d%s,?]? "),
hunk => N__("Stage this hunk [y,n,q,a,d%s,?]? "),
},
stash => {
mode => N__("Stash mode change [y,n,q,a,d%s,?]? "),
deletion => N__("Stash deletion [y,n,q,a,d%s,?]? "),
+ addition => N__("Stash addition [y,n,q,a,d%s,?]? "),
hunk => N__("Stash this hunk [y,n,q,a,d%s,?]? "),
},
reset_head => {
mode => N__("Unstage mode change [y,n,q,a,d%s,?]? "),
deletion => N__("Unstage deletion [y,n,q,a,d%s,?]? "),
+ addition => N__("Unstage addition [y,n,q,a,d%s,?]? "),
hunk => N__("Unstage this hunk [y,n,q,a,d%s,?]? "),
},
reset_nothead => {
mode => N__("Apply mode change to index [y,n,q,a,d%s,?]? "),
deletion => N__("Apply deletion to index [y,n,q,a,d%s,?]? "),
+ addition => N__("Apply addition to index [y,n,q,a,d%s,?]? "),
hunk => N__("Apply this hunk to index [y,n,q,a,d%s,?]? "),
},
checkout_index => {
mode => N__("Discard mode change from worktree [y,n,q,a,d%s,?]? "),
deletion => N__("Discard deletion from worktree [y,n,q,a,d%s,?]? "),
+ addition => N__("Discard addition from worktree [y,n,q,a,d%s,?]? "),
hunk => N__("Discard this hunk from worktree [y,n,q,a,d%s,?]? "),
},
checkout_head => {
mode => N__("Discard mode change from index and worktree [y,n,q,a,d%s,?]? "),
deletion => N__("Discard deletion from index and worktree [y,n,q,a,d%s,?]? "),
+ addition => N__("Discard addition from index and worktree [y,n,q,a,d%s,?]? "),
hunk => N__("Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "),
},
checkout_nothead => {
mode => N__("Apply mode change to index and worktree [y,n,q,a,d%s,?]? "),
deletion => N__("Apply deletion to index and worktree [y,n,q,a,d%s,?]? "),
+ addition => N__("Apply addition to index and worktree [y,n,q,a,d%s,?]? "),
hunk => N__("Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "),
},
worktree_head => {
mode => N__("Discard mode change from worktree [y,n,q,a,d%s,?]? "),
deletion => N__("Discard deletion from worktree [y,n,q,a,d%s,?]? "),
+ addition => N__("Discard addition from worktree [y,n,q,a,d%s,?]? "),
hunk => N__("Discard this hunk from worktree [y,n,q,a,d%s,?]? "),
},
worktree_nothead => {
mode => N__("Apply mode change to worktree [y,n,q,a,d%s,?]? "),
deletion => N__("Apply deletion to worktree [y,n,q,a,d%s,?]? "),
+ addition => N__("Apply addition to worktree [y,n,q,a,d%s,?]? "),
hunk => N__("Apply this hunk to worktree [y,n,q,a,d%s,?]? "),
},
);
@@ -1476,7 +1487,7 @@ sub patch_update_file {
my ($ix, $num);
my $path = shift;
my ($head, @hunk) = parse_diff($path);
- ($head, my $mode, my $deletion) = parse_diff_header($head);
+ ($head, my $mode, my $deletion, my $addition) = parse_diff_header($head);
for (@{$head->{DISPLAY}}) {
print;
}
@@ -1490,6 +1501,12 @@ sub patch_update_file {
push @{$deletion->{DISPLAY}}, @{$hunk->{DISPLAY}};
}
@hunk = ($deletion);
+ } elsif (@{$addition->{TEXT}}) {
+ foreach my $hunk (@hunk) {
+ push @{$addition->{TEXT}}, @{$hunk->{TEXT}};
+ push @{$addition->{DISPLAY}}, @{$hunk->{DISPLAY}};
+ }
+ @hunk = ($addition);
}
$num = scalar @hunk;
diff --git a/git-bisect.sh b/git-bisect.sh
index 08a6ed5..f03fbb1 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -41,7 +41,7 @@ TERM_GOOD=good
bisect_head()
{
- if test -f "$GIT_DIR/BISECT_HEAD"
+ if git rev-parse --verify -q BISECT_HEAD > /dev/null
then
echo BISECT_HEAD
else
@@ -153,7 +153,7 @@ bisect_next() {
git bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD $TERM_GOOD|| exit
# Perform all bisection computation, display and checkout
- git bisect--helper --next-all $(test -f "$GIT_DIR/BISECT_HEAD" && echo --no-checkout)
+ git bisect--helper --next-all $(git rev-parse --verify -q BISECT_HEAD > /dev/null && echo --no-checkout)
res=$?
# Check if we should exit because bisection is finished
diff --git a/git-compat-util.h b/git-compat-util.h
index a73632e..5637114 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -869,6 +869,12 @@ FILE *fopen_for_writing(const char *path);
FILE *fopen_or_warn(const char *path, const char *mode);
/*
+ * Like strncmp, but only return zero if s is NUL-terminated and exactly len
+ * characters long. If it is not, consider it greater than t.
+ */
+int xstrncmpz(const char *s, const char *t, size_t len);
+
+/*
* FREE_AND_NULL(ptr) is like free(ptr) followed by ptr = NULL. Note
* that ptr is used twice, so don't pass e.g. ptr++.
*/
diff --git a/git-cvsexportcommit.perl b/git-cvsexportcommit.perl
index fc00d59..6483d79 100755
--- a/git-cvsexportcommit.perl
+++ b/git-cvsexportcommit.perl
@@ -22,6 +22,10 @@ die "Need at least one commit identifier!" unless @ARGV;
my $repo = Git->repository();
$opt_w = $repo->config('cvsexportcommit.cvsdir') unless defined $opt_w;
+my $tmpdir = File::Temp->newdir;
+my $hash_algo = $repo->config('extensions.objectformat') || 'sha1';
+my $hexsz = $hash_algo eq 'sha256' ? 64 : 40;
+
if ($opt_w || $opt_W) {
# Remember where GIT_DIR is before changing to CVS checkout
unless ($ENV{GIT_DIR}) {
@@ -96,7 +100,7 @@ foreach my $line (@commit) {
}
if ($stage eq 'headers') {
- if ($line =~ m/^parent (\w{40})$/) { # found a parent
+ if ($line =~ m/^parent ([0-9a-f]{$hexsz})$/) { # found a parent
push @parents, $1;
} elsif ($line =~ m/^author (.+) \d+ [-+]\d+$/) {
$author = $1;
@@ -111,7 +115,7 @@ foreach my $line (@commit) {
}
}
-my $noparent = "0000000000000000000000000000000000000000";
+my $noparent = "0" x $hexsz;
if ($parent) {
my $found;
# double check that it's a valid parent
@@ -174,7 +178,7 @@ my $context = $opt_p ? '' : '-C1';
print "Checking if patch will apply\n";
my @stat;
-open APPLY, "GIT_DIR= git-apply $context --summary --numstat<.cvsexportcommit.diff|" || die "cannot patch";
+open APPLY, "GIT_INDEX_FILE=$tmpdir/index git-apply $context --summary --numstat<.cvsexportcommit.diff|" || die "cannot patch";
@stat=<APPLY>;
close APPLY || die "Cannot patch";
my (@bfiles,@files,@afiles,@dfiles);
@@ -329,7 +333,7 @@ print "Applying\n";
if ($opt_W) {
system("git checkout -q $commit^0") && die "cannot patch";
} else {
- `GIT_DIR= git-apply $context --summary --numstat --apply <.cvsexportcommit.diff` || die "cannot patch";
+ `GIT_INDEX_FILE=$tmpdir/index git-apply $context --summary --numstat --apply <.cvsexportcommit.diff` || die "cannot patch";
}
print "Patch applied successfully. Adding new files and directories to CVS\n";
@@ -407,7 +411,7 @@ unlink(".cvsexportcommit.diff");
if ($opt_W) {
system("git checkout $go_back_to") && die "cannot move back to $go_back_to";
- if (!($go_back_to =~ /^[0-9a-fA-F]{40}$/)) {
+ if (!($go_back_to =~ /^[0-9a-fA-F]{$hexsz}$/)) {
system("git symbolic-ref HEAD $go_back_to") &&
die "cannot move back to $go_back_to";
}
diff --git a/git-cvsimport.perl b/git-cvsimport.perl
index 1057f38..7bf3c12 100755
--- a/git-cvsimport.perl
+++ b/git-cvsimport.perl
@@ -637,9 +637,9 @@ sub getwd() {
return $pwd;
}
-sub is_sha1 {
+sub is_oid {
my $s = shift;
- return $s =~ /^[a-f0-9]{40}$/;
+ return $s =~ /^[a-f0-9]{40}(?:[a-f0-9]{24})?$/;
}
sub get_headref ($) {
@@ -810,7 +810,7 @@ sub write_tree () {
open(my $fh, '-|', qw(git write-tree))
or die "unable to open git write-tree: $!";
chomp(my $tree = <$fh>);
- is_sha1($tree)
+ is_oid($tree)
or die "Cannot get tree id ($tree): $!";
close($fh)
or die "Error running git write-tree: $?\n";
@@ -896,7 +896,7 @@ sub commit {
print "Committed patch $patchset ($branch $commit_date)\n" if $opt_v;
chomp(my $cid = <$commit_read>);
- is_sha1($cid) or die "Cannot get commit id ($cid): $!\n";
+ is_oid($cid) or die "Cannot get commit id ($cid): $!\n";
print "Commit ID $cid\n" if $opt_v;
close($commit_read);
diff --git a/git-cvsserver.perl b/git-cvsserver.perl
index ae10442..f6f3fc1 100755
--- a/git-cvsserver.perl
+++ b/git-cvsserver.perl
@@ -365,7 +365,7 @@ sub req_Root
}
foreach my $line ( @gitvars )
{
- next unless ( $line =~ /^(gitcvs)\.(?:(ext|pserver)\.)?([\w-]+)=(.*)$/ );
+ next unless ( $line =~ /^(gitcvs|extensions)\.(?:(ext|pserver)\.)?([\w-]+)=(.*)$/ );
unless ($2) {
$cfg->{$1}{$3} = $4;
} else {
@@ -392,6 +392,9 @@ sub req_Root
$log->nofile();
}
+ $state->{rawsz} = ($cfg->{'extensions'}{'objectformat'} || 'sha1') eq 'sha256' ? 32 : 20;
+ $state->{hexsz} = $state->{rawsz} * 2;
+
return 1;
}
@@ -1581,7 +1584,7 @@ sub req_ci
$parenthash = safe_pipe_capture('git', 'show-ref', '-s', $branchRef);
chomp $parenthash;
- if ($parenthash !~ /^[0-9a-f]{40}$/)
+ if ($parenthash !~ /^[0-9a-f]{$state->{hexsz}}$/)
{
if ( defined($stickyInfo) && defined($stickyInfo->{tag}) )
{
@@ -1708,7 +1711,7 @@ sub req_ci
chomp($commithash);
$log->info("Commit hash : $commithash");
- unless ( $commithash =~ /[a-zA-Z0-9]{40}/ )
+ unless ( $commithash =~ /[a-zA-Z0-9]{$state->{hexsz}}/ )
{
$log->warn("Commit failed (Invalid commit hash)");
print "error 1 Commit failed (unknown reason)\n";
@@ -2375,7 +2378,7 @@ sub req_annotate
print "E ***************\n";
while ( <ANNOTATE> )
{
- if (m/^([a-zA-Z0-9]{40})\t\([^\)]*\)(.*)$/i)
+ if (m/^([a-zA-Z0-9]{$state->{hexsz}})\t\([^\)]*\)(.*)$/i)
{
my $commithash = $1;
my $data = $2;
@@ -2852,7 +2855,7 @@ sub transmitfile
return;
}
- die "Need filehash" unless ( defined ( $filehash ) and $filehash =~ /^[a-zA-Z0-9]{40}$/ );
+ die "Need filehash" unless ( defined ( $filehash ) and $filehash =~ /^[a-zA-Z0-9]{$state->{hexsz}}$/ );
my $type = safe_pipe_capture('git', 'cat-file', '-t', $filehash);
chomp $type;
@@ -3042,7 +3045,7 @@ sub ensureWorkTree
my $ver = safe_pipe_capture('git', 'show-ref', '-s', "refs/heads/$state->{module}");
chomp $ver;
- if ($ver !~ /^[0-9a-f]{40}$/)
+ if ($ver !~ /^[0-9a-f]{$state->{hexsz}}$/)
{
$log->warn("Error from git show-ref -s refs/head$state->{module}");
print "error 1 cannot find the current HEAD of module";
@@ -3281,7 +3284,7 @@ sub open_blob_or_die
}
elsif( $srcType eq "sha1" )
{
- unless ( defined ( $name ) and $name =~ /^[a-zA-Z0-9]{40}$/ )
+ unless ( defined ( $name ) and $name =~ /^[a-zA-Z0-9]{$state->{hexsz}}$/ )
{
$log->warn("Need filehash");
die "Need filehash\n";
@@ -3817,7 +3820,7 @@ sub update
chomp $commitsha1;
my $commitinfo = ::safe_pipe_capture('git', 'cat-file', 'commit', $self->{module});
- unless ( $commitinfo =~ /tree\s+[a-zA-Z0-9]{40}/ )
+ unless ( $commitinfo =~ /tree\s+[a-zA-Z0-9]{$state->{hexsz}}/ )
{
die("Invalid module '$self->{module}'");
}
@@ -3957,7 +3960,7 @@ sub update
while ( <FILELIST> )
{
chomp;
- unless ( /^:\d{6}\s+([0-7]{6})\s+[a-f0-9]{40}\s+([a-f0-9]{40})\s+(\w)$/o )
+ unless ( /^:\d{6}\s+([0-7]{6})\s+[a-f0-9]{$state->{hexsz}}\s+([a-f0-9]{$state->{hexsz}})\s+(\w)$/o )
{
die("Couldn't process git-diff-tree line : $_");
}
@@ -4625,11 +4628,11 @@ sub getmeta
$db_query->execute($filename, $intRev);
$meta = $db_query->fetchrow_hashref;
}
- elsif ( $revision =~ /^2\.1\.1\.2000(\.[1-3][0-9][0-9]){20}$/ )
+ elsif ( $revision =~ /^2\.1\.1\.2000(\.[1-3][0-9][0-9]){$state->{rawsz}}$/ )
{
my ($commitHash)=($revision=~/^2\.1\.1\.2000(.*)$/);
$commitHash=~s/\.([0-9]+)/sprintf("%02x",$1-100)/eg;
- if($commitHash=~/^[0-9a-f]{40}$/)
+ if($commitHash=~/^[0-9a-f]{$state->{hexsz}}$/)
{
return $self->getMetaFromCommithash($filename,$commitHash);
}
@@ -4639,7 +4642,7 @@ sub getmeta
$log->warning("failed get $revision with commithash=$commitHash");
undef $revision;
}
- elsif ( $revision =~ /^[0-9a-f]{40}$/ )
+ elsif ( $revision =~ /^[0-9a-f]{$state->{hexsz}}$/ )
{
# Try DB first. This is mostly only useful for req_annotate(),
# which only calls this for stuff that should already be in
@@ -4658,7 +4661,7 @@ sub getmeta
if(! $meta)
{
my($revCommit)=$self->lookupCommitRef($revision);
- if($revCommit=~/^[0-9a-f]{40}$/)
+ if($revCommit=~/^[0-9a-f]{$state->{hexsz}}$/)
{
return $self->getMetaFromCommithash($filename,$revCommit);
}
@@ -4672,7 +4675,7 @@ sub getmeta
else
{
my($revCommit)=$self->lookupCommitRef($revision);
- if($revCommit=~/^[0-9a-f]{40}$/)
+ if($revCommit=~/^[0-9a-f]{$state->{hexsz}}$/)
{
return $self->getMetaFromCommithash($filename,$revCommit);
}
@@ -4767,7 +4770,7 @@ sub getMetaFromCommithash
my($fileHash) = ::safe_pipe_capture("git","rev-parse","$revCommit:$filename");
chomp $fileHash;
- if(!($fileHash=~/^[0-9a-f]{40}$/))
+ if(!($fileHash=~/^[0-9a-f]{$state->{hexsz}}$/))
{
die "Invalid fileHash '$fileHash' looking up"
." '$revCommit:$filename'\n";
@@ -4863,7 +4866,7 @@ sub lookupCommitRef
$commitHash = ::safe_pipe_capture("git","rev-parse","--verify","--quiet",
$self->unescapeRefName($ref));
$commitHash=~s/\s*$//;
- if(!($commitHash=~/^[0-9a-f]{40}$/))
+ if(!($commitHash=~/^[0-9a-f]{$state->{hexsz}}$/))
{
$commitHash=undef;
}
@@ -4909,7 +4912,7 @@ sub commitmessage
my $commithash = shift;
my $tablename = $self->tablename("commitmsgs");
- die("Need commithash") unless ( defined($commithash) and $commithash =~ /^[a-zA-Z0-9]{40}$/ );
+ die("Need commithash") unless ( defined($commithash) and $commithash =~ /^[a-zA-Z0-9]{$state->{hexsz}}$/ );
my $db_query;
$db_query = $self->{dbh}->prepare_cached("SELECT value FROM $tablename WHERE key=?",{},1);
diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl
index e54f3e6..af1fee7 100644
--- a/git-gui/lib/choose_repository.tcl
+++ b/git-gui/lib/choose_repository.tcl
@@ -357,31 +357,10 @@ proc _is_git {path {outdir_var ""}} {
if {$outdir_var ne ""} {
upvar 1 $outdir_var outdir
}
- if {[file isfile $path]} {
- set fp [open $path r]
- gets $fp line
- close $fp
- if {[regexp "^gitdir: (.+)$" $line line link_target]} {
- set path [file join [file dirname $path] $link_target]
- set path [file normalize $path]
- }
- }
-
- if {[file exists [file join $path HEAD]]
- && [file exists [file join $path objects]]
- && [file exists [file join $path config]]} {
- set outdir $path
- return 1
- }
- if {[is_Cygwin]} {
- if {[file exists [file join $path HEAD]]
- && [file exists [file join $path objects.lnk]]
- && [file exists [file join $path config.lnk]]} {
- set outdir $path
- return 1
- }
+ if {[catch {set outdir [git rev-parse --resolve-git-dir $path]}]} {
+ return 0
}
- return 0
+ return 1
}
proc _objdir {path} {
diff --git a/git-p4.py b/git-p4.py
index d551efb..ca79dc0 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -2537,11 +2537,12 @@ class P4Submit(Command, P4UserMap):
ok = self.applyCommit(commit)
if ok:
applied.append(commit)
- else:
- if self.prepare_p4_only and i < last:
- print("Processing only the first commit due to option" \
- " --prepare-p4-only")
+ if self.prepare_p4_only:
+ if i < last:
+ print("Processing only the first commit due to option" \
+ " --prepare-p4-only")
break
+ else:
if i < last:
# prompt for what to do, or use the option/variable
if self.conflict_behavior == "ask":
diff --git a/git-send-email.perl b/git-send-email.perl
index dc95656..36c47ba 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -1699,10 +1699,14 @@ sub process_file {
$xfer_encoding = $1 if not defined $xfer_encoding;
}
elsif (/^In-Reply-To: (.*)/i) {
- $in_reply_to = $1;
+ if (!$initial_in_reply_to || $thread) {
+ $in_reply_to = $1;
+ }
}
elsif (/^References: (.*)/i) {
- $references = $1;
+ if (!$initial_in_reply_to || $thread) {
+ $references = $1;
+ }
}
elsif (!/^Date:\s/i && /^[-A-Za-z]+:\s+\S/) {
push @xh, $_;
diff --git a/git-submodule.sh b/git-submodule.sh
index 39ebdf2..43eb605 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -719,7 +719,7 @@ cmd_update()
# $@ = requested path
#
cmd_set_branch() {
- unset_branch=false
+ default=
branch=
while test $# -ne 0
@@ -729,7 +729,7 @@ cmd_set_branch() {
# we don't do anything with this but we need to accept it
;;
-d|--default)
- unset_branch=true
+ default=1
;;
-b|--branch)
case "$2" in '') usage ;; esac
@@ -750,33 +750,7 @@ cmd_set_branch() {
shift
done
- if test $# -ne 1
- then
- usage
- fi
-
- # we can't use `git submodule--helper name` here because internally, it
- # hashes the path so a trailing slash could lead to an unintentional no match
- name="$(git submodule--helper list "$1" | cut -f2)"
- if test -z "$name"
- then
- exit 1
- fi
-
- test -n "$branch"; has_branch=$?
- test "$unset_branch" = true; has_unset_branch=$?
-
- if test $((!$has_branch != !$has_unset_branch)) -eq 0
- then
- usage
- fi
-
- if test $has_branch -eq 0
- then
- git submodule--helper config submodule."$name".branch "$branch"
- else
- git submodule--helper config --unset submodule."$name".branch
- fi
+ git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper set-branch ${GIT_QUIET:+--quiet} ${branch:+--branch "$branch"} ${default:+--default} -- "$@"
}
#
diff --git a/git-svn.perl b/git-svn.perl
index 4aa208f..58f5a7a 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -5,7 +5,8 @@ use 5.008;
use warnings;
use strict;
use vars qw/ $AUTHOR $VERSION
- $sha1 $sha1_short $_revision $_repository
+ $oid $oid_short $oid_length
+ $_revision $_repository
$_q $_authors $_authors_prog %users/;
$AUTHOR = 'Eric Wong <normalperson@yhbt.net>';
$VERSION = '@@GIT_VERSION@@';
@@ -103,8 +104,9 @@ sub _req_svn {
}
}
-$sha1 = qr/[a-f\d]{40}/;
-$sha1_short = qr/[a-f\d]{4,40}/;
+$oid = qr/(?:[a-f\d]{40}(?:[a-f\d]{24})?)/;
+$oid_short = qr/[a-f\d]{4,64}/;
+$oid_length = 40;
my ($_stdin, $_help, $_edit,
$_message, $_file, $_branch_dest,
$_template, $_shared,
@@ -498,6 +500,7 @@ sub do_git_init_db {
command_noisy('config', "$pfx.preserve-empty-dirs", 'true');
command_noisy('config', "$pfx.placeholder-filename", $$fname);
}
+ load_object_format();
}
sub init_subdir {
@@ -582,7 +585,7 @@ sub cmd_set_tree {
print "Reading from stdin...\n";
@commits = ();
while (<STDIN>) {
- if (/\b($sha1_short)\b/o) {
+ if (/\b($oid_short)\b/o) {
unshift @commits, $1;
}
}
@@ -1831,7 +1834,7 @@ sub get_tree_from_treeish {
if ($type eq 'commit') {
$expected = (grep /^tree /, command(qw/cat-file commit/,
$treeish))[0];
- ($expected) = ($expected =~ /^tree ($sha1)$/o);
+ ($expected) = ($expected =~ /^tree ($oid)$/o);
die "Unable to get tree from $treeish\n" unless $expected;
} elsif ($type eq 'tree') {
$expected = $treeish;
@@ -1975,9 +1978,15 @@ sub read_git_config {
}
}
}
+ load_object_format();
delete @$opts{@config_only} if @config_only;
}
+sub load_object_format {
+ chomp(my $hash = `git config --get extensions.objectformat`);
+ $::oid_length = 64 if $hash eq 'sha256';
+}
+
sub extract_metadata {
my $id = shift or return (undef, undef, undef);
my ($url, $rev, $uuid) = ($id =~ /^\s*git-svn-id:\s+(.*)\@(\d+)
@@ -2006,10 +2015,10 @@ sub cmt_sha2rev_batch {
print $out $sha, "\n";
while (my $line = <$in>) {
- if ($first && $line =~ /^[[:xdigit:]]{40}\smissing$/) {
+ if ($first && $line =~ /^$::oid\smissing$/) {
last;
} elsif ($first &&
- $line =~ /^[[:xdigit:]]{40}\scommit\s(\d+)$/) {
+ $line =~ /^$::oid\scommit\s(\d+)$/) {
$first = 0;
$size = $1;
next;
@@ -2036,7 +2045,7 @@ sub working_head_info {
my $hash;
my %max;
while (<$fh>) {
- if ( m{^commit ($::sha1)$} ) {
+ if ( m{^commit ($::oid)$} ) {
unshift @$refs, $hash if $hash and $refs;
$hash = $1;
next;
diff --git a/git.c b/git.c
index a2d337e..6cd887b 100644
--- a/git.c
+++ b/git.c
@@ -346,6 +346,8 @@ static int handle_alias(int *argcp, const char ***argv)
commit_pager_choice();
child.use_shell = 1;
+ child.clean_on_exit = 1;
+ child.wait_after_clean = 1;
child.trace2_child_class = "shell_alias";
argv_array_push(&child.args, alias_string + 1);
argv_array_pushv(&child.args, (*argv) + 1);
@@ -574,7 +576,7 @@ static struct cmd_struct commands[] = {
{ "shortlog", cmd_shortlog, RUN_SETUP_GENTLY | USE_PAGER },
{ "show", cmd_show, RUN_SETUP },
{ "show-branch", cmd_show_branch, RUN_SETUP },
- { "show-index", cmd_show_index },
+ { "show-index", cmd_show_index, RUN_SETUP_GENTLY },
{ "show-ref", cmd_show_ref, RUN_SETUP },
{ "sparse-checkout", cmd_sparse_checkout, RUN_SETUP | NEED_WORK_TREE },
{ "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
@@ -767,7 +769,7 @@ static int run_argv(int *argcp, const char ***argv)
* OK to return. Otherwise, we just pass along the status code.
*/
i = run_command_v_opt_tr2(args.argv, RUN_SILENT_EXEC_FAILURE |
- RUN_CLEAN_ON_EXIT, "git_alias");
+ RUN_CLEAN_ON_EXIT | RUN_WAIT_AFTER_CLEAN, "git_alias");
if (i >= 0 || errno != ENOENT)
exit(i);
die("could not execute builtin %s", **argv);
diff --git a/grep.c b/grep.c
index 13232a9..54af9f8 100644
--- a/grep.c
+++ b/grep.c
@@ -1817,7 +1817,7 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
* We might set up the shared textconv cache data here, which
* is not thread-safe. Also, get_oid_with_context() and
* parse_object() might be internally called. As they are not
- * currenty thread-safe and might be racy with object reading,
+ * currently thread-safe and might be racy with object reading,
* obj_read_lock() must be called.
*/
grep_attr_lock();
diff --git a/hashmap.h b/hashmap.h
index 79ae9f8..ef220de 100644
--- a/hashmap.h
+++ b/hashmap.h
@@ -168,7 +168,7 @@ struct hashmap_entry {
* argument `keydata`, respectively. Otherwise, `keydata` is NULL.
*
* When it is too expensive to allocate a user entry (either because it is
- * large or varialbe sized, such that it is not on the stack), then the
+ * large or variable sized, such that it is not on the stack), then the
* relevant data to check for equality should be passed via `keydata`.
* In this case `key` can be a stripped down version of the user key data
* or even just a hashmap_entry having the correct hash.
diff --git a/help.c b/help.c
index 1de9c0d..44cee69 100644
--- a/help.c
+++ b/help.c
@@ -641,6 +641,7 @@ void get_version_info(struct strbuf *buf, int show_build_options)
strbuf_addstr(buf, "no commit associated with this build\n");
strbuf_addf(buf, "sizeof-long: %d\n", (int)sizeof(long));
strbuf_addf(buf, "sizeof-size_t: %d\n", (int)sizeof(size_t));
+ strbuf_addf(buf, "shell-path: %s\n", SHELL_PATH);
/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */
}
}
diff --git a/http-fetch.c b/http-fetch.c
index a32ac11..1df376e 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -5,22 +5,90 @@
#include "walker.h"
static const char http_fetch_usage[] = "git http-fetch "
-"[-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin] commit-id url";
+"[-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin | --packfile=hash | commit-id] url";
-int cmd_main(int argc, const char **argv)
+static int fetch_using_walker(const char *raw_url, int get_verbosely,
+ int get_recover, int commits, char **commit_id,
+ const char **write_ref, int commits_on_stdin)
{
+ char *url = NULL;
struct walker *walker;
+ int rc;
+
+ str_end_url_with_slash(raw_url, &url);
+
+ http_init(NULL, url, 0);
+
+ walker = get_http_walker(url);
+ walker->get_verbosely = get_verbosely;
+ walker->get_recover = get_recover;
+ walker->get_progress = 0;
+
+ rc = walker_fetch(walker, commits, commit_id, write_ref, url);
+
+ if (commits_on_stdin)
+ walker_targets_free(commits, commit_id, write_ref);
+
+ if (walker->corrupt_object_found) {
+ fprintf(stderr,
+"Some loose object were found to be corrupt, but they might be just\n"
+"a false '404 Not Found' error message sent with incorrect HTTP\n"
+"status code. Suggest running 'git fsck'.\n");
+ }
+
+ walker_free(walker);
+ http_cleanup();
+ free(url);
+
+ return rc;
+}
+
+static void fetch_single_packfile(struct object_id *packfile_hash,
+ const char *url) {
+ struct http_pack_request *preq;
+ struct slot_results results;
+ int ret;
+
+ http_init(NULL, url, 0);
+
+ preq = new_direct_http_pack_request(packfile_hash->hash, xstrdup(url));
+ if (preq == NULL)
+ die("couldn't create http pack request");
+ preq->slot->results = &results;
+ preq->generate_keep = 1;
+
+ if (start_active_slot(preq->slot)) {
+ run_active_slot(preq->slot);
+ if (results.curl_result != CURLE_OK) {
+ die("Unable to get pack file %s\n%s", preq->url,
+ curl_errorstr);
+ }
+ } else {
+ die("Unable to start request");
+ }
+
+ if ((ret = finish_http_pack_request(preq)))
+ die("finish_http_pack_request gave result %d", ret);
+
+ release_http_pack_request(preq);
+ http_cleanup();
+}
+
+int cmd_main(int argc, const char **argv)
+{
int commits_on_stdin = 0;
int commits;
const char **write_ref = NULL;
char **commit_id;
- char *url = NULL;
int arg = 1;
- int rc = 0;
int get_verbosely = 0;
int get_recover = 0;
+ int packfile = 0;
+ struct object_id packfile_hash;
while (arg < argc && argv[arg][0] == '-') {
+ const char *p;
+
if (argv[arg][1] == 't') {
} else if (argv[arg][1] == 'c') {
} else if (argv[arg][1] == 'a') {
@@ -35,46 +103,34 @@ int cmd_main(int argc, const char **argv)
get_recover = 1;
} else if (!strcmp(argv[arg], "--stdin")) {
commits_on_stdin = 1;
+ } else if (skip_prefix(argv[arg], "--packfile=", &p)) {
+ const char *end;
+
+ packfile = 1;
+ if (parse_oid_hex(p, &packfile_hash, &end) || *end)
+ die(_("argument to --packfile must be a valid hash (got '%s')"), p);
}
arg++;
}
- if (argc != arg + 2 - commits_on_stdin)
+ if (argc != arg + 2 - (commits_on_stdin || packfile))
usage(http_fetch_usage);
- if (commits_on_stdin) {
- commits = walker_targets_stdin(&commit_id, &write_ref);
- } else {
- commit_id = (char **) &argv[arg++];
- commits = 1;
- }
-
- if (argv[arg])
- str_end_url_with_slash(argv[arg], &url);
setup_git_directory();
git_config(git_default_config, NULL);
- http_init(NULL, url, 0);
- walker = get_http_walker(url);
- walker->get_verbosely = get_verbosely;
- walker->get_recover = get_recover;
-
- rc = walker_fetch(walker, commits, commit_id, write_ref, url);
-
- if (commits_on_stdin)
- walker_targets_free(commits, commit_id, write_ref);
-
- if (walker->corrupt_object_found) {
- fprintf(stderr,
-"Some loose object were found to be corrupt, but they might be just\n"
-"a false '404 Not Found' error message sent with incorrect HTTP\n"
-"status code. Suggest running 'git fsck'.\n");
+ if (packfile) {
+ fetch_single_packfile(&packfile_hash, argv[arg]);
+ return 0;
}
- walker_free(walker);
- http_cleanup();
-
- free(url);
-
- return rc;
+ if (commits_on_stdin) {
+ commits = walker_targets_stdin(&commit_id, &write_ref);
+ } else {
+ 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);
}
diff --git a/http-push.c b/http-push.c
index 822f326..1ff1883 100644
--- a/http-push.c
+++ b/http-push.c
@@ -70,10 +70,10 @@ enum XML_Status {
#define LOCK_REFRESH 30
/* Remember to update object flag allocation in object.h */
-#define LOCAL (1u<<16)
-#define REMOTE (1u<<17)
-#define FETCHING (1u<<18)
-#define PUSHING (1u<<19)
+#define LOCAL (1u<<11)
+#define REMOTE (1u<<12)
+#define FETCHING (1u<<13)
+#define PUSHING (1u<<14)
/* We allow "recursive" symbolic refs. Only within reason, though */
#define MAXDEPTH 5
@@ -117,6 +117,7 @@ enum transfer_state {
struct transfer_request {
struct object *obj;
+ struct packed_git *target;
char *url;
char *dest;
struct remote_lock *lock;
@@ -314,17 +315,18 @@ static void start_fetch_packed(struct transfer_request *request)
release_request(request);
return;
}
+ close_pack_index(target);
+ request->target = target;
fprintf(stderr, "Fetching pack %s\n",
hash_to_hex(target->hash));
fprintf(stderr, " which contains %s\n", oid_to_hex(&request->obj->oid));
- preq = new_http_pack_request(target, repo->url);
+ preq = new_http_pack_request(target->hash, repo->url);
if (preq == NULL) {
repo->can_update_info_refs = 0;
return;
}
- preq->lst = &repo->packs;
/* Make sure there isn't another open request for this pack */
while (check_request) {
@@ -597,6 +599,8 @@ static void finish_request(struct transfer_request *request)
}
if (fail)
repo->can_update_info_refs = 0;
+ else
+ http_install_packfile(request->target, &repo->packs);
release_request(request);
}
}
diff --git a/http-walker.c b/http-walker.c
index fe15e32..4fb1235 100644
--- a/http-walker.c
+++ b/http-walker.c
@@ -439,6 +439,7 @@ static int http_fetch_pack(struct walker *walker, struct alt_base *repo, unsigne
target = find_sha1_pack(sha1, repo->packs);
if (!target)
return -1;
+ close_pack_index(target);
if (walker->get_verbosely) {
fprintf(stderr, "Getting pack %s\n",
@@ -447,10 +448,9 @@ static int http_fetch_pack(struct walker *walker, struct alt_base *repo, unsigne
hash_to_hex(sha1));
}
- preq = new_http_pack_request(target, repo->base);
+ preq = new_http_pack_request(target->hash, repo->base);
if (preq == NULL)
goto abort;
- preq->lst = &repo->packs;
preq->slot->results = &results;
if (start_active_slot(preq->slot)) {
@@ -469,6 +469,7 @@ static int http_fetch_pack(struct walker *walker, struct alt_base *repo, unsigne
release_http_pack_request(preq);
if (ret)
return ret;
+ http_install_packfile(target, &repo->packs);
return 0;
diff --git a/http.c b/http.c
index 62aa995..3b12843 100644
--- a/http.c
+++ b/http.c
@@ -18,7 +18,7 @@
static struct trace_key trace_curl = TRACE_KEY_INIT(CURL);
static int trace_curl_data = 1;
-static struct string_list cookies_to_redact = STRING_LIST_INIT_DUP;
+static int trace_curl_redact = 1;
#if LIBCURL_VERSION_NUM >= 0x070a08
long int git_curl_ipresolve = CURL_IPRESOLVE_WHATEVER;
#else
@@ -642,8 +642,9 @@ static void redact_sensitive_header(struct strbuf *header)
{
const char *sensitive_header;
- if (skip_prefix(header->buf, "Authorization:", &sensitive_header) ||
- skip_prefix(header->buf, "Proxy-Authorization:", &sensitive_header)) {
+ if (trace_curl_redact &&
+ (skip_prefix(header->buf, "Authorization:", &sensitive_header) ||
+ skip_prefix(header->buf, "Proxy-Authorization:", &sensitive_header))) {
/* The first token is the type, which is OK to log */
while (isspace(*sensitive_header))
sensitive_header++;
@@ -652,20 +653,15 @@ static void redact_sensitive_header(struct strbuf *header)
/* Everything else is opaque and possibly sensitive */
strbuf_setlen(header, sensitive_header - header->buf);
strbuf_addstr(header, " <redacted>");
- } else if (cookies_to_redact.nr &&
+ } else if (trace_curl_redact &&
skip_prefix(header->buf, "Cookie:", &sensitive_header)) {
struct strbuf redacted_header = STRBUF_INIT;
- char *cookie;
+ const char *cookie;
while (isspace(*sensitive_header))
sensitive_header++;
- /*
- * The contents of header starting from sensitive_header will
- * subsequently be overridden, so it is fine to mutate this
- * string (hence the assignment to "char *").
- */
- cookie = (char *) sensitive_header;
+ cookie = sensitive_header;
while (cookie) {
char *equals;
@@ -678,14 +674,8 @@ static void redact_sensitive_header(struct strbuf *header)
strbuf_addstr(&redacted_header, cookie);
continue;
}
- *equals = 0; /* temporarily set to NUL for lookup */
- if (string_list_lookup(&cookies_to_redact, cookie)) {
- strbuf_addstr(&redacted_header, cookie);
- strbuf_addstr(&redacted_header, "=<redacted>");
- } else {
- *equals = '=';
- strbuf_addstr(&redacted_header, cookie);
- }
+ strbuf_add(&redacted_header, cookie, equals - cookie);
+ strbuf_addstr(&redacted_header, "=<redacted>");
if (semicolon) {
/*
* There are more cookies. (Or, for some
@@ -804,6 +794,12 @@ static int curl_trace(CURL *handle, curl_infotype type, char *data, size_t size,
return 0;
}
+void http_trace_curl_no_data(void)
+{
+ trace_override_envvar(&trace_curl, "1");
+ trace_curl_data = 0;
+}
+
void setup_curl_trace(CURL *handle)
{
if (!trace_want(&trace_curl))
@@ -993,15 +989,12 @@ static CURL *get_curl_handle(void)
warning(_("Protocol restrictions not supported with cURL < 7.19.4"));
#endif
if (getenv("GIT_CURL_VERBOSE"))
- curl_easy_setopt(result, CURLOPT_VERBOSE, 1L);
+ http_trace_curl_no_data();
setup_curl_trace(result);
if (getenv("GIT_TRACE_CURL_NO_DATA"))
trace_curl_data = 0;
- if (getenv("GIT_REDACT_COOKIES")) {
- string_list_split(&cookies_to_redact,
- getenv("GIT_REDACT_COOKIES"), ',', -1);
- string_list_sort(&cookies_to_redact);
- }
+ if (!git_env_bool("GIT_TRACE_REDACT", 1))
+ trace_curl_redact = 0;
curl_easy_setopt(result, CURLOPT_USERAGENT,
user_agent ? user_agent : git_user_agent());
@@ -2268,70 +2261,74 @@ void release_http_pack_request(struct http_pack_request *preq)
int finish_http_pack_request(struct http_pack_request *preq)
{
- struct packed_git **lst;
- struct packed_git *p = preq->target;
- char *tmp_idx;
- size_t len;
struct child_process ip = CHILD_PROCESS_INIT;
-
- close_pack_index(p);
+ int tmpfile_fd;
+ int ret = 0;
fclose(preq->packfile);
preq->packfile = NULL;
- lst = preq->lst;
- while (*lst != p)
- lst = &((*lst)->next);
- *lst = (*lst)->next;
-
- if (!strip_suffix(preq->tmpfile.buf, ".pack.temp", &len))
- BUG("pack tmpfile does not end in .pack.temp?");
- tmp_idx = xstrfmt("%.*s.idx.temp", (int)len, preq->tmpfile.buf);
+ tmpfile_fd = xopen(preq->tmpfile.buf, O_RDONLY);
argv_array_push(&ip.args, "index-pack");
- argv_array_pushl(&ip.args, "-o", tmp_idx, NULL);
- argv_array_push(&ip.args, preq->tmpfile.buf);
+ argv_array_push(&ip.args, "--stdin");
ip.git_cmd = 1;
- ip.no_stdin = 1;
- ip.no_stdout = 1;
+ ip.in = tmpfile_fd;
+ if (preq->generate_keep) {
+ argv_array_pushf(&ip.args, "--keep=git %"PRIuMAX,
+ (uintmax_t)getpid());
+ ip.out = 0;
+ } else {
+ ip.no_stdout = 1;
+ }
if (run_command(&ip)) {
- unlink(preq->tmpfile.buf);
- unlink(tmp_idx);
- free(tmp_idx);
- return -1;
+ ret = -1;
+ goto cleanup;
}
- unlink(sha1_pack_index_name(p->hash));
+cleanup:
+ close(tmpfile_fd);
+ unlink(preq->tmpfile.buf);
+ return ret;
+}
- if (finalize_object_file(preq->tmpfile.buf, sha1_pack_name(p->hash))
- || finalize_object_file(tmp_idx, sha1_pack_index_name(p->hash))) {
- free(tmp_idx);
- return -1;
- }
+void http_install_packfile(struct packed_git *p,
+ struct packed_git **list_to_remove_from)
+{
+ struct packed_git **lst = list_to_remove_from;
+
+ while (*lst != p)
+ lst = &((*lst)->next);
+ *lst = (*lst)->next;
install_packed_git(the_repository, p);
- free(tmp_idx);
- return 0;
}
struct http_pack_request *new_http_pack_request(
- struct packed_git *target, const char *base_url)
+ const unsigned char *packed_git_hash, const char *base_url) {
+
+ struct strbuf buf = STRBUF_INIT;
+
+ end_url_with_slash(&buf, base_url);
+ strbuf_addf(&buf, "objects/pack/pack-%s.pack",
+ hash_to_hex(packed_git_hash));
+ return new_direct_http_pack_request(packed_git_hash,
+ strbuf_detach(&buf, NULL));
+}
+
+struct http_pack_request *new_direct_http_pack_request(
+ const unsigned char *packed_git_hash, char *url)
{
off_t prev_posn = 0;
- struct strbuf buf = STRBUF_INIT;
struct http_pack_request *preq;
preq = xcalloc(1, sizeof(*preq));
strbuf_init(&preq->tmpfile, 0);
- preq->target = target;
- end_url_with_slash(&buf, base_url);
- strbuf_addf(&buf, "objects/pack/pack-%s.pack",
- hash_to_hex(target->hash));
- preq->url = strbuf_detach(&buf, NULL);
+ preq->url = url;
- strbuf_addf(&preq->tmpfile, "%s.temp", sha1_pack_name(target->hash));
+ strbuf_addf(&preq->tmpfile, "%s.temp", sha1_pack_name(packed_git_hash));
preq->packfile = fopen(preq->tmpfile.buf, "a");
if (!preq->packfile) {
error("Unable to open local file %s for pack",
@@ -2355,7 +2352,7 @@ struct http_pack_request *new_http_pack_request(
if (http_is_verbose)
fprintf(stderr,
"Resuming fetch of pack %s at byte %"PRIuMAX"\n",
- hash_to_hex(target->hash),
+ hash_to_hex(packed_git_hash),
(uintmax_t)prev_posn);
http_opt_request_remainder(preq->slot->curl, prev_posn);
}
diff --git a/http.h b/http.h
index 5e0ad72..5de792e 100644
--- a/http.h
+++ b/http.h
@@ -216,18 +216,36 @@ int http_get_info_packs(const char *base_url,
struct http_pack_request {
char *url;
- struct packed_git *target;
- struct packed_git **lst;
+
+ /*
+ * If this is true, finish_http_pack_request() will pass "--keep" to
+ * index-pack, resulting in the creation of a keep file, and will not
+ * suppress its stdout (that is, the "keep\t<hash>\n" line will be
+ * printed to stdout).
+ */
+ unsigned generate_keep : 1;
+
FILE *packfile;
struct strbuf tmpfile;
struct active_request_slot *slot;
};
struct http_pack_request *new_http_pack_request(
- struct packed_git *target, const char *base_url);
+ const unsigned char *packed_git_hash, const char *base_url);
+struct http_pack_request *new_direct_http_pack_request(
+ const unsigned char *packed_git_hash, char *url);
int finish_http_pack_request(struct http_pack_request *preq);
void release_http_pack_request(struct http_pack_request *preq);
+/*
+ * Remove p from the given list, and invoke install_packed_git() on it.
+ *
+ * This is a convenience function for users that have obtained a list of packs
+ * from http_get_info_packs() and have chosen a specific pack to fetch.
+ */
+void http_install_packfile(struct packed_git *p,
+ struct packed_git **list_to_remove_from);
+
/* Helpers for fetching object */
struct http_object_request {
char *url;
@@ -252,6 +270,13 @@ 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);
+/*
+ * Instead of using environment variables to determine if curl tracing happens,
+ * behave as if GIT_TRACE_CURL=1 and GIT_TRACE_CURL_NO_DATA=1 is set. Call this
+ * before calling setup_curl_trace().
+ */
+void http_trace_curl_no_data(void);
+
/* setup routine for curl_easy_setopt CURLOPT_DEBUGFUNCTION */
void setup_curl_trace(CURL *handle);
#endif /* HTTP_H */
diff --git a/imap-send.c b/imap-send.c
index 6c54d8c..5273754 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -1464,7 +1464,7 @@ static CURL *setup_curl(struct imap_server_conf *srvc, struct credential *cred)
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
if (0 < verbosity || getenv("GIT_CURL_VERBOSE"))
- curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
+ http_trace_curl_no_data();
setup_curl_trace(curl);
return curl;
diff --git a/line-log.c b/line-log.c
index 40e1738..c536928 100644
--- a/line-log.c
+++ b/line-log.c
@@ -15,6 +15,7 @@
#include "userdiff.h"
#include "line-log.h"
#include "argv-array.h"
+#include "bloom.h"
static void range_set_grow(struct range_set *rs, size_t extra)
{
@@ -1146,6 +1147,37 @@ int line_log_print(struct rev_info *rev, struct commit *commit)
return 1;
}
+static int bloom_filter_check(struct rev_info *rev,
+ struct commit *commit,
+ struct line_log_data *range)
+{
+ struct bloom_filter *filter;
+ struct bloom_key key;
+ int result = 0;
+
+ if (!commit->parents)
+ return 1;
+
+ if (!rev->bloom_filter_settings ||
+ !(filter = get_bloom_filter(rev->repo, commit, 0)))
+ return 1;
+
+ if (!range)
+ return 0;
+
+ while (!result && range) {
+ fill_bloom_key(range->path, strlen(range->path), &key, rev->bloom_filter_settings);
+
+ if (bloom_filter_contains(filter, &key, rev->bloom_filter_settings))
+ result = 1;
+
+ clear_bloom_key(&key);
+ range = range->next;
+ }
+
+ return result;
+}
+
static int process_ranges_ordinary_commit(struct rev_info *rev, struct commit *commit,
struct line_log_data *range)
{
@@ -1159,6 +1191,7 @@ static int process_ranges_ordinary_commit(struct rev_info *rev, struct commit *c
queue_diffs(range, &rev->diffopt, &queue, commit, parent);
changed = process_all_files(&parent_range, rev, &queue, range);
+
if (parent)
add_line_range(rev, parent, parent_range);
free_line_log_data(parent_range);
@@ -1227,13 +1260,17 @@ static int process_ranges_merge_commit(struct rev_info *rev, struct commit *comm
/* NEEDSWORK leaking like a sieve */
}
-static int process_ranges_arbitrary_commit(struct rev_info *rev, struct commit *commit)
+int line_log_process_ranges_arbitrary_commit(struct rev_info *rev, struct commit *commit)
{
struct line_log_data *range = lookup_line_range(rev, commit);
int changed = 0;
if (range) {
- if (!commit->parents || !commit->parents->next)
+ if (commit->parents && !bloom_filter_check(rev, commit, range)) {
+ struct line_log_data *prange = line_log_data_copy(range);
+ add_line_range(rev, commit->parents->item, prange);
+ clear_commit_line_range(rev, commit);
+ } else if (!commit->parents || !commit->parents->next)
changed = process_ranges_ordinary_commit(rev, commit, range);
else
changed = process_ranges_merge_commit(rev, commit, range);
@@ -1270,7 +1307,7 @@ int line_log_filter(struct rev_info *rev)
while (list) {
struct commit_list *to_free = NULL;
commit = list->item;
- if (process_ranges_arbitrary_commit(rev, commit)) {
+ if (line_log_process_ranges_arbitrary_commit(rev, commit)) {
*pp = list;
pp = &list->next;
} else
diff --git a/line-log.h b/line-log.h
index 8ee7a2b..82ae8d9 100644
--- a/line-log.h
+++ b/line-log.h
@@ -46,10 +46,7 @@ void sort_and_merge_range_set(struct range_set *);
struct line_log_data {
struct line_log_data *next;
char *path;
- char status;
struct range_set ranges;
- int arg_alloc, arg_nr;
- const char **args;
struct diff_filepair *pair;
struct diff_ranges diff;
};
@@ -57,6 +54,8 @@ struct line_log_data {
void line_log_init(struct rev_info *rev, const char *prefix, struct string_list *args);
int line_log_filter(struct rev_info *rev);
+int line_log_process_ranges_arbitrary_commit(struct rev_info *rev,
+ struct commit *commit);
int line_log_print(struct rev_info *rev, struct commit *commit);
diff --git a/list-objects-filter-options.c b/list-objects-filter-options.c
index 256bcfb..3553ad7 100644
--- a/list-objects-filter-options.c
+++ b/list-objects-filter-options.c
@@ -326,7 +326,8 @@ void partial_clone_register(
/* Check if it is already registered */
if (!promisor_remote_find(remote)) {
- git_config_set("core.repositoryformatversion", "1");
+ if (upgrade_repository_format(1) < 0)
+ die(_("unable to upgrade repository format to support partial clone"));
/* Add promisor config for the remote */
cfg_name = xstrfmt("remote.%s.promisor", remote);
diff --git a/object-store.h b/object-store.h
index d1e490f..f439d47 100644
--- a/object-store.h
+++ b/object-store.h
@@ -70,6 +70,7 @@ struct packed_git {
size_t index_size;
uint32_t num_objects;
uint32_t num_bad_objects;
+ uint32_t crc_offset;
unsigned char *bad_object_sha1;
int index_version;
time_t mtime;
diff --git a/object.c b/object.c
index 794c866..3257518 100644
--- a/object.c
+++ b/object.c
@@ -157,13 +157,13 @@ void *create_object(struct repository *r, const struct object_id *oid, void *o)
return obj;
}
-void *object_as_type(struct repository *r, struct object *obj, enum object_type type, int quiet)
+void *object_as_type(struct object *obj, enum object_type type, int quiet)
{
if (obj->type == type)
return obj;
else if (obj->type == OBJ_NONE) {
if (type == OBJ_COMMIT)
- init_commit_node(r, (struct commit *) obj);
+ init_commit_node((struct commit *) obj);
else
obj->type = type;
return obj;
diff --git a/object.h b/object.h
index b22328b..96a2105 100644
--- a/object.h
+++ b/object.h
@@ -15,7 +15,6 @@ struct parsed_object_pool {
struct alloc_state *commit_state;
struct alloc_state *tag_state;
struct alloc_state *object_state;
- unsigned commit_count;
/* parent substitutions from .git/info/grafts and .git/shallow */
struct commit_graft **grafts;
@@ -26,6 +25,7 @@ struct parsed_object_pool {
char *alternate_shallow_file;
int commit_graft_prepared;
+ int substituted_parent;
struct buffer_slab *buffer_slab;
};
@@ -59,7 +59,7 @@ struct object_array {
/*
* object flag allocation:
- * revision.h: 0---------10 15 25----28
+ * revision.h: 0---------10 15 23------26
* fetch-pack.c: 01
* negotiator/default.c: 2--5
* walker.c: 0-2
@@ -67,7 +67,7 @@ struct object_array {
* builtin/blame.c: 12-13
* bisect.c: 16
* bundle.c: 16
- * http-push.c: 16-----19
+ * http-push.c: 11-----14
* commit-graph.c: 15
* commit-reach.c: 16-----19
* sha1-name.c: 20
@@ -79,7 +79,7 @@ struct object_array {
* builtin/show-branch.c: 0-------------------------------------------26
* builtin/unpack-objects.c: 2021
*/
-#define FLAG_BITS 29
+#define FLAG_BITS 28
/*
* The object type is stored in 3 bits.
@@ -121,7 +121,7 @@ struct object *lookup_object(struct repository *r, const struct object_id *oid);
void *create_object(struct repository *r, const struct object_id *oid, void *obj);
-void *object_as_type(struct repository *r, struct object *obj, enum object_type type, int quiet);
+void *object_as_type(struct object *obj, enum object_type type, int quiet);
/*
* Returns the object, having parsed it to find out what it is.
diff --git a/pack-write.c b/pack-write.c
index f0017be..685d327 100644
--- a/pack-write.c
+++ b/pack-write.c
@@ -38,9 +38,8 @@ static int need_large_offset(off_t offset, const struct pack_idx_option *opts)
}
/*
- * On entry *sha1 contains the pack content SHA1 hash, on exit it is
- * the SHA1 hash of sorted object names. The objects array passed in
- * will be sorted by SHA1 on exit.
+ * The *sha1 contains the pack content SHA1 hash.
+ * The objects array passed in will be sorted by SHA1 on exit.
*/
const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects,
int nr_objects, const struct pack_idx_option *opts,
diff --git a/packfile.c b/packfile.c
index f4e7529..6ab5233 100644
--- a/packfile.c
+++ b/packfile.c
@@ -178,6 +178,7 @@ int load_idx(const char *path, const unsigned int hashsz, void *idx_map,
*/
(sizeof(off_t) <= 4))
return error("pack too large for current definition of off_t in %s", path);
+ p->crc_offset = 8 + 4 * 256 + nr * hashsz;
}
p->index_version = version;
diff --git a/perl/Git/IndexInfo.pm b/perl/Git/IndexInfo.pm
index a43108c..2a7b490 100644
--- a/perl/Git/IndexInfo.pm
+++ b/perl/Git/IndexInfo.pm
@@ -5,13 +5,15 @@ use Git qw/command_input_pipe command_close_pipe/;
sub new {
my ($class) = @_;
+ my $hash_algo = Git::config('extensions.objectformat') || 'sha1';
my ($gui, $ctx) = command_input_pipe(qw/update-index -z --index-info/);
- bless { gui => $gui, ctx => $ctx, nr => 0}, $class;
+ bless { gui => $gui, ctx => $ctx, nr => 0, hash_algo => $hash_algo}, $class;
}
sub remove {
my ($self, $path) = @_;
- if (print { $self->{gui} } '0 ', 0 x 40, "\t", $path, "\0") {
+ my $length = $self->{hash_algo} eq 'sha256' ? 64 : 40;
+ if (print { $self->{gui} } '0 ', 0 x $length, "\t", $path, "\0") {
return ++$self->{nr};
}
undef;
diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm
index 4b28b87..d1c352f 100644
--- a/perl/Git/SVN.pm
+++ b/perl/Git/SVN.pm
@@ -2,7 +2,7 @@ package Git::SVN;
use strict;
use warnings;
use Fcntl qw/:DEFAULT :seek/;
-use constant rev_map_fmt => 'NH40';
+use constant rev_map_fmt => 'NH*';
use vars qw/$_no_metadata
$_repack $_repack_flags $_use_svm_props $_head
$_use_svnsync_props $no_reuse_existing
@@ -874,7 +874,7 @@ sub assert_index_clean {
command_noisy('read-tree', $treeish) unless -e $self->{index};
my $x = command_oneline('write-tree');
my ($y) = (command(qw/cat-file commit/, $treeish) =~
- /^tree ($::sha1)/mo);
+ /^tree ($::oid)/mo);
return if $y eq $x;
warn "Index mismatch: $y != $x\nrereading $treeish\n";
@@ -1020,7 +1020,7 @@ sub do_git_commit {
$tree = $self->tmp_index_do(sub {
command_oneline('write-tree') });
}
- die "Tree is not a valid sha1: $tree\n" if $tree !~ /^$::sha1$/o;
+ die "Tree is not a valid oid $tree\n" if $tree !~ /^$::oid$/o;
my @exec = ('git', 'commit-tree', $tree);
foreach ($self->get_commit_parents($log_entry)) {
@@ -1048,8 +1048,8 @@ sub do_git_commit {
close $out_fh or croak $!;
waitpid $pid, 0;
croak $? if $?;
- if ($commit !~ /^$::sha1$/o) {
- die "Failed to commit, invalid sha1: $commit\n";
+ if ($commit !~ /^$::oid$/o) {
+ die "Failed to commit, invalid oid: $commit\n";
}
$self->rev_map_set($log_entry->{revision}, $commit, 1);
@@ -2087,10 +2087,10 @@ sub rebuild_from_rev_db {
open my $fh, '<', $path or croak "open: $!";
binmode $fh or croak "binmode: $!";
while (<$fh>) {
- length($_) == 41 or croak "inconsistent size in ($_) != 41";
+ length($_) == $::oid_length + 1 or croak "inconsistent size in ($_)";
chomp($_);
++$r;
- next if $_ eq ('0' x 40);
+ next if $_ eq ('0' x $::oid_length);
$self->rev_map_set($r, $_);
print "r$r = $_\n";
}
@@ -2150,7 +2150,7 @@ sub rebuild {
my $svn_uuid = $self->rewrite_uuid || $self->ra_uuid;
my $c;
while (<$log>) {
- if ( m{^commit ($::sha1)$} ) {
+ if ( m{^commit ($::oid)$} ) {
$c = $1;
next;
}
@@ -2196,9 +2196,9 @@ sub rebuild {
# (mainly tags)
#
# The format is this:
-# - 24 bytes for every record,
+# - 24 or 36 bytes for every record,
# * 4 bytes for the integer representing an SVN revision number
-# * 20 bytes representing the sha1 of a git commit
+# * 20 or 32 bytes representing the oid of a git commit
# - No empty padding records like the old format
# (except the last record, which can be overwritten)
# - new records are written append-only since SVN revision numbers
@@ -2207,7 +2207,7 @@ sub rebuild {
# - Piping the file to xxd -c24 is a good way of dumping it for
# viewing or editing (piped back through xxd -r), should the need
# ever arise.
-# - The last record can be padding revision with an all-zero sha1
+# - The last record can be padding revision with an all-zero oid
# This is used to optimize fetch performance when using multiple
# "fetch" directives in .git/config
#
@@ -2215,38 +2215,39 @@ sub rebuild {
sub _rev_map_set {
my ($fh, $rev, $commit) = @_;
+ my $record_size = ($::oid_length / 2) + 4;
binmode $fh or croak "binmode: $!";
my $size = (stat($fh))[7];
- ($size % 24) == 0 or croak "inconsistent size: $size";
+ ($size % $record_size) == 0 or croak "inconsistent size: $size";
my $wr_offset = 0;
if ($size > 0) {
- sysseek($fh, -24, SEEK_END) or croak "seek: $!";
- my $read = sysread($fh, my $buf, 24) or croak "read: $!";
- $read == 24 or croak "read only $read bytes (!= 24)";
+ sysseek($fh, -$record_size, SEEK_END) or croak "seek: $!";
+ my $read = sysread($fh, my $buf, $record_size) or croak "read: $!";
+ $read == $record_size or croak "read only $read bytes (!= $record_size)";
my ($last_rev, $last_commit) = unpack(rev_map_fmt, $buf);
- if ($last_commit eq ('0' x40)) {
- if ($size >= 48) {
- sysseek($fh, -48, SEEK_END) or croak "seek: $!";
- $read = sysread($fh, $buf, 24) or
+ if ($last_commit eq ('0' x $::oid_length)) {
+ if ($size >= ($record_size * 2)) {
+ sysseek($fh, -($record_size * 2), SEEK_END) or croak "seek: $!";
+ $read = sysread($fh, $buf, $record_size) or
croak "read: $!";
- $read == 24 or
- croak "read only $read bytes (!= 24)";
+ $read == $record_size or
+ croak "read only $read bytes (!= $record_size)";
($last_rev, $last_commit) =
unpack(rev_map_fmt, $buf);
- if ($last_commit eq ('0' x40)) {
+ if ($last_commit eq ('0' x $::oid_length)) {
croak "inconsistent .rev_map\n";
}
}
if ($last_rev >= $rev) {
croak "last_rev is higher!: $last_rev >= $rev";
}
- $wr_offset = -24;
+ $wr_offset = -$record_size;
}
}
sysseek($fh, $wr_offset, SEEK_END) or croak "seek: $!";
- syswrite($fh, pack(rev_map_fmt, $rev, $commit), 24) == 24 or
+ syswrite($fh, pack(rev_map_fmt, $rev, $commit), $record_size) == $record_size or
croak "write: $!";
}
@@ -2271,7 +2272,7 @@ sub mkfile {
sub rev_map_set {
my ($self, $rev, $commit, $update_ref, $uuid) = @_;
defined $commit or die "missing arg3\n";
- length $commit == 40 or die "arg3 must be a full SHA1 hexsum\n";
+ $commit =~ /^$::oid$/ or die "arg3 must be a full hex object ID\n";
my $db = $self->map_path($uuid);
my $db_lock = "$db.lock";
my $sigmask;
@@ -2344,29 +2345,30 @@ sub rev_map_max {
sub rev_map_max_norebuild {
my ($self, $want_commit) = @_;
+ my $record_size = ($::oid_length / 2) + 4;
my $map_path = $self->map_path;
stat $map_path or return $want_commit ? (0, undef) : 0;
sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!";
binmode $fh or croak "binmode: $!";
my $size = (stat($fh))[7];
- ($size % 24) == 0 or croak "inconsistent size: $size";
+ ($size % $record_size) == 0 or croak "inconsistent size: $size";
if ($size == 0) {
close $fh or croak "close: $!";
return $want_commit ? (0, undef) : 0;
}
- sysseek($fh, -24, SEEK_END) or croak "seek: $!";
- sysread($fh, my $buf, 24) == 24 or croak "read: $!";
+ sysseek($fh, -$record_size, SEEK_END) or croak "seek: $!";
+ sysread($fh, my $buf, $record_size) == $record_size or croak "read: $!";
my ($r, $c) = unpack(rev_map_fmt, $buf);
- if ($want_commit && $c eq ('0' x40)) {
- if ($size < 48) {
+ if ($want_commit && $c eq ('0' x $::oid_length)) {
+ if ($size < $record_size * 2) {
return $want_commit ? (0, undef) : 0;
}
- sysseek($fh, -48, SEEK_END) or croak "seek: $!";
- sysread($fh, $buf, 24) == 24 or croak "read: $!";
+ sysseek($fh, -($record_size * 2), SEEK_END) or croak "seek: $!";
+ sysread($fh, $buf, $record_size) == $record_size or croak "read: $!";
($r, $c) = unpack(rev_map_fmt, $buf);
- if ($c eq ('0'x40)) {
+ if ($c eq ('0' x $::oid_length)) {
croak "Penultimate record is all-zeroes in $map_path";
}
}
@@ -2387,30 +2389,31 @@ sub rev_map_get {
sub _rev_map_get {
my ($fh, $rev) = @_;
+ my $record_size = ($::oid_length / 2) + 4;
binmode $fh or croak "binmode: $!";
my $size = (stat($fh))[7];
- ($size % 24) == 0 or croak "inconsistent size: $size";
+ ($size % $record_size) == 0 or croak "inconsistent size: $size";
if ($size == 0) {
return undef;
}
- my ($l, $u) = (0, $size - 24);
+ my ($l, $u) = (0, $size - $record_size);
my ($r, $c, $buf);
while ($l <= $u) {
- my $i = int(($l/24 + $u/24) / 2) * 24;
+ my $i = int(($l/$record_size + $u/$record_size) / 2) * $record_size;
sysseek($fh, $i, SEEK_SET) or croak "seek: $!";
- sysread($fh, my $buf, 24) == 24 or croak "read: $!";
+ sysread($fh, my $buf, $record_size) == $record_size or croak "read: $!";
my ($r, $c) = unpack(rev_map_fmt, $buf);
if ($r < $rev) {
- $l = $i + 24;
+ $l = $i + $record_size;
} elsif ($r > $rev) {
- $u = $i - 24;
+ $u = $i - $record_size;
} else { # $r == $rev
- return $c eq ('0' x 40) ? undef : $c;
+ return $c eq ('0' x $::oid_length) ? undef : $c;
}
}
undef;
diff --git a/perl/Git/SVN/Editor.pm b/perl/Git/SVN/Editor.pm
index 0df16ed..c961444 100644
--- a/perl/Git/SVN/Editor.pm
+++ b/perl/Git/SVN/Editor.pm
@@ -63,7 +63,7 @@ sub generate_diff {
my @mods;
while (defined($_ = get_record($diff_fh, "\0"))) {
if ($state eq 'meta' && /^:(\d{6})\s(\d{6})\s
- ($::sha1)\s($::sha1)\s
+ ($::oid)\s($::oid)\s
([MTCRAD])\d*$/xo) {
push @mods, { mode_a => $1, mode_b => $2,
sha1_a => $3, sha1_b => $4,
@@ -400,12 +400,12 @@ sub T {
($m->{mode_b} !~ /^120/ && $m->{mode_a} =~ /^120/)) {
$self->D({
mode_a => $m->{mode_a}, mode_b => '000000',
- sha1_a => $m->{sha1_a}, sha1_b => '0' x 40,
+ sha1_a => $m->{sha1_a}, sha1_b => '0' x $::oid_length,
chg => 'D', file_b => $m->{file_b}
}, $deletions);
$self->A({
mode_a => '000000', mode_b => $m->{mode_b},
- sha1_a => '0' x 40, sha1_b => $m->{sha1_b},
+ sha1_a => '0' x $::oid_length, sha1_b => $m->{sha1_b},
chg => 'A', file_b => $m->{file_b}
}, $deletions);
return;
@@ -434,7 +434,7 @@ sub _chg_file_get_blob ($$$$) {
$self->change_file_prop($fbat,'svn:special',undef);
}
my $blob = $m->{"sha1_$which"};
- return ($fh,) if ($blob =~ /^0{40}$/);
+ return ($fh,) if ($blob =~ /^0+$/);
my $size = $::_repository->cat_blob($blob, $fh);
croak "Failed to read object $blob" if ($size < 0);
$fh->flush == 0 or croak $!;
diff --git a/perl/Git/SVN/Fetcher.pm b/perl/Git/SVN/Fetcher.pm
index 64e900a..729e533 100644
--- a/perl/Git/SVN/Fetcher.pm
+++ b/perl/Git/SVN/Fetcher.pm
@@ -173,7 +173,7 @@ sub delete_entry {
# remove entire directories.
my ($tree) = (command('ls-tree', '-z', $self->{c}, "./$gpath")
- =~ /\A040000 tree ([a-f\d]{40})\t\Q$gpath\E\0/);
+ =~ /\A040000 tree ($::oid)\t\Q$gpath\E\0/);
if ($tree) {
my ($ls, $ctx) = command_output_pipe(qw/ls-tree
-r --name-only -z/,
@@ -203,7 +203,7 @@ sub open_file {
my $gpath = $self->git_path($path);
($mode, $blob) = (command('ls-tree', '-z', $self->{c}, "./$gpath")
- =~ /\A(\d{6}) blob ([a-f\d]{40})\t\Q$gpath\E\0/);
+ =~ /\A(\d{6}) blob ($::oid)\t\Q$gpath\E\0/);
unless (defined $mode && defined $blob) {
die "$path was not found in commit $self->{c} (r$rev)\n";
}
@@ -413,7 +413,7 @@ sub close_file {
$hash = $::_repository->hash_and_insert_object(
Git::temp_path($fh));
- $hash =~ /^[a-f\d]{40}$/ or die "not a sha1: $hash\n";
+ $hash =~ /^$::oid$/ or die "not an object ID: $hash\n";
Git::temp_release($fb->{base}, 1);
Git::temp_release($fh, 1);
diff --git a/perl/Git/SVN/Log.pm b/perl/Git/SVN/Log.pm
index 6641053..3858fcf 100644
--- a/perl/Git/SVN/Log.pm
+++ b/perl/Git/SVN/Log.pm
@@ -285,7 +285,7 @@ sub cmd_show_log {
my (@k, $c, $d, $stat);
my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/;
while (<$log>) {
- if (/^${esc_color}commit (?:- )?($::sha1_short)/o) {
+ if (/^${esc_color}commit (?:- )?($::oid_short)/o) {
my $cmt = $1;
if ($c && cmt_showable($c) && $c->{r} != $r_last) {
$r_last = $c->{r};
diff --git a/perl/Git/SVN/Ra.pm b/perl/Git/SVN/Ra.pm
index 56ad987..2cfe055 100644
--- a/perl/Git/SVN/Ra.pm
+++ b/perl/Git/SVN/Ra.pm
@@ -486,11 +486,11 @@ sub gs_fetch_loop_common {
$reload_ra->() if $ra_invalid;
}
# pre-fill the .rev_db since it'll eventually get filled in
- # with '0' x40 if something new gets committed
+ # with '0' x $oid_length if something new gets committed
foreach my $gs (@$gsv) {
next if $gs->rev_map_max >= $max;
next if defined $gs->rev_map_get($max);
- $gs->rev_map_set($max, 0 x40);
+ $gs->rev_map_set($max, 0 x $::oid_length);
}
foreach my $g (@$globs) {
my $k = "svn-remote.$g->{remote}.$g->{t}-maxRev";
diff --git a/pkt-line.c b/pkt-line.c
index a0e87b1..844c253 100644
--- a/pkt-line.c
+++ b/pkt-line.c
@@ -99,6 +99,13 @@ void packet_delim(int fd)
die_errno(_("unable to write delim packet"));
}
+void packet_response_end(int fd)
+{
+ packet_trace("0002", 4, 1);
+ if (write_in_full(fd, "0002", 4) < 0)
+ die_errno(_("unable to write stateless separator packet"));
+}
+
int packet_flush_gently(int fd)
{
packet_trace("0000", 4, 1);
@@ -306,10 +313,10 @@ static int get_packet_data(int fd, char **src_buf, size_t *src_size,
return ret;
}
-static int packet_length(const char *linelen)
+int packet_length(const char lenbuf_hex[4])
{
- int val = hex2chr(linelen);
- return (val < 0) ? val : (val << 8) | hex2chr(linelen + 2);
+ int val = hex2chr(lenbuf_hex);
+ return (val < 0) ? val : (val << 8) | hex2chr(lenbuf_hex + 2);
}
enum packet_read_status packet_read_with_status(int fd, char **src_buffer,
@@ -337,6 +344,10 @@ enum packet_read_status packet_read_with_status(int fd, char **src_buffer,
packet_trace("0001", 4, 0);
*pktlen = 0;
return PACKET_READ_DELIM;
+ } else if (len == 2) {
+ packet_trace("0002", 4, 0);
+ *pktlen = 0;
+ return PACKET_READ_RESPONSE_END;
} else if (len < 4) {
die(_("protocol error: bad line length %d"), len);
}
@@ -479,6 +490,7 @@ void packet_reader_init(struct packet_reader *reader, int fd,
reader->buffer_size = sizeof(packet_buffer);
reader->options = options;
reader->me = "git";
+ reader->hash_algo = &hash_algos[GIT_HASH_SHA1];
}
enum packet_read_status packet_reader_read(struct packet_reader *reader)
diff --git a/pkt-line.h b/pkt-line.h
index fef3a0d..8c90daa 100644
--- a/pkt-line.h
+++ b/pkt-line.h
@@ -22,6 +22,7 @@
*/
void packet_flush(int fd);
void packet_delim(int fd);
+void packet_response_end(int fd);
void packet_write_fmt(int fd, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
void packet_buf_flush(struct strbuf *buf);
void packet_buf_delim(struct strbuf *buf);
@@ -75,6 +76,15 @@ int packet_read(int fd, char **src_buffer, size_t *src_len, char
*buffer, unsigned size, int options);
/*
+ * Convert a four hex digit packet line length header into its numeric
+ * representation.
+ *
+ * If lenbuf_hex contains non-hex characters, return -1. Otherwise, return the
+ * numeric value of the length header.
+ */
+int packet_length(const char lenbuf_hex[4]);
+
+/*
* Read a packetized line into a buffer like the 'packet_read()' function but
* returns an 'enum packet_read_status' which indicates the status of the read.
* The number of bytes read will be assigned to *pktlen if the status of the
@@ -85,6 +95,7 @@ enum packet_read_status {
PACKET_READ_NORMAL,
PACKET_READ_FLUSH,
PACKET_READ_DELIM,
+ PACKET_READ_RESPONSE_END,
};
enum packet_read_status packet_read_with_status(int fd, char **src_buffer,
size_t *src_len, char *buffer,
@@ -166,6 +177,9 @@ struct packet_reader {
unsigned use_sideband : 1;
const char *me;
+
+ /* hash algorithm in use */
+ const struct git_hash_algo *hash_algo;
};
/*
diff --git a/po/ca.po b/po/ca.po
index 3a0246e..c43c21b 100644
--- a/po/ca.po
+++ b/po/ca.po
@@ -51,7 +51,7 @@ msgstr ""
"Project-Id-Version: Git\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
"POT-Creation-Date: 2020-05-27 07:23+0800\n"
-"PO-Revision-Date: 2020-05-22 07:51+0200\n"
+"PO-Revision-Date: 2020-05-28 18:14+0200\n"
"Last-Translator: Jordi Mas <jmas@softcatala.org>\n"
"Language-Team: Catalan\n"
"Language: ca\n"
@@ -59,7 +59,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 2.3\n"
+"X-Generator: Poedit 2.3.1\n"
#: add-interactive.c:368
#, c-format
@@ -222,7 +222,7 @@ msgstr "desselecciona els ítems especificats"
#: add-interactive.c:1032
msgid "choose all items"
-msgstr "escolliu tots els ítems"
+msgstr "trieu tots els ítems"
#: add-interactive.c:1034
msgid "(empty) finish selecting"
@@ -304,9 +304,9 @@ msgid ""
msgstr ""
"y - fes «stage» d'aquest tros\n"
"n - no facis «stage» d'aquest tros\n"
-"q - surt; no facis «stage» d'aquest tros o de cap altre restant\n"
-"a - fes «stage» d'aquest tros i tota la resta de trossos del fitxer\n"
-"d - no facis «stage» d'aquest tros o de cap altre restant del fitxer\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"
#: add-patch.c:55 git-add--interactive.perl:1433
#, c-format, perl-format
@@ -341,9 +341,9 @@ msgid ""
msgstr ""
"y - fes «stash» d'aquest tros\n"
"n - no facis «stash» d'aquest tros\n"
-"q - surt; no facis «stash» d'aquest tros o de cap altre restant\n"
-"a - fes «stash» d'aquest tros i tota la resta de trossos del fitxer\n"
-"d - no facis «stash» d'aquest tros o de cap altre restant del fitxer\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"
#: add-patch.c:78 git-add--interactive.perl:1438
#, c-format, perl-format
@@ -378,9 +378,9 @@ msgid ""
msgstr ""
"y - fes «unstage» d'aquest tros\n"
"n - no facis «unstage» d'aquest tros\n"
-"q - surt; no facis «unstage» d'aquest tros o de cap altre restant\n"
-"a - fes «unstage» d'aquest tros i tota la resta de trossos del fitxer\n"
-"d - no facis «unstage» d'aquest tros o de cap altre restant del fitxer\n"
+"q - surt; no facis «unstage» d'aquest tros ni de cap altre restant\n"
+"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:100 git-add--interactive.perl:1443
#, c-format, perl-format
@@ -390,7 +390,7 @@ msgstr "Aplica el canvi de mode a l'índex [y,n,q,a,d%s,?]? "
#: add-patch.c:101 git-add--interactive.perl:1444
#, c-format, perl-format
msgid "Apply deletion to index [y,n,q,a,d%s,?]? "
-msgstr "Aplica l'esborrat a l'índex [y,n,q,a,d%s,?]? "
+msgstr "Aplica la supressió a l'índex [y,n,q,a,d%s,?]? "
#: add-patch.c:102 git-add--interactive.perl:1445
#, c-format, perl-format
@@ -423,19 +423,19 @@ msgstr ""
#: git-add--interactive.perl:1463
#, c-format, perl-format
msgid "Discard mode change from worktree [y,n,q,a,d%s,?]? "
-msgstr "Descarta el canvi de mode des de l'arbre de treball [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:123 git-add--interactive.perl:1449
#: git-add--interactive.perl:1464
#, c-format, perl-format
msgid "Discard deletion from worktree [y,n,q,a,d%s,?]? "
-msgstr "Descarta l'esborrat des de l'arbre de treball [y,n,q,a,d%s,?]? "
+msgstr "Descarta suprimir de l'arbre de treball [y,n,q,a,d%s,?]? "
#: add-patch.c:124 git-add--interactive.perl:1450
#: git-add--interactive.perl:1465
#, c-format, perl-format
msgid "Discard this hunk from worktree [y,n,q,a,d%s,?]? "
-msgstr "Descarta aquest tros des de l'arbre de treball [y,n,q,a,d%s,?]? "
+msgstr "Descarta aquest tros de l'arbre de treball [y,n,q,a,d%s,?]? "
#: add-patch.c:126 add-patch.c:148 add-patch.c:191
msgid ""
@@ -454,7 +454,7 @@ msgid ""
"d - do not discard this hunk or any of the later hunks in the file\n"
msgstr ""
"y - descarta aquest tros de l'arbre de treball\n"
-"n - no descartis aquest tros des de l'arbre de treball\n"
+"n - no descartis aquest tros de l'arbre de treball\n"
"q - surt; no apliquis aquest tros ni cap dels pendents\n"
"a - descarta aquest tros i tots els trossos posteriors en el fitxer\n"
"d - no descartis aquest tros ni cap dels trossos posteriors en el fitxer\n"
@@ -463,20 +463,19 @@ msgstr ""
#, c-format, perl-format
msgid "Discard mode change from index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
-"Descarta el canvi de mode des de l'índex i l'arbre de treball [y,n,q,a,d"
+"Descarta el canvi de mode de l'índex i de l'arbre de treball [y,n,q,a,d"
"%s,?]? "
#: add-patch.c:145 add-patch.c:188 git-add--interactive.perl:1454
#, c-format, perl-format
msgid "Discard deletion from index and worktree [y,n,q,a,d%s,?]? "
-msgstr ""
-"Descarta la supressió des de l'índex i l'arbre de treball [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:146 add-patch.c:189 git-add--interactive.perl:1455
#, c-format, perl-format
msgid "Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
-"Descarta aquest tros des de l'índex i l'arbre de treball [y,n,q,a,d%s,?]? "
+"Descarta aquest tros de l'índex i de l'arbre de treball [y,n,q,a,d%s,?]? "
#: add-patch.c:151
msgid ""
@@ -486,8 +485,8 @@ 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 - descarta aquest tros de l'arbre de treball\n"
-"n - no descartis aquest tros des de l'arbre de treball\n"
+"y - descarta aquest tros de l'índex i de l'arbre de treball\n"
+"n - no descartis aquest tros de l'índex ni de l'arbre de treball\n"
"q - surt; no apliquis aquest tros ni cap dels pendents\n"
"a - descarta aquest tros i tots els trossos posteriors en el fitxer\n"
"d - no descartis aquest tros ni cap dels trossos posteriors en el fitxer\n"
@@ -496,17 +495,17 @@ msgstr ""
#, c-format, perl-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 l'arbre de treball [y,n,q,a,d%s,?]? "
+"Aplica el canvi de mode a l'índex i a l'arbre de treball [y,n,q,a,d%s,?]? "
#: add-patch.c:166 add-patch.c:209 git-add--interactive.perl:1459
#, c-format, perl-format
msgid "Apply deletion to index and worktree [y,n,q,a,d%s,?]? "
-msgstr "Aplica la supressió a l'índex i l'arbre de treball [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:167 add-patch.c:210 git-add--interactive.perl:1460
#, c-format, perl-format
msgid "Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "
-msgstr "Aplica aquest tros a l'índex i l'arbre de treball [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:172
msgid ""
@@ -516,8 +515,8 @@ 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 - aplica aquest tros a l'índex i l'arbre de treball\n"
-"n - no apliquis aquest tros des de l'índex i de l'arbre de treball\n"
+"y - aplica aquest tros a l'índex i a l'arbre de treball\n"
+"n - no apliquis aquest tros a l'índex ni a l'arbre de treball\n"
"q - surt; no apliquis aquest tros ni cap dels pendents\n"
"a - aplica aquest tros i tots els trossos posteriors en el fitxer\n"
"d - no apliquis aquest tros ni cap dels trossos posteriors en el fitxer\n"
@@ -607,9 +606,9 @@ msgid ""
"Lines starting with %c will be removed.\n"
msgstr ""
"---\n"
-"Per suprimir «%c» línies, convertiu-les a ' ' (context).\n"
-"Per suprimir «%c» línies, suprimiu-les.\n"
-"Les línies que comencin per %c seran suprimides.\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"
#. TRANSLATORS: 'it' refers to the patch mentioned in the previous messages.
#: add-patch.c:1071 git-add--interactive.perl:1126
@@ -619,8 +618,7 @@ msgid ""
"aborted and the hunk is left unchanged.\n"
msgstr ""
"Si no s'aplica correctament, tindreu una oportunitat per editar-lo\n"
-"de nou. Si totes les línies del tros se suprimeixen, llavors l'edició "
-"s'avorta\n"
+"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:1104
@@ -629,7 +627,7 @@ msgstr "no s'ha pogut analitzar la capçalera del tros"
#: add-patch.c:1149
msgid "'git apply --cached' failed"
-msgstr "'git apply --cached' ha fallat"
+msgstr "«git apply --cached» ha fallat"
#. TRANSLATORS: do not translate [y/n]
#. The program will only accept that input at this point.
@@ -698,7 +696,7 @@ msgstr "No hi ha altres trossos on anar-hi"
#: add-patch.c:1479 git-add--interactive.perl:1577
msgid "go to which hunk (<ret> to see more)? "
-msgstr "vés a quin tros (<ret> per veure'n més)? "
+msgstr "vés a quin tros (<ret> per a veure'n més)? "
#: add-patch.c:1480 git-add--interactive.perl:1579
msgid "go to which hunk? "
@@ -793,7 +791,7 @@ msgid ""
"as appropriate to mark resolution and make a commit."
msgstr ""
"Arregleu-los en l'arbre de treball, i després useu\n"
-"'git add/rm <fitxer>' segons sigui apropiat per a marcar la\n"
+"«git add/rm <fitxer>» segons sigui apropiat per a marcar la\n"
"resolució i feu una comissió."
#: advice.c:273
@@ -843,7 +841,7 @@ msgstr ""
"Si voleu crear una branca nova per a conservar les comissions que creeu,\n"
"poder fer-ho (ara o més tard) usant -c amb l'ordre switch. Exemple:\n"
"\n"
-" git switch -b <nom-de-branca-nova>\n"
+" git switch -c <nom-de-branca-nova>\n"
"\n"
"O desfer aquesta operació amb:\n"
"\n"
@@ -1411,7 +1409,7 @@ msgstr "assegura que el pedaç sigui aplicable a l'índex actual"
#: apply.c:4991
msgid "mark new files with `git add --intent-to-add`"
-msgstr "marca els fitxers nous amb «git add --inten-to-add»"
+msgstr "marca els fitxers nous amb «git add --intent-to-add»"
#: apply.c:4993
msgid "apply a patch without touching the working tree"
@@ -1584,7 +1582,7 @@ msgstr "no és un objecte d'arbre: %s"
#: archive.c:432
msgid "current working directory is untracked"
-msgstr "no es segueix el directori de treball actual"
+msgstr "no se segueix el directori de treball actual"
#: archive.c:464
msgid "fmt"
@@ -1677,7 +1675,7 @@ msgstr "Format d'arxiu desconegut «%s»"
#: archive.c:529
#, c-format
msgid "Argument not supported for format '%s': -%d"
-msgstr "Paràmetre no admès per al format «%s»: -%d"
+msgstr "Argument no admès per al format «%s»: -%d"
#: attr.c:212
#, c-format
@@ -1695,7 +1693,7 @@ msgid ""
"Use '\\!' for literal leading exclamation."
msgstr ""
"Els patrons negatius s'ignoren en els atributs de git\n"
-"Useu '\\!' per exclamació capdavantera literal."
+"Useu «\\!» per exclamació capdavantera literal."
#: bisect.c:468
#, c-format
@@ -1867,7 +1865,7 @@ msgstr ""
"\n"
"Després de corregir la causa de l'error, podeu\n"
"intentar corregir la informació de seguiment remot\n"
-"invocant \"git branch --set-upstream-to=%s%s%s\"."
+"invocant «git branch --set-upstream-to=%s%s%s»."
#: branch.c:67
#, c-format
@@ -2053,7 +2051,7 @@ msgstr "no s'ha pogut duplicar el descriptor del farcell"
#: bundle.c:280
msgid "Could not spawn pack-objects"
-msgstr "No s'ha pogut executar el pack-objects"
+msgstr "No s'ha pogut generar el pack-objects"
#: bundle.c:291
msgid "pack-objects died"
@@ -2071,7 +2069,7 @@ msgstr "les opcions de la llista de revisions exclouen la referència «%s»"
#: bundle.c:461 builtin/log.c:208 builtin/log.c:1834 builtin/shortlog.c:306
#, c-format
msgid "unrecognized argument: %s"
-msgstr "paràmetre no reconegut: %s"
+msgstr "argument no reconegut: %s"
#: bundle.c:469
msgid "Refusing to create empty bundle."
@@ -2124,9 +2122,9 @@ msgid "commit-graph improper chunk offset %08x%08x"
msgstr "desplaçament %08x%08x del gràfic de comissions incorrecte"
#: commit-graph.c:362
-#, fuzzy, c-format
+#, c-format
msgid "commit-graph chunk id %08x appears multiple times"
-msgstr "id%08x del graf de comissions múltiples vegades"
+msgstr "id %08x del graf de comissions apareix múltiples vegades"
#: commit-graph.c:436
msgid "commit-graph has no base graphs chunk"
@@ -2140,7 +2138,7 @@ msgstr "la cadena del graf de comissions no coincideix"
#, 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ínea «%s» no és un hash"
+"la cadena del graf de comissions no és vàlida: la línia «%s» no és un hash"
#: commit-graph.c:518
msgid "unable to find all commit-graph files"
@@ -2185,7 +2183,7 @@ msgstr "S'estan expandint les comissions abastables al graf de comissions"
#: commit-graph.c:1233
msgid "Clearing commit marks in commit graph"
-msgstr "S'estan netejant les marques de comissions al graf de comissions"
+msgstr "S'estan esborrant les marques de comissions al graf de comissions"
#: commit-graph.c:1252
msgid "Computing commit graph generation numbers"
@@ -2374,7 +2372,7 @@ 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 "
-"commisió %s però té zero en altres llocs"
+"comissió %s però té zero en altres llocs"
#: commit-graph.c:2322
#, c-format
@@ -2493,7 +2491,7 @@ msgstr "clau no vàlida: %s"
#: config.c:414
#, c-format
msgid "invalid key (newline): %s"
-msgstr "clau no vàlida (línea nova): %s"
+msgstr "clau no vàlida (línia nova): %s"
#: config.c:450 config.c:462
#, c-format
@@ -2568,7 +2566,7 @@ msgstr ""
#, 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 "
+"valor de configuració numèric «%s» erroni per «%s» en el blob de submòdul "
"%s: %s"
#: config.c:1025
@@ -2924,7 +2922,7 @@ msgstr "S'està comprovant la connectivitat"
#: connected.c:119
msgid "Could not run 'git rev-list'"
-msgstr "No s'ha pogut executar 'git rev-list'"
+msgstr "No s'ha pogut executar «git rev-list»"
#: connected.c:139
msgid "failed write to rev-list"
@@ -2937,7 +2935,7 @@ msgstr "s'ha produït un error en tancar l'stdin del rev-list"
#: convert.c:194
#, c-format
msgid "illegal crlf_action %d"
-msgstr "crlf_action %d il·legal"
+msgstr "crlf_action %d il·legal"
#: convert.c:207
#, c-format
@@ -2957,7 +2955,7 @@ msgstr ""
#: convert.c:217
#, c-format
msgid "LF would be replaced by CRLF in %s"
-msgstr "LF es reemplaçà per LF en %s"
+msgstr "LF es reemplaçà per CRLF en %s"
#: convert.c:219
#, c-format
@@ -2994,7 +2992,7 @@ 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-"
+"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."
#: convert.c:419 convert.c:490
@@ -3038,7 +3036,7 @@ msgstr "tipus de filtre inesperat"
#: convert.c:851
msgid "path name too long for external filter"
-msgstr "el nom del camí és massa llarg per al filtre extern"
+msgstr "el nom del camí és massa gran per al filtre extern"
#: convert.c:943
#, c-format
@@ -3240,7 +3238,7 @@ msgstr ""
#, c-format
msgid "Unknown value for 'diff.submodule' config variable: '%s'"
msgstr ""
-"Valor desconegut de la variable de configuració de 'diff.submodule': «%s»"
+"Valor desconegut de la variable de configuració de «diff.submodule»: «%s»"
#: diff.c:465
#, c-format
@@ -3248,7 +3246,7 @@ msgid ""
"Found errors in 'diff.dirstat' config variable:\n"
"%s"
msgstr ""
-"S'han trobat errors en la variable de configuració 'diff.dirstat':\n"
+"S'han trobat errors en la variable de configuració «diff.dirstat»:\n"
"%s"
#: diff.c:4238
@@ -3316,12 +3314,12 @@ msgstr "%s esperava un caràcter, s'ha rebut «%s»"
#: diff.c:4961
#, c-format
msgid "bad --color-moved argument: %s"
-msgstr "paràmetre --color-moved incorrecte: %s"
+msgstr "argument --color-moved incorrecte: %s"
#: diff.c:4980
#, c-format
msgid "invalid mode '%s' in --color-moved-ws"
-msgstr "mode «%s» no vàlid en -color-moved-ws"
+msgstr "mode «%s» no vàlid en --color-moved-ws"
#: diff.c:5020
msgid ""
@@ -3344,7 +3342,7 @@ msgstr ""
#: diff.c:5270
#, c-format
msgid "bad --word-diff argument: %s"
-msgstr "paràmetre --word-diff incorrecte: %s"
+msgstr "argument --word-diff incorrecte: %s"
#: diff.c:5293
msgid "Diff output format options"
@@ -3372,11 +3370,11 @@ msgstr "genera el diff en format cru"
#: diff.c:5312
msgid "synonym for '-p --raw'"
-msgstr "sinònim de per a «-p --raw»"
+msgstr "sinònim de «-p --raw»"
#: diff.c:5316
msgid "synonym for '-p --stat'"
-msgstr "sinònim de per a «-p --stat»"
+msgstr "sinònim de «-p --stat»"
#: diff.c:5320
msgid "machine friendly --stat"
@@ -3399,11 +3397,11 @@ msgstr ""
#: diff.c:5330
msgid "synonym for --dirstat=cumulative"
-msgstr "sinònim per -dirstat=cumulative"
+msgstr "sinònim de --dirstat=cumulative"
#: diff.c:5334
msgid "synonym for --dirstat=files,param1,param2..."
-msgstr "sinònim per --dirstat=files,param1,param2..."
+msgstr "sinònim de --dirstat=files,param1,param2..."
#: diff.c:5338
msgid "warn if changes introduce conflict markers or whitespace errors"
@@ -3425,7 +3423,7 @@ msgstr "mostra només els noms i l'estat dels fitxers canviats"
#: diff.c:5349
msgid "<width>[,<name-width>[,<count>]]"
-msgstr "<width>[<name-width>[<count>]]"
+msgstr "<amplada>[<amplada-nom>[,<recompte>]]"
#: diff.c:5350
msgid "generate diffstat"
@@ -3461,7 +3459,7 @@ msgstr "genera un resum compacte a diffstat"
#: diff.c:5368
msgid "output a binary diff that can be applied"
-msgstr "diff amb sortida binaria que pot ser aplicada"
+msgstr "diff amb sortida binària que pot ser aplicada"
#: diff.c:5371
#, fuzzy
@@ -3474,17 +3472,15 @@ msgid "show colored diff"
msgstr "mostra un diff amb colors"
#: diff.c:5374
-#, fuzzy
msgid "<kind>"
msgstr "<kind>"
#: diff.c:5375
-#, fuzzy
msgid ""
"highlight whitespace errors in the 'context', 'old' or 'new' lines in the "
"diff"
msgstr ""
-"ressalta els errors d'espai en blanc a les línies «context» «old» o «new» al "
+"ressalta els errors d'espai en blanc a les línies «context», «old» o «new» al "
"diff"
#: diff.c:5378
@@ -3501,12 +3497,10 @@ msgid "<prefix>"
msgstr "<prefix>"
#: diff.c:5382
-#, fuzzy
msgid "show the given source prefix instead of \"a/\""
msgstr "mostra el prefix d'origen donat en lloc de «a/»"
#: diff.c:5385
-#, fuzzy
msgid "show the given destination prefix instead of \"b/\""
msgstr "mostra el prefix de destinació indicat en lloc de «b/»"
@@ -3519,7 +3513,6 @@ msgid "do not show any source or destination prefix"
msgstr "no mostris cap prefix d'origen o destí"
#: diff.c:5394
-#, fuzzy
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 "
@@ -3585,17 +3578,16 @@ 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:5439
-#, fuzzy
msgid ""
"prevent rename/copy detection if the number of rename/copy targets exceeds "
"given limit"
msgstr ""
-"Evita la detecció de canvi de nom/còpia si el nombre d'objectius de canvi de "
-"nom supera el límit indicat"
+"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:5441
msgid "Diff algorithm options"
-msgstr "Opcions d'algorisme Diff"
+msgstr "Opcions de l'algorisme Diff"
#: diff.c:5443
msgid "produce the smallest possible diff"
@@ -3603,7 +3595,7 @@ msgstr "produeix el diff més petit possible"
#: diff.c:5446
msgid "ignore whitespace when comparing lines"
-msgstr "ignora els espai en blanc en comparar línies"
+msgstr "ignora els espais en blanc en comparar línies"
#: diff.c:5449
msgid "ignore changes in amount of whitespace"
@@ -3622,10 +3614,9 @@ msgid "ignore changes whose lines are all blank"
msgstr "ignora els canvis en línies que estan en blanc"
#: diff.c:5461
-#, fuzzy
msgid "heuristic to shift diff hunk boundaries for easy reading"
msgstr ""
-"heurística per canviar els límits del tros de diferència per a lectura fàcil"
+"heurística per a desplaçar els límits del tros de diferència per a una lectura fàcil"
#: diff.c:5464
msgid "generate diff using the \"patience diff\" algorithm"
@@ -3641,7 +3632,7 @@ msgstr "<algorisme>"
#: diff.c:5471
msgid "choose a diff algorithm"
-msgstr "escolliu un algorisme pel diff"
+msgstr "trieu un algorisme per al diff"
#: diff.c:5473
msgid "<text>"
@@ -4070,7 +4061,7 @@ msgstr "git fetch-pack: l'obtenció ha fallat."
#: fetch-pack.c:1211
msgid "Server does not support shallow requests"
-msgstr "El servidor no permet peticions superficials"
+msgstr "El servidor no permet sol·licituds superficials"
#: fetch-pack.c:1218
msgid "Server supports filter"
@@ -4078,7 +4069,7 @@ msgstr "El servidor accepta filtratge"
#: fetch-pack.c:1242
msgid "unable to write request to remote"
-msgstr "no s'ha pogut escriure la petició al remot"
+msgstr "no s'ha pogut escriure la sol·licitud al remot"
#: fetch-pack.c:1260
#, c-format
@@ -4102,11 +4093,11 @@ msgstr "s'ha produït un error en processar els acks: %d"
#: fetch-pack.c:1342
msgid "expected packfile to be sent after 'ready'"
-msgstr "s'espera l'enviament del fitxer de paquet després de «ready»"
+msgstr "s'esperava l'enviament del fitxer de paquet després de «ready»"
#: fetch-pack.c:1344
msgid "expected no other sections to be sent after no 'ready'"
-msgstr "s'espera que cap altra seccions s'enviï després de no «ready»"
+msgstr "s'esperava que no s'enviés cap altra secció després de no «ready»"
#: fetch-pack.c:1386
#, c-format
@@ -4209,17 +4200,14 @@ msgid "collaborate (see also: git help workflows)"
msgstr "col·laborar (vegeu també: git help workflow)"
#: help.c:31
-#, fuzzy
msgid "Main Porcelain Commands"
msgstr "Ordres principals de porcellana"
#: help.c:32
-#, fuzzy
msgid "Ancillary Commands / Manipulators"
-msgstr "Ordres Auxiliars / Manipuladors"
+msgstr "Ordres auxiliars / manipuladors"
#: help.c:33
-#, fuzzy
msgid "Ancillary Commands / Interrogators"
msgstr "Ordres auxiliars / interrogadors"
@@ -4477,7 +4465,7 @@ msgid ""
"may have crashed in this repository earlier:\n"
"remove the file manually to continue."
msgstr ""
-"No s'ha pogut crear '%s.lock': %s.\n"
+"No s'ha pogut crear «%s.lock»: %s.\n"
"\n"
"Sembla que un altre procés de git s'està executant en aquest\n"
"dipòsit, per exemple, un editor obert per «git commit». \n"
@@ -4586,8 +4574,7 @@ msgstr "Avançament ràpid al submòdul %s"
#, 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)"
+"Ha fallat en fusionar el submòdul %s (no s'ha trobat les comissions següents)"
#: merge-recursive.c:1255
#, c-format
@@ -4611,7 +4598,7 @@ msgid ""
msgstr ""
"Si això és correcte simplement afegiu-ho a l'índex per exemple utilitzant "
"git update-index --cacheinfo 160000 per cents \"%s\" que acceptaran aquest "
-"suggeriment."
+"suggeriment.\n"
#: merge-recursive.c:1268
#, c-format
@@ -5050,9 +5037,8 @@ msgid "did not see pack-file %s to drop"
msgstr "no s'han vist caure els paquets del fitxer"
#: midx.c:925
-#, fuzzy
msgid "no pack files to index."
-msgstr "Afegint fitxers de paquets a multi-index"
+msgstr "no hi ha fitxers empaquetats a indexar."
#: midx.c:977
#, fuzzy
@@ -5066,7 +5052,7 @@ msgstr "no s'han pogut netejar els percentatges multi-paquet"
#: midx.c:1112
msgid "Looking for referenced packfiles"
-msgstr "S'estan cercant fitxers de paquets referenciats"
+msgstr "S'estan cercant fitxers empaquetats referenciats"
#: midx.c:1127
#, fuzzy, c-format
@@ -5124,7 +5110,7 @@ msgstr "S'estan cercant i suprimint els fitxers de paquets no referenciats"
#: midx.c:1433
msgid "could not start pack-objects"
-msgstr "no s'ha pogut executar el pack-objects"
+msgstr "no s'ha pogut iniciar el pack-objects"
#: midx.c:1452
msgid "could not finish pack-objects"
@@ -5205,14 +5191,14 @@ msgid "unable to parse object: %s"
msgstr "no s'ha pogut analitzar l'objecte: %s"
#: object.c:266 object.c:278
-#, fuzzy, c-format
+#, c-format
msgid "hash mismatch %s"
-msgstr "els resums no coincideixen"
+msgstr "el resum no coincideix %s"
#: pack-bitmap.c:815 pack-bitmap.c:821 builtin/pack-objects.c:2135
-#, fuzzy, c-format
+#, c-format
msgid "unable to get size of %s"
-msgstr "no s'ha pogut obtenir la mida dels percentatges"
+msgstr "no s'ha pogut obtenir la mida de %s"
#: packfile.c:629
msgid "offset before end of packfile (broken .idx?)"
@@ -5325,7 +5311,7 @@ msgstr "ús: %s"
#: parse-options.c:907
#, c-format
msgid " or: %s"
-msgstr " o: %s"
+msgstr " o: %s"
#: parse-options.c:910
#, c-format
@@ -5381,7 +5367,7 @@ msgstr "paràmetre no vàlid per a la màgia d'especificació de camí «prefix
#: pathspec.c:327
#, c-format
msgid "Invalid pathspec magic '%.*s' in '%s'"
-msgstr "Màgia d'especificació de camí no vàlida '%.*s' en «%s»"
+msgstr "Màgia d'especificació de camí no vàlida «%.*s» en «%s»"
#: pathspec.c:332
#, c-format
@@ -5728,7 +5714,7 @@ msgid "unable to unlink: %s"
msgstr "no s'ha pogut desenllaçar: %s"
#: read-cache.c:3179
-#, fuzzy, c-format
+#, c-format
msgid "cannot fix permission bits on '%s'"
msgstr "no s'han pogut corregir els bits de permisos en «%s»"
@@ -5743,8 +5729,9 @@ msgid ""
"continue'.\n"
"Or you can abort the rebase with 'git rebase --abort'.\n"
msgstr ""
-"Podeu arreglar això amb 'git rebase --edit-todo' i després 'git rebase --"
-"continue'.\n"
+"Podeu arreglar-ho amb «git rebase --edit-todo» i després «git rebase --"
+"continue».\n"
+"O bé, podeu avortar el «rebase» amb «git rebase --abort».\n"
#: rebase-interactive.c:33
#, c-format
@@ -5776,9 +5763,26 @@ msgid ""
"\n"
"These lines can be re-ordered; they are executed from top to bottom.\n"
msgstr ""
-"Les ordres p select <commit> = fa servir «commit» (commit) «commit» (commit) "
-"«commit» (commit) «commit» (commit) «commit» (commit)"
-
+"\n"
+"Ordres:\n"
+" p, pick <comissió> = usa la comissió\n"
+" r, reword <comissió> = usa la comissió, però edita el missatge de comissió\n"
+" e, edit <comissió> = usa la comissió, però atura't per a esmenar\n"
+" s, squash <comissió> = usa la comissió, però fusiona-la a la comissió prèvia\n"
+" f, fixup <comissió> = com a «squash», però descarta el missatge de registre d'aquesta "
+"comissió\n"
+"x, exec <comissió> = executa l'ordre (la resta de la línia) usant l'intèrpret "
+"d'ordres\n"
+"b, break = atura't aquí (continua fent «rebase» després amb «git rebase --continue»)\n"
+"d, drop <comissió> = elimina la comissió\n"
+"l, label <etiqueta> = etiqueta la HEAD actual amb un nom\n"
+"t, reset <etiqueta> = reinicia HEAD a una etiqueta \n"
+"m, merge [-C <comissió> | -c <comissió>] <etiqueta> [# <oneline>]\n"
+". crea una comissió de fusió usant el missatge de la comissió\n"
+". de fusió original (o línia única, si no hi ha cap comissió de fusió original\n"
+". especificada). Useu -c <comissió> per a reescriure el missatge de publicació.\n"
+"\n"
+"Es pot canviar l'ordre d'aquestes línies; s'executen de dalt a baix.\n"
#: rebase-interactive.c:63
#, c-format
msgid "Rebase %s onto %s (%d command)"
@@ -5915,37 +5919,37 @@ msgstr "Valor enter esperat pel nom de referència:rstrip=%s"
#: ref-filter.c:195
#, c-format
msgid "unrecognized %%(%s) argument: %s"
-msgstr "paràmetre %%(%s) desconegut: %s"
+msgstr "argument %%(%s) desconegut: %s"
#: ref-filter.c:250
#, c-format
msgid "%%(objecttype) does not take arguments"
-msgstr "%%(subject) no accepta paràmetres"
+msgstr "%%(objecttype) no accepta arguments"
#: ref-filter.c:272
#, c-format
msgid "unrecognized %%(objectsize) argument: %s"
-msgstr "paràmetre %%(objectsize) no reconegut: %s"
+msgstr "argument %%(objectsize) no reconegut: %s"
#: ref-filter.c:280
#, c-format
msgid "%%(deltabase) does not take arguments"
-msgstr "%%(deltabase) no accepta paràmetres"
+msgstr "%%(deltabase) no accepta arguments"
#: ref-filter.c:292
#, c-format
msgid "%%(body) does not take arguments"
-msgstr "%%(body) no accepta paràmetres"
+msgstr "%%(body) no accepta arguments"
#: ref-filter.c:301
#, c-format
msgid "%%(subject) does not take arguments"
-msgstr "%%(subject) no accepta paràmetres"
+msgstr "%%(subject) no accepta arguments"
#: ref-filter.c:323
#, c-format
msgid "unknown %%(trailers) argument: %s"
-msgstr "paràmetre %%(trailers) desconegut: %s"
+msgstr "argument %%(trailers) desconegut: %s"
#: ref-filter.c:352
#, c-format
@@ -5955,7 +5959,7 @@ msgstr "valor positiu esperat conté:lines=%s"
#: ref-filter.c:354
#, c-format
msgid "unrecognized %%(contents) argument: %s"
-msgstr "paràmetre %%(contents) no reconegut: %s"
+msgstr "argument %%(contents) no reconegut: %s"
#: ref-filter.c:369
#, c-format
@@ -5965,7 +5969,7 @@ msgstr "valor positiu esperat nom d'objecte:curt=%s"
#: ref-filter.c:373
#, c-format
msgid "unrecognized %%(objectname) argument: %s"
-msgstr "paràmetre %%(objectname) no reconegut: %s"
+msgstr "argument %%(objectname) no reconegut: %s"
#: ref-filter.c:403
#, c-format
@@ -5985,7 +5989,7 @@ msgstr "amplada no reconeguda:%s"
#: ref-filter.c:431
#, c-format
msgid "unrecognized %%(align) argument: %s"
-msgstr "paràmetre %%(align) no reconegut: %s"
+msgstr "argument %%(align) no reconegut: %s"
#: ref-filter.c:439
#, c-format
@@ -5995,7 +5999,7 @@ msgstr "amplada positiva esperada amb l'àtom %%(align)"
#: ref-filter.c:457
#, c-format
msgid "unrecognized %%(if) argument: %s"
-msgstr "paràmetre %%(if) no reconegut: %s"
+msgstr "argument %%(if) no reconegut: %s"
#: ref-filter.c:559
#, c-format
@@ -6450,7 +6454,7 @@ msgstr "La vostra branca i «%s» es refereixen a diferents comissions.\n"
#: remote.c:2016
#, c-format
msgid " (use \"%s\" for details)\n"
-msgstr " (useu «%s» per detalls)\n"
+msgstr " (useu «%s» per a detalls)\n"
#: remote.c:2020
#, c-format
@@ -6461,7 +6465,7 @@ msgstr[1] "La vostra branca està %2$d comissions per davant de «%1$s».\n"
#: remote.c:2026
msgid " (use \"git push\" to publish your local commits)\n"
-msgstr " (useu \"git push\" per a publicar les vostres comissions locals)\n"
+msgstr " (useu «git push» per a publicar les vostres comissions locals)\n"
#: remote.c:2029
#, c-format
@@ -6713,7 +6717,7 @@ msgstr "no s'ha pogut suprimir «%s»"
#: sequencer.c:316 builtin/rebase.c:743 builtin/rebase.c:1582 builtin/rm.c:385
#, c-format
msgid "could not remove '%s'"
-msgstr "no s'ha pogut suprimir «%s»"
+msgstr "no s'ha pogut eliminar «%s»"
#: sequencer.c:326
msgid "revert"
@@ -6739,7 +6743,7 @@ msgid ""
"with 'git add <paths>' or 'git rm <paths>'"
msgstr ""
"després de resoldre els conflictes, marqueu els camins\n"
-"corregits amb 'git add <camins>' o 'git rm <camins>'"
+"corregits amb «git add <camins>» o «git rm <camins>»"
#: sequencer.c:393
msgid ""
@@ -6748,8 +6752,8 @@ msgid ""
"and commit the result with 'git commit'"
msgstr ""
"després de resoldre els conflictes, marqueu els camins\n"
-"corregits amb 'git add <camins>' o 'git rm <camins>'\n"
-"i cometeu el resultat amb 'git commit'"
+"corregits amb «git add <camins>» o «git rm <camins>»\n"
+"i cometeu el resultat amb «git commit»"
#: sequencer.c:406 sequencer.c:2921
#, c-format
@@ -6839,7 +6843,7 @@ msgstr "Ja s'ha donat «GIT_AUTHOR_DATE»"
#: sequencer.c:809
#, c-format
msgid "unknown variable '%s'"
-msgstr "variable «%s» desconeguda"
+msgstr "variable «%s» desconeguda"
#: sequencer.c:814
msgid "missing 'GIT_AUTHOR_NAME'"
@@ -6932,8 +6936,8 @@ msgstr ""
"Comproveu que siguin correctes. Podeu suprimir aquest\n"
"missatge establint-los explícitament:\n"
"\n"
-" git config --global user.name \"El Vostre Nom\"\n"
-" git config --global user.email tu@example.com\n"
+" git config --global user.name \"El vostre nom\"\n"
+" git config --global user.email usuari@example.com\n"
"\n"
"Després de fer això, podeu arreglar la identitat usada per a aquesta\n"
"comissió amb:\n"
@@ -7116,12 +7120,12 @@ msgstr "git %s: s'ha produït un error en actualitzar l'índex"
#: sequencer.c:2114
#, c-format
msgid "%s does not accept arguments: '%s'"
-msgstr "%s no accepta paràmetres: «%s»"
+msgstr "%s no accepta arguments: «%s»"
#: sequencer.c:2123
#, c-format
msgid "missing arguments for %s"
-msgstr "falten els arguments per %s"
+msgstr "falten els arguments per a %s"
#: sequencer.c:2154
#, c-format
@@ -7515,7 +7519,7 @@ msgstr "no s'ha pogut llegir orig-head"
#: sequencer.c:4111
msgid "could not read 'onto'"
-msgstr "no s'ha pogut llegir 'onto'"
+msgstr "no s'ha pogut llegir «onto»"
#: sequencer.c:4125
#, c-format
@@ -7624,15 +7628,15 @@ msgid ""
"Use '--' to separate paths from revisions, like this:\n"
"'git <command> [<revision>...] -- [<file>...]'"
msgstr ""
-"paràmetre ambigu «%s»: revisió no coneguda o el camí no és en l'arbre de "
+"argument ambigu «%s»: revisió no coneguda o el camí no és en l'arbre de "
"treball.\n"
"Useu «--» per a separar els camins de les revisions:\n"
-"'git <ordre> [<revisió>...] -- [<fitxer>...]'"
+"«git <ordre> [<revisió>...] -- [<fitxer>...]»"
#: setup.c:264
#, c-format
msgid "option '%s' must come before non-option arguments"
-msgstr "l'opció «%s» ha de venir abans dels arguments opcionals"
+msgstr "l'opció «%s» ha d'aparèixer abans que els arguments opcionals"
#: setup.c:283
#, c-format
@@ -7641,9 +7645,9 @@ msgid ""
"Use '--' to separate paths from revisions, like this:\n"
"'git <command> [<revision>...] -- [<file>...]'"
msgstr ""
-"paràmetre ambigu «%s»: ambdós una revisió i un nom de fitxer\n"
-"Useu '--' per a separar els camins de les revisions:\n"
-"'git <ordre> [<revisió>...] -- [<fitxer>...]'"
+"argument ambigu «%s»: ambdós una revisió i un nom de fitxer\n"
+"Useu «--» per a separar els camins de les revisions:\n"
+"«git <ordre> [<revisió>...] -- [<fitxer>...]»"
#: setup.c:419
msgid "unable to set up work tree using invalid config"
@@ -7672,7 +7676,7 @@ msgstr "s'ha produït un error en obrir «%s»"
#: setup.c:598
#, c-format
msgid "too large to be a .git file: '%s'"
-msgstr "massa larg per a ser un fitxer .git: «%s»"
+msgstr "massa llarg per a ser un fitxer .git: «%s»"
#: setup.c:600
#, c-format
@@ -7763,7 +7767,7 @@ msgstr "el «fork» ha fallat"
#: setup.c:1324
msgid "setsid failed"
-msgstr "l'«stash» ha fallat"
+msgstr "«setsid» ha fallat"
#: sha1-file.c:470
#, c-format
@@ -7810,7 +7814,7 @@ msgstr "el camí «%s» no existeix"
#, c-format
msgid "reference repository '%s' as a linked checkout is not supported yet."
msgstr ""
-"Encara no se suporta el dipòsit de referència «%s» com a agafament enllaçat."
+"encara no s'admet el dipòsit de referència «%s» com a agafament enllaçat."
#: sha1-file.c:730
#, c-format
@@ -8259,13 +8263,13 @@ 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:995
-#, fuzzy, c-format
+#, c-format
msgid ""
"Could not run 'git rev-list <commits> --not --remotes -n 1' command in "
"submodule %s"
msgstr ""
"No s'ha pogut executar l'ordre «git rev-list <commits> --not --remotes -n 1» "
-"en els submòdul %s"
+"en el submòdul %s"
#: submodule.c:1118
#, fuzzy, c-format
@@ -8287,9 +8291,9 @@ msgid "Unable to push submodule '%s'\n"
msgstr "No s'ha pogut prémer el submòdul «%s»"
#: submodule.c:1453
-#, fuzzy, c-format
+#, c-format
msgid "Fetching submodule %s%s\n"
-msgstr "Obtenint submòdul %s%s\n"
+msgstr "S'està obtenint el submòdul %s%s\n"
#: submodule.c:1483
#, c-format
@@ -8313,12 +8317,12 @@ msgstr "«%s» no reconegut com un dipòsit git"
#: submodule.c:1679
#, c-format
msgid "Could not run 'git status --porcelain=2' in submodule %s"
-msgstr "No s'ha pogut executar «git status --porcelain=2» en els submòdul %s"
+msgstr "No s'ha pogut executar «git status --porcelain=2» en el submòdul %s"
#: submodule.c:1720
#, c-format
msgid "'git status --porcelain=2' failed in submodule %s"
-msgstr "«git status --porcelain=2» ha fallat en els submòdul %s"
+msgstr "«git status --porcelain=2» ha fallat en el submòdul %s"
#: submodule.c:1800
#, c-format
@@ -8328,7 +8332,7 @@ msgstr "no s'ha pogut iniciar «git status» al submòdul «%s»"
#: submodule.c:1813
#, c-format
msgid "could not run 'git status' in submodule '%s'"
-msgstr "no s'ha pogut executar 'git status' al submòdul «%s»"
+msgstr "no s'ha pogut executar «git status» al submòdul «%s»"
#: submodule.c:1828
#, fuzzy, c-format
@@ -8358,7 +8362,7 @@ msgstr "No s'ha pogut actualitzar el submòdul «%s»."
#: submodule.c:2038
#, c-format
msgid "submodule git dir '%s' is inside git dir '%.*s'"
-msgstr "submodule git dir «%s» està dins git dir '%.*s'"
+msgstr "submodule git dir «%s» està dins git dir «%.*s»"
#: submodule.c:2059
#, c-format
@@ -8417,7 +8421,7 @@ msgstr "més d'un %s"
#: trailer.c:730
#, c-format
msgid "empty trailer token in trailer '%.*s'"
-msgstr "testimoni de remolc buit en el remolc '%.*s'"
+msgstr "testimoni de remolc buit en el remolc «%.*s»"
#: trailer.c:750
#, c-format
@@ -9014,7 +9018,7 @@ msgstr "s'esperava una neteja després de les capacitats"
#: urlmatch.c:163
msgid "invalid URL scheme name or missing '://' suffix"
-msgstr "l'esquema d'URL no és vàlid o li manca el sufix '://'"
+msgstr "l'esquema d'URL no és vàlid o li manca el sufix «://»"
#: urlmatch.c:187 urlmatch.c:346 urlmatch.c:405
#, c-format
@@ -9023,11 +9027,11 @@ msgstr "seqüència d'escapament %XX no vàlida"
#: urlmatch.c:215
msgid "missing host and scheme is not 'file:'"
-msgstr "manca la màquina i l'esquema no és 'file:'"
+msgstr "manca la màquina i l'esquema no és «file:»"
#: urlmatch.c:232
msgid "a 'file:' URL may not have a port number"
-msgstr "un URL 'file:' no pot tenir número de port"
+msgstr "un URL «file:» no pot tenir número de port"
#: urlmatch.c:247
msgid "invalid characters in host name"
@@ -9039,7 +9043,7 @@ msgstr "número de port no vàlid"
#: urlmatch.c:371
msgid "invalid '..' path segment"
-msgstr "segment de camí '..' no vàlid"
+msgstr "segment de camí «..» no vàlid"
#: walker.c:170
#, fuzzy
@@ -9107,21 +9111,21 @@ msgstr "(useu \"git restitution --source=%s --staged <file>\" per a unstage)"
#: wt-status.c:193 wt-status.c:225
msgid " (use \"git rm --cached <file>...\" to unstage)"
-msgstr " (useu \"git rm --cached <fitxer>...\" per a fer «unstage»)"
+msgstr " (useu «git rm --cached <fitxer>...» per a fer «unstage»)"
#: wt-status.c:197
msgid " (use \"git add <file>...\" to mark resolution)"
-msgstr " (useu \"git add <fitxer>...\" per a senyalar resolució)"
+msgstr " (useu «git add <fitxer>...» per a senyalar resolució)"
#: wt-status.c:199 wt-status.c:203
msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)"
msgstr ""
-" (useu \"git add/rm <fitxer>...\" segons sigui apropiat per a senyalar "
+" (useu «git add/rm <fitxer>...» segons sigui apropiat per a senyalar "
"resolució)"
#: wt-status.c:201
msgid " (use \"git rm <file>...\" to mark resolution)"
-msgstr " (useu \"git rm <fitxer>...\" per a senyalar resolució)"
+msgstr " (useu «git rm <fitxer>...» per a senyalar resolució)"
#: wt-status.c:211 wt-status.c:1072
msgid "Changes to be committed:"
@@ -9133,11 +9137,11 @@ msgstr "Canvis no «staged» per a cometre:"
#: wt-status.c:238
msgid " (use \"git add <file>...\" to update what will be committed)"
-msgstr " (useu \"git add <fitxer>...\" per a actualitzar què es cometrà)"
+msgstr " (useu «git add <fitxer>...» per a actualitzar què es cometrà)"
#: wt-status.c:240
msgid " (use \"git add/rm <file>...\" to update what will be committed)"
-msgstr " (useu \"git add/rm <fitxer>...\" per a actualitzar què es cometrà)"
+msgstr " (useu «git add/rm <fitxer>...» per a actualitzar què es cometrà)"
#: wt-status.c:241
#, fuzzy
@@ -9155,7 +9159,7 @@ msgstr ""
#: wt-status.c:254
#, c-format
msgid " (use \"git %s <file>...\" to include in what will be committed)"
-msgstr " (useu «git %s <fitxer>...» per a incloure-ho en el que es cometrà)"
+msgstr " (useu «git %s <fitxer>...» per a incloure-ho en la comissió)"
#: wt-status.c:268
msgid "both deleted:"
@@ -9249,7 +9253,7 @@ msgid ""
"Do not modify or remove the line above.\n"
"Everything below it will be ignored."
msgstr ""
-"No modifiqueu o suprimiu la línia de dalt.\n"
+"No modifiqueu ni elimineu la línia de dalt.\n"
"Tot el que hi ha a sota s'ignorarà."
#: wt-status.c:1112
@@ -9268,11 +9272,11 @@ msgstr "Teniu camins sense fusionar."
#: wt-status.c:1145
msgid " (fix conflicts and run \"git commit\")"
-msgstr " (arregleu els conflictes i executeu \"git commit\")"
+msgstr " (arregleu els conflictes i executeu «git commit»)"
#: wt-status.c:1147
msgid " (use \"git merge --abort\" to abort the merge)"
-msgstr " (useu \"git merge --abort\" per a avortar la fusió)"
+msgstr " (useu «git merge --abort» per a avortar la fusió)"
#: wt-status.c:1151
msgid "All conflicts fixed but you are still merging."
@@ -9280,7 +9284,7 @@ msgstr "Tots els conflictes estan arreglats però encara esteu fusionant."
#: wt-status.c:1154
msgid " (use \"git commit\" to conclude merge)"
-msgstr " (useu \"git commit\" per a concloure la fusió)"
+msgstr " (useu «git commit» per a concloure la fusió)"
#: wt-status.c:1163
msgid "You are in the middle of an am session."
@@ -9292,15 +9296,15 @@ msgstr "El pedaç actual està buit."
#: wt-status.c:1170
msgid " (fix conflicts and then run \"git am --continue\")"
-msgstr " (arregleu els conflictes i després executeu \"git am --continue\")"
+msgstr " (arregleu els conflictes i després executeu «git am --continue»)"
#: wt-status.c:1172
msgid " (use \"git am --skip\" to skip this patch)"
-msgstr " (useu \"git am --skip\" per a ometre aquest pedaç)"
+msgstr " (useu «git am --skip» per a ometre aquest pedaç)"
#: wt-status.c:1174
msgid " (use \"git am --abort\" to restore the original branch)"
-msgstr " (useu \"git am --abort\" per a restaurar la branca original)"
+msgstr " (useu «git am --abort» per a restaurar la branca original)"
#: wt-status.c:1307
msgid "git-rebase-todo is missing."
@@ -9335,7 +9339,7 @@ msgstr[1] "Ordres següents a fer (manquen %d ordres):"
#: wt-status.c:1339
msgid " (use \"git rebase --edit-todo\" to view and edit)"
-msgstr " (useu \"git rebase --edit-todo\" per a veure i editar)"
+msgstr " (useu «git rebase --edit-todo» per a veure i editar)"
#: wt-status.c:1351
#, c-format
@@ -9378,8 +9382,8 @@ msgstr "Actualment esteu dividint una comissió durant un «rebase»."
#: wt-status.c:1392
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\")"
+" (Una vegada que el vostre directori de treball sigui net, executeu «git "
+"rebase --continue»)"
#: wt-status.c:1396
#, c-format
@@ -9394,13 +9398,13 @@ msgstr "Actualment esteu editant una comissió durant un «rebase»."
#: wt-status.c:1404
msgid " (use \"git commit --amend\" to amend the current commit)"
-msgstr " (useu \"git commit --amend\" per a esmenar la comissió actual)"
+msgstr " (useu «git commit --amend» per a esmenar la comissió actual)"
#: wt-status.c:1406
msgid ""
" (use \"git rebase --continue\" once you are satisfied with your changes)"
msgstr ""
-" (useu \"git rebase --continue\" una vegada que estigueu satisfet amb els "
+" (useu «git rebase --continue» una vegada que estigueu satisfet amb els "
"vostres canvis)"
#: wt-status.c:1417
@@ -9417,9 +9421,8 @@ msgid " (fix conflicts and run \"git cherry-pick --continue\")"
msgstr " (arregleu els conflictes i executeu «git cherry-pick --continue»)"
#: wt-status.c:1430
-#, fuzzy
msgid " (run \"git cherry-pick --continue\" to continue)"
-msgstr "(executa \"git cherry-pick --continue\" per continuar)"
+msgstr " (executeu «git cherry-pick --continue» per a continuar)"
#: wt-status.c:1433
msgid " (all conflicts fixed: run \"git cherry-pick --continue\")"
@@ -9434,7 +9437,7 @@ msgstr " (useu «git cherry-pick --skip» per a ometre aquest pedaç)"
#: wt-status.c:1437
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 "
+" (useu «git cherry-pick --abort» per a cancel·lar l'operació de «cherry "
"pick»)"
#: wt-status.c:1447
@@ -9448,27 +9451,24 @@ msgstr "Actualment esteu revertint la comissió %s."
#: wt-status.c:1456
msgid " (fix conflicts and run \"git revert --continue\")"
-msgstr " (arregleu els conflictes i executeu \"git revert --continue\")"
+msgstr " (arregleu els conflictes i executeu «git revert --continue»)"
#: wt-status.c:1459
-#, fuzzy
msgid " (run \"git revert --continue\" to continue)"
-msgstr "(executa \"git revert --continue\" per continuar)"
+msgstr " (executeu «git revert --continue» per a continuar)"
#: wt-status.c:1462
msgid " (all conflicts fixed: run \"git revert --continue\")"
msgstr ""
-" (tots els conflictes estan arreglats: executeu \"git revert --continue\")"
+" (tots els conflictes estan arreglats: executeu «git revert --continue»)"
#: wt-status.c:1464
-#, fuzzy
msgid " (use \"git revert --skip\" to skip this patch)"
-msgstr "(useu \"git revert --skip\" per ometre aquest pedaç)"
+msgstr " (useu «git revert --skip» per a ometre aquest pedaç)"
#: wt-status.c:1466
msgid " (use \"git revert --abort\" to cancel the revert operation)"
-msgstr ""
-" (useu \"git revert --abort\" per a cancel·lar l'operació de reversió)"
+msgstr " (useu «git revert --abort» per a cancel·lar l'operació de reversió)"
#: wt-status.c:1476
#, c-format
@@ -9481,7 +9481,7 @@ msgstr "Actualment esteu bisecant."
#: wt-status.c:1483
msgid " (use \"git bisect reset\" to get back to the original branch)"
-msgstr " (useu \"git bisect reset\" per a tornar a la branca original)"
+msgstr " (useu «git bisect reset» per a tornar a la branca original)"
#: wt-status.c:1692
msgid "On branch "
@@ -9523,9 +9523,9 @@ msgid ""
"new files yourself (see 'git help status')."
msgstr ""
"Ha trigat %.2f segons enumerar els fitxers no seguits.\n"
-"'status -uno' pot accelerar-ho, però heu d'anar amb compte de no\n"
+"«status -uno» pot accelerar-ho, però heu d'anar amb compte de no\n"
"oblidar-vos d'afegir fitxers nous vosaltres mateixos (vegeu\n"
-"'git help status')."
+"«git help status»)."
#: wt-status.c:1755
#, c-format
@@ -9543,8 +9543,7 @@ msgstr "Sense canvis"
#: wt-status.c:1768
#, 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"
+msgstr "no hi ha canvis afegits a cometre (useu «git add» o «git commit -a»)\n"
#: wt-status.c:1771
#, c-format
@@ -9780,12 +9779,12 @@ msgstr ""
"\n"
"\tgit submodule add <url> %s\n"
"\n"
-"Si heu afegit aquest camí per error, podeu suprimir-lo de\n"
+"Si heu afegit aquest camí per error, podeu eliminar-lo de\n"
"l'índex amb:\n"
"\n"
"\tgit rm --cached %s\n"
"\n"
-"Vegeu \"git help submodule\" per a més informació."
+"Vegeu «git help submodule» per a més informació."
#: builtin/add.c:391
#, c-format
@@ -9916,20 +9915,19 @@ msgstr "S'ha produït un error en dividir els pedaços."
#: builtin/am.c:1089
#, c-format
msgid "When you have resolved this problem, run \"%s --continue\"."
-msgstr "Quan hàgiu resolt aquest problema, executeu \"%s --continue\"."
+msgstr "Quan hàgiu resolt aquest problema, executeu «%s --continue»."
#: builtin/am.c:1090
#, 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ò."
+msgstr "Si preferiu ometre aquest pedaç, executeu «%s --skip» en lloc d'això."
#: builtin/am.c:1091
#, 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"
-"\"."
+"Per a restaurar la branca original i deixar d'apedaçar, executeu «%s --"
+"abort»."
#: builtin/am.c:1174
#, fuzzy
@@ -10035,7 +10033,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 ""
-"Cap canvi - heu oblidat d'usar 'git add'?\n"
+"Cap canvi - heu oblidat d'usar «git add»?\n"
"Si no hi ha res per fer «stage», probablement alguna altra cosa ja ha\n"
"introduït els mateixos canvis; potser voleu ometre aquest pedaç."
@@ -10047,9 +10045,9 @@ msgid ""
"You might run `git rm` on a file to accept \"deleted by them\" for it."
msgstr ""
"Encara teniu camins sense fusionar a l'índex.\n"
-"Heu de fer 'git add' a cada fitxer amb conflictes resolts per marcar-los com "
-"a tal.\n"
-"Podeu executar `git rm` en un fitxer per acceptar \"suprimit per ells\" pel "
+"Heu de fer «git add» a cada fitxer amb conflictes resolts per a marcar-los "
+"com a tal.\n"
+"Podeu executar «git rm» en un fitxer per a acceptar «suprimit per ells» pel "
"fitxer."
#: builtin/am.c:1928 builtin/am.c:1932 builtin/am.c:1944 builtin/reset.c:347
@@ -10067,7 +10065,7 @@ msgid ""
"You seem to have moved HEAD since the last 'am' failure.\n"
"Not rewinding to ORIG_HEAD"
msgstr ""
-"Sembla que heu mogut HEAD després de l'última fallada de 'am'.\n"
+"Sembla que heu mogut HEAD després de l'última fallada de «am».\n"
"No s'està rebobinant a ORIG_HEAD"
#: builtin/am.c:2131
@@ -10247,7 +10245,7 @@ msgid ""
"Use \"git am --abort\" to remove it."
msgstr ""
"S'ha trobat un directori %s extraviat.\n"
-"Useu \"git am --abort\" per a eliminar-lo."
+"Useu «git am --abort» per a eliminar-lo."
#: builtin/am.c:2370
msgid "Resolve operation not in progress, we are not resuming."
@@ -10396,9 +10394,9 @@ msgid "Bad bisect_write argument: %s"
msgstr "Arguments de bisectriu incorrectes"
#: builtin/bisect--helper.c:221
-#, fuzzy, c-format
+#, c-format
msgid "couldn't get the oid of the rev '%s'"
-msgstr "no s'ha pogut obtenir l'oide de la revista '%s'"
+msgstr "no s'ha pogut obtenir l'oid de la revisió «%s»"
#: builtin/bisect--helper.c:233
#, fuzzy, c-format
@@ -10426,9 +10424,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 ""
-"Heu de començar per \"git bisect start\". Després heu de donar-me com a "
-"mínim un per cents i per cents revisió. Podeu utilitzar \"git bisectrius\" i "
-"\"git bisectrius\" per a això."
+"Heu de començar per «git bisect start». \n"
+"Després heu de donar-me com a mínim un per cents i per cents revisió. Podeu "
+"utilitzar «git bisect %s» i «git bisect %s» per a això."
#: builtin/bisect--helper.c:310
#, c-format
@@ -10462,7 +10460,7 @@ msgid ""
"invalid argument %s for 'git bisect terms'.\n"
"Supported options are: --term-good|--term-old and --term-bad|--term-new."
msgstr ""
-"paràmetre no vàlid %s per a 'git bisect terms'.\n"
+"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."
#: builtin/bisect--helper.c:478
@@ -10483,7 +10481,7 @@ msgstr "HEAD incorrecte - Cal un HEAD"
#, 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>»."
+"l'agafament de «%s» ha fallat. Proveu «git bisect start <branca-vàlida>»."
#: builtin/bisect--helper.c:550
msgid "won't bisect on cg-seek'ed tree"
@@ -10501,7 +10499,7 @@ msgstr "ref '%s' no és vàlid"
#: builtin/bisect--helper.c:633
msgid "perform 'git bisect next'"
-msgstr "realitza 'git bisect next'"
+msgstr "realitza «git bisect next»"
#: builtin/bisect--helper.c:635
msgid "write the terms to .git/BISECT_TERMS"
@@ -10556,11 +10554,11 @@ msgstr "no hi ha registre per BISECTWRITE"
#: builtin/bisect--helper.c:673
msgid "--write-terms requires two arguments"
-msgstr "--write-terms requereix dos paràmetres"
+msgstr "--write-terms requereix dos arguments"
#: builtin/bisect--helper.c:677
msgid "--bisect-clean-state requires no arguments"
-msgstr "--bisect-clean-state no accepta paràmetres"
+msgstr "--bisect-clean-state no requereix cap argument"
#: builtin/bisect--helper.c:684
#, fuzzy
@@ -10834,7 +10832,7 @@ msgid ""
"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'."
+"Si esteu segur que la voleu suprimir, executeu «git branch -D %s»."
#: builtin/branch.c:189
msgid "Update of config-file failed"
@@ -11135,7 +11133,7 @@ msgstr "hi ha massa branques per a una operació de còpia"
#: builtin/branch.c:790
msgid "too many arguments for a rename operation"
-msgstr "hi ha massa arguments per a una operació remota"
+msgstr "hi ha massa arguments per a una operació de canvi de nom"
#: builtin/branch.c:795
msgid "too many arguments to set new upstream"
@@ -11186,8 +11184,8 @@ msgid ""
"the '--set-upstream' option is no longer supported. Please use '--track' or "
"'--set-upstream-to' instead."
msgstr ""
-"L'opció --set-upstream ja no està suportada. Useu en comptes --track o --set-"
-"upstream-to."
+"L'opció --set-upstream ja no s'admet. En lloc seu, useu «--track» o «--set-"
+"upstream-to»."
#: builtin/bundle.c:15 builtin/bundle.c:23
#, fuzzy
@@ -11944,7 +11942,7 @@ msgstr ""
#: builtin/checkout.c:1697
#, c-format
msgid "git checkout: --detach does not take a path argument '%s'"
-msgstr "git checkout: --detach no accepta un paràmetre de camí «%s»"
+msgstr "git checkout: --detach no accepta un argument de camí «%s»"
#: builtin/checkout.c:1706
#, fuzzy
@@ -11990,7 +11988,7 @@ msgstr "crea un registre de referència per a la branca nova"
#: builtin/checkout.c:1757
#, fuzzy
msgid "second guess 'git checkout <no-such-branch>' (default)"
-msgstr "segon conjectura 'git checkout <no-such-branch>' (per defecte)"
+msgstr "segon conjectura «git checkout <no-such-branch>» (per defecte)"
#: builtin/checkout.c:1758
#, fuzzy
@@ -12010,7 +12008,7 @@ msgstr "crea/reestableix i canvia a una branca"
#: builtin/checkout.c:1807
#, fuzzy
msgid "second guess 'git switch <no-such-branch>'"
-msgstr "segon conjectura 'git switch <no-such-branch>'"
+msgstr "segon conjectura «git switch <no-such-branch>»"
#: builtin/checkout.c:1809
#, fuzzy
@@ -12149,9 +12147,9 @@ msgid ""
"? - help for prompt selection"
msgstr ""
"clean - comença a netejar\n"
-"filter by pattern - exclou ítems de supressió\n"
+"filter by pattern - exclou ítems de la supressió\n"
"select by numbers - selecciona ítems a suprimir per números\n"
-"ask each - confirma cada supressió (com \"rm -i\")\n"
+"ask each - confirma cada supressió (com «rm -i»)\n"
"quit - deixa de netejar\n"
"help - aquesta pantalla\n"
"? - ajuda de selecció de l'avís"
@@ -12478,7 +12476,7 @@ msgstr "no es pot desenllaçar el fitxer d'alternatives temporal"
#: builtin/clone.c:971 builtin/receive-pack.c:1972
msgid "Too many arguments."
-msgstr "Hi ha massa paràmetres."
+msgstr "Hi ha massa arguments."
#: builtin/clone.c:975
msgid "You must specify a repository to clone."
@@ -12607,7 +12605,7 @@ msgstr "Espai d'encoixinada entre columnes"
#: builtin/column.c:51
msgid "--command must be the first argument"
-msgstr "--command ha de ser el primer paràmetre"
+msgstr "--command ha de ser el primer argument"
#: builtin/commit-graph.c:11 builtin/commit-graph.c:19
#, fuzzy
@@ -12657,9 +12655,9 @@ msgid "Could not open commit-graph '%s'"
msgstr "No s'ha pogut obrir el graf de comissions «%s»"
#: builtin/commit-graph.c:136
-#, fuzzy, c-format
+#, c-format
msgid "unrecognized --split argument, %s"
-msgstr "paràmetre --type no reconegut, %s"
+msgstr "argument --split no reconegut, %s"
#: builtin/commit-graph.c:155
#, fuzzy
@@ -12807,7 +12805,7 @@ msgid ""
msgstr ""
"Heu demanat esmenar la comissió més recent, però fer això la\n"
"deixaria buida. Podeu repetir la vostra ordre amb --allow-empty, o\n"
-"podeu eliminar la comissió per complet amb \"git reset HEAD^\".\n"
+"podeu eliminar la comissió per complet amb «git reset HEAD^».\n"
#: builtin/commit.c:56
msgid ""
@@ -12817,22 +12815,20 @@ msgid ""
" git commit --allow-empty\n"
"\n"
msgstr ""
-"El «cherry pick» previ ja està buit, possiblement a causa de resolució de "
-"conflicte.\n"
+"El «cherry pick» previ està ara buit, possiblement a causa de resolució de "
+"conflictes.\n"
"Si el voleu cometre de totes maneres, useu:\n"
"\n"
" git commit --allow-empty\n"
"\n"
#: builtin/commit.c:63
-#, fuzzy
msgid "Otherwise, please use 'git rebase --skip'\n"
-msgstr "Altrament si us plau useu 'git cherry-pick --skip'"
+msgstr "Altrament si us plau useu «git rebase --skip»\n"
#: builtin/commit.c:66
-#, fuzzy
msgid "Otherwise, please use 'git cherry-pick --skip'\n"
-msgstr "Altrament si us plau useu 'git cherry-pick --skip'"
+msgstr "Altrament si us plau useu «git cherry-pick --skip»\n"
#: builtin/commit.c:69
#, fuzzy
@@ -12929,7 +12925,7 @@ msgstr ""
#: builtin/commit.c:717 builtin/commit.c:750 builtin/commit.c:1099
#, c-format
msgid "could not lookup commit %s"
-msgstr "no s'ha pogut trobar la comissió %s"
+msgstr "no s'ha pogut cercar la comissió %s"
#: builtin/commit.c:729 builtin/shortlog.c:319
#, c-format
@@ -13047,7 +13043,7 @@ msgstr ""
#: builtin/commit.c:1071
#, c-format
msgid "Invalid ignored mode '%s'"
-msgstr "mode ignorat no vàlid «%s»"
+msgstr "Mode ignorat no vàlid «%s»"
#: builtin/commit.c:1089 builtin/commit.c:1333
#, c-format
@@ -13354,7 +13350,7 @@ msgstr "git config [<opcions>]"
#: builtin/config.c:104 builtin/env--helper.c:23
#, c-format
msgid "unrecognized --type argument, %s"
-msgstr "paràmetre --type no reconegut, %s"
+msgstr "argument --type no reconegut, %s"
#: builtin/config.c:116
msgid "only one type at a time"
@@ -13634,7 +13630,7 @@ msgstr "no s'ha pogut llegir el fitxer de configuració «%s»"
#: builtin/config.c:760
msgid "error processing config file(s)"
-msgstr "s'ha produït un error processant els fitxers de configuració"
+msgstr "s'ha produït un error en processar els fitxers de configuració"
#: builtin/config.c:770
msgid "editing stdin is not supported"
@@ -13815,11 +13811,11 @@ msgstr "marca"
#: builtin/describe.c:572
msgid "append <mark> on dirty working tree (default: \"-dirty\")"
-msgstr "annexa <marca> en l'arbre de treball brut (per defecte: \"-dirty\")"
+msgstr "annexa <marca> en l'arbre de treball brut (per defecte: «-dirty»)"
#: builtin/describe.c:575
msgid "append <mark> on broken working tree (default: \"-broken\")"
-msgstr "annexa <marca> en l'arbre de treball brut (per defecte: \"-broken\")"
+msgstr "annexa <marca> en l'arbre de treball brut (per defecte: «-broken»)"
#: builtin/describe.c:593
msgid "--long is incompatible with --abbrev=0"
@@ -13888,15 +13884,15 @@ msgstr "no s'ha pogut llegir el fitxer d'enllaç simbòlic %s"
#: builtin/difftool.c:312
#, 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"
+msgstr "no es pot llegir l'objecte %s per l'enllaç simbòlic %s"
#: builtin/difftool.c:413
msgid ""
"combined diff formats('-c' and '--cc') are not supported in\n"
"directory diff mode('-d' and '--dir-diff')."
msgstr ""
-"els formats de diff combinats ('-c' and '--cc') no són admesos \n"
-"en el mode diff per directoris ('-d' and '--dir-diff')."
+"els formats de diff combinats («-c» i «--cc») no s'admeten\n"
+"en el mode diff per directoris («-d» i «--dir-diff»)."
#: builtin/difftool.c:634
#, c-format
@@ -13918,7 +13914,7 @@ msgstr "podeu netejar o recuperar-los."
#: builtin/difftool.c:697
msgid "use `diff.guitool` instead of `diff.tool`"
-msgstr "utilitza `diff.guitool` en comptes de `diff.tool`"
+msgstr "usa «diff.guitool» en lloc de «diff.tool»"
#: builtin/difftool.c:699
msgid "perform a full-directory diff"
@@ -13943,14 +13939,14 @@ msgstr "utilitza l'eina de diff especificada"
#: builtin/difftool.c:710
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`"
+"imprimeix una llista de totes les eines diff que podeu usar amb «--tool»"
#: builtin/difftool.c:713
msgid ""
"make 'git-difftool' exit when an invoked diff tool returns a non - zero exit "
"code"
msgstr ""
-"fes que 'git-difftool' surti quan l'eina de diff invocada torna un codi de "
+"fes que «git-difftool» surti quan l'eina de diff invocada torna un codi de "
"sortida diferent de zero"
#: builtin/difftool.c:716
@@ -13975,11 +13971,11 @@ msgstr "--gui, --tool and --extcmd són mútuament excloents"
#: builtin/difftool.c:750
msgid "no <tool> given for --tool=<tool>"
-msgstr "no s'ha proporcionat <tool> per --tool=<tool>"
+msgstr "no s'ha proporcionat l'<eina> per a --tool=<eina>"
#: builtin/difftool.c:757
msgid "no <cmd> given for --extcmd=<cmd>"
-msgstr "no s'ha proporcionat <cmd> per --extcmd=<cmd>"
+msgstr "no s'ha proporcionat l'<ordre> per a --extcmd=<ordre>"
#: builtin/env--helper.c:6
msgid "git env--helper --type=[bool|ulong] <options> <env-var>"
@@ -14352,7 +14348,7 @@ msgid ""
" 'git remote prune %s' to remove any old, conflicting branches"
msgstr ""
"algunes referències locals no s'han pogut actualitzar;\n"
-" intenteu executar 'git remote prune %s' per a eliminar\n"
+" intenteu executar «git remote prune %s» per a eliminar\n"
" qualsevol branca antiga o conflictiva"
#: builtin/fetch.c:1128
@@ -14462,7 +14458,7 @@ msgstr "--unshallow en un dipòsit complet no té sentit"
#: builtin/fetch.c:1798
msgid "fetch --all does not take a repository argument"
-msgstr "fetch --all no accepta un paràmetre de dipòsit"
+msgstr "fetch --all no accepta un argument de dipòsit"
#: builtin/fetch.c:1800
msgid "fetch --all does not make sense with refspecs"
@@ -14667,7 +14663,7 @@ msgstr "%s: objecte corrupte o no trobat"
#: builtin/fsck.c:501
#, c-format
msgid "%s: invalid reflog entry %s"
-msgstr " %s: entrada de referència no vàlida %s"
+msgstr "%s: entrada de referència no vàlida %s"
#: builtin/fsck.c:515
#, fuzzy, c-format
@@ -14915,7 +14911,7 @@ msgstr ""
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-"
+"Hi ha massa objectes solts inabastables; executeu «git prune» per a eliminar-"
"los."
#: builtin/grep.c:30
@@ -14940,7 +14936,7 @@ msgstr "s'ha especificat un nombre de fils no vàlid (%d) per a %s"
#: builtin/pack-objects.c:2855
#, c-format
msgid "no threads support, ignoring %s"
-msgstr "no hi ha suport de fils, s'està ignorant %s"
+msgstr "no s'admeten fils, s'ignorarà %s"
#: builtin/grep.c:475 builtin/grep.c:600 builtin/grep.c:640
#, c-format
@@ -14971,7 +14967,7 @@ msgstr "cerca tant en fitxers seguits com en no seguits"
#: builtin/grep.c:829
msgid "ignore files specified via '.gitignore'"
-msgstr "ignora els fitxers especificats mitjançant '.gitignore'"
+msgstr "ignora els fitxers especificats mitjançant «.gitignore»"
#: builtin/grep.c:831
msgid "recursively search in each submodule"
@@ -15003,7 +14999,7 @@ msgstr "processa els fitxers binaris amb filtres de textconv"
#: builtin/grep.c:847
msgid "search in subdirectories (default)"
-msgstr "cerca als subdirectories (per defecte)"
+msgstr "cerca als subdirectoris (per defecte)"
#: builtin/grep.c:849
msgid "descend at most <depth> levels"
@@ -15163,9 +15159,8 @@ msgid "unable to resolve revision: %s"
msgstr "no s'ha pogut resoldre la revisió: %s"
#: builtin/grep.c:1077
-#, fuzzy
msgid "--untracked not supported with --recurse-submodules"
-msgstr "--untracked no està suportat amb --recurse-submodules"
+msgstr "--untracked no s'admet amb --recurse-submodules"
#: builtin/grep.c:1081
msgid "invalid option combination, ignoring --threads"
@@ -15173,7 +15168,7 @@ msgstr "combinació d'opcions no vàlida, s'està ignorant --threads"
#: builtin/grep.c:1084 builtin/pack-objects.c:3548
msgid "no threads support, ignoring --threads"
-msgstr "no hi ha suport de fils, s'està ignorant --threads"
+msgstr "no s'admeten fils, s'ignorarà --threads"
#: builtin/grep.c:1087 builtin/index-pack.c:1534 builtin/pack-objects.c:2852
#, c-format
@@ -15305,7 +15300,7 @@ msgid ""
"Please consider using 'man.<tool>.cmd' instead."
msgstr ""
"«%s»: camí a un visualitzador de manuals no compatible.\n"
-"Considereu usar 'man.<eina>.cmd' en lloc d'això."
+"Considereu usar «man.<eina>.cmd» en lloc d'això."
#: builtin/help.c:319
#, c-format
@@ -15314,7 +15309,7 @@ msgid ""
"Please consider using 'man.<tool>.path' instead."
msgstr ""
"«%s»: ordre per a un visualitzador de manuals compatible.\n"
-"Considereu usar 'man.<eina>.path' en lloc d'això."
+"Considereu usar «man.<eina>.path» en lloc d'això."
#: builtin/help.c:436
#, c-format
@@ -15560,7 +15555,7 @@ msgstr "l'objecte local %s és malmès"
#: builtin/index-pack.c:1405
#, c-format
msgid "packfile name '%s' does not end with '.pack'"
-msgstr "el nom del fitxer de paquet «%s» no acaba amb '.pack'"
+msgstr "el nom del fitxer de paquet «%s» no acaba amb «.pack»"
#: builtin/index-pack.c:1430
#, c-format
@@ -16023,7 +16018,7 @@ msgstr "sufix"
#: builtin/log.c:1663
msgid "use <sfx> instead of '.patch'"
-msgstr "usa <sufix> en lloc de '.patch'"
+msgstr "usa <sufix> en lloc de «.patch»"
#: builtin/log.c:1665
msgid "start numbering patches at <n> instead of 1"
@@ -16281,11 +16276,11 @@ msgstr "identifica l'estat de fitxer amb etiquetes"
#: builtin/ls-files.c:529
msgid "use lowercase letters for 'assume unchanged' files"
-msgstr "usa lletres minúscules per als fitxers 'assume unchanged'"
+msgstr "usa lletres minúscules per als fitxers «assume unchanged»"
#: builtin/ls-files.c:531
msgid "use lowercase letters for 'fsmonitor clean' files"
-msgstr "usa lletres minúscules per als fitxers 'fsmonitor clean'"
+msgstr "usa lletres minúscules per als fitxers «fsmonitor clean»"
#: builtin/ls-files.c:533
msgid "show cached files in the output (default)"
@@ -16422,7 +16417,7 @@ msgstr "surt amb codi de sortida 2 si no es troba cap referència coincident"
#: builtin/ls-remote.c:75
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 senyali"
+msgstr "mostra la referència subjacent a més de l'objecte que assenyali"
#: builtin/ls-tree.c:30
msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
@@ -16763,7 +16758,7 @@ msgstr "No s'ha pogut llegir de «%s»"
#, 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"
+"No s'està cometent la fusió; useu «git commit» per a completar la fusió.\n"
#: builtin/merge.c:812
#, fuzzy
@@ -16839,20 +16834,19 @@ msgstr "no és quelcom que puguem fusionar"
#: builtin/merge.c:1295
msgid "--abort expects no arguments"
-msgstr "--abort no accepta paràmetres"
+msgstr "--abort no espera cap argument"
#: builtin/merge.c:1299
msgid "There is no merge to abort (MERGE_HEAD missing)."
msgstr "No hi ha fusió a avortar (manca MERGE_HEAD)."
#: builtin/merge.c:1317
-#, fuzzy
msgid "--quit expects no arguments"
msgstr "--quit no espera cap argument"
#: builtin/merge.c:1330
msgid "--continue expects no arguments"
-msgstr "--continue no accepta paràmetres"
+msgstr "--continue no espera cap argument"
#: builtin/merge.c:1334
msgid "There is no merge in progress (MERGE_HEAD missing)."
@@ -17015,12 +17009,11 @@ msgstr ""
#: builtin/multi-pack-index.c:50 builtin/prune-packed.c:25
msgid "too many arguments"
-msgstr "hi ha massa paràmetres"
+msgstr "hi ha massa arguments"
#: builtin/multi-pack-index.c:60
-#, fuzzy
msgid "--batch-size option is only for 'repack' subcommand"
-msgstr "--batch-size l'opció només és per la subordre 'repack'"
+msgstr "--batch-size l'opció només és per a la subordre «repack»"
#: builtin/multi-pack-index.c:69
#, fuzzy, c-format
@@ -17294,7 +17287,7 @@ msgstr "no s'ha pogut llegir la sortida de «show»"
#: builtin/notes.c:162
#, 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»"
+msgstr "S'ha produït un error en finalitzar «show» per a l'objecte «%s»"
#: builtin/notes.c:197
msgid "please supply the note contents using either -m or -F option"
@@ -17437,7 +17430,7 @@ 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 ""
-"Es desaconsellen les opcions -m/-F/-c/-C en favor de la subordre 'edit'.\n"
+"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:698
@@ -17451,7 +17444,7 @@ msgstr "s'ha produït un error en suprimir la referència NOTES_MERGE_REF"
#: builtin/notes.c:702
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'"
+"s'ha produït un error en eliminar l'arbre de treball de «git notes merge»"
#: builtin/notes.c:722
msgid "failed to read ref NOTES_MERGE_PARTIAL"
@@ -17543,8 +17536,8 @@ msgid ""
"abort'.\n"
msgstr ""
"La fusió de notes automàtica ha fallat. Arregleu els conflictes en %s i "
-"cometeu el resultat amb 'git notes merge --commit', o avorteu la fusió amb "
-"'git notes merge --abort'.\n"
+"cometeu el resultat amb «git notes merge --commit», o avorteu la fusió amb "
+"«git notes merge --abort».\n"
#: builtin/notes.c:897 builtin/tag.c:546
#, c-format
@@ -17818,7 +17811,7 @@ msgstr "no creïs una emissió de paquet buida"
#: builtin/pack-objects.c:3410
msgid "read revision arguments from standard input"
-msgstr "llegeix els paràmetres de revisió des de l'entrada estàndard"
+msgstr "llegeix els arguments de revisió des de l'entrada estàndard"
#: builtin/pack-objects.c:3412
msgid "limit the objects to those that are not yet packed"
@@ -18117,7 +18110,7 @@ msgstr "Especifiqueu amb quina branca voleu fusionar."
#: builtin/pull.c:475 builtin/pull.c:490
msgid "See git-pull(1) for details."
-msgstr "Vegeu git-pull(1) per detalls."
+msgstr "Vegeu git-pull(1) per a més informació."
#: builtin/pull.c:477 builtin/pull.c:483 builtin/pull.c:492
#: builtin/rebase.c:1240 git-parse-remote.sh:64
@@ -18232,8 +18225,8 @@ msgid ""
"To choose either option permanently, see push.default in 'git help config'."
msgstr ""
"\n"
-"Per a triar qualsevol opció permanentment, vegeu push.default a 'git help "
-"config'."
+"Per a triar qualsevol opció permanentment, vegeu push.default a «git help "
+"config»."
#: builtin/push.c:171
#, c-format
@@ -18321,8 +18314,9 @@ msgid ""
msgstr ""
"S'han rebutjat les actualitzacions perquè el punt de la vostra branca\n"
"actual està darrere de la seva branca remota corresponent. Integreu\n"
-"els canvis remots (per exemple, 'git pull ...') abans de pujar de nou.\n"
-"Vegeu la 'Nota sobre avanços ràpids' a 'git push --help' per detalls."
+"els canvis remots (per exemple, «git pull ...») abans de pujar de nou.\n"
+"Vegeu la «Nota sobre avanços ràpids» a «git push --help» per a més "
+"informació."
#: builtin/push.c:283
msgid ""
@@ -18333,9 +18327,10 @@ msgid ""
msgstr ""
"S'han rebutjat les actualitzacions perquè un punt de branca pujada\n"
"està darrere de la seva branca remota corresponent. Agafeu aquesta\n"
-"branca i integreu els canvis remots (per exemple, 'git pull ...')\n"
+"branca i integreu els canvis remots (per exemple, «git pull ...»)\n"
"abans de pujar de nou.\n"
-"Vegeu la 'Nota sobre avanços ràpids' a 'git push --help' per detalls."
+"Vegeu la «Nota sobre avanços ràpids» a «git push --help» per a més "
+"informació."
#: builtin/push.c:289
msgid ""
@@ -18348,9 +18343,10 @@ msgstr ""
"S'han rebutjat les actualitzacions perquè el remot conté canvis\n"
"que no teniu localment. Això acostuma a ser causat per un altre dipòsit\n"
"que ha pujat a la mateixa referència. Pot ser que primer vulgueu\n"
-"integrar els canvis remots (per exemple, 'git pull ...') abans de\n"
+"integrar els canvis remots (per exemple, «git pull ...») abans de\n"
"pujar de nou.\n"
-"Vegeu la 'Nota sobre avanços ràpids' a 'git push --help' per detalls."
+"Vegeu la «Nota sobre avanços ràpids» a «git push --help» per a més "
+"informació."
#: builtin/push.c:296
msgid "Updates were rejected because the tag already exists in the remote."
@@ -18366,7 +18362,7 @@ msgstr ""
"No podeu actualitzar una referència remota que assenyala un\n"
"objecte no de comissió, ni actualitzar una referència remota per\n"
"fer que assenyali un objecte no de comissió, sense usar l'opció\n"
-"'--force'.\n"
+"«--force».\n"
#: builtin/push.c:361
#, c-format
@@ -18916,8 +18912,8 @@ msgid ""
"\n"
msgstr ""
"%s\n"
-"Especifiqueu sobre què branca voleu fer «rebase».\n"
-"Vegeu git-rebase(1) per detalls.\n"
+"Especifiqueu sobre quina branca voleu fer «rebase».\n"
+"Vegeu git-rebase(1) per a més informació.\n"
"\n"
" git rebase '<branca>'\n"
"\n"
@@ -18933,7 +18929,7 @@ msgstr ""
"Si voleu establir informació de seguiment per a aquesta branca, podeu fer-ho "
"amb:\n"
"\n"
-" git branch --set-upstream-to=%s/<branch> %s\n"
+" git branch --set-upstream-to=%s/<branca> %s\n"
"\n"
#: builtin/rebase.c:1272
@@ -19208,7 +19204,7 @@ msgstr "font no vàlida: «%s»"
#: builtin/rebase.c:1824
msgid "Could not create new root commit"
-msgstr "no s'ha pogut crear una comissió arrel nova"
+msgstr "No s'ha pogut crear una comissió arrel nova"
#: builtin/rebase.c:1850
#, fuzzy, c-format
@@ -19275,7 +19271,7 @@ msgstr "El lligam pre-«rebase» ha refusat a fer «rebase»."
#: builtin/rebase.c:2001
#, c-format
msgid "Changes to %s:\n"
-msgstr "Canvis a %s:\n"
+msgstr "Canvis a %s:\n"
#: builtin/rebase.c:2004
#, c-format
@@ -19319,18 +19315,18 @@ msgid ""
"'receive.denyCurrentBranch' configuration variable to 'refuse'."
msgstr ""
"Per defecte, es denega actualitzar la branca actual en un dipòsit no\n"
-"nu, perquè faria l'índex i l'arbre de treball inconsistents amb el\n"
-"que hàgiu pujat, i requeriria 'git reset --hard' per a fer que\n"
-"l'arbre de treball coincideixi amb HEAD.\n"
+"nu, perquè faria l'índex i l'arbre de treball inconsistents amb allò\n"
+"que hàgiu pujat, i requeriria «git reset --hard» per a fer que\n"
+"l'arbre de treball coincidís amb HEAD.\n"
"\n"
"Podeu establir la variable de configuració\n"
"«receive.denyCurrentBranch» a «ignore» o «warn» en el dipòsit remot\n"
-"per a permetre pujar a la seva branca actual; no obstant, no es\n"
-"recomana això a menys que hàgiu decidit actualitzar el seu arbre en\n"
-"alguna altra manera per a coincidir amb el que hàgiu pujat.\n"
+"per a permetre pujar a la seva branca actual; això no obstant, no es\n"
+"recomana a menys que hàgiu decidit actualitzar el seu arbre de treball\n"
+"per a coincidir amb allò que hàgiu pujat d'alguna altra manera.\n"
"\n"
"Per a silenciar aquest missatge i mantenir el comportament\n"
-"predeterminat, establiu la variable de configuració\n"
+"per defecte, establiu la variable de configuració\n"
"«receive.denyCurrentBranch» a «refuse»."
#: builtin/receive-pack.c:863
@@ -19345,7 +19341,7 @@ msgid ""
"To squelch this message, you can set it to 'refuse'."
msgstr ""
"Per defecte, es denega suprimir la branca actual, perquè el\n"
-"'git clone' següent no resultarà en cap fitxer agafat, causant\n"
+"«git clone» següent no resultarà en cap fitxer agafat, causant\n"
"confusió.\n"
"\n"
"Podeu establir la variable de configuració\n"
@@ -19369,20 +19365,21 @@ msgid ""
"rewrite] [--updateref] [--stale-fix] [--dry-run | -n] [--verbose] [--all] "
"<refs>..."
msgstr ""
-"git reflog expire [--expire=<time>] [--expire-unreachable=<time>] [--"
+"git reflog expire [--expire=<hora>] [--expire-unreachable=<hora>] [--"
"rewrite] [--updateref] [--stale-fix] [--dry-run | -n] [--verbose] [--all] "
+"<referències>..."
#: builtin/reflog.c:22
msgid ""
"git reflog delete [--rewrite] [--updateref] [--dry-run | -n] [--verbose] "
"<refs>..."
msgstr ""
-"git reflog remove [--rewrite] [--updateref] [---dry-run | -n] [--verbose] "
-"<refs>"
+"git reflog delete [--rewrite] [--updateref] [--dry-run | -n] [--verbose] "
+"<referències>..."
#: builtin/reflog.c:25
msgid "git reflog exists <ref>"
-msgstr "git reflog exists <ref>"
+msgstr "git reflog exists <referència>"
#: builtin/reflog.c:568 builtin/reflog.c:573
#, c-format
@@ -19420,9 +19417,8 @@ msgid "invalid ref format: %s"
msgstr "format de referència no vàlid: %s"
#: builtin/reflog.c:765
-#, fuzzy
msgid "git reflog [ show | expire | delete | exists ]"
-msgstr "git reflog [ mostra | expira | suprimeix | existeix ]"
+msgstr "git reflog [ show | expire | delete | exists ]"
#: builtin/remote.c:17
msgid "git remote [-v | --verbose]"
@@ -19523,7 +19519,7 @@ msgstr ""
#: builtin/remote.c:148
#, c-format
msgid "unknown mirror argument: %s"
-msgstr "paràmetre de reflexió desconegut: %s"
+msgstr "argument de «mirror» desconegut: %s"
#: builtin/remote.c:164
msgid "fetch the remote branches"
@@ -19665,7 +19661,7 @@ msgstr " seguit"
#: builtin/remote.c:998
msgid " stale (use 'git remote prune' to remove)"
-msgstr " estancat (useu 'git remote prune' per a eliminar)"
+msgstr " estancat (useu «git remote prune» per a eliminar)"
#: builtin/remote.c:1000
msgid " ???"
@@ -19823,11 +19819,11 @@ msgstr[1] " Referències locals configurades per a «git push»%s:"
#: builtin/remote.c:1318
msgid "set refs/remotes/<name>/HEAD according to remote"
-msgstr "estableix refs/remotes/<name>/HEAD segons el remot"
+msgstr "estableix refs/remotes/<nom>/HEAD segons el remot"
#: builtin/remote.c:1320
msgid "delete refs/remotes/<name>/HEAD"
-msgstr "suprimeix refs/remotes/<name>/HEAD"
+msgstr "suprimeix refs/remotes/<nom>/HEAD"
#: builtin/remote.c:1335
msgid "Cannot determine remote HEAD"
@@ -19951,8 +19947,8 @@ msgid ""
"Incremental repacks are incompatible with bitmap indexes. Use\n"
"--no-write-bitmap-index or disable the pack.writebitmaps configuration."
msgstr ""
-"Els reempaquetaments incrementals són incompatibles amb els índexs de "
-"bitmaps. Useu\n"
+"Els reempaquetaments incrementals són incompatibles amb els índexs de mapes "
+"de bits. Useu\n"
"--no-write-bitmap-index o inhabiliteu el paràmetre de configuració pack."
"writebitmaps."
@@ -20075,7 +20071,7 @@ msgid "Nothing new to pack."
msgstr "Res nou per empaquetar."
#: builtin/repack.c:488
-#, fuzzy, c-format
+#, c-format
msgid ""
"WARNING: Some packs in use have been renamed by\n"
"WARNING: prefixing old- to their name, in order to\n"
@@ -20085,11 +20081,13 @@ msgid ""
"WARNING: original names also failed.\n"
"WARNING: Please rename them in %s manually:\n"
msgstr ""
-"AVÍS Alguns paquets en ús s'han reanomenat ALERTA prefixant «old-» al seu "
-"nom per tal d' AVÍS reemplaçar-los per la nova versió del fitxer ALERTA. "
-"Però l'operació ha fallat i l'intent ALERTA de tornar-los a canviar el nom "
-"també ha fallat en el seu ALERTA els noms originals. AVÍS Els reanomeneu "
-"manualment en percentatges"
+"AVÍS: Alguns paquets en ús han canviat de nom\n"
+"AVÍS: prefixant «old-» al seu nom per tal de\n"
+"AVÍS: reemplaçar-los per la nova versió del fitxer.\n"
+"AVÍS: Però l'operació ha fallat i l'intent de\n"
+"AVÍS: tornar-los a canviar als seus noms originals\n"
+"AVÍS: també ha fallat. Canvieu-los de nom en %s\n"
+"AVÍS: manualment:\n"
#: builtin/repack.c:536
#, c-format
@@ -20479,7 +20477,7 @@ msgstr "--patch és incompatible amb --{hard,mixed,soft}"
#: builtin/reset.c:371
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 "
+"--mixed amb camins està en desús; useu «git reset -- <camins>» en lloc "
"d'això."
#: builtin/reset.c:373
@@ -20540,15 +20538,15 @@ msgstr "el recompte marcat és incompatible amb --objects"
#: builtin/rev-parse.c:409
msgid "git rev-parse --parseopt [<options>] -- [<args>...]"
-msgstr "git rev-parse --parseopt [<opcions>] -- [<paràmetres>...]"
+msgstr "git rev-parse --parseopt [<opcions>] -- [<arguments>...]"
#: builtin/rev-parse.c:414
msgid "keep the `--` passed as an arg"
-msgstr "retén el «--» passat com a paràmetre"
+msgstr "retén el «--» passat com a argument"
#: builtin/rev-parse.c:416
msgid "stop parsing after the first non-option argument"
-msgstr "deixa d'analitzar després del primer paràmetre no d'opció"
+msgstr "deixa d'analitzar després del primer argument que no sigui d'opció"
#: builtin/rev-parse.c:419
msgid "output in stuck long form"
@@ -20562,12 +20560,12 @@ msgid ""
"\n"
"Run \"git rev-parse --parseopt -h\" for more information on the first usage."
msgstr ""
-"git rev-parse --parseopt [<opcions>] -- [<paràmetres>...]\n"
-" or: git rev-parse --sq-quote [<paràmetre>...]\n"
-" or: git rev-parse [<opcions>] [<paràmetre>...]\n"
+"git rev-parse --parseopt [<opcions>] -- [<arguments>...]\n"
+" o bé: git rev-parse --sq-quote [<argument>...]\n"
+" o bé: git rev-parse [<opcions>] [<argument>...]\n"
"\n"
-"Executeu \"git rev-parse --parseopt -h\" per més informació sobre l'ús "
-"inicial."
+"Executeu «git rev-parse --parseopt -h» per a més informació sobre el primer "
+"ús."
#: builtin/revert.c:24
msgid "git revert [<options>] <commit-ish>..."
@@ -20736,7 +20734,7 @@ msgstr ""
#: builtin/rm.c:323
#, c-format
msgid "not removing '%s' recursively without -r"
-msgstr "no s'ha suprimit «%s» recursivament sense -r"
+msgstr "no s'eliminarà «%s» recursivament sense -r"
#: builtin/rm.c:362
#, c-format
@@ -20846,7 +20844,7 @@ msgstr "mostra les branques amb seguiment remot"
#: builtin/show-branch.c:649
msgid "color '*!+-' corresponding to the branch"
-msgstr "colora '*!+-' corresponent a la branca"
+msgstr "colora «*!+-» corresponent a la branca"
#: builtin/show-branch.c:651
msgid "show <n> more commits after the common ancestor"
@@ -21212,7 +21210,7 @@ msgstr "missatge «stash»"
#: builtin/stash.c:828
msgid "\"git stash store\" requires one <commit> argument"
-msgstr "«git stash store» requereix un paràmetre <comissió>"
+msgstr "«git stash store» requereix un argument <comissió>"
#: builtin/stash.c:1046
msgid "No changes selected"
@@ -21495,7 +21493,7 @@ msgid ""
"really want to remove it including all of its history)"
msgstr ""
"L'arbre de treball de submòdul «%s» conté un directori .git\n"
-"(useu 'rm -rf' si realment voleu eliminar-lo, incloent tota la seva història)"
+"(useu «rm -rf» si realment voleu eliminar-lo, incloent tota la seva història)"
#: builtin/submodule--helper.c:1134
#, c-format
@@ -21509,7 +21507,7 @@ msgstr ""
#: builtin/submodule--helper.c:1142
#, c-format
msgid "Cleared directory '%s'\n"
-msgstr "S'ha netejat el directori «%s»\n"
+msgstr "S'ha esborrat el directori «%s»\n"
#: builtin/submodule--helper.c:1144
#, c-format
@@ -21529,7 +21527,7 @@ msgstr "S'ha desregistrat el submòdul «%s» (%s) per al camí «%s»\n"
#: builtin/submodule--helper.c:1200
msgid "Remove submodule working trees even if they contain local changes"
msgstr ""
-"Suprimeix els arbres de treball dels submòduls fins i tot si contenen canvis "
+"Elimina els arbres de treball dels submòduls fins i tot si contenen canvis "
"locals"
#: builtin/submodule--helper.c:1201
@@ -21544,7 +21542,7 @@ msgstr ""
#: builtin/submodule--helper.c:1220
msgid "Use '--all' if you really want to deinitialize all submodules"
-msgstr "Useu '--all' si realment voleu desinicialitzar tots els submòduls"
+msgstr "Useu «--all» si realment voleu desinicialitzar tots els submòduls"
#: builtin/submodule--helper.c:1289
#, fuzzy
@@ -21647,7 +21645,7 @@ msgstr "El camí de submòdul «%s» no està inicialitzat"
#: builtin/submodule--helper.c:1621
msgid "Maybe you want to use 'update --init'?"
-msgstr "Potser voleu usar 'update --init'?"
+msgstr "Potser voleu usar «update --init»?"
#: builtin/submodule--helper.c:1651
#, c-format
@@ -22056,33 +22054,34 @@ msgstr "S'està provant mtime en «%s» "
#: builtin/update-index.c:154
msgid "directory stat info does not change after adding a new file"
msgstr ""
-"la informació d'stat de directori no canvia després d'afegir un fitxer nou"
+"la informació de stat de directori no canvia després d'afegir un fitxer nou"
#: builtin/update-index.c:167
msgid "directory stat info does not change after adding a new directory"
msgstr ""
-"la informació d'stat de directori no canvia després d'afegir un directori nou"
+"la informació de stat de directori no canvia després d'afegir un directori "
+"nou"
#: builtin/update-index.c:180
msgid "directory stat info changes after updating a file"
msgstr ""
-"la informació d'stat de directori canvia després d'actualitzar un fitxer"
+"la informació de stat de directori canvia després d'actualitzar un fitxer"
#: builtin/update-index.c:191
msgid "directory stat info changes after adding a file inside subdirectory"
msgstr ""
-"la informació d'stat de directori canvia després d'afegir un fitxer dins "
+"la informació de stat de directori canvia després d'afegir un fitxer dins "
"d'un subdirectori"
#: builtin/update-index.c:202
msgid "directory stat info does not change after deleting a file"
msgstr ""
-"la informació d'stat de directori no canvia després de suprimir un fitxer"
+"la informació de stat de directori no canvia després de suprimir un fitxer"
#: builtin/update-index.c:215
msgid "directory stat info does not change after deleting a directory"
msgstr ""
-"la informació d'stat de directori no canvia després de suprimir un directori"
+"la informació de stat de directori no canvia després de suprimir un directori"
#: builtin/update-index.c:222
msgid " OK"
@@ -22135,19 +22134,19 @@ msgstr "afegeix l'entrada especificada a l'índex"
#: builtin/update-index.c:1008
msgid "mark files as \"not changing\""
-msgstr "marca els fitxers com a \"no canviant\""
+msgstr "marca els fitxers com a «no canviant»"
#: builtin/update-index.c:1011
msgid "clear assumed-unchanged bit"
-msgstr "neteja el bit assumed-unchanged"
+msgstr "esborra el bit assumed-unchanged"
#: builtin/update-index.c:1014
msgid "mark files as \"index-only\""
-msgstr "marca els fitxers com a \"només índex\""
+msgstr "marca els fitxers com a «només índex»"
#: builtin/update-index.c:1017
msgid "clear skip-worktree bit"
-msgstr "neteja el bit skip-worktree"
+msgstr "esborra el bit skip-worktree"
#: builtin/update-index.c:1020
#, fuzzy
@@ -22233,7 +22232,7 @@ msgstr "marca els fitxers com a vàlids pel fsmonitor"
#: builtin/update-index.c:1070
msgid "clear fsmonitor valid bit"
-msgstr "neteja el bit de validesa del fsmonitor"
+msgstr "esborra el bit de validesa del fsmonitor"
#: builtin/update-index.c:1173
msgid ""
@@ -22320,7 +22319,7 @@ msgstr "actualitza <nom de referència>, no la que apunti"
#: builtin/update-ref.c:490
msgid "stdin has NUL-terminated arguments"
-msgstr "stdin té paràmetres acabats amb NUL"
+msgstr "stdin té arguments acabats amb NUL"
#: builtin/update-ref.c:491
msgid "read updates from stdin"
@@ -22389,7 +22388,7 @@ msgstr "imprimeix els continguts de l'etiqueta"
#: builtin/worktree.c:17
msgid "git worktree add [<options>] <path> [<commit-ish>]"
-msgstr "git worktree add [<opcions>] <camí> [<commit-ish>"
+msgstr "git worktree add [<opcions>] <camí> [<commit-ish>]"
#: builtin/worktree.c:18
msgid "git worktree list [<options>]"
@@ -22409,7 +22408,7 @@ msgstr "git worktree prune [<opcions>]"
#: builtin/worktree.c:22
msgid "git worktree remove [<options>] <worktree>"
-msgstr "git worktree lock [<opcions>] <arbre de treball>"
+msgstr "git worktree remove [<opcions>] <arbre de treball>"
#: builtin/worktree.c:23
msgid "git worktree unlock <path>"
@@ -22441,8 +22440,8 @@ msgid ""
"Removing worktrees/%s: short read (expected %<PRIuMAX> bytes, read "
"%<PRIuMAX>)"
msgstr ""
-"S'estan suprimint els arbres de treball/%s: lectura curta (s'esperaven "
-"%<PRIuMAX> bytes, llegits %<PRIuMAX>)"
+"S'estan eliminant els arbres de treball/%s: lectura curta (s'esperaven "
+"%<PRIuMAX> bytes, se n'han llegit %<PRIuMAX>)"
#: builtin/worktree.c:117
#, c-format
@@ -22589,7 +22588,7 @@ msgstr "«%s» no està bloquejat"
#: builtin/worktree.c:766
msgid "working trees containing submodules cannot be moved or removed"
msgstr ""
-"els arbres de treball que contenen submòduls no es poden moure o suprimir"
+"els arbres de treball que contenen submòduls no es poden moure ni eliminar"
#: builtin/worktree.c:774
msgid "force move even if worktree is dirty or locked"
@@ -22658,7 +22657,7 @@ msgstr "no s'ha pogut executar «git status» a «%s», codi %d"
#: builtin/worktree.c:906
msgid "force removal even if worktree is dirty or locked"
msgstr ""
-"força la supressió encara que l'arbre de treball estigui brut o bloquejat"
+"força l'eliminació encara que l'arbre de treball estigui brut o bloquejat"
#: builtin/worktree.c:929
#, fuzzy, c-format
@@ -22834,7 +22833,7 @@ msgstr "la comissió %s no està marcada com abastable"
#: t/helper/test-reach.c:162
msgid "too many commits marked reachable"
-msgstr "masses comission marcades com abastable"
+msgstr "hi ha massa comissions marcades com abastables"
#: t/helper/test-serve-v2.c:7
msgid "test-tool serve-v2 [<options>]"
@@ -22911,12 +22910,12 @@ msgid "while expanding alias '%s': '%s'"
msgstr "en expandir l'àlies '%s' '%s'"
#: git.c:371
-#, fuzzy, c-format
+#, c-format
msgid ""
"alias '%s' changes environment variables.\n"
"You can use '!git' in the alias to do this"
msgstr ""
-"àlies '%s' canvia variables d'entorn. Podeu utilitzar '!git' a l'àlies per "
+"àlies «%s» canvia variables d'entorn. Podeu utilitzar «!git» a l'àlies per a "
"fer-ho"
#: git.c:378
@@ -22981,7 +22980,7 @@ msgstr "No s'admet el control de delegació amb el cURL < 7.22.0"
#: http.c:429
msgid "Public key pinning not supported with cURL < 7.44.0"
-msgstr "No s'admet l'enganx de clau pública amb cURL < 7.44.0"
+msgstr "No s'admet la fixació de clau pública amb cURL < 7.44.0"
#: http.c:914
#, fuzzy
@@ -23156,7 +23155,7 @@ msgstr "mostra la informació de branca"
#: list-objects-filter-options.h:85
msgid "args"
-msgstr "args"
+msgstr "arguments"
#: list-objects-filter-options.h:86
msgid "object filtering"
@@ -23210,7 +23209,7 @@ msgstr "nom del camp en el qual ordenar"
#: rerere.h:44
msgid "update the index with reused conflict resolution if possible"
msgstr ""
-"actualitza l'índex amb la resolució de conflicte reusada si és possible"
+"actualitza l'índex amb la resolució de conflictes reusada si és possible"
#: wt-status.h:80
msgid "HEAD detached at "
@@ -23311,7 +23310,7 @@ msgstr "Alternativa gràfica a git-commit"
#: command-list.h:71
msgid "Remove untracked files from the working tree"
-msgstr "Suprimeix els fitxers no seguits de l'arbre de treball"
+msgstr "Elimina els fitxers no seguits de l'arbre de treball"
#: command-list.h:72
msgid "Clone a repository into a new directory"
@@ -23561,7 +23560,7 @@ msgstr "El programa d'ajuda estàndard a utilitzar amb git-merge-index"
#: command-list.h:127
msgid "Run merge conflict resolution tools to resolve merge conflicts"
msgstr ""
-"Executa eines de resolució de conflictes per a resoldre conflictes de fussió"
+"Executa eines de resolució de conflictes per a resoldre conflictes de fusió"
#: command-list.h:128
#, fuzzy
@@ -23620,16 +23619,15 @@ msgstr "Rutines per ajudar a analitzar els paràmetres d'accés al dipòsit remo
#: command-list.h:140
msgid "Compute unique ID for a patch"
-msgstr "Calcula un identificador única per a cada pedaç"
+msgstr "Calcula un identificador únic per a cada pedaç"
#: command-list.h:141
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:142
-#, fuzzy
msgid "Remove extra objects that are already in pack files"
-msgstr "Elimina els objectes extres que ja estan en fitxers de paquet"
+msgstr "Elimina els objectes extres que ja estan en fitxers empaquetats"
#: command-list.h:143
msgid "Fetch from and integrate with another repository or a local branch"
@@ -23652,7 +23650,6 @@ msgstr ""
"Compara dos intervals de comissions (p. ex. dues versions d'una branca)"
#: command-list.h:147
-#, fuzzy
msgid "Reads tree information into the index"
msgstr "Llegeix la informació de l'arbre a l'índex"
@@ -23666,19 +23663,16 @@ msgid "Receive what is pushed into the repository"
msgstr "Rep el que s'envia al repositori"
#: command-list.h:150
-#, fuzzy
msgid "Manage reflog information"
msgstr "Gestiona la informació del registre de referències"
#: command-list.h:151
-#, fuzzy
msgid "Manage set of tracked repositories"
-msgstr "Gestiona el conjunt de repositoris seguits"
+msgstr "Gestiona el conjunt de dipòsits seguits"
#: command-list.h:152
-#, fuzzy
msgid "Pack unpacked objects in a repository"
-msgstr "Empaqueta els objectes desempaquetats en un repositori"
+msgstr "Empaqueta els objectes desempaquetats en un dipòsit"
#: command-list.h:153
#, fuzzy
@@ -23686,14 +23680,12 @@ msgid "Create, list, delete refs to replace objects"
msgstr "Crea una llista suprimeix les referències per substituir els objectes"
#: command-list.h:154
-#, fuzzy
msgid "Generates a summary of pending changes"
msgstr "Genera un resum dels canvis pendents"
#: command-list.h:155
-#, fuzzy
msgid "Reuse recorded resolution of conflicted merges"
-msgstr "Reutilitza la resolució registrada dels fusionats en conflicte"
+msgstr "Reutilitza la resolució registrada dels conflictes de fusió"
#: command-list.h:156
msgid "Reset current HEAD to the specified state"
@@ -23713,7 +23705,7 @@ msgstr "Mostra les comissions en ordre topològic invers"
#: command-list.h:160
msgid "Pick out and massage parameters"
-msgstr "Escolliu i personalitzeu els paràmetres"
+msgstr "Trieu i personalitzeu els paràmetres"
#: command-list.h:161
msgid "Remove files from the working tree and from the index"
@@ -23728,9 +23720,8 @@ msgid "Push objects over Git protocol to another repository"
msgstr "Puja objectes sobre el protocol Git a un altre dipòsit"
#: command-list.h:164
-#, fuzzy
msgid "Restricted login shell for Git-only SSH access"
-msgstr "Intèrpret d'ordres d'entrada restringit per a accés SSH només al Git"
+msgstr "Intèrpret d'ordres d'entrada restringit només per a accés SSH al Git"
#: command-list.h:165
msgid "Summarize 'git log' output"
@@ -23753,7 +23744,6 @@ msgid "List references in a local repository"
msgstr "Llista les referències en un dipòsit local"
#: command-list.h:170
-#, fuzzy
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"
@@ -23773,9 +23763,8 @@ msgid "Stash the changes in a dirty working directory away"
msgstr "Desa els canvis en un directori de treball brut"
#: command-list.h:174
-#, fuzzy
msgid "Add file contents to the staging area"
-msgstr "Afegeix el contingut del fitxer a l'àrea de proves"
+msgstr "Afegeix el contingut del fitxer a l'àrea de «staging»"
#: command-list.h:175
msgid "Show the working tree status"
@@ -23783,7 +23772,7 @@ msgstr "Mostra l'estat de l'arbre de treball"
#: command-list.h:176
msgid "Remove unnecessary whitespace"
-msgstr "Suprimeix l'espai en blanc innecessari"
+msgstr "Elimina l'espai en blanc innecessari"
#: command-list.h:177
msgid "Initialize, update or inspect submodules"
@@ -23824,10 +23813,8 @@ msgstr ""
"Actualitza el nom de l'objecte emmagatzema en una referència de forma segura"
#: command-list.h:186
-#, fuzzy
msgid "Update auxiliary info file to help dumb servers"
-msgstr ""
-"Actualitza el fitxer d'informació auxiliar per ajudar als servidors ximples"
+msgstr "Actualitza el fitxer d'informació auxiliar per a ajudar als servidors ximples"
#: command-list.h:187
msgid "Send archive back to git-archive"
@@ -23886,7 +23873,6 @@ msgid "Git for CVS users"
msgstr "Git per a usuaris del CVS"
#: command-list.h:201
-#, fuzzy
msgid "Tweaking diff output"
msgstr "Ajustament de la sortida de diferències"
@@ -23944,7 +23930,7 @@ msgstr "Una visió de conjunt de fluxos de treball recomanats amb Git"
#: git-bisect.sh:54
msgid "You need to start by \"git bisect start\""
-msgstr "Cal començar per \"git bisect start\""
+msgstr "Cal començar per «git bisect start»"
#. TRANSLATORS: Make sure to include [Y] and [n] in your
#. translation. The program will only accept English input
@@ -23971,7 +23957,7 @@ msgstr "Introducció de revisió errònia: $rev"
#: git-bisect.sh:139
#, sh-format
msgid "'git bisect $TERM_BAD' can take only one argument."
-msgstr "'git bisect $TERM_BAD' pot acceptar només un paràmetre."
+msgstr "«git bisect $TERM_BAD» pot acceptar només un argument."
#: git-bisect.sh:209
msgid "No logfile given"
@@ -24002,7 +23988,7 @@ msgid ""
"exit code $res from '$command' is < 0 or >= 128"
msgstr ""
"el pas de bisecció ha fallat:\n"
-"el codi de sortida $res de '$command' és < 0 o >= 128"
+"el codi de sortida $res de «$command» és < 0 o bé >= 128"
#: git-bisect.sh:281
msgid "bisect run cannot continue any more"
@@ -24015,7 +24001,7 @@ msgid ""
"'bisect_state $state' exited with error code $res"
msgstr ""
"el pas de bisecció ha fallat:\n"
-"'bisect_state $state' ha sortit amb el codi d'error $res"
+"«bisect_state $state» ha sortit amb el codi d'error $res"
#: git-bisect.sh:294
msgid "bisect run success"
@@ -24088,25 +24074,25 @@ msgid "'$sm_path' already exists in the index and is not a submodule"
msgstr "«$sm_path» ja existeix en l'índex i no és submòdul"
#: git-submodule.sh:244
-#, fuzzy, sh-format
+#, sh-format
msgid "'$sm_path' does not have a commit checked out"
-msgstr "«sm_path» no té una comissió marcada"
+msgstr "«$sm_path» no té una comissió agafada"
#: git-submodule.sh:275
#, sh-format
msgid "Adding existing repo at '$sm_path' to the index"
-msgstr "S'està afegint el dipòsit existent a '$sm_path' a l'índex"
+msgstr "S'està afegint el dipòsit existent a «$sm_path» a l'índex"
#: git-submodule.sh:277
#, sh-format
msgid "'$sm_path' already exists and is not a valid git repo"
-msgstr "'$sm_path' ja existeix i no és un dipòsit de git vàlid"
+msgstr "«$sm_path» ja existeix i no és un dipòsit de git vàlid"
#: git-submodule.sh:285
#, sh-format
msgid "A git directory for '$sm_name' is found locally with remote(s):"
msgstr ""
-"Es troba un directori de git per a '$sm_name' localment amb els remots:"
+"S'ha trobat un directori de git per a «$sm_name» localment amb els remots:"
#: git-submodule.sh:287
#, sh-format
@@ -24122,8 +24108,8 @@ msgstr ""
" $realrepo\n"
"useu l'opció «--force». Si el directori de git local no és el dipòsit "
"correcte\n"
-"o no esteu segur de què vol dir això, trieu un altre nom amb l'opció '--"
-"name'."
+"o no esteu segur de què vol dir això, trieu un altre nom amb l'opció «--"
+"name»."
#: git-submodule.sh:293
#, sh-format
@@ -24164,7 +24150,7 @@ msgid ""
"'$sm_path'"
msgstr ""
"No s'ha pogut trobar la revisió actual de ${remote_name}/${branch} en el "
-"camí de submòdul '$sm_path'"
+"camí de submòdul «$sm_path»"
#: git-submodule.sh:625
#, sh-format
@@ -24198,7 +24184,7 @@ msgstr "Camí de submòdul «$displaypath»: s'ha agafat «$sha1»"
#, sh-format
msgid "Unable to rebase '$sha1' in submodule path '$displaypath'"
msgstr ""
-"No s'ha pogut fer «rebase» «$sha1»' en el camí de submòdul «$displaypath»"
+"No s'ha pogut fer «rebase» «$sha1» en el camí de submòdul «$displaypath»"
#: git-submodule.sh:644
#, sh-format
@@ -24261,7 +24247,7 @@ msgstr " Avís: $display_name no conté les comissions $sha1_src i $sha1_dst"
#: git-parse-remote.sh:89
#, sh-format
msgid "See git-${cmd}(1) for details."
-msgstr "Vegeu git-${cmd}(1) per detalls."
+msgstr "Vegeu git-${cmd}(1) per a més informació."
#: git-rebase--preserve-merges.sh:109
msgid "Applied autostash."
@@ -24280,7 +24266,7 @@ msgid ""
msgstr ""
"L'aplicació del «stash» automàtic ha resultat en conflictes.\n"
"Els vostres canvis estan segurs en el «stash».\n"
-"Podeu executar \"git stash pop\" o \"git stash drop\" en qualsevol moment.\n"
+"Podeu executar «git stash pop» o «git stash drop» en qualsevol moment.\n"
#: git-rebase--preserve-merges.sh:191
#, sh-format
@@ -24288,7 +24274,6 @@ msgid "Rebasing ($new_count/$total)"
msgstr "S'està fent «rebase» ($new_count/$total)"
#: git-rebase--preserve-merges.sh:207
-#, fuzzy
msgid ""
"\n"
"Commands:\n"
@@ -24308,8 +24293,25 @@ msgid ""
"\n"
"These lines can be re-ordered; they are executed from top to bottom.\n"
msgstr ""
-"Les ordres p select <commit> = fa servir «commit» o «commit» o "
-"«commit» (commit) o «commit» (commit)"
+"\n"
+"Ordres:\n"
+" p, pick <comissió> = usa la comissió\n"
+" r, reword <comissió> = usa la comissió, però edita el missatge de comissió\n"
+" e, edit <comissió> = usa la comissió, però atura't per a esmenar\n"
+" s, squash <comissió> = usa la comissió, però fusiona-la a la comissió prèvia\n"
+" f, fixup <comissió> = com a «squash», però descarta el missatge de registre d'aquesta "
+"comissió\n"
+"x, exec <comissió> = executa l'ordre (la resta de la línia) usant l'intèrpret "
+"d'ordres\n"
+"d, drop <comissió> = elimina la comissió\n"
+"l, label <etiqueta> = etiqueta la HEAD actual amb un nom\n"
+"t, reset <etiqueta> = reinicia HEAD a una etiqueta \n"
+"m, merge [-C <comissió> | -c <comissió>] <etiqueta> [# <oneline>]\n"
+". crea una comissió de fusió usant el missatge de la comissió\n"
+". de fusió original (o línia única, si no hi ha cap comissió de fusió original\n"
+". especificada). Useu -c <comissió> per a reescriure el missatge de publicació.\n"
+"\n"
+"Es pot canviar l'ordre d'aquestes línies; s'executen de dalt a baix.\n"
#: git-rebase--preserve-merges.sh:270
#, sh-format
@@ -24333,7 +24335,7 @@ msgstr ""
#: git-rebase--preserve-merges.sh:295
#, sh-format
msgid "$sha1: not a commit that can be picked"
-msgstr "$sha1: no és una comissió que es pugui escollir"
+msgstr "$sha1: no és una comissió que es pugui triar"
#: git-rebase--preserve-merges.sh:334
#, sh-format
@@ -24372,7 +24374,7 @@ msgstr "Error en refer la fusió $sha1"
#: git-rebase--preserve-merges.sh:458
#, sh-format
msgid "Could not pick $sha1"
-msgstr "No s'ha pogut escollir $sha1"
+msgstr "No s'ha pogut triar $sha1"
#: git-rebase--preserve-merges.sh:467
#, sh-format
@@ -24388,7 +24390,7 @@ msgstr "El missatge de comissió núm. ${n} s'ometrà:"
#, sh-format
msgid "This is a combination of $count commit."
msgid_plural "This is a combination of $count commits."
-msgstr[0] "Això és una combinació de $count comissió."
+msgstr[0] "Això és una combinació d'$count comissió."
msgstr[1] "Això és una combinació de $count comissions."
#: git-rebase--preserve-merges.sh:492
@@ -24415,7 +24417,7 @@ msgid ""
"before\n"
"you are able to reword the commit."
msgstr ""
-"No s'ha pogut esmenar la comissió després d'escollir amb èxit $sha1... "
+"No s'ha pogut esmenar la comissió després de triar correctament $sha1... "
"$rest\n"
"Això és probablement a causa d'un missatge de comissió buit, o el lligam de\n"
"precomissió ha fallat. Si el lligam de precomissió ha fallat, pot ser que\n"
@@ -24430,7 +24432,7 @@ msgstr "S'ha aturat a $sha1_abbrev... $rest"
#: git-rebase--preserve-merges.sh:641
#, sh-format
msgid "Cannot '$squash_style' without a previous commit"
-msgstr "No es pot '$squash_style' sense una comissió prèvia"
+msgstr "No es pot fer «$squash_style» sense una comissió prèvia"
#: git-rebase--preserve-merges.sh:683
#, sh-format
@@ -24706,9 +24708,9 @@ msgid ""
"Lines starting with %s will be removed.\n"
msgstr ""
"---\n"
-"Per suprimir «%s» línies, feu-les línies ' ' (context).\n"
-"Per suprimir «%s» línies, suprimiu-les.\n"
-"Les línies que comencin per %s seran suprimides.\n"
+"Per a eliminar les línies «%s», convertiu-les en línies ' ' (context).\n"
+"Per a eliminar les línies «%s», suprimiu-les.\n"
+"Les línies que comencin per %s s'eliminaran.\n"
#: git-add--interactive.perl:1140
#, perl-format
@@ -24984,7 +24986,7 @@ msgstr "«%s» conté una versió intermèdia del correu que estàveu redactant.
#: git-send-email.perl:315
#, perl-format
msgid "'%s.final' contains the composed email.\n"
-msgstr "'%s.final' conté el correu redactat.\n"
+msgstr "«%s.final» conté el correu redactat.\n"
#: git-send-email.perl:408
msgid "--dump-aliases incompatible with other options\n"
@@ -25011,22 +25013,22 @@ msgstr "Camp --suppress-cc desconegut: «%s»\n"
#: git-send-email.perl:528
#, perl-format
msgid "Unknown --confirm setting: '%s'\n"
-msgstr "--confirm setting desconegut: «%s»\n"
+msgstr "Paràmetre --confirm desconegut: «%s»\n"
#: git-send-email.perl:556
#, perl-format
msgid "warning: sendmail alias with quotes is not supported: %s\n"
-msgstr "avís: el sobrenom de sendmail amb cometes no està suportat: %s\n"
+msgstr "avís: no s'admet l'àlies de sendmail amb cometes: %s\n"
#: git-send-email.perl:558
#, perl-format
msgid "warning: `:include:` not supported: %s\n"
-msgstr "avís: `:include:` no està suportat: %s\n"
+msgstr "avís: «:include:» no s'admet: %s\n"
#: git-send-email.perl:560
#, perl-format
msgid "warning: `/file` or `|pipe` redirection not supported: %s\n"
-msgstr "avís: les redireccions `/file` or `|pipe no són admeses: %s\n"
+msgstr "avís: les redireccions «/file» ni «|pipe» no s'admeten: %s\n"
#: git-send-email.perl:565
#, perl-format
@@ -25042,11 +25044,11 @@ msgid ""
" * Saying \"./%s\" if you mean a file; or\n"
" * Giving --format-patch option if you mean a range.\n"
msgstr ""
-"El fitxer «%s» existeix però també pot ser un rang de comissions\n"
-"per produir pedaços. Desambigüeu...\n"
+"El fitxer «%s» existeix, però també pot ser un rang de comissions\n"
+"per produir pedaços. Desambigüeu-ho...\n"
"\n"
-" * Dient \"./%s\" si volíeu especificar aquest fitxer; o\n"
-" * Proporcionant l'opció --format-patch si volíeu especificar un rang.\n"
+" * 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:670
#, perl-format
@@ -25090,11 +25092,11 @@ msgid ""
"\n"
"Clear the body content if you don't wish to send a summary.\n"
msgstr ""
-"Se suprimiran les línies que comencen amb \"GIT:\".\n"
+"S'eliminaran les línies que comencen amb «GIT:».\n"
"Considereu incloure un diffstat global o una taula de continguts\n"
-"per cada pedaç que esteu escrivint.\n"
+"per al pedaç que esteu escrivint.\n"
"\n"
-"Netegeu el contingut del cos si no voleu enviar un resum.\n"
+"Esborreu el contingut del cos si no voleu enviar cap resum.\n"
#: git-send-email.perl:763
#, perl-format
@@ -25138,8 +25140,8 @@ msgid ""
msgstr ""
"S'ha refusat a enviar perquè el pedaç\n"
"\t%s\n"
-"perquè la plantilla té l'assumpte '*** SUBJECT HERE ***'. Passeu --force si "
-"realment voleu enviar-lo.\n"
+"perquè la plantilla té l'assumpte «*** SUBJECT HERE ***». Passeu --force si "
+"realment voleu enviar-ho.\n"
#: git-send-email.perl:945
msgid "To whom should the emails be sent (if anyone)?"
@@ -25193,9 +25195,9 @@ msgstr ""
" Aquest comportament està controlat pel paràmetre de configuració\n"
" sendemail.confirm.\n"
"\n"
-" Per a informació addicional, executeu 'git send-email --help'.\n"
+" Per a informació addicional, executeu «git send-email --help».\n"
" Per mantenir el comportament actual, però silenciar aquest\n"
-" missatge, executeu 'git config --global sendemail.confirm auto'.\n"
+" missatge, executeu «git config --global sendemail.confirm auto».\n"
"\n"
#. TRANSLATORS: Make sure to include [y] [n] [e] [q] [a] in your
@@ -25298,7 +25300,7 @@ msgstr "(%s) S'està afegint %s: %s des de: «%s»\n"
#: git-send-email.perl:1875
#, perl-format
-msgid "(%s) failed to close pipe to '%s'"
+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:1905
diff --git a/po/de.po b/po/de.po
index 6356276..656de24 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: 2020-05-27 07:23+0800\n"
-"PO-Revision-Date: 2020-05-24 15:57+0100\n"
+"POT-Creation-Date: 2020-07-10 09:53+0800\n"
+"PO-Revision-Date: 2020-07-12 13:20+0100\n"
"Last-Translator: Matthias Rüster <matthias.ruester@gmail.com>\n"
"Language-Team: Matthias Rüster <matthias.ruester@gmail.com>\n"
"Language: de\n"
@@ -111,21 +111,21 @@ msgstr[1] "%d Pfade hinzugefügt\n"
msgid "ignoring unmerged: %s"
msgstr "Ignoriere nicht zusammengeführte Datei: %s"
-#: add-interactive.c:929 add-patch.c:1675 git-add--interactive.perl:1366
+#: add-interactive.c:929 add-patch.c:1691 git-add--interactive.perl:1368
#, c-format
msgid "Only binary files changed.\n"
msgstr "Nur Binärdateien geändert.\n"
-#: add-interactive.c:931 add-patch.c:1673 git-add--interactive.perl:1368
+#: add-interactive.c:931 add-patch.c:1689 git-add--interactive.perl:1370
#, c-format
msgid "No changes.\n"
msgstr "Keine Änderungen.\n"
-#: add-interactive.c:935 git-add--interactive.perl:1376
+#: add-interactive.c:935 git-add--interactive.perl:1378
msgid "Patch update"
msgstr "Patch Aktualisierung"
-#: add-interactive.c:974 git-add--interactive.perl:1754
+#: add-interactive.c:974 git-add--interactive.perl:1771
msgid "Review diff"
msgstr "Diff überprüfen"
@@ -193,11 +193,11 @@ msgstr "Ein nummeriertes Element auswählen"
msgid "(empty) select nothing"
msgstr "(leer) nichts auswählen"
-#: add-interactive.c:1083 builtin/clean.c:816 git-add--interactive.perl:1851
+#: add-interactive.c:1083 builtin/clean.c:816 git-add--interactive.perl:1868
msgid "*** Commands ***"
msgstr "*** Befehle ***"
-#: add-interactive.c:1084 builtin/clean.c:817 git-add--interactive.perl:1848
+#: add-interactive.c:1084 builtin/clean.c:817 git-add--interactive.perl:1865
msgid "What now"
msgstr "Was nun"
@@ -214,7 +214,7 @@ msgstr "aus Staging-Area entfernt"
#: builtin/merge.c:276 builtin/pull.c:190 builtin/submodule--helper.c:409
#: builtin/submodule--helper.c:1394 builtin/submodule--helper.c:1397
#: builtin/submodule--helper.c:1902 builtin/submodule--helper.c:1905
-#: builtin/submodule--helper.c:2148 bugreport.c:129
+#: builtin/submodule--helper.c:2148 bugreport.c:135
#: git-add--interactive.perl:213
msgid "path"
msgstr "Pfad"
@@ -223,27 +223,32 @@ msgstr "Pfad"
msgid "could not refresh index"
msgstr "Index konnte nicht aktualisiert werden"
-#: add-interactive.c:1157 builtin/clean.c:781 git-add--interactive.perl:1765
+#: add-interactive.c:1157 builtin/clean.c:781 git-add--interactive.perl:1782
#, c-format
msgid "Bye.\n"
msgstr "Tschüss.\n"
-#: add-patch.c:34 git-add--interactive.perl:1428
+#: add-patch.c:34 git-add--interactive.perl:1430
#, c-format, perl-format
msgid "Stage mode change [y,n,q,a,d%s,?]? "
msgstr "Modusänderung der Staging-Area hinzufügen [y,n,q,a,d%s,?]? "
-#: add-patch.c:35 git-add--interactive.perl:1429
+#: add-patch.c:35 git-add--interactive.perl:1431
#, c-format, perl-format
msgid "Stage deletion [y,n,q,a,d%s,?]? "
msgstr "Löschung der Staging-Area hinzufügen [y,n,q,a,d%s,?]? "
-#: add-patch.c:36 git-add--interactive.perl:1430
+#: add-patch.c:36 git-add--interactive.perl:1432
+#, c-format, perl-format
+msgid "Stage addition [y,n,q,a,d%s,?]? "
+msgstr "Ergänzung der Staging-Area hinzufügen [y,n,q,a,d%s,?]? "
+
+#: add-patch.c:37 git-add--interactive.perl:1433
#, c-format, perl-format
msgid "Stage this hunk [y,n,q,a,d%s,?]? "
msgstr "Diesen Patch-Block der Staging-Area hinzufügen [y,n,q,a,d%s,?]? "
-#: add-patch.c:38
+#: add-patch.c:39
msgid ""
"If the patch applies cleanly, the edited hunk will immediately be marked for "
"staging."
@@ -251,7 +256,7 @@ msgstr ""
"Wenn der Patch sauber angewendet werden kann, wird der bearbeitete Patch-"
"Block direkt für die Staging-Area markiert."
-#: add-patch.c:41
+#: add-patch.c:42
msgid ""
"y - stage this hunk\n"
"n - do not stage this hunk\n"
@@ -267,22 +272,27 @@ msgstr ""
"d - diesen oder alle weiteren Patch-Blöcke in dieser Datei nicht zum Commit "
"vormerken\n"
-#: add-patch.c:55 git-add--interactive.perl:1433
+#: add-patch.c:56 git-add--interactive.perl:1436
#, c-format, perl-format
msgid "Stash mode change [y,n,q,a,d%s,?]? "
msgstr "Modusänderung stashen [y,n,q,a,d%s,?]? "
-#: add-patch.c:56 git-add--interactive.perl:1434
+#: add-patch.c:57 git-add--interactive.perl:1437
#, c-format, perl-format
msgid "Stash deletion [y,n,q,a,d%s,?]? "
msgstr "Löschung stashen [y,n,q,a,d%s,?]? "
-#: add-patch.c:57 git-add--interactive.perl:1435
+#: add-patch.c:58 git-add--interactive.perl:1438
+#, c-format, perl-format
+msgid "Stash addition [y,n,q,a,d%s,?]? "
+msgstr "Ergänzung stashen [y,n,q,a,d%s,?]? "
+
+#: add-patch.c:59 git-add--interactive.perl:1439
#, c-format, perl-format
msgid "Stash this hunk [y,n,q,a,d%s,?]? "
msgstr "Diesen Patch-Block stashen [y,n,q,a,d%s,?]? "
-#: add-patch.c:59
+#: add-patch.c:61
msgid ""
"If the patch applies cleanly, the edited hunk will immediately be marked for "
"stashing."
@@ -290,7 +300,7 @@ msgstr ""
"Wenn der Patch sauber angewendet werden kann, wird der bearbeitete Patch-"
"Block direkt zum Stashen markiert."
-#: add-patch.c:62
+#: add-patch.c:64
msgid ""
"y - stash this hunk\n"
"n - do not stash this hunk\n"
@@ -304,22 +314,27 @@ msgstr ""
"a - diesen und alle weiteren Patch-Blöcke dieser Datei stashen\n"
"d - diesen oder alle weiteren Patch-Blöcke dieser Datei nicht stashen\n"
-#: add-patch.c:78 git-add--interactive.perl:1438
+#: add-patch.c:80 git-add--interactive.perl:1442
#, c-format, perl-format
msgid "Unstage mode change [y,n,q,a,d%s,?]? "
msgstr "Modusänderung aus der Staging-Area entfernen [y,n,q,a,d%s,?]? "
-#: add-patch.c:79 git-add--interactive.perl:1439
+#: add-patch.c:81 git-add--interactive.perl:1443
#, c-format, perl-format
msgid "Unstage deletion [y,n,q,a,d%s,?]? "
msgstr "Löschung aus der Staging-Area entfernen [y,n,q,a,d%s,?]? "
-#: add-patch.c:80 git-add--interactive.perl:1440
+#: add-patch.c:82 git-add--interactive.perl:1444
+#, c-format, perl-format
+msgid "Unstage addition [y,n,q,a,d%s,?]? "
+msgstr "Ergänzung aus der Staging-Area entfernen [y,n,q,a,d%s,?]? "
+
+#: add-patch.c:83 git-add--interactive.perl:1445
#, c-format, perl-format
msgid "Unstage this hunk [y,n,q,a,d%s,?]? "
msgstr "Diesen Patch-Block aus der Staging-Area entfernen [y,n,q,a,d%s,?]? "
-#: add-patch.c:82
+#: add-patch.c:85
msgid ""
"If the patch applies cleanly, the edited hunk will immediately be marked for "
"unstaging."
@@ -327,7 +342,7 @@ msgstr ""
"Wenn der Patch sauber angewendet werden kann, wird der bearbeitete Patch-"
"Block direkt zum Entfernen aus der Staging-Area markiert."
-#: add-patch.c:85
+#: add-patch.c:88
msgid ""
"y - unstage this hunk\n"
"n - do not unstage this hunk\n"
@@ -344,22 +359,27 @@ msgstr ""
"d - diesen oder alle weiteren Patch-Blöcke dieser Datei nicht aus Staging-"
"Area entfernen\n"
-#: add-patch.c:100 git-add--interactive.perl:1443
+#: add-patch.c:103 git-add--interactive.perl:1448
#, c-format, perl-format
msgid "Apply mode change to index [y,n,q,a,d%s,?]? "
msgstr "Modusänderung auf Index anwenden [y,n,q,a,d%s,?]? "
-#: add-patch.c:101 git-add--interactive.perl:1444
+#: add-patch.c:104 git-add--interactive.perl:1449
#, c-format, perl-format
msgid "Apply deletion to index [y,n,q,a,d%s,?]? "
msgstr "Löschung auf Index anwenden [y,n,q,a,d%s,?]? "
-#: add-patch.c:102 git-add--interactive.perl:1445
+#: add-patch.c:105 git-add--interactive.perl:1450
+#, c-format, perl-format
+msgid "Apply addition to index [y,n,q,a,d%s,?]? "
+msgstr "Ergänzung auf Index anwenden [y,n,q,a,d%s,?]? "
+
+#: add-patch.c:106 git-add--interactive.perl:1451
#, c-format, perl-format
msgid "Apply this hunk to index [y,n,q,a,d%s,?]? "
msgstr "Diesen Patch-Block auf Index anwenden [y,n,q,a,d%s,?]? "
-#: add-patch.c:104 add-patch.c:169 add-patch.c:212
+#: add-patch.c:108 add-patch.c:176 add-patch.c:221
msgid ""
"If the patch applies cleanly, the edited hunk will immediately be marked for "
"applying."
@@ -367,7 +387,7 @@ msgstr ""
"Wenn der Patch sauber angewendet werden kann, wird der bearbeitete Patch-"
"Block direkt zum Anwenden markiert."
-#: add-patch.c:107
+#: add-patch.c:111
msgid ""
"y - apply this hunk to index\n"
"n - do not apply this hunk to index\n"
@@ -384,25 +404,31 @@ msgstr ""
"d - diesen oder alle weiteren Patch-Blöcke dieser Datei nicht auf den Index "
"anwenden\n"
-#: add-patch.c:122 git-add--interactive.perl:1448
-#: git-add--interactive.perl:1463
+#: add-patch.c:126 git-add--interactive.perl:1454
+#: git-add--interactive.perl:1472
#, c-format, perl-format
msgid "Discard mode change from worktree [y,n,q,a,d%s,?]? "
msgstr "Modusänderung im Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? "
-#: add-patch.c:123 git-add--interactive.perl:1449
-#: git-add--interactive.perl:1464
+#: add-patch.c:127 git-add--interactive.perl:1455
+#: git-add--interactive.perl:1473
#, c-format, perl-format
msgid "Discard deletion from worktree [y,n,q,a,d%s,?]? "
msgstr "Löschung im Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? "
-#: add-patch.c:124 git-add--interactive.perl:1450
-#: git-add--interactive.perl:1465
+#: add-patch.c:128 git-add--interactive.perl:1456
+#: git-add--interactive.perl:1474
+#, c-format, perl-format
+msgid "Discard addition from worktree [y,n,q,a,d%s,?]? "
+msgstr "Ergänzung im Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? "
+
+#: add-patch.c:129 git-add--interactive.perl:1457
+#: git-add--interactive.perl:1475
#, c-format, perl-format
msgid "Discard this hunk from worktree [y,n,q,a,d%s,?]? "
msgstr "Diesen Patch-Block im Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? "
-#: add-patch.c:126 add-patch.c:148 add-patch.c:191
+#: add-patch.c:131 add-patch.c:154 add-patch.c:199
msgid ""
"If the patch applies cleanly, the edited hunk will immediately be marked for "
"discarding."
@@ -410,7 +436,7 @@ msgstr ""
"Wenn der Patch sauber angewendet werden kann, wird der bearbeitete Patch-"
"Block direkt zum Verwerfen markiert."
-#: add-patch.c:129 add-patch.c:194
+#: add-patch.c:134 add-patch.c:202
msgid ""
"y - discard this hunk from worktree\n"
"n - do not discard this hunk from worktree\n"
@@ -427,25 +453,30 @@ msgstr ""
"d - diesen oder alle weiteren Patch-Blöcke dieser Datei nicht im "
"Arbeitsverzeichnis verwerfen\n"
-#: add-patch.c:144 add-patch.c:187 git-add--interactive.perl:1453
+#: add-patch.c:149 add-patch.c:194 git-add--interactive.perl:1460
#, c-format, perl-format
msgid "Discard mode change from index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Modusänderung vom Index und Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? "
-#: add-patch.c:145 add-patch.c:188 git-add--interactive.perl:1454
+#: add-patch.c:150 add-patch.c:195 git-add--interactive.perl:1461
#, c-format, perl-format
msgid "Discard deletion from index and worktree [y,n,q,a,d%s,?]? "
msgstr "Löschung vom Index und Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? "
-#: add-patch.c:146 add-patch.c:189 git-add--interactive.perl:1455
+#: add-patch.c:151 add-patch.c:196 git-add--interactive.perl:1462
+#, c-format, perl-format
+msgid "Discard addition from index and worktree [y,n,q,a,d%s,?]? "
+msgstr "Ergänzung im Index und Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? "
+
+#: add-patch.c:152 add-patch.c:197 git-add--interactive.perl:1463
#, c-format, perl-format
msgid "Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Diesen Patch-Block vom Index und Arbeitsverzeichnis verwerfen [y,n,q,a,d"
"%s,?]? "
-#: add-patch.c:151
+#: add-patch.c:157
msgid ""
"y - discard this hunk from index and worktree\n"
"n - do not discard this hunk from index and worktree\n"
@@ -459,25 +490,30 @@ msgstr ""
"a - diesen und alle weiteren Patch-Blöcke in der Datei verwerfen\n"
"d - diesen oder alle weiteren Patch-Blöcke in der Datei nicht verwerfen\n"
-#: add-patch.c:165 add-patch.c:208 git-add--interactive.perl:1458
+#: add-patch.c:171 add-patch.c:216 git-add--interactive.perl:1466
#, c-format, perl-format
msgid "Apply mode change to index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Modusänderung auf Index und Arbeitsverzeichnis anwenden [y,n,q,a,d%s,?]? "
-#: add-patch.c:166 add-patch.c:209 git-add--interactive.perl:1459
+#: add-patch.c:172 add-patch.c:217 git-add--interactive.perl:1467
#, c-format, perl-format
msgid "Apply deletion to index and worktree [y,n,q,a,d%s,?]? "
msgstr "Löschung auf Index und Arbeitsverzeichnis anwenden [y,n,q,a,d%s,?]? "
-#: add-patch.c:167 add-patch.c:210 git-add--interactive.perl:1460
+#: add-patch.c:173 add-patch.c:218 git-add--interactive.perl:1468
+#, c-format, perl-format
+msgid "Apply addition to index and worktree [y,n,q,a,d%s,?]? "
+msgstr "Ergänzung auf Index und Arbeitsverzeichnis anwenden [y,n,q,a,d%s,?]? "
+
+#: add-patch.c:174 add-patch.c:219 git-add--interactive.perl:1469
#, c-format, perl-format
msgid "Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Diesen Patch-Block auf Index und Arbeitsverzeichnis anwenden [y,n,q,a,d"
"%s,?]? "
-#: add-patch.c:172
+#: add-patch.c:179
msgid ""
"y - apply this hunk to index and worktree\n"
"n - do not apply this hunk to index and worktree\n"
@@ -492,7 +528,7 @@ msgstr ""
"a - diesen und alle weiteren Patch-Blöcke in der Datei anwenden\n"
"d - diesen oder alle weiteren Patch-Blöcke in der Datei nicht anwenden\n"
-#: add-patch.c:215
+#: add-patch.c:224
msgid ""
"y - apply this hunk to worktree\n"
"n - do not apply this hunk to worktree\n"
@@ -506,34 +542,34 @@ msgstr ""
"a - diesen und alle weiteren Patch-Blöcke in der Datei anwenden\n"
"d - diesen und alle weiteren Patch-Blöcke in der Datei nicht anwenden\n"
-#: add-patch.c:319
+#: add-patch.c:328
#, c-format
msgid "could not parse hunk header '%.*s'"
msgstr "Konnte Block-Header '%.*s' nicht parsen."
-#: add-patch.c:338 add-patch.c:342
+#: add-patch.c:347 add-patch.c:351
#, c-format
msgid "could not parse colored hunk header '%.*s'"
msgstr "Konnte farbigen Block-Header '%.*s' nicht parsen."
-#: add-patch.c:396
+#: add-patch.c:405
msgid "could not parse diff"
msgstr "Konnte Differenz nicht parsen."
-#: add-patch.c:415
+#: add-patch.c:424
msgid "could not parse colored diff"
msgstr "Konnte farbige Differenz nicht parsen."
-#: add-patch.c:429
+#: add-patch.c:438
#, c-format
msgid "failed to run '%s'"
msgstr "'%s' konnte nicht ausgeführt werden"
-#: add-patch.c:588
+#: add-patch.c:602
msgid "mismatched output from interactive.diffFilter"
msgstr "nicht übereinstimmende Ausgabe von interactive.diffFilter"
-#: add-patch.c:589
+#: add-patch.c:603
msgid ""
"Your filter must maintain a one-to-one correspondence\n"
"between its input and output lines."
@@ -541,7 +577,7 @@ msgstr ""
"Der Filter muss eine Eins-zu-Eins-Beziehung\n"
"zwischen den Ein- und Ausgabe-Zeilen einhalten."
-#: add-patch.c:762
+#: add-patch.c:776
#, c-format
msgid ""
"expected context line #%d in\n"
@@ -550,7 +586,7 @@ msgstr ""
"Erwartete Kontextzeile #%d in\n"
"%.*s"
-#: add-patch.c:777
+#: add-patch.c:791
#, c-format
msgid ""
"hunks do not overlap:\n"
@@ -563,13 +599,13 @@ msgstr ""
"\tendet nicht mit:\n"
"%.*s"
-#: add-patch.c:1053 git-add--interactive.perl:1112
+#: add-patch.c:1067 git-add--interactive.perl:1114
msgid "Manual hunk edit mode -- see bottom for a quick guide.\n"
msgstr ""
"Manueller Editiermodus für Patch-Blöcke -- siehe nach unten für eine\n"
"Kurzanleitung.\n"
-#: add-patch.c:1057
+#: add-patch.c:1071
#, c-format
msgid ""
"---\n"
@@ -583,7 +619,7 @@ msgstr ""
"Zeilen, die mit %c beginnen, werden entfernt.\n"
#. TRANSLATORS: 'it' refers to the patch mentioned in the previous messages.
-#: add-patch.c:1071 git-add--interactive.perl:1126
+#: add-patch.c:1085 git-add--interactive.perl:1128
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"
@@ -594,11 +630,11 @@ msgstr ""
"werden,\n"
"wird die Bearbeitung abgebrochen und der Patch-Block bleibt unverändert.\n"
-#: add-patch.c:1104
+#: add-patch.c:1118
msgid "could not parse hunk header"
msgstr "Konnte Block-Header nicht parsen."
-#: add-patch.c:1149
+#: add-patch.c:1163
msgid "'git apply --cached' failed"
msgstr "'git apply --cached' schlug fehl."
@@ -614,27 +650,27 @@ msgstr "'git apply --cached' schlug fehl."
#. Consider translating (saying "no" discards!) as
#. (saying "n" for "no" discards!) if the translation
#. of the word "no" does not start with n.
-#: add-patch.c:1218 git-add--interactive.perl:1239
+#: add-patch.c:1232 git-add--interactive.perl:1241
msgid ""
"Your edited hunk does not apply. Edit again (saying \"no\" discards!) [y/n]? "
msgstr ""
"Ihr bearbeiteter Patch-Block kann nicht angewendet werden.\n"
"Erneut bearbeiten? (\"n\" verwirft Bearbeitung!) [y/n]?"
-#: add-patch.c:1261
+#: add-patch.c:1275
msgid "The selected hunks do not apply to the index!"
msgstr ""
"Die ausgewählten Patch-Blöcke können nicht auf den Index angewendet werden!"
-#: add-patch.c:1262 git-add--interactive.perl:1343
+#: add-patch.c:1276 git-add--interactive.perl:1345
msgid "Apply them to the worktree anyway? "
msgstr "Trotzdem auf Arbeitsverzeichnis anwenden? "
-#: add-patch.c:1269 git-add--interactive.perl:1346
+#: add-patch.c:1283 git-add--interactive.perl:1348
msgid "Nothing was applied.\n"
msgstr "Nichts angewendet.\n"
-#: add-patch.c:1326
+#: add-patch.c:1340
msgid ""
"j - leave this hunk undecided, see next undecided hunk\n"
"J - leave this hunk undecided, see next hunk\n"
@@ -658,69 +694,69 @@ msgstr ""
"e - aktuellen Patch-Block manuell editieren\n"
"? - Hilfe anzeigen\n"
-#: add-patch.c:1447 add-patch.c:1457
+#: add-patch.c:1463 add-patch.c:1473
msgid "No previous hunk"
msgstr "Kein vorheriger Patch-Block"
-#: add-patch.c:1452 add-patch.c:1462
+#: add-patch.c:1468 add-patch.c:1478
msgid "No next hunk"
msgstr "Kein folgender Patch-Block"
-#: add-patch.c:1468
+#: add-patch.c:1484
msgid "No other hunks to goto"
msgstr "Keine anderen Patch-Blöcke verbleibend"
-#: add-patch.c:1479 git-add--interactive.perl:1577
+#: add-patch.c:1495 git-add--interactive.perl:1594
msgid "go to which hunk (<ret> to see more)? "
msgstr "zu welchem Patch-Block springen (<Enter> für mehr Informationen)? "
-#: add-patch.c:1480 git-add--interactive.perl:1579
+#: add-patch.c:1496 git-add--interactive.perl:1596
msgid "go to which hunk? "
msgstr "zu welchem Patch-Block springen? "
-#: add-patch.c:1491
+#: add-patch.c:1507
#, c-format
msgid "Invalid number: '%s'"
msgstr "Ungültige Nummer: '%s'"
-#: add-patch.c:1496
+#: add-patch.c:1512
#, c-format
msgid "Sorry, only %d hunk available."
msgid_plural "Sorry, only %d hunks available."
msgstr[0] "Entschuldigung, nur %d Patch-Block verfügbar."
msgstr[1] "Entschuldigung, nur %d Patch-Blöcke verfügbar."
-#: add-patch.c:1505
+#: add-patch.c:1521
msgid "No other hunks to search"
msgstr "Keine anderen Patch-Blöcke zum Durchsuchen"
-#: add-patch.c:1511 git-add--interactive.perl:1623
+#: add-patch.c:1527 git-add--interactive.perl:1640
msgid "search for regex? "
msgstr "Suche nach regulärem Ausdruck? "
-#: add-patch.c:1526
+#: add-patch.c:1542
#, c-format
msgid "Malformed search regexp %s: %s"
msgstr "Fehlerhafter regulärer Ausdruck für Suche %s: %s"
-#: add-patch.c:1543
+#: add-patch.c:1559
msgid "No hunk matches the given pattern"
msgstr "Kein Patch-Block entspricht dem angegebenen Muster"
-#: add-patch.c:1550
+#: add-patch.c:1566
msgid "Sorry, cannot split this hunk"
msgstr "Entschuldigung, kann diesen Patch-Block nicht aufteilen"
-#: add-patch.c:1554
+#: add-patch.c:1570
#, c-format
msgid "Split into %d hunks."
msgstr "In %d Patch-Block aufgeteilt."
-#: add-patch.c:1558
+#: add-patch.c:1574
msgid "Sorry, cannot edit this hunk"
msgstr "Entschuldigung, kann diesen Patch-Block nicht bearbeiten"
-#: add-patch.c:1609
+#: add-patch.c:1625
msgid "'git apply' failed"
msgstr "'git apply' schlug fehl"
@@ -1438,7 +1474,7 @@ msgstr ""
#: apply.c:5008 builtin/am.c:2238 builtin/interpret-trailers.c:98
#: builtin/interpret-trailers.c:100 builtin/interpret-trailers.c:102
-#: builtin/pack-objects.c:3458 builtin/rebase.c:1332
+#: builtin/pack-objects.c:3530 builtin/rebase.c:1332
msgid "action"
msgstr "Aktion"
@@ -1528,7 +1564,7 @@ msgstr "Pfad ist kein gültiges UTF-8: %s"
msgid "path too long (%d chars, SHA1: %s): %s"
msgstr "Pfad zu lang (%d Zeichen, SHA1: %s): %s"
-#: archive-zip.c:480 builtin/pack-objects.c:232 builtin/pack-objects.c:235
+#: archive-zip.c:480 builtin/pack-objects.c:243 builtin/pack-objects.c:246
#, c-format
msgid "deflate error (%d)"
msgstr "Fehler beim Komprimieren (%d)"
@@ -1598,8 +1634,8 @@ msgid "prepend prefix to each pathname in the archive"
msgstr "einen Präfix vor jeden Pfadnamen in dem Archiv stellen"
#: archive.c:467 builtin/blame.c:861 builtin/blame.c:865 builtin/blame.c:866
-#: builtin/commit-tree.c:117 builtin/config.c:130 builtin/fast-export.c:1162
-#: builtin/fast-export.c:1164 builtin/fast-export.c:1168 builtin/grep.c:907
+#: builtin/commit-tree.c:117 builtin/config.c:130 builtin/fast-export.c:1208
+#: builtin/fast-export.c:1210 builtin/fast-export.c:1214 builtin/grep.c:907
#: builtin/hash-object.c:105 builtin/ls-files.c:561 builtin/ls-files.c:564
#: builtin/notes.c:412 builtin/notes.c:578 builtin/read-tree.c:123
#: parse-options.h:190
@@ -1828,10 +1864,10 @@ msgstr ""
"endgültigen\n"
"Commits"
-#: blame.c:2821 bundle.c:167 ref-filter.c:2200 remote.c:1924 sequencer.c:2018
+#: blame.c:2821 bundle.c:187 ref-filter.c:2200 remote.c:1924 sequencer.c:2018
#: sequencer.c:4466 submodule.c:847 builtin/commit.c:1047 builtin/log.c:405
#: builtin/log.c:1012 builtin/log.c:1541 builtin/log.c:1945 builtin/log.c:2235
-#: builtin/merge.c:415 builtin/pack-objects.c:3276 builtin/pack-objects.c:3291
+#: builtin/merge.c:415 builtin/pack-objects.c:3348 builtin/pack-objects.c:3363
#: builtin/shortlog.c:192
msgid "revision walk setup failed"
msgstr "Einrichtung des Revisionsgangs fehlgeschlagen"
@@ -1995,84 +2031,88 @@ msgstr "'%s' ist bereits in '%s' ausgecheckt"
msgid "HEAD of working tree %s is not updated"
msgstr "HEAD des Arbeitsverzeichnisses %s ist nicht aktualisiert."
-#: bundle.c:36
+#: bundle.c:47
#, c-format
msgid "'%s' does not look like a v2 bundle file"
msgstr "'%s' sieht nicht wie eine v2 Paketdatei aus"
-#: bundle.c:64
+#: bundle.c:69
+msgid "unknown hash algorithm length"
+msgstr "unbekannte Länge des Hash-Algorithmus"
+
+#: bundle.c:84
#, c-format
msgid "unrecognized header: %s%s (%d)"
msgstr "nicht erkannter Kopfbereich: %s%s (%d)"
-#: bundle.c:90 rerere.c:480 rerere.c:690 sequencer.c:2270 sequencer.c:3034
+#: bundle.c:110 rerere.c:480 rerere.c:690 sequencer.c:2270 sequencer.c:3034
#: builtin/commit.c:814
#, c-format
msgid "could not open '%s'"
msgstr "Konnte '%s' nicht öffnen"
-#: bundle.c:143
+#: bundle.c:163
msgid "Repository lacks these prerequisite commits:"
msgstr "Dem Repository fehlen folgende vorausgesetzte Commits:"
-#: bundle.c:146
+#: bundle.c:166
msgid "need a repository to verify a bundle"
msgstr "Um ein Paket zu überprüfen wird ein Repository benötigt."
-#: bundle.c:197
+#: bundle.c:217
#, c-format
msgid "The bundle contains this ref:"
msgid_plural "The bundle contains these %d refs:"
msgstr[0] "Das Paket enthält diese Referenz:"
msgstr[1] "Das Paket enthält diese %d Referenzen:"
-#: bundle.c:204
+#: bundle.c:224
msgid "The bundle records a complete history."
msgstr "Das Paket speichert eine komplette Historie."
-#: bundle.c:206
+#: bundle.c:226
#, c-format
msgid "The bundle requires this ref:"
msgid_plural "The bundle requires these %d refs:"
msgstr[0] "Das Paket benötigt diese Referenz:"
msgstr[1] "Das Paket benötigt diese %d Referenzen:"
-#: bundle.c:273
+#: bundle.c:293
msgid "unable to dup bundle descriptor"
msgstr "Konnte dup für Descriptor des Pakets nicht ausführen."
-#: bundle.c:280
+#: bundle.c:300
msgid "Could not spawn pack-objects"
msgstr "Konnte Paketobjekte nicht erstellen"
-#: bundle.c:291
+#: bundle.c:311
msgid "pack-objects died"
msgstr "Erstellung der Paketobjekte abgebrochen"
-#: bundle.c:333
+#: bundle.c:353
msgid "rev-list died"
msgstr "\"rev-list\" abgebrochen"
-#: bundle.c:382
+#: bundle.c:402
#, c-format
msgid "ref '%s' is excluded by the rev-list options"
msgstr "Referenz '%s' wird durch \"rev-list\" Optionen ausgeschlossen"
-#: bundle.c:461 builtin/log.c:208 builtin/log.c:1834 builtin/shortlog.c:306
+#: bundle.c:481 builtin/log.c:208 builtin/log.c:1834 builtin/shortlog.c:306
#, c-format
msgid "unrecognized argument: %s"
msgstr "nicht erkanntes Argument: %s"
-#: bundle.c:469
+#: bundle.c:489
msgid "Refusing to create empty bundle."
msgstr "Erstellung eines leeren Pakets zurückgewiesen."
-#: bundle.c:479
+#: bundle.c:499
#, c-format
msgid "cannot create '%s'"
msgstr "kann '%s' nicht erstellen"
-#: bundle.c:504
+#: bundle.c:524
msgid "index-pack died"
msgstr "Erstellung der Paketindexdatei abgebrochen"
@@ -2081,258 +2121,250 @@ msgstr "Erstellung der Paketindexdatei abgebrochen"
msgid "invalid color value: %.*s"
msgstr "Ungültiger Farbwert: %.*s"
-#: commit-graph.c:183
+#: commit-graph.c:238
msgid "commit-graph file is too small"
msgstr "Commit-Graph-Datei ist zu klein."
-#: commit-graph.c:248
+#: commit-graph.c:303
#, c-format
msgid "commit-graph signature %X does not match signature %X"
msgstr "Commit-Graph-Signatur %X stimmt nicht mit Signatur %X überein."
-#: commit-graph.c:255
+#: commit-graph.c:310
#, c-format
msgid "commit-graph version %X does not match version %X"
msgstr "Commit-Graph-Version %X stimmt nicht mit Version %X überein."
-#: commit-graph.c:262
+#: commit-graph.c:317
#, c-format
msgid "commit-graph hash version %X does not match version %X"
msgstr "Hash-Version des Commit-Graph %X stimmt nicht mit Version %X überein."
-#: commit-graph.c:284
+#: commit-graph.c:339
msgid "commit-graph chunk lookup table entry missing; file may be incomplete"
msgstr ""
"fehlender Tabelleneintrag für Commit-Graph Chunk-Lookup; Datei "
"möglicherweise unvollständig"
-#: commit-graph.c:294
+#: commit-graph.c:349
#, c-format
msgid "commit-graph improper chunk offset %08x%08x"
msgstr "Unzulässiger Commit-Graph Chunk-Offset %08x%08x"
-#: commit-graph.c:362
+#: commit-graph.c:417
#, c-format
msgid "commit-graph chunk id %08x appears multiple times"
msgstr "Commit-Graph Chunk-Id %08x kommt mehrfach vor."
-#: commit-graph.c:436
+#: commit-graph.c:491
msgid "commit-graph has no base graphs chunk"
msgstr "Commit-Graph hat keinen Basis-Graph-Chunk"
-#: commit-graph.c:446
+#: commit-graph.c:501
msgid "commit-graph chain does not match"
msgstr "Commit-Graph Verkettung stimmt nicht überein."
-#: commit-graph.c:494
+#: commit-graph.c:549
#, c-format
msgid "invalid commit-graph chain: line '%s' not a hash"
msgstr "Ungültige Commit-Graph Verkettung: Zeile '%s' ist kein Hash"
-#: commit-graph.c:518
+#: commit-graph.c:573
msgid "unable to find all commit-graph files"
msgstr "Konnte nicht alle Commit-Graph-Dateien finden."
-#: commit-graph.c:651 commit-graph.c:711
+#: commit-graph.c:706 commit-graph.c:770
msgid "invalid commit position. commit-graph is likely corrupt"
msgstr "Ungültige Commit-Position. Commit-Graph ist wahrscheinlich beschädigt."
-#: commit-graph.c:672
+#: commit-graph.c:727
#, c-format
msgid "could not find commit %s"
msgstr "Konnte Commit %s nicht finden."
-#: commit-graph.c:948 builtin/am.c:1292
+#: commit-graph.c:1009 builtin/am.c:1292
#, c-format
msgid "unable to parse commit %s"
msgstr "Konnte Commit '%s' nicht parsen."
-#: commit-graph.c:1096
+#: commit-graph.c:1157
msgid "Writing changed paths Bloom filters index"
msgstr "Schreibe Index für veränderte Pfade Bloom-Filter"
-#: commit-graph.c:1121
+#: commit-graph.c:1182
msgid "Writing changed paths Bloom filters data"
msgstr "Schreibe Daten für veränderte Pfade Bloom-Filter"
-#: commit-graph.c:1160 builtin/pack-objects.c:2783
+#: commit-graph.c:1221 builtin/pack-objects.c:2832
#, c-format
msgid "unable to get type of object %s"
msgstr "Konnte Art von Objekt '%s' nicht bestimmen."
-#: commit-graph.c:1196
+#: commit-graph.c:1257
msgid "Loading known commits in commit graph"
msgstr "Lade bekannte Commits in Commit-Graph"
-#: commit-graph.c:1213
+#: commit-graph.c:1274
msgid "Expanding reachable commits in commit graph"
msgstr "Erweitere erreichbare Commits in Commit-Graph"
-#: commit-graph.c:1233
+#: commit-graph.c:1294
msgid "Clearing commit marks in commit graph"
msgstr "Lösche Commit-Markierungen in Commit-Graph"
-#: commit-graph.c:1252
+#: commit-graph.c:1313
msgid "Computing commit graph generation numbers"
msgstr "Commit-Graph Generationsnummern berechnen"
-#: commit-graph.c:1300
+#: commit-graph.c:1367
msgid "Computing commit changed paths Bloom filters"
msgstr "Berechnung der Bloom-Filter für veränderte Pfade des Commits"
-#: commit-graph.c:1359
+#: commit-graph.c:1423
+msgid "Collecting referenced commits"
+msgstr "Sammle referenzierte Commits"
+
+#: commit-graph.c:1447
#, c-format
msgid "Finding commits for commit graph in %d pack"
msgid_plural "Finding commits for commit graph in %d packs"
msgstr[0] "Suche Commits für Commit-Graph in %d Paket"
msgstr[1] "Suche Commits für Commit-Graph in %d Paketen"
-#: commit-graph.c:1372
+#: commit-graph.c:1460
#, c-format
msgid "error adding pack %s"
msgstr "Fehler beim Hinzufügen von Paket %s."
-#: commit-graph.c:1376
+#: commit-graph.c:1464
#, c-format
msgid "error opening index for %s"
msgstr "Fehler beim Öffnen des Index für %s."
-#: commit-graph.c:1405
-#, c-format
-msgid "Finding commits for commit graph from %d ref"
-msgid_plural "Finding commits for commit graph from %d refs"
-msgstr[0] "Suche Commits für Commit-Graph in %d Referenz"
-msgstr[1] "Suche Commits für Commit-Graph in %d Referenzen"
-
-#: commit-graph.c:1426
-#, c-format
-msgid "invalid commit object id: %s"
-msgstr "ungültige Commit-Objekt-ID: %s"
-
-#: commit-graph.c:1442
+#: commit-graph.c:1503
msgid "Finding commits for commit graph among packed objects"
msgstr "Suche Commits für Commit-Graph in gepackten Objekten"
-#: commit-graph.c:1457
+#: commit-graph.c:1518
msgid "Counting distinct commits in commit graph"
msgstr "Zähle Commits in Commit-Graph"
-#: commit-graph.c:1489
+#: commit-graph.c:1550
msgid "Finding extra edges in commit graph"
msgstr "Suche zusätzliche Ränder in Commit-Graph"
-#: commit-graph.c:1538
+#: commit-graph.c:1599
msgid "failed to write correct number of base graph ids"
msgstr "Fehler beim Schreiben der korrekten Anzahl von Basis-Graph-IDs."
-#: commit-graph.c:1572 midx.c:812
+#: commit-graph.c:1633 midx.c:812
#, c-format
msgid "unable to create leading directories of %s"
msgstr "Konnte führende Verzeichnisse von '%s' nicht erstellen."
-#: commit-graph.c:1585
+#: commit-graph.c:1646
msgid "unable to create temporary graph layer"
msgstr "konnte temporäre Graphen-Schicht nicht erstellen"
-#: commit-graph.c:1590
+#: commit-graph.c:1651
#, c-format
msgid "unable to adjust shared permissions for '%s'"
msgstr "konnte geteilte Zugriffsberechtigungen für '%s' nicht ändern"
-#: commit-graph.c:1667
+#: commit-graph.c:1728
#, c-format
msgid "Writing out commit graph in %d pass"
msgid_plural "Writing out commit graph in %d passes"
msgstr[0] "Schreibe Commit-Graph in %d Durchgang"
msgstr[1] "Schreibe Commit-Graph in %d Durchgängen"
-#: commit-graph.c:1712
+#: commit-graph.c:1773
msgid "unable to open commit-graph chain file"
msgstr "Konnte Commit-Graph Chain-Datei nicht öffnen."
-#: commit-graph.c:1728
+#: commit-graph.c:1789
msgid "failed to rename base commit-graph file"
msgstr "Konnte Basis-Commit-Graph-Datei nicht umbenennen."
-#: commit-graph.c:1748
+#: commit-graph.c:1809
msgid "failed to rename temporary commit-graph file"
msgstr "Konnte temporäre Commit-Graph-Datei nicht umbenennen."
-#: commit-graph.c:1874
+#: commit-graph.c:1935
msgid "Scanning merged commits"
msgstr "Durchsuche zusammengeführte Commits"
-#: commit-graph.c:1885
+#: commit-graph.c:1946
#, c-format
msgid "unexpected duplicate commit id %s"
msgstr "Unerwartete doppelte Commit-ID %s"
-#: commit-graph.c:1908
+#: commit-graph.c:1969
msgid "Merging commit-graph"
msgstr "Zusammenführen von Commit-Graph"
-#: commit-graph.c:2096
+#: commit-graph.c:2156
#, c-format
msgid "the commit graph format cannot write %d commits"
msgstr "Das Commit-Graph Format kann nicht %d Commits schreiben."
-#: commit-graph.c:2107
+#: commit-graph.c:2167
msgid "too many commits to write graph"
msgstr "Zu viele Commits zum Schreiben des Graphen."
-#: commit-graph.c:2200
+#: commit-graph.c:2260
msgid "the commit-graph file has incorrect checksum and is likely corrupt"
msgstr ""
"Die Commit-Graph-Datei hat eine falsche Prüfsumme und ist wahrscheinlich "
"beschädigt."
-#: commit-graph.c:2210
+#: commit-graph.c:2270
#, c-format
msgid "commit-graph has incorrect OID order: %s then %s"
msgstr "Commit-Graph hat fehlerhafte OID-Reihenfolge: %s dann %s"
-#: commit-graph.c:2220 commit-graph.c:2235
+#: commit-graph.c:2280 commit-graph.c:2295
#, c-format
msgid "commit-graph has incorrect fanout value: fanout[%d] = %u != %u"
msgstr "Commit-Graph hat fehlerhaften Fanout-Wert: fanout[%d] = %u != %u"
-#: commit-graph.c:2227
+#: commit-graph.c:2287
#, c-format
msgid "failed to parse commit %s from commit-graph"
msgstr "Konnte Commit %s von Commit-Graph nicht parsen."
-#: commit-graph.c:2245
+#: commit-graph.c:2305
msgid "Verifying commits in commit graph"
msgstr "Commit in Commit-Graph überprüfen"
-#: commit-graph.c:2259
+#: commit-graph.c:2320
#, c-format
msgid "failed to parse commit %s from object database for commit-graph"
msgstr ""
"Fehler beim Parsen des Commits %s von Objekt-Datenbank für Commit-Graph"
-#: commit-graph.c:2266
+#: commit-graph.c:2327
#, c-format
msgid "root tree OID for commit %s in commit-graph is %s != %s"
msgstr ""
"OID des Wurzelverzeichnisses für Commit %s in Commit-Graph ist %s != %s"
-#: commit-graph.c:2276
+#: commit-graph.c:2337
#, c-format
msgid "commit-graph parent list for commit %s is too long"
msgstr "Commit-Graph Vorgänger-Liste für Commit %s ist zu lang"
-#: commit-graph.c:2285
+#: commit-graph.c:2346
#, c-format
msgid "commit-graph parent for %s is %s != %s"
msgstr "Commit-Graph-Vorgänger für %s ist %s != %s"
-#: commit-graph.c:2298
+#: commit-graph.c:2360
#, c-format
msgid "commit-graph parent list for commit %s terminates early"
msgstr "Commit-Graph Vorgänger-Liste für Commit %s endet zu früh"
-#: commit-graph.c:2303
+#: commit-graph.c:2365
#, c-format
msgid ""
"commit-graph has generation number zero for commit %s, but non-zero elsewhere"
@@ -2340,7 +2372,7 @@ msgstr ""
"Commit-Graph hat Generationsnummer null für Commit %s, aber sonst ungleich "
"null"
-#: commit-graph.c:2307
+#: commit-graph.c:2369
#, c-format
msgid ""
"commit-graph has non-zero generation number for commit %s, but zero elsewhere"
@@ -2348,12 +2380,12 @@ msgstr ""
"Commit-Graph hat Generationsnummer ungleich null für Commit %s, aber sonst "
"null"
-#: commit-graph.c:2322
+#: commit-graph.c:2385
#, c-format
msgid "commit-graph generation for commit %s is %u != %u"
msgstr "Commit-Graph Erstellung für Commit %s ist %u != %u"
-#: commit-graph.c:2328
+#: commit-graph.c:2391
#, c-format
msgid "commit date for commit %s in commit-graph is %<PRIuMAX> != %<PRIuMAX>"
msgstr ""
@@ -2391,28 +2423,28 @@ msgstr ""
"Sie können diese Meldung unterdrücken, indem Sie\n"
"\"git config advice.graftFileDeprecated false\" ausführen."
-#: commit.c:1168
+#: commit.c:1172
#, 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."
-#: commit.c:1172
+#: commit.c:1176
#, c-format
msgid "Commit %s has a bad GPG signature allegedly by %s."
msgstr "Commit %s hat eine ungültige GPG-Signatur, angeblich von %s."
-#: commit.c:1175
+#: commit.c:1179
#, c-format
msgid "Commit %s does not have a GPG signature."
msgstr "Commit %s hat keine GPG-Signatur."
-#: commit.c:1178
+#: commit.c:1182
#, c-format
msgid "Commit %s has a good GPG signature by %s\n"
msgstr "Commit %s hat eine gültige GPG-Signatur von %s\n"
-#: commit.c:1432
+#: commit.c:1436
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"
@@ -2614,7 +2646,7 @@ msgid "must be one of nothing, matching, simple, upstream or current"
msgstr ""
"Muss einer von diesen sein: nothing, matching, simple, upstream, current"
-#: config.c:1533 builtin/pack-objects.c:3542
+#: config.c:1533 builtin/pack-objects.c:3617
#, c-format
msgid "bad pack compression level %d"
msgstr "ungültiger Komprimierungsgrad (%d) für Paketierung"
@@ -2770,74 +2802,83 @@ msgstr ""
msgid "server doesn't support '%s'"
msgstr "Der Server unterstützt kein '%s'."
-#: connect.c:103
+#: connect.c:118
#, c-format
msgid "server doesn't support feature '%s'"
msgstr "Der Server unterstützt das Feature '%s' nicht."
-#: connect.c:114
+#: connect.c:129
msgid "expected flush after capabilities"
msgstr "Erwartete Flush nach Fähigkeiten."
-#: connect.c:233
+#: connect.c:263
#, c-format
msgid "ignoring capabilities after first line '%s'"
msgstr "Ignoriere Fähigkeiten nach der ersten Zeile '%s'."
-#: connect.c:252
+#: connect.c:284
msgid "protocol error: unexpected capabilities^{}"
msgstr "Protokollfehler: unerwartetes capabilities^{}"
-#: connect.c:273
+#: connect.c:306
#, c-format
msgid "protocol error: expected shallow sha-1, got '%s'"
msgstr "Protokollfehler: shallow SHA-1 erwartet, '%s' bekommen"
-#: connect.c:275
+#: connect.c:308
msgid "repository on the other end cannot be shallow"
msgstr ""
"Repository auf der Gegenseite kann keine unvollständige Historie (shallow) "
"enthalten"
-#: connect.c:313
+#: connect.c:347
msgid "invalid packet"
-msgstr "Ungültiges Paket."
+msgstr "ungültiges Paket"
-#: connect.c:333
+#: connect.c:367
#, c-format
msgid "protocol error: unexpected '%s'"
msgstr "Protokollfehler: unerwartetes '%s'"
-#: connect.c:441
+#: connect.c:473
+#, c-format
+msgid "unknown object format '%s' specified by server"
+msgstr "unbekanntes Objekt-Format '%s' vom Server angegeben"
+
+#: connect.c:500
#, c-format
msgid "invalid ls-refs response: %s"
-msgstr "Ungültige ls-refs Antwort: %s"
+msgstr "ungültige ls-refs Antwort: %s"
-#: connect.c:445
+#: connect.c:504
msgid "expected flush after ref listing"
-msgstr "Erwartete Flush nach Auflistung der Referenzen."
+msgstr "Flush nach Auflistung der Referenzen erwartet"
-#: connect.c:544
+#: connect.c:507
+msgid "expected response end packet after ref listing"
+msgstr "Antwort-Endpaket nach Auflistung der Referenzen erwartet"
+
+#: connect.c:640
#, c-format
msgid "protocol '%s' is not supported"
-msgstr "Protokoll '%s' wird nicht unterstützt."
+msgstr "Protokoll '%s' wird nicht unterstützt"
-#: connect.c:595
+#: connect.c:691
msgid "unable to set SO_KEEPALIVE on socket"
-msgstr "Kann SO_KEEPALIVE bei Socket nicht setzen."
+msgstr "kann SO_KEEPALIVE bei Socket nicht setzen"
-#: connect.c:635 connect.c:698
+#: connect.c:731 connect.c:794
#, c-format
msgid "Looking up %s ... "
msgstr "Suche nach %s ..."
-#: connect.c:639
+#: connect.c:735
#, c-format
msgid "unable to look up %s (port %s) (%s)"
msgstr "Fehler bei Suche nach %s (Port %s) (%s)."
#. TRANSLATORS: this is the end of "Looking up %s ... "
-#: connect.c:643 connect.c:714
+#: connect.c:739 connect.c:810
#, c-format
msgid ""
"done.\n"
@@ -2846,7 +2887,7 @@ msgstr ""
"Fertig.\n"
"Verbinde nach %s (Port %s) ... "
-#: connect.c:665 connect.c:742
+#: connect.c:761 connect.c:838
#, c-format
msgid ""
"unable to connect to %s:\n"