summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/Makefile5
-rw-r--r--Documentation/RelNotes/2.41.0.txt126
-rw-r--r--Documentation/blame-options.txt8
-rw-r--r--Documentation/config/feature.txt3
-rw-r--r--Documentation/config/gc.txt12
-rw-r--r--Documentation/config/pack.txt8
-rw-r--r--Documentation/config/sendemail.txt1
-rwxr-xr-xDocumentation/doc-diff2
-rw-r--r--Documentation/fetch-options.txt7
-rw-r--r--Documentation/git-checkout.txt54
-rw-r--r--Documentation/git-credential.txt6
-rw-r--r--Documentation/git-diff.txt8
-rw-r--r--Documentation/git-fetch.txt9
-rw-r--r--Documentation/git-gc.txt12
-rw-r--r--Documentation/git-interpret-trailers.txt97
-rw-r--r--Documentation/git-merge.txt11
-rw-r--r--Documentation/git-name-rev.txt11
-rw-r--r--Documentation/git-notes.txt42
-rw-r--r--Documentation/git-push.txt3
-rw-r--r--Documentation/git-send-email.txt19
-rw-r--r--Documentation/git.txt14
-rw-r--r--Documentation/gitattributes.txt59
-rw-r--r--Documentation/gitformat-pack.txt4
-rw-r--r--Documentation/githooks.txt27
-rw-r--r--Documentation/gitignore.txt4
-rw-r--r--Documentation/gittutorial.txt129
-rw-r--r--Documentation/manpage-normal.xsl16
-rw-r--r--Documentation/revisions.txt15
-rw-r--r--Documentation/user-manual.txt27
-rw-r--r--abspath.c36
-rw-r--r--abspath.h21
-rw-r--r--add-interactive.c1
-rw-r--r--add-patch.c12
-rw-r--r--alloc.c1
-rw-r--r--apply.c3
-rw-r--r--apply.h2
-rw-r--r--archive-zip.c2
-rw-r--r--archive.c4
-rw-r--r--attr.c38
-rw-r--r--attr.h13
-rw-r--r--banned.h4
-rw-r--r--base85.c3
-rw-r--r--base85.h7
-rw-r--r--blame.c8
-rw-r--r--bloom.c1
-rw-r--r--branch.c28
-rw-r--r--branch.h8
-rw-r--r--builtin/am.c2
-rw-r--r--builtin/apply.c1
-rw-r--r--builtin/archive.c1
-rw-r--r--builtin/bisect.c1
-rw-r--r--builtin/branch.c75
-rw-r--r--builtin/bundle.c2
-rw-r--r--builtin/check-attr.c18
-rw-r--r--builtin/check-ignore.c1
-rw-r--r--builtin/checkout-index.c1
-rw-r--r--builtin/checkout.c1
-rw-r--r--builtin/clean.c1
-rw-r--r--builtin/clone.c2
-rw-r--r--builtin/commit.c2
-rw-r--r--builtin/config.c1
-rw-r--r--builtin/credential-cache--daemon.c3
-rw-r--r--builtin/credential-cache.c1
-rw-r--r--builtin/credential-store.c20
-rw-r--r--builtin/diff-files.c4
-rw-r--r--builtin/diff-tree.c1
-rw-r--r--builtin/diff.c1
-rw-r--r--builtin/difftool.c1
-rw-r--r--builtin/fetch.c483
-rw-r--r--builtin/for-each-repo.c2
-rw-r--r--builtin/fsck.c40
-rw-r--r--builtin/gc.c13
-rw-r--r--builtin/help.c1
-rw-r--r--builtin/index-pack.c5
-rw-r--r--builtin/init-db.c2
-rw-r--r--builtin/log.c1
-rw-r--r--builtin/ls-remote.c1
-rw-r--r--builtin/merge-index.c1
-rw-r--r--builtin/merge-recursive.c2
-rw-r--r--builtin/merge-tree.c4
-rw-r--r--builtin/merge.c10
-rw-r--r--builtin/mv.c1
-rw-r--r--builtin/name-rev.c6
-rw-r--r--builtin/notes.c151
-rw-r--r--builtin/pack-objects.c7
-rw-r--r--builtin/pull.c2
-rw-r--r--builtin/push.c9
-rw-r--r--builtin/read-tree.c1
-rw-r--r--builtin/rebase.c2
-rw-r--r--builtin/receive-pack.c1
-rw-r--r--builtin/repack.c3
-rw-r--r--builtin/rerere.c1
-rw-r--r--builtin/rm.c2
-rw-r--r--builtin/show-branch.c2
-rw-r--r--builtin/show-index.c2
-rw-r--r--builtin/stripspace.c6
-rw-r--r--builtin/tag.c9
-rw-r--r--builtin/update-index.c3
-rw-r--r--builtin/update-ref.c2
-rw-r--r--builtin/update-server-info.c1
-rw-r--r--builtin/upload-archive.c1
-rw-r--r--builtin/worktree.c2
-rw-r--r--builtin/write-tree.c1
-rw-r--r--bundle-uri.c7
-rw-r--r--cache.h122
-rw-r--r--checkout.c1
-rw-r--r--checkout.h2
-rw-r--r--chunk-format.c1
-rw-r--r--chunk-format.h2
-rwxr-xr-xci/run-build-and-tests.sh2
-rw-r--r--color.c3
-rw-r--r--combine-diff.c3
-rw-r--r--commit-graph.c1
-rw-r--r--commit.c58
-rw-r--r--commit.h11
-rw-r--r--common-main.c4
-rw-r--r--compat/fsmonitor/fsm-health-darwin.c2
-rw-r--r--compat/fsmonitor/fsm-ipc-darwin.c4
-rw-r--r--compat/fsmonitor/fsm-ipc-win32.c1
-rw-r--r--compat/fsmonitor/fsm-listen-darwin.c3
-rw-r--r--compat/mingw.c1
-rw-r--r--compat/precompose_utf8.c1
-rw-r--r--compat/win32/trace2_win32_process_info.c1
-rw-r--r--config.c3
-rw-r--r--contrib/coccinelle/tests/unused.c82
-rw-r--r--contrib/coccinelle/tests/unused.res45
-rw-r--r--contrib/coccinelle/unused.cocci43
-rw-r--r--contrib/completion/git-completion.bash2
-rw-r--r--contrib/completion/git-prompt.sh2
-rw-r--r--contrib/credential/gnome-keyring/.gitignore1
-rw-r--r--contrib/credential/gnome-keyring/Makefile25
-rw-r--r--contrib/credential/gnome-keyring/git-credential-gnome-keyring.c470
-rw-r--r--contrib/credential/libsecret/.gitignore1
-rw-r--r--contrib/credential/libsecret/git-credential-libsecret.c15
-rw-r--r--contrib/credential/osxkeychain/git-credential-osxkeychain.c10
-rw-r--r--contrib/credential/wincred/git-credential-wincred.c107
-rwxr-xr-xcontrib/subtree/git-subtree.sh4
-rw-r--r--convert.c3
-rw-r--r--convert.h2
-rw-r--r--copy.c4
-rw-r--r--copy.h10
-rw-r--r--credential.c11
-rw-r--r--credential.h1
-rw-r--r--csum-file.c1
-rw-r--r--csum-file.h2
-rw-r--r--daemon.c3
-rw-r--r--date.c3
-rwxr-xr-xdetect-compiler10
-rw-r--r--diagnose.c2
-rw-r--r--diff-lib.c1
-rw-r--r--diff.c38
-rw-r--r--diff.h1
-rw-r--r--diffcore.h2
-rw-r--r--dir.c2
-rw-r--r--dir.h17
-rw-r--r--editor.c1
-rw-r--r--entry.c1
-rw-r--r--environment.c3
-rw-r--r--environment.h1
-rw-r--r--exec-cmd.c1
-rw-r--r--fetch-pack.c1
-rw-r--r--fmt-merge-msg.c9
-rw-r--r--fsck.c1
-rw-r--r--fsmonitor--daemon.h1
-rw-r--r--fsmonitor-ipc.c1
-rwxr-xr-xgit-send-email.perl186
-rw-r--r--git.c16
-rwxr-xr-xgitk-git/gitk36
-rw-r--r--gpg-interface.c9
-rw-r--r--grep.c1
-rw-r--r--hash-ll.h276
-rw-r--r--hash-lookup.c1
-rw-r--r--hash.h273
-rw-r--r--hashmap.h2
-rw-r--r--hex.c1
-rw-r--r--hex.h2
-rw-r--r--hook.c2
-rw-r--r--http-push.c2
-rw-r--r--imap-send.c1
-rw-r--r--khash.h1
-rw-r--r--line-log.c1
-rw-r--r--ll-merge.c7
-rw-r--r--log-tree.c1
-rw-r--r--ls-refs.c1
-rw-r--r--match-trees.c3
-rw-r--r--match-trees.h10
-rw-r--r--merge-ort-wrappers.c2
-rw-r--r--merge-ort.c9
-rw-r--r--merge-ort.h2
-rw-r--r--merge-recursive.c2
-rw-r--r--merge.c1
-rw-r--r--midx.c2
-rw-r--r--negotiator/default.c40
-rw-r--r--negotiator/skipping.c23
-rw-r--r--notes-cache.c1
-rw-r--r--notes-utils.c1
-rw-r--r--notes.c6
-rw-r--r--object-file.c3
-rw-r--r--object-file.h2
-rw-r--r--object-name.c17
-rw-r--r--object-name.h9
-rw-r--r--object-store.h8
-rw-r--r--object.h3
-rw-r--r--oidmap.c1
-rw-r--r--oidtree.h2
-rw-r--r--pack-bitmap-write.c2
-rw-r--r--pack-bitmap.c72
-rw-r--r--pack-bitmap.h2
-rw-r--r--pack-revindex.c55
-rw-r--r--pack-revindex.h22
-rw-r--r--pack-write.c15
-rw-r--r--packfile.c4
-rw-r--r--packfile.h16
-rw-r--r--parallel-checkout.c2
-rw-r--r--parse-options-cb.c1
-rw-r--r--parse-options.c1
-rw-r--r--path.c20
-rw-r--r--path.h5
-rw-r--r--pathspec.c4
-rw-r--r--pkt-line.c3
-rw-r--r--pkt-line.h2
-rw-r--r--preload-index.c1
-rw-r--r--pretty.c1
-rw-r--r--progress.c1
-rw-r--r--protocol-caps.c2
-rw-r--r--range-diff.c2
-rw-r--r--read-cache.c81
-rw-r--r--rebase-interactive.c16
-rw-r--r--ref-filter.c4
-rw-r--r--reflog.c2
-rw-r--r--refs/debug.c1
-rw-r--r--refs/files-backend.c2
-rw-r--r--refs/packed-backend.c3
-rw-r--r--refs/ref-cache.c2
-rw-r--r--refs/ref-cache.h3
-rw-r--r--refspec.c2
-rw-r--r--reftable/dump.c2
-rw-r--r--reftable/error.c1
-rw-r--r--reftable/publicbasics.c2
-rw-r--r--reftable/system.h2
-rw-r--r--reftable/tree.c2
-rw-r--r--reftable/tree_test.c1
-rw-r--r--repo-settings.c5
-rw-r--r--repository.h2
-rw-r--r--rerere.c1
-rw-r--r--reset.h2
-rw-r--r--resolve-undo.c1
-rw-r--r--resolve-undo.h2
-rw-r--r--revision.h1
-rw-r--r--run-command.c2
-rw-r--r--send-pack.c1
-rw-r--r--sequencer.c31
-rw-r--r--server-info.c3
-rw-r--r--server-info.h7
-rw-r--r--setup.c1
-rw-r--r--split-index.c2
-rw-r--r--split-index.h2
-rw-r--r--strbuf.c113
-rw-r--r--strbuf.h57
-rw-r--r--string-list.c13
-rw-r--r--string-list.h12
-rw-r--r--submodule-config.c1
-rw-r--r--symlinks.c3
-rw-r--r--symlinks.h28
-rw-r--r--t/README2
-rw-r--r--t/annotate-tests.sh11
-rw-r--r--t/helper/test-bloom.c1
-rw-r--r--t/helper/test-cache-tree.c1
-rw-r--r--t/helper/test-ctype.c2
-rw-r--r--t/helper/test-dump-cache-tree.c2
-rw-r--r--t/helper/test-dump-fsmonitor.c1
-rw-r--r--t/helper/test-dump-untracked-cache.c1
-rw-r--r--t/helper/test-example-decorate.c1
-rw-r--r--t/helper/test-fsmonitor-client.c1
-rw-r--r--t/helper/test-hashmap.c22
-rw-r--r--t/helper/test-json-writer.c76
-rw-r--r--t/helper/test-lazy-init-name-hash.c1
-rw-r--r--t/helper/test-match-trees.c3
-rw-r--r--t/helper/test-mergesort.c2
-rw-r--r--t/helper/test-oid-array.c2
-rw-r--r--t/helper/test-oidmap.c21
-rw-r--r--t/helper/test-oidtree.c2
-rw-r--r--t/helper/test-parse-options.c2
-rw-r--r--t/helper/test-path-utils.c1
-rw-r--r--t/helper/test-read-cache.c1
-rw-r--r--t/helper/test-read-midx.c2
-rw-r--r--t/helper/test-reftable.c1
-rw-r--r--t/helper/test-scrap-cache-tree.c1
-rw-r--r--t/helper/test-string-list.c6
-rw-r--r--t/helper/test-submodule-config.c2
-rw-r--r--t/helper/test-submodule-nested-repo-config.c1
-rw-r--r--t/helper/test-submodule.c1
-rw-r--r--t/helper/test-trace2.c1
-rw-r--r--t/helper/test-write-cache.c1
-rw-r--r--t/lib-credential.sh59
-rw-r--r--t/lib-diff-alternative.sh31
-rwxr-xr-xt/perf/p2000-sparse-operations.sh2
-rwxr-xr-xt/perf/p5312-pack-bitmaps-revs.sh3
-rwxr-xr-xt/t0003-attributes.sh11
-rwxr-xr-xt/t0020-crlf.sh38
-rwxr-xr-xt/t0035-safe-bare-repository.sh32
-rwxr-xr-xt/t0063-string-list.sh51
-rwxr-xr-xt/t0300-credentials.sh20
-rwxr-xr-xt/t0301-credential-cache.sh1
-rwxr-xr-xt/t1092-sparse-checkout-compatibility.sh66
-rwxr-xr-xt/t1300-config.sh43
-rwxr-xr-xt/t1301-shared-repo.sh4
-rwxr-xr-xt/t1450-fsck.sh5
-rwxr-xr-xt/t1502-rev-parse-parseopt.sh6
-rwxr-xr-xt/t1507-rev-parse-upstream.sh3
-rwxr-xr-xt/t2019-checkout-ambiguous-ref.sh4
-rwxr-xr-xt/t3200-branch.sh29
-rwxr-xr-xt/t3202-show-branch.sh18
-rwxr-xr-xt/t3301-notes.sh126
-rwxr-xr-xt/t3321-notes-stripspace.sh577
-rwxr-xr-xt/t3427-rebase-subtree.sh12
-rwxr-xr-xt/t3501-revert-cherry-pick.sh18
-rwxr-xr-xt/t4018-diff-funcname.sh19
-rwxr-xr-xt/t4022-diff-rewrite.sh2
-rwxr-xr-xt/t4047-diff-dirstat.sh2
-rwxr-xr-xt/t4062-diff-pickaxe.sh2
-rwxr-xr-xt/t4212-log-corrupt.sh51
-rwxr-xr-xt/t4300-merge-tree.sh18
-rwxr-xr-xt/t5304-prune.sh44
-rwxr-xr-xt/t5325-reverse-index.sh90
-rwxr-xr-xt/t5326-multi-pack-bitmaps.sh44
-rwxr-xr-xt/t5510-fetch.sh53
-rwxr-xr-xt/t5523-push-upstream.sh12
-rwxr-xr-xt/t5526-fetch-submodules.sh13
-rwxr-xr-xt/t5543-atomic-push.sh5
-rwxr-xr-xt/t5574-fetch-output.sh293
-rwxr-xr-xt/t5583-push-branches.sh115
-rwxr-xr-xt/t6006-rev-list-format.sh2
-rwxr-xr-xt/t6500-gc.sh133
-rwxr-xr-xt/t6501-freshen-objects.sh12
-rwxr-xr-xt/t7001-mv.sh37
-rwxr-xr-xt/t7300-clean.sh4
-rwxr-xr-xt/t7510-signed-commit.sh21
-rwxr-xr-xt/t9001-send-email.sh115
-rwxr-xr-xt/t9300-fast-import.sh13
-rwxr-xr-xt/t9800-git-p4-basic.sh2
-rwxr-xr-xt/t9902-completion.sh30
-rw-r--r--t/test-lib-functions.sh9
-rw-r--r--tempfile.c1
-rw-r--r--trace2.c1
-rw-r--r--trace2/tr2_tgt_event.c1
-rw-r--r--trace2/tr2_tgt_normal.c1
-rw-r--r--trace2/tr2_tgt_perf.c1
-rw-r--r--tree-diff.c16
-rw-r--r--tree-walk.c2
-rw-r--r--tree-walk.h3
-rw-r--r--tree.c72
-rw-r--r--tree.h11
-rw-r--r--unpack-trees.c1
-rw-r--r--userdiff.c2
-rw-r--r--versioncmp.c3
-rw-r--r--versioncmp.h6
-rw-r--r--wrapper.c5
-rw-r--r--ws.c8
-rw-r--r--ws.h33
-rw-r--r--wt-status.c7
-rw-r--r--xdiff-interface.h2
362 files changed, 4755 insertions, 2532 deletions
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 3133ea3182..b629176d7d 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -144,13 +144,16 @@ man5dir = $(mandir)/man5
man7dir = $(mandir)/man7
# DESTDIR =
+GIT_DATE := $(shell git show --quiet --pretty='%as')
+
ASCIIDOC = asciidoc
ASCIIDOC_EXTRA =
ASCIIDOC_HTML = xhtml11
ASCIIDOC_DOCBOOK = docbook
ASCIIDOC_CONF = -f asciidoc.conf
ASCIIDOC_COMMON = $(ASCIIDOC) $(ASCIIDOC_EXTRA) $(ASCIIDOC_CONF) \
- -amanmanual='Git Manual' -amansource='Git $(GIT_VERSION)'
+ -amanmanual='Git Manual' -amansource='Git $(GIT_VERSION)' \
+ -arevdate='$(GIT_DATE)'
ASCIIDOC_DEPS = asciidoc.conf GIT-ASCIIDOCFLAGS
TXT_TO_HTML = $(ASCIIDOC_COMMON) -b $(ASCIIDOC_HTML)
TXT_TO_XML = $(ASCIIDOC_COMMON) -b $(ASCIIDOC_DOCBOOK)
diff --git a/Documentation/RelNotes/2.41.0.txt b/Documentation/RelNotes/2.41.0.txt
index 63345b9595..a4b4b1d826 100644
--- a/Documentation/RelNotes/2.41.0.txt
+++ b/Documentation/RelNotes/2.41.0.txt
@@ -3,7 +3,7 @@ Git v2.41 Release Notes
UI, Workflows & Features
- * Allow information carried on the WWW-AUthenticate header to be
+ * Allow information carried on the WWW-Authenticate header to be
passed to the credential helpers.
* A new "fetch.hideRefs" option can be used to exclude specified refs
@@ -73,6 +73,50 @@ UI, Workflows & Features
number of input files and where in the sequence each invocation is
via environment variables.
+ * When "gc" needs to retain unreachable objects, packing them into
+ cruft packs (instead of exploding them into loose object files) has
+ been offered as a more efficient option for some time. Now the use
+ of cruft packs has been made the default and no longer considered
+ an experimental feature.
+
+ * The output given by "git blame" that attributes a line to contents
+ taken from the file specified by the "--contents" option shows it
+ differently from a line attributed to the working tree file.
+
+ * "git send-email" learned to give the e-mail headers to the validate
+ hook by passing an extra argument from the command line.
+
+ * The credential subsystem learns to help OAuth framework.
+
+ * The titles of manual pages used to be chomped at an unreasonably
+ short limit, which has been removed.
+
+ * Error messages given when working on an unborn branch that is
+ checked out in another worktree have been improved.
+
+ * The documentation was misleading about the interaction between
+ GIT_DEFAULT_HASH and "git clone", which has been clarified to
+ stress that the variable is to be ignored by the command.
+
+ * "git send-email" learned "--header-cmd=<cmd>" that can inject
+ arbitrary e-mail header lines to the outgoing messages.
+
+ * "git fsck" learned to detect bit-flip breakages in the reachability
+ bitmap files.
+
+ * The "--stdin" option of "git name-rev" has been replaced with
+ the "--annotate-stdin" option more than a year ago. We stop
+ advertising it in the "git name-rev -h" output.
+
+ * "git push --all" gained an alias "git push --branches".
+
+ * "git fetch" learned the "--porcelain" option that emits what it did
+ in a machine-parseable format.
+
+ * "git --attr-source=<tree> cmd $args" is a new way to have any
+ command to read attributes not from the working tree but from the
+ given tree object.
+
Performance, Internal Implementation, Development Support etc.
@@ -113,6 +157,42 @@ Performance, Internal Implementation, Development Support etc.
* "git write-tree" learns to work better with sparse-index.
+ * The on-disk reverse index that allows mapping from the pack offset
+ to the object name for the object stored at the offset has been
+ enabled by default.
+
+ * "git fsck" learned to validate the on-disk pack reverse index files.
+
+ * strtok() and strtok_r() are banned in this codebase.
+
+ * The detect-compilers script to help auto-tweaking the build system
+ had trouble working with compilers whose version number has extra
+ suffixes. The script has been taught that certain suffixes (like
+ "-win32" in "gcc 10-win32") can be safely stripped as they share
+ the same features and bugs with the version without the suffix.
+
+ * ctype tests have been taught to test EOF, too.
+
+ * The implementation of credential helpers used fgets() over fixed
+ size buffers to read protocol messages, causing the remainder of
+ the folded long line to trigger unexpected behaviour, which has
+ been corrected.
+
+ * The implementation of the default "negotiator", used to find common
+ ancestor over the network for object tranfer, used to be recursive;
+ it was updated to be iterative to conserve stackspace usage.
+
+ * Our custom callout formatter is no longer used in the documentation
+ formatting toolchain, as the upstream default ones give better
+ output these days.
+
+ * The tracing mechanism learned to notice and report when
+ auto-discovered bare repositories are being used, as allowing so
+ without explicitly stating the user intends to do so (with setting
+ GIT_DIR for example) can be used with social engineering as an
+ attack vector.
+
+ * "git diff-files" learned not to expand sparse-index unless needed.
Fixes since v2.40
@@ -253,6 +333,42 @@ Fixes since v2.40
case bugs, which have been corrected.
(merge d85cd18777 ps/fix-geom-repack-with-alternates later to maint).
+ * The "%GT" placeholder for the "--format" option of "git log" and
+ friends caused BUG() to trigger on a commit signed with an unknown
+ key, which has been corrected.
+ (merge 7891e46585 jk/gpg-trust-level-fix later to maint).
+
+ * The completion script used to use bare "read" without the "-r"
+ option to read the contents of various state files, which risked
+ getting confused with backslashes in them. This has been
+ corrected.
+ (merge 197152098a ek/completion-use-read-r-to-read-literally later to maint).
+
+ * A small API fix to the ort merge strategy backend.
+ (merge 000c4ceca7 en/ort-finalize-after-0-merges-fix later to maint).
+
+ * The commit object parser has been taught to be a bit more lenient
+ to parse timestamps on the author/committer line with a malformed
+ author/committer ident.
+ (merge 90ef0f14eb jk/parse-commit-with-malformed-ident later to maint).
+
+ * Retitle a test script with an overly narrow name.
+ (merge 8bb19c14fb ob/t3501-retitle later to maint).
+
+ * Doc update to clarify how text and eol attributes interact to
+ specify the end-of-line conversion.
+ (merge 6696077ace ah/doc-attributes-text later to maint).
+
+ * Gitk updates from GfW project.
+ (merge 99e70f3077 js/gitk-fixes-from-gfw later to maint).
+
+ * "git diff --dirstat" leaked memory, which has been plugged.
+ (merge 83973981eb jc/dirstat-plug-leaks later to maint).
+
+ * "git merge-tree" reads the basic configuration, which can be used
+ by git forges to disable replace-refs feature.
+ (merge b6551feadf ds/merge-tree-use-config later to maint).
+
* Other code cleanup, docfix, build fix, etc.
(merge f7111175df as/doc-markup-fix later to maint).
(merge 90ff7c9898 fc/test-aggregation-clean-up later to maint).
@@ -269,3 +385,11 @@ Fixes since v2.40
(merge 4833b08426 ow/ref-format-remove-unused-member later to maint).
(merge d0ea2ca1cf dw/doc-submittingpatches-grammofix later to maint).
(merge fd72637423 ar/t2024-checkout-output-fix later to maint).
+ (merge d45cbe3fe0 ob/sequencer-i18n-fix later to maint).
+ (merge b734fe49fd ob/messages-capitalize-exception later to maint).
+ (merge ad353d7e77 ma/gittutorial-fixes later to maint).
+ (merge a5855fd8d4 ar/test-cleanup-unused-file-creation-part2 later to maint).
+ (merge 0c5308af30 sd/doc-gitignore-and-rm-cached later to maint).
+ (merge cbb83daeaf kh/doc-interpret-trailers-updates later to maint).
+ (merge 3d77fbb664 ar/config-count-tests-updates later to maint).
+ (merge b7cf25c8f4 jc/t9800-fix-use-of-show-s-raw later to maint).
diff --git a/Documentation/blame-options.txt b/Documentation/blame-options.txt
index 95599bd6e5..552dcc60f2 100644
--- a/Documentation/blame-options.txt
+++ b/Documentation/blame-options.txt
@@ -64,11 +64,9 @@ include::line-range-format.txt[]
manual page.
--contents <file>::
- Pretend the file being annotated has a commit with the
- contents from the named file and a parent of <rev>,
- defaulting to HEAD when no <rev> is specified. You may
- specify '-' to make the command read from the standard
- input for the file contents.
+ Annotate using the contents from the named file, starting from <rev>
+ if it is specified, and HEAD otherwise. You may specify '-' to make
+ the command read from the standard input for the file contents.
--date <format>::
Specifies the format used to output dates. If --date is not
diff --git a/Documentation/config/feature.txt b/Documentation/config/feature.txt
index e52bc6b858..17b4d39f89 100644
--- a/Documentation/config/feature.txt
+++ b/Documentation/config/feature.txt
@@ -14,9 +14,6 @@ feature.experimental::
+
* `fetch.negotiationAlgorithm=skipping` may improve fetch negotiation times by
skipping more commits at a time, reducing the number of round trips.
-+
-* `gc.cruftPacks=true` reduces disk space used by unreachable objects during
-garbage collection, preventing loose object explosions.
feature.manyFiles::
Enable config options that optimize for repos with many files in the
diff --git a/Documentation/config/gc.txt b/Documentation/config/gc.txt
index 38fea076a2..7f95c866e1 100644
--- a/Documentation/config/gc.txt
+++ b/Documentation/config/gc.txt
@@ -43,11 +43,11 @@ gc.autoDetach::
if the system supports it. Default is true.
gc.bigPackThreshold::
- If non-zero, all packs larger than this limit are kept when
- `git gc` is run. This is very similar to `--keep-largest-pack`
- except that all packs that meet the threshold are kept, not
- just the largest pack. Defaults to zero. Common unit suffixes of
- 'k', 'm', or 'g' are supported.
+ If non-zero, all non-cruft packs larger than this limit are kept
+ when `git gc` is run. This is very similar to
+ `--keep-largest-pack` except that all non-cruft packs that meet
+ the threshold are kept, not just the largest pack. Defaults to
+ zero. Common unit suffixes of 'k', 'm', or 'g' are supported.
+
Note that if the number of kept packs is more than gc.autoPackLimit,
this configuration variable is ignored, all packs except the base pack
@@ -84,7 +84,7 @@ gc.packRefs::
gc.cruftPacks::
Store unreachable objects in a cruft pack (see
linkgit:git-repack[1]) instead of as loose objects. The default
- is `false`.
+ is `true`.
gc.pruneExpire::
When 'git gc' is run, it will call 'prune --expire 2.weeks.ago'
diff --git a/Documentation/config/pack.txt b/Documentation/config/pack.txt
index 53093d9996..d4c7c9d4e4 100644
--- a/Documentation/config/pack.txt
+++ b/Documentation/config/pack.txt
@@ -171,9 +171,15 @@ pack.writeBitmapLookupTable::
beneficial in repositories that have relatively large bitmap
indexes. Defaults to false.
+pack.readReverseIndex::
+ When true, git will read any .rev file(s) that may be available
+ (see: linkgit:gitformat-pack[5]). When false, the reverse index
+ will be generated from scratch and stored in memory. Defaults to
+ true.
+
pack.writeReverseIndex::
When true, git will write a corresponding .rev file (see:
linkgit:gitformat-pack[5])
for each new packfile that it writes in all places except for
linkgit:git-fast-import[1] and in the bulk checkin mechanism.
- Defaults to false.
+ Defaults to true.
diff --git a/Documentation/config/sendemail.txt b/Documentation/config/sendemail.txt
index 51da7088a8..92a9ebe98c 100644
--- a/Documentation/config/sendemail.txt
+++ b/Documentation/config/sendemail.txt
@@ -61,6 +61,7 @@ sendemail.ccCmd::
sendemail.chainReplyTo::
sendemail.envelopeSender::
sendemail.from::
+sendemail.headerCmd::
sendemail.signedoffbycc::
sendemail.smtpPass::
sendemail.suppresscc::
diff --git a/Documentation/doc-diff b/Documentation/doc-diff
index 1694300e50..fb09e0ac0e 100755
--- a/Documentation/doc-diff
+++ b/Documentation/doc-diff
@@ -153,7 +153,7 @@ render_tree () {
make -j$parallel -C "$tmp/worktree" \
$makemanflags \
GIT_VERSION=omitted \
- SOURCE_DATE_EPOCH=0 \
+ GIT_DATE=1970-01-01 \
DESTDIR="$tmp/installed/$dname+" \
install-man &&
mv "$tmp/installed/$dname+" "$tmp/installed/$dname"
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index 622bd84768..41fc7ca3c6 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -78,6 +78,13 @@ linkgit:git-config[1].
--dry-run::
Show what would be done, without making any changes.
+--porcelain::
+ Print the output to standard output in an easy-to-parse format for
+ scripts. See section OUTPUT in linkgit:git-fetch[1] for details.
++
+This is incompatible with `--recurse-submodules=[yes|on-demand]` and takes
+precedence over the `fetch.output` config option.
+
ifndef::git-pull[]
--[no-]write-fetch-head::
Write the list of remote refs fetched in the `FETCH_HEAD`
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 6bb32ab460..4af0904f47 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -483,14 +483,11 @@ $ git checkout -b foo # or "git switch -c foo" <1>
$ git branch foo <2>
$ git tag foo <3>
------------
-
<1> creates a new branch `foo`, which refers to commit `f`, and then
updates `HEAD` to refer to branch `foo`. In other words, we'll no longer
be in detached `HEAD` state after this command.
-
<2> similarly creates a new branch `foo`, which refers to commit `f`,
but leaves `HEAD` detached.
-
<3> creates a new tag `foo`, which refers to commit `f`,
leaving `HEAD` detached.
@@ -519,84 +516,89 @@ to checkout these paths out of the index.
EXAMPLES
--------
-. The following sequence checks out the `master` branch, reverts
- the `Makefile` to two revisions back, deletes `hello.c` by
- mistake, and gets it back from the index.
-+
+=== 1. Paths
+
+The following sequence checks out the `master` branch, reverts
+the `Makefile` to two revisions back, deletes `hello.c` by
+mistake, and gets it back from the index.
+
------------
$ git checkout master <1>
$ git checkout master~2 Makefile <2>
$ rm -f hello.c
$ git checkout hello.c <3>
------------
-+
<1> switch branch
<2> take a file out of another commit
<3> restore `hello.c` from the index
-+
+
If you want to check out _all_ C source files out of the index,
you can say
-+
+
------------
$ git checkout -- '*.c'
------------
-+
+
Note the quotes around `*.c`. The file `hello.c` will also be
checked out, even though it is no longer in the working tree,
because the file globbing is used to match entries in the index
(not in the working tree by the shell).
-+
+
If you have an unfortunate branch that is named `hello.c`, this
step would be confused as an instruction to switch to that branch.
You should instead write:
-+
+
------------
$ git checkout -- hello.c
------------
-. After working in the wrong branch, switching to the correct
- branch would be done using:
-+
+=== 2. Merge
+
+After working in the wrong branch, switching to the correct
+branch would be done using:
+
------------
$ git checkout mytopic
------------
-+
+
However, your "wrong" branch and correct `mytopic` branch may
differ in files that you have modified locally, in which case
the above checkout would fail like this:
-+
+
------------
$ git checkout mytopic
error: You have local changes to 'frotz'; not switching branches.
------------
-+
+
You can give the `-m` flag to the command, which would try a
three-way merge:
-+
+
------------
$ git checkout -m mytopic
Auto-merging frotz
------------
-+
+
After this three-way merge, the local modifications are _not_
registered in your index file, so `git diff` would show you what
changes you made since the tip of the new branch.
-. When a merge conflict happens during switching branches with
- the `-m` option, you would see something like this:
-+
+=== 3. Merge conflict
+
+When a merge conflict happens during switching branches with
+the `-m` option, you would see something like this:
+
------------
$ git checkout -m mytopic
Auto-merging frotz
ERROR: Merge conflict in frotz
fatal: merge program failed
------------
-+
+
At this point, `git diff` shows the changes cleanly merged as in
the previous example, as well as the changes in the conflicted
files. Edit and resolve the conflict and mark it resolved with
`git add` as usual:
-+
+
------------
$ edit frotz
$ git add frotz
diff --git a/Documentation/git-credential.txt b/Documentation/git-credential.txt
index 3394c03611..0e6d9e85ec 100644
--- a/Documentation/git-credential.txt
+++ b/Documentation/git-credential.txt
@@ -156,6 +156,12 @@ Git understands the following attributes:
When reading credentials from helpers, `git credential fill` ignores expired
passwords. Represented as Unix time UTC, seconds since 1970.
+`oauth_refresh_token`::
+
+ An OAuth refresh token may accompany a password that is an OAuth access
+ token. Helpers must treat this attribute as confidential like the password
+ attribute. Git itself has no special behaviour for this attribute.
+
`url`::
When this special attribute is read by `git credential`, the
diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt
index 52b679256c..a85cc756eb 100644
--- a/Documentation/git-diff.txt
+++ b/Documentation/git-diff.txt
@@ -102,7 +102,11 @@ If --merge-base is given, use the merge base of the two commits for the
Just in case you are doing something exotic, it should be
noted that all of the <commit> in the above description, except
in the `--merge-base` case and in the last two forms that use `..`
-notations, can be any <tree>.
+notations, can be any <tree>. A tree of interest is the one pointed to
+by the special ref `AUTO_MERGE`, which is written by the 'ort' merge
+strategy upon hitting merge conflicts (see linkgit:git-merge[1]).
+Comparing the working tree with `AUTO_MERGE` shows changes you've made
+so far to resolve conflicts (see the examples below).
For a more complete list of ways to spell <commit>, see
"SPECIFYING REVISIONS" section in linkgit:gitrevisions[7].
@@ -152,6 +156,7 @@ Various ways to check your working tree::
$ git diff <1>
$ git diff --cached <2>
$ git diff HEAD <3>
+$ git diff AUTO_MERGE <4>
------------
+
<1> Changes in the working tree not yet staged for the next commit.
@@ -159,6 +164,7 @@ $ git diff HEAD <3>
would be committing if you run `git commit` without `-a` option.
<3> Changes in the working tree since your last commit; what you
would be committing if you run `git commit -a`
+<4> Changes in the working tree you've made to resolve conflicts so far.
Comparing with arbitrary commits::
+
diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt
index fba66f1460..f123139c58 100644
--- a/Documentation/git-fetch.txt
+++ b/Documentation/git-fetch.txt
@@ -204,6 +204,15 @@ representing the status of a single ref. Each line is of the form:
<flag> <summary> <from> -> <to> [<reason>]
-------------------------------
+When using `--porcelain`, the output format is intended to be
+machine-parseable. In contrast to the human-readable output formats it
+thus prints to standard output instead of standard error. Each line is
+of the form:
+
+-------------------------------
+<flag> <old-object-id> <new-object-id> <local-reference>
+-------------------------------
+
The status of up-to-date refs is shown only if the --verbose option is
used.
diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt
index a65c9aa62d..90806fd26a 100644
--- a/Documentation/git-gc.txt
+++ b/Documentation/git-gc.txt
@@ -54,9 +54,10 @@ other housekeeping tasks (e.g. rerere, working trees, reflog...) will
be performed as well.
---cruft::
+--[no-]cruft::
When expiring unreachable objects, pack them separately into a
- cruft pack instead of storing them as loose objects.
+ cruft pack instead of storing them as loose objects. `--cruft`
+ is on by default.
--prune=<date>::
Prune loose objects older than date (default is 2 weeks ago,
@@ -77,9 +78,10 @@ be performed as well.
instance running on this repository.
--keep-largest-pack::
- All packs except the largest pack and those marked with a
- `.keep` files are consolidated into a single pack. When this
- option is used, `gc.bigPackThreshold` is ignored.
+ All packs except the largest non-cruft pack, any packs marked
+ with a `.keep` file, and any cruft pack(s) are consolidated into
+ a single pack. When this option is used, `gc.bigPackThreshold`
+ is ignored.
AGGRESSIVE
----------
diff --git a/Documentation/git-interpret-trailers.txt b/Documentation/git-interpret-trailers.txt
index 22ff3a603e..4b97f812be 100644
--- a/Documentation/git-interpret-trailers.txt
+++ b/Documentation/git-interpret-trailers.txt
@@ -280,7 +280,7 @@ $ cat msg.txt
subject
message
-$ cat msg.txt | git interpret-trailers --trailer 'sign: Alice <alice@example.com>' --trailer 'sign: Bob <bob@example.com>'
+$ git interpret-trailers --trailer 'sign: Alice <alice@example.com>' --trailer 'sign: Bob <bob@example.com>' <msg.txt
subject
message
@@ -322,17 +322,30 @@ $ git interpret-trailers --trailer 'Cc: Alice <alice@example.com>' --trailer 'Re
'Signed-off-by: ' already, and show how it works:
+
------------
+$ cat msg1.txt
+subject
+
+message
$ git config trailer.sign.key "Signed-off-by: "
$ git config trailer.sign.ifmissing add
$ git config trailer.sign.ifexists doNothing
-$ git config trailer.sign.command 'echo "$(git config user.name) <$(git config user.email)>"'
-$ git interpret-trailers <<EOF
-> EOF
+$ git config trailer.sign.cmd 'echo "$(git config user.name) <$(git config user.email)>"'
+$ git interpret-trailers --trailer sign <msg1.txt
+subject
+
+message
Signed-off-by: Bob <bob@example.com>
-$ git interpret-trailers <<EOF
-> Signed-off-by: Alice <alice@example.com>
-> EOF
+$ cat msg2.txt
+subject
+
+message
+
+Signed-off-by: Alice <alice@example.com>
+$ git interpret-trailers --trailer sign <msg2.txt
+subject
+
+message
Signed-off-by: Alice <alice@example.com>
------------
@@ -357,15 +370,14 @@ Fix #42
$ cat ~/bin/glog-find-author
#!/bin/sh
test -n "$1" && git log --author="$1" --pretty="%an <%ae>" -1 || true
+$ cat msg.txt
+subject
+
+message
$ git config trailer.help.key "Helped-by: "
$ git config trailer.help.ifExists "addIfDifferentNeighbor"
$ git config trailer.help.cmd "~/bin/glog-find-author"
-$ git interpret-trailers --trailer="help:Junio" --trailer="help:Couder" <<EOF
-> subject
->
-> message
->
-> EOF
+$ git interpret-trailers --trailer="help:Junio" --trailer="help:Couder" <msg.txt
subject
message
@@ -382,15 +394,14 @@ Helped-by: Christian Couder <christian.couder@gmail.com>
$ cat ~/bin/glog-grep
#!/bin/sh
test -n "$1" && git log --grep "$1" --pretty=reference -1 || true
+$ cat msg.txt
+subject
+
+message
$ git config trailer.ref.key "Reference-to: "
$ git config trailer.ref.ifExists "replace"
$ git config trailer.ref.cmd "~/bin/glog-grep"
-$ git interpret-trailers --trailer="ref:Add copyright notices." <<EOF
-> subject
->
-> message
->
-> EOF
+$ git interpret-trailers --trailer="ref:Add copyright notices." <msg.txt
subject
message
@@ -402,17 +413,20 @@ Reference-to: 8bc9a0c769 (Add copyright notices., 2005-04-07)
commit that is related, and show how it works:
+
------------
+$ cat msg.txt
+subject
+
+message
+
+see: HEAD~2
+$ cat ~/bin/glog-ref
+#!/bin/sh
+git log -1 --oneline --format="%h (%s)" --abbrev-commit --abbrev=14
$ git config trailer.see.key "See-also: "
$ git config trailer.see.ifExists "replace"
$ git config trailer.see.ifMissing "doNothing"
-$ git config trailer.see.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG"
-$ git interpret-trailers <<EOF
-> subject
->
-> message
->
-> see: HEAD~2
-> EOF
+$ git config trailer.see.cmd "glog-ref"
+$ git interpret-trailers --trailer=see <msg.txt
subject
message
@@ -427,22 +441,21 @@ See-also: fe3187489d69c4 (subject of related commit)
to add a 'git-version' trailer:
+
------------
-$ sed -e 's/ Z$/ /' >commit_template.txt <<EOF
-> ***subject***
->
-> ***message***
->
-> Fixes: Z
-> Cc: Z
-> Reviewed-by: Z
-> Signed-off-by: Z
-> EOF
+$ cat temp.txt
+***subject***
+
+***message***
+
+Fixes: Z
+Cc: Z
+Reviewed-by: Z
+Signed-off-by: Z
+$ sed -e 's/ Z$/ /' temp.txt > commit_template.txt
$ git config commit.template commit_template.txt
-$ cat >.git/hooks/commit-msg <<EOF
-> #!/bin/sh
-> git interpret-trailers --trim-empty --trailer "git-version: \$(git describe)" "\$1" > "\$1.new"
-> mv "\$1.new" "\$1"
-> EOF
+$ cat .git/hooks/commit-msg
+#!/bin/sh
+git interpret-trailers --trim-empty --trailer "git-version: \$(git describe)" "\$1" > "\$1.new"
+mv "\$1.new" "\$1"
$ chmod +x .git/hooks/commit-msg
------------
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index 0aeff572a5..3f61389c1c 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -194,9 +194,13 @@ happens:
versions: stage 1 stores the version from the common ancestor,
stage 2 from `HEAD`, and stage 3 from `MERGE_HEAD` (you
can inspect the stages with `git ls-files -u`). The working
- tree files contain the result of the "merge" program; i.e. 3-way
+ tree files contain the result of the merge operation; i.e. 3-way
merge results with familiar conflict markers `<<<` `===` `>>>`.
-5. No other changes are made. In particular, the local
+5. A special ref `AUTO_MERGE` is written, pointing to a tree corresponding
+ to the current content of the working tree (including conflict markers).
+ Note that this ref is only written when the 'ort' merge strategy
+ is used (the default).
+6. No other changes are made. In particular, the local
modifications you had before you started merge will stay the
same and the index entries for them stay as they were,
i.e. matching `HEAD`.
@@ -336,7 +340,8 @@ You can work through the conflict with a number of tools:
* Look at the diffs. `git diff` will show a three-way diff,
highlighting changes from both the `HEAD` and `MERGE_HEAD`
- versions.
+ versions. `git diff AUTO_MERGE` will show what changes you've
+ made so far to resolve conlicts.
* Look at the diffs from each branch. `git log --merge -p <path>`
will show diffs first for the `HEAD` version and then the
diff --git a/Documentation/git-name-rev.txt b/Documentation/git-name-rev.txt
index ec8a27ce8b..5c56c87025 100644
--- a/Documentation/git-name-rev.txt
+++ b/Documentation/git-name-rev.txt
@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git name-rev' [--tags] [--refs=<pattern>]
- ( --all | --stdin | <commit-ish>... )
+ ( --all | --annotate-stdin | <commit-ish>... )
DESCRIPTION
-----------
@@ -46,7 +46,8 @@ OPTIONS
Transform stdin by substituting all the 40-character SHA-1
hexes (say $hex) with "$hex ($rev_name)". When used with
--name-only, substitute with "$rev_name", omitting $hex
- altogether.
+ altogether. This option was called `--stdin` in older versions
+ of Git.
+
For example:
+
@@ -70,10 +71,6 @@ The full name after substitution is master,
while its tree object is 70d105cc79e63b81cfdcb08a15297c23e60b07ad
-----------
---stdin::
- This option is deprecated in favor of 'git name-rev --annotate-stdin'.
- They are functionally equivalent.
-
--name-only::
Instead of printing both the SHA-1 and the name, print only
the name. If given with --tags the usual tag prefix of
@@ -107,7 +104,7 @@ Now you are wiser, because you know that it happened 940 revisions before v0.99.
Another nice thing you can do is:
------------
-% git log | git name-rev --stdin
+% git log | git name-rev --annotate-stdin
------------
GIT
diff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt
index efbc10f0f5..5f3a9479a9 100644
--- a/Documentation/git-notes.txt
+++ b/Documentation/git-notes.txt
@@ -9,10 +9,10 @@ SYNOPSIS
--------
[verse]
'git notes' [list [<object>]]
-'git notes' add [-f] [--allow-empty] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
+'git notes' add [-f] [--allow-empty] [--separator=<paragraph-break>] [--[no-]stripspace] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
'git notes' copy [-f] ( --stdin | <from-object> [<to-object>] )
-'git notes' append [--allow-empty] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
-'git notes' edit [--allow-empty] [<object>]
+'git notes' append [--allow-empty] [--separator=<paragraph-break>] [--[no-]stripspace] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
+'git notes' edit [--allow-empty] [<object>] [--[no-]stripspace]
'git notes' show [<object>]
'git notes' merge [-v | -q] [-s <strategy> ] <notes-ref>
'git notes' merge --commit [-v | -q]
@@ -65,7 +65,9 @@ add::
However, if you're using `add` interactively (using an editor
to supply the notes contents), then - instead of aborting -
the existing notes will be opened in the editor (like the `edit`
- subcommand).
+ subcommand). If you specify multiple `-m` and `-F`, a blank
+ line will be inserted between the messages. Use the `--separator`
+ option to insert other delimiters.
copy::
Copy the notes for the first object onto the second object (defaults to
@@ -85,8 +87,12 @@ corresponding <to-object>. (The optional `<rest>` is ignored so that
the command can read the input given to the `post-rewrite` hook.)
append::
- Append to the notes of an existing object (defaults to HEAD).
- Creates a new notes object if needed.
+ Append new message(s) given by `-m` or `-F` options to an
+ existing note, or add them as a new note if one does not
+ exist, for the object (defaults to HEAD). When appending to
+ an existing note, a blank line is added before each new
+ message as an inter-paragraph separator. The separator can
+ be customized with the `--separator` option.
edit::
Edit the notes for a given object (defaults to HEAD).
@@ -135,20 +141,26 @@ OPTIONS
If multiple `-m` options are given, their values
are concatenated as separate paragraphs.
Lines starting with `#` and empty lines other than a
- single line between paragraphs will be stripped out.
+ single line between paragraphs will be stripped out,
+ if you wish to keep them verbatim, use `--no-stripspace`.
-F <file>::
--file=<file>::
Take the note message from the given file. Use '-' to
read the note message from the standard input.
Lines starting with `#` and empty lines other than a
- single line between paragraphs will be stripped out.
+ single line between paragraphs will be stripped out,
+ if you wish to keep them verbatim, use with
+ `--no-stripspace` option.
-C <object>::
--reuse-message=<object>::
Take the given blob object (for example, another note) as the
note message. (Use `git notes copy <object>` instead to
- copy notes between objects.)
+ copy notes between objects.). By default, message will be
+ copied verbatim, but if you wish to strip out the lines
+ starting with `#` and empty lines other than a single line
+ between paragraphs, use with`--stripspace` option.
-c <object>::
--reedit-message=<object>::
@@ -159,6 +171,18 @@ OPTIONS
Allow an empty note object to be stored. The default behavior is
to automatically remove empty notes.
+--separator <paragraph-break>::
+ Specify a string used as a custom inter-paragraph separator
+ (a newline is added at the end as needed). Defaults to a
+ blank line.
+
+--[no-]stripspace::
+ Strip leading and trailing whitespace from the note message.
+ Also strip out empty lines other than a single line between
+ paragraphs. For lines starting with `#` will be stripped out
+ in non-editor cases like "-m", "-F" and "-C", but not in
+ editor case like "git notes edit", "-c", etc.
+
--ref <ref>::
Manipulate the notes tree in <ref>. This overrides
`GIT_NOTES_REF` and the "core.notesRef" configuration. The ref
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 5bb1d5aae2..297927d866 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -9,7 +9,7 @@ git-push - Update remote refs along with associated objects
SYNOPSIS
--------
[verse]
-'git push' [--all | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
+'git push' [--all | --branches | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
[--repo=<repository>] [-f | --force] [-d | --delete] [--prune] [-v | --verbose]
[-u | --set-upstream] [-o <string> | --push-option=<string>]
[--[no-]signed|--signed=(true|false|if-asked)]
@@ -147,6 +147,7 @@ already exists on the remote side.
`tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`.
--all::
+--branches::
Push all branches (i.e. refs under `refs/heads/`); cannot be
used with other <refspec>.
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index b0f438ec99..492a82323d 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -320,6 +320,17 @@ Automating
Output of this command must be single email address per line.
Default is the value of `sendemail.ccCmd` configuration value.
+--header-cmd=<command>::
+ Specify a command that is executed once per outgoing message
+ and output RFC 2822 style header lines to be inserted into
+ them. When the `sendemail.headerCmd` configuration variable is
+ set, its value is always used. When --header-cmd is provided
+ at the command line, its value takes precedence over the
+ `sendemail.headerCmd` configuration variable.
+
+--no-header-cmd::
+ Disable any header command in use.
+
--[no-]chain-reply-to::
If this is set, each email will be sent as a reply to the previous
email sent. If disabled with "--no-chain-reply-to", all emails after
@@ -484,14 +495,10 @@ edit ~/.gitconfig to specify your account settings:
smtpServerPort = 587
----
-If you have multi-factor authentication set up on your Gmail account, you will
-need to generate an app-specific password for use with 'git send-email'. Visit
+If you have multi-factor authentication set up on your Gmail account, you can
+generate an app-specific password for use with 'git send-email'. Visit
https://security.google.com/settings/security/apppasswords to create it.
-If you do not have multi-factor authentication set up on your Gmail account,
-you will need to allow less secure app access. Visit
-https://myaccount.google.com/lesssecureapps to enable it.
-
Once your commits are ready to be sent to the mailing list, run the
following commands:
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 74973d3cc4..f0cafa2290 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -212,6 +212,11 @@ If you just want to run git as if it was started in `<path>` then use
nohelpers (exclude helper commands), alias and config
(retrieve command list from config variable completion.commands)
+--attr-source=<tree-ish>::
+ Read gitattributes from <tree-ish> instead of the worktree. See
+ linkgit:gitattributes[5]. This is equivalent to setting the
+ `GIT_ATTR_SOURCE` environment variable.
+
GIT COMMANDS
------------
@@ -546,9 +551,9 @@ double-quotes and respecting backslash escapes. E.g., the value
`GIT_DEFAULT_HASH`::
If this variable is set, the default hash algorithm for new
- repositories will be set to this value. This value is currently
- ignored when cloning; the setting of the remote repository
- is used instead. The default is "sha1". THIS VARIABLE IS
+ repositories will be set to this value. This value is
+ ignored when cloning and the setting of the remote repository
+ is always used. The default is "sha1". THIS VARIABLE IS
EXPERIMENTAL! See `--object-format` in linkgit:git-init[1].
Git Commits
@@ -686,6 +691,9 @@ for further details.
tells Git not to verify the SSL certificate when fetching or
pushing over HTTPS.
+`GIT_ATTR_SOURCE`::
+ Sets the treeish that gitattributes will be read from.
+
`GIT_ASKPASS`::
If this environment variable is set, then Git commands which need to
acquire passwords or passphrases (e.g. for HTTP or IMAP authentication)
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 39bfbca1ff..02a3ec83e4 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -120,20 +120,19 @@ repository upon 'git add' and 'git commit'.
`text`
^^^^^^
-This attribute enables and controls end-of-line normalization. When a
-text file is normalized, its line endings are converted to LF in the
-repository. To control what line ending style is used in the working
-directory, use the `eol` attribute for a single file and the
-`core.eol` configuration variable for all text files.
-Note that setting `core.autocrlf` to `true` or `input` overrides
-`core.eol` (see the definitions of those options in
-linkgit:git-config[1]).
+This attribute marks the path as a text file, which enables end-of-line
+conversion: When a matching file is added to the index, the file's line
+endings are normalized to LF in the index. Conversely, when the file is
+copied from the index to the working directory, its line endings may be
+converted from LF to CRLF depending on the `eol` attribute, the Git
+config, and the platform (see explanation of `eol` below).
Set::
Setting the `text` attribute on a path enables end-of-line
- normalization and marks the path as a text file. End-of-line
- conversion takes place without guessing the content type.
+ conversion on checkin and checkout as described above. Line endings
+ are normalized to LF in the index every time the file is checked in,
+ even if the file was previously added to Git with CRLF line endings.
Unset::
@@ -142,10 +141,11 @@ Unset::
Set to string value "auto"::
- When `text` is set to "auto", the path is marked for automatic
- end-of-line conversion. If Git decides that the content is
- text, its line endings are converted to LF on checkin.
- When the file has been committed with CRLF, no conversion is done.
+ When `text` is set to "auto", Git decides by itself whether the file
+ is text or binary. If it is text and the file was not already in
+ Git with CRLF endings, line endings are converted on checkin and
+ checkout as described above. Otherwise, no conversion is done on
+ checkin or checkout.
Unspecified::
@@ -159,26 +159,29 @@ unspecified.
`eol`
^^^^^
-This attribute sets a specific line-ending style to be used in the
-working directory. This attribute has effect only if the `text`
-attribute is set or unspecified, or if it is set to `auto`, the file is
-detected as text, and it is stored with LF endings in the index. Note
-that setting this attribute on paths which are in the index with CRLF
-line endings may make the paths to be considered dirty unless
-`text=auto` is set. Adding the path to the index again will normalize
-the line endings in the index.
+This attribute marks a path to use a specific line-ending style in the
+working tree when it is checked out. It has effect only if `text` or
+`text=auto` is set (see above), but specifying `eol` automatically sets
+`text` if `text` was left unspecified.
Set to string value "crlf"::
- This setting forces Git to normalize line endings for this
- file on checkin and convert them to CRLF when the file is
- checked out.
+ This setting converts the file's line endings in the working
+ directory to CRLF when the file is checked out.
Set to string value "lf"::
- This setting forces Git to normalize line endings to LF on
- checkin and prevents conversion to CRLF when the file is
- checked out.
+ This setting uses the same line endings in the working directory as
+ in the index when the file is checked out.
+
+Unspecified::
+
+ If the `eol` attribute is unspecified for a file, its line endings
+ in the working directory are determined by the `core.autocrlf` or
+ `core.eol` configuration variable (see the definitions of those
+ options in linkgit:git-config[1]). If `text` is set but neither of
+ those variables is, the default is `eol=crlf` on Windows and
+ `eol=lf` on all other platforms.
Backwards compatibility with `crlf` attribute
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/Documentation/gitformat-pack.txt b/Documentation/gitformat-pack.txt
index e06af02f21..0c1be2dbe8 100644
--- a/Documentation/gitformat-pack.txt
+++ b/Documentation/gitformat-pack.txt
@@ -611,8 +611,8 @@ result of repeatedly resetting the objects' mtimes to the present time.
If you are GC-ing repositories in a mixed version environment, consider omitting
the `--cruft` option when using linkgit:git-repack[1] and linkgit:git-gc[1], and
-leaving the `gc.cruftPacks` configuration unset until all writers understand
-cruft packs.
+setting the `gc.cruftPacks` configuration to "false" until all writers
+understand cruft packs.
=== Alternatives
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index c8e55b2613..86f804720a 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -595,10 +595,29 @@ processed by rebase.
sendemail-validate
~~~~~~~~~~~~~~~~~~
-This hook is invoked by linkgit:git-send-email[1]. It takes a single parameter,
-the name of the file that holds the e-mail to be sent. Exiting with a
-non-zero status causes `git send-email` to abort before sending any
-e-mails.
+This hook is invoked by linkgit:git-send-email[1].
+
+It takes these command line arguments. They are,
+1. the name of the file which holds the contents of the email to be sent.
+2. The name of the file which holds the SMTP headers of the email.
+
+The SMTP headers are passed in the exact same way as they are passed to the
+user's Mail Transport Agent (MTA). In effect, the email given to the user's
+MTA, is the contents of $2 followed by the contents of $1.
+
+An example of a few common headers is shown below. Take notice of the
+capitalization and multi-line tab structure.
+
+ From: Example <from@example.com>
+ To: to@example.com
+ Cc: cc@example.com,
+ A <author@example.com>,
+ One <one@example.com>,
+ two@example.com
+ Subject: PATCH-STRING
+
+Exiting with a non-zero status causes `git send-email` to abort
+before sending any e-mails.
The following environment variables are set when executing the hook.
diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt
index f2738b10db..4c17f2356c 100644
--- a/Documentation/gitignore.txt
+++ b/Documentation/gitignore.txt
@@ -146,7 +146,9 @@ The purpose of gitignore files is to ensure that certain files
not tracked by Git remain untracked.
To stop tracking a file that is currently tracked, use
-'git rm --cached'.
+'git rm --cached' to remove the file from the index. The filename
+can then be added to the `.gitignore` file to stop the file from
+being reintroduced in later commits.
Git does not follow symbolic links when accessing a `.gitignore` file in
the working tree. This keeps behavior consistent when the file is
diff --git a/Documentation/gittutorial.txt b/Documentation/gittutorial.txt
index 0e0b863105..c7cadd8aaf 100644
--- a/Documentation/gittutorial.txt
+++ b/Documentation/gittutorial.txt
@@ -49,7 +49,7 @@ $ git config --global user.email you@yourdomain.example.com
Importing a new project
-----------------------
-Assume you have a tarball project.tar.gz with your initial work. You
+Assume you have a tarball `project.tar.gz` with your initial work. You
can place it under Git revision control as follows.
------------------------------------------------
@@ -65,10 +65,10 @@ Initialized empty Git repository in .git/
------------------------------------------------
You've now initialized the working directory--you may notice a new
-directory created, named ".git".
+directory created, named `.git`.
Next, tell Git to take a snapshot of the contents of all files under the
-current directory (note the '.'), with 'git add':
+current directory (note the `.`), with `git add`:
------------------------------------------------
$ git add .
@@ -76,7 +76,7 @@ $ git add .
This snapshot is now stored in a temporary staging area which Git calls
the "index". You can permanently store the contents of the index in the
-repository with 'git commit':
+repository with `git commit`:
------------------------------------------------
$ git commit
@@ -95,21 +95,20 @@ $ git add file1 file2 file3
------------------------------------------------
You are now ready to commit. You can see what is about to be committed
-using 'git diff' with the --cached option:
+using `git diff` with the `--cached` option:
------------------------------------------------
$ git diff --cached
------------------------------------------------
-(Without --cached, 'git diff' will show you any changes that
+(Without `--cached`, `git diff` will show you any changes that
you've made but not yet added to the index.) You can also get a brief
-summary of the situation with 'git status':
+summary of the situation with `git status`:
------------------------------------------------
$ git status
On branch master
Changes to be committed:
-Your branch is up to date with 'origin/master'.
(use "git restore --staged <file>..." to unstage)
modified: file1
@@ -128,7 +127,7 @@ $ git commit
This will again prompt you for a message describing the change, and then
record a new version of the project.
-Alternatively, instead of running 'git add' beforehand, you can use
+Alternatively, instead of running `git add` beforehand, you can use
------------------------------------------------
$ git commit -a
@@ -151,7 +150,7 @@ Git tracks content not files
Many revision control systems provide an `add` command that tells the
system to start tracking changes to a new file. Git's `add` command
-does something simpler and more powerful: 'git add' is used both for new
+does something simpler and more powerful: `git add` is used both for new
and newly modified files, and in both cases it takes a snapshot of the
given files and stages that content in the index, ready for inclusion in
the next commit.
@@ -182,7 +181,7 @@ Managing branches
-----------------
A single Git repository can maintain multiple branches of
-development. To create a new branch named "experimental", use
+development. To create a new branch named `experimental`, use
------------------------------------------------
$ git branch experimental
@@ -201,8 +200,8 @@ you'll get a list of all existing branches:
* master
------------------------------------------------
-The "experimental" branch is the one you just created, and the
-"master" branch is a default branch that was created for you
+The `experimental` branch is the one you just created, and the
+`master` branch is a default branch that was created for you
automatically. The asterisk marks the branch you are currently on;
type
@@ -210,8 +209,8 @@ type
$ git switch experimental
------------------------------------------------
-to switch to the experimental branch. Now edit a file, commit the
-change, and switch back to the master branch:
+to switch to the `experimental` branch. Now edit a file, commit the
+change, and switch back to the `master` branch:
------------------------------------------------
(edit file)
@@ -220,9 +219,9 @@ $ git switch master
------------------------------------------------
Check that the change you made is no longer visible, since it was
-made on the experimental branch and you're back on the master branch.
+made on the `experimental` branch and you're back on the `master` branch.
-You can make a different change on the master branch:
+You can make a different change on the `master` branch:
------------------------------------------------
(edit file)
@@ -230,7 +229,7 @@ $ git commit -a
------------------------------------------------
at this point the two branches have diverged, with different changes
-made in each. To merge the changes made in experimental into master, run
+made in each. To merge the changes made in `experimental` into `master`, run
------------------------------------------------
$ git merge experimental
@@ -258,16 +257,16 @@ $ gitk
will show a nice graphical representation of the resulting history.
-At this point you could delete the experimental branch with
+At this point you could delete the `experimental` branch with
------------------------------------------------
$ git branch -d experimental
------------------------------------------------
-This command ensures that the changes in the experimental branch are
+This command ensures that the changes in the `experimental` branch are
already in the current branch.
-If you develop on a branch crazy-idea, then regret it, you can always
+If you develop on a branch `crazy-idea`, then regret it, you can always
delete the branch with
-------------------------------------
@@ -281,7 +280,7 @@ Using Git for collaboration
---------------------------
Suppose that Alice has started a new project with a Git repository in
-/home/alice/project, and that Bob, who has a home directory on the
+`/home/alice/project`, and that Bob, who has a home directory on the
same machine, wants to contribute.
Bob begins with:
@@ -290,7 +289,7 @@ Bob begins with:
bob$ git clone /home/alice/project myrepo
------------------------------------------------
-This creates a new directory "myrepo" containing a clone of Alice's
+This creates a new directory `myrepo` containing a clone of Alice's
repository. The clone is on an equal footing with the original
project, possessing its own copy of the original project's history.
@@ -303,31 +302,31 @@ bob$ git commit -a
------------------------------------------------
When he's ready, he tells Alice to pull changes from the repository
-at /home/bob/myrepo. She does this with:
+at `/home/bob/myrepo`. She does this with:
------------------------------------------------
alice$ cd /home/alice/project
alice$ git pull /home/bob/myrepo master
------------------------------------------------
-This merges the changes from Bob's "master" branch into Alice's
+This merges the changes from Bob's `master` branch into Alice's
current branch. If Alice has made her own changes in the meantime,
then she may need to manually fix any conflicts.
-The "pull" command thus performs two operations: it fetches changes
+The `pull` command thus performs two operations: it fetches changes
from a remote branch, then merges them into the current branch.
Note that in general, Alice would want her local changes committed before
-initiating this "pull". If Bob's work conflicts with what Alice did since
+initiating this `pull`. If Bob's work conflicts with what Alice did since
their histories forked, Alice will use her working tree and the index to
resolve conflicts, and existing local changes will interfere with the
conflict resolution process (Git will still perform the fetch but will
refuse to merge -- Alice will have to get rid of her local changes in
some way and pull again when this happens).
-Alice can peek at what Bob did without merging first, using the "fetch"
+Alice can peek at what Bob did without merging first, using the `fetch`
command; this allows Alice to inspect what Bob did, using a special
-symbol "FETCH_HEAD", in order to determine if he has anything worth
+symbol `FETCH_HEAD`, in order to determine if he has anything worth
pulling, like this:
------------------------------------------------
@@ -336,10 +335,10 @@ alice$ git log -p HEAD..FETCH_HEAD
------------------------------------------------
This operation is safe even if Alice has uncommitted local changes.
-The range notation "HEAD..FETCH_HEAD" means "show everything that is reachable
-from the FETCH_HEAD but exclude anything that is reachable from HEAD".
-Alice already knows everything that leads to her current state (HEAD),
-and reviews what Bob has in his state (FETCH_HEAD) that she has not
+The range notation `HEAD..FETCH_HEAD` means "show everything that is reachable
+from the `FETCH_HEAD` but exclude anything that is reachable from `HEAD`".
+Alice already knows everything that leads to her current state (`HEAD`),
+and reviews what Bob has in his state (`FETCH_HEAD`) that she has not
seen with this command.
If Alice wants to visualize what Bob did since their histories forked
@@ -349,7 +348,7 @@ she can issue the following command:
$ gitk HEAD..FETCH_HEAD
------------------------------------------------
-This uses the same two-dot range notation we saw earlier with 'git log'.
+This uses the same two-dot range notation we saw earlier with `git log`.
Alice may want to view what both of them did since they forked.
She can use three-dot form instead of the two-dot form:
@@ -361,13 +360,13 @@ $ gitk HEAD...FETCH_HEAD
This means "show everything that is reachable from either one, but
exclude anything that is reachable from both of them".
-Please note that these range notation can be used with both gitk
-and "git log".
+Please note that these range notation can be used with both `gitk`
+and `git log`.
After inspecting what Bob did, if there is nothing urgent, Alice may
decide to continue working without pulling from Bob. If Bob's history
does have something Alice would immediately need, Alice may choose to
-stash her work-in-progress first, do a "pull", and then finally unstash
+stash her work-in-progress first, do a `pull`, and then finally unstash
her work-in-progress on top of the resulting history.
When you are working in a small closely knit group, it is not
@@ -379,8 +378,8 @@ it easier:
alice$ git remote add bob /home/bob/myrepo
------------------------------------------------
-With this, Alice can perform the first part of the "pull" operation
-alone using the 'git fetch' command without merging them with her own
+With this, Alice can perform the first part of the `pull` operation
+alone using the `git fetch` command without merging them with her own
branch, using:
-------------------------------------
@@ -388,7 +387,7 @@ alice$ git fetch bob
-------------------------------------
Unlike the longhand form, when Alice fetches from Bob using a
-remote repository shorthand set up with 'git remote', what was
+remote repository shorthand set up with `git remote`, what was
fetched is stored in a remote-tracking branch, in this case
`bob/master`. So after this:
@@ -397,10 +396,10 @@ alice$ git log -p master..bob/master
-------------------------------------
shows a list of all the changes that Bob made since he branched from
-Alice's master branch.
+Alice's `master` branch.
After examining those changes, Alice
-could merge the changes into her master branch:
+could merge the changes into her `master` branch:
-------------------------------------
alice$ git merge bob/master
@@ -432,12 +431,12 @@ bob$ git config --get remote.origin.url
/home/alice/project
-------------------------------------
-(The complete configuration created by 'git clone' is visible using
+(The complete configuration created by `git clone` is visible using
`git config -l`, and the linkgit:git-config[1] man page
explains the meaning of each option.)
-Git also keeps a pristine copy of Alice's master branch under the
-name "origin/master":
+Git also keeps a pristine copy of Alice's `master` branch under the
+name `origin/master`:
-------------------------------------
bob$ git branch -r
@@ -462,8 +461,8 @@ Exploring history
-----------------
Git history is represented as a series of interrelated commits. We
-have already seen that the 'git log' command can list those commits.
-Note that first line of each git log entry also gives a name for the
+have already seen that the `git log` command can list those commits.
+Note that first line of each `git log` entry also gives a name for the
commit:
-------------------------------------
@@ -475,7 +474,7 @@ Date: Tue May 16 17:18:22 2006 -0700
merge-base: Clarify the comments on post processing.
-------------------------------------
-We can give this name to 'git show' to see the details about this
+We can give this name to `git show` to see the details about this
commit.
-------------------------------------
@@ -514,7 +513,7 @@ You can also give commits names of your own; after running
$ git tag v2.5 1b2e1d63ff
-------------------------------------
-you can refer to 1b2e1d63ff by the name "v2.5". If you intend to
+you can refer to `1b2e1d63ff` by the name `v2.5`. If you intend to
share this name with other people (for example, to identify a release
version), you should create a "tag" object, and perhaps sign it; see
linkgit:git-tag[1] for details.
@@ -533,22 +532,22 @@ $ git reset --hard HEAD^ # reset your current branch and working
Be careful with that last command: in addition to losing any changes
in the working directory, it will also remove all later commits from
this branch. If this branch is the only branch containing those
-commits, they will be lost. Also, don't use 'git reset' on a
+commits, they will be lost. Also, don't use `git reset` on a
publicly-visible branch that other developers pull from, as it will
force needless merges on other developers to clean up the history.
-If you need to undo changes that you have pushed, use 'git revert'
+If you need to undo changes that you have pushed, use `git revert`
instead.
-The 'git grep' command can search for strings in any version of your
+The `git grep` command can search for strings in any version of your
project, so
-------------------------------------
$ git grep "hello" v2.5
-------------------------------------
-searches for all occurrences of "hello" in v2.5.
+searches for all occurrences of "hello" in `v2.5`.
-If you leave out the commit name, 'git grep' will search any of the
+If you leave out the commit name, `git grep` will search any of the
files it manages in your current directory. So
-------------------------------------
@@ -558,7 +557,7 @@ $ git grep "hello"
is a quick way to search just the files that are tracked by Git.
Many Git commands also take sets of commits, which can be specified
-in a number of ways. Here are some examples with 'git log':
+in a number of ways. Here are some examples with `git log`:
-------------------------------------
$ git log v2.5..v2.6 # commits between v2.5 and v2.6
@@ -568,16 +567,16 @@ $ git log v2.5.. Makefile # commits since v2.5 which modify
# Makefile
-------------------------------------
-You can also give 'git log' a "range" of commits where the first is not
+You can also give `git log` a "range" of commits where the first is not
necessarily an ancestor of the second; for example, if the tips of
-the branches "stable" and "master" diverged from a common
+the branches `stable` and `master` diverged from a common
commit some time ago, then
-------------------------------------
$ git log stable..master
-------------------------------------
-will list commits made in the master branch but not in the
+will list commits made in the `master` branch but not in the
stable branch, while
-------------------------------------
@@ -585,15 +584,15 @@ $ git log master..stable
-------------------------------------
will show the list of commits made on the stable branch but not
-the master branch.
+the `master` branch.
-The 'git log' command has a weakness: it must present commits in a
+The `git log` command has a weakness: it must present commits in a
list. When the history has lines of development that diverged and
-then merged back together, the order in which 'git log' presents
+then merged back together, the order in which `git log` presents
those commits is meaningless.
Most projects with multiple contributors (such as the Linux kernel,
-or Git itself) have frequent merges, and 'gitk' does a better job of
+or Git itself) have frequent merges, and `gitk` does a better job of
visualizing their history. For example,
-------------------------------------
@@ -601,7 +600,7 @@ $ gitk --since="2 weeks ago" drivers/
-------------------------------------
allows you to browse any commits from the last 2 weeks of commits
-that modified files under the "drivers" directory. (Note: you can
+that modified files under the `drivers` directory. (Note: you can
adjust gitk's fonts by holding down the control key while pressing
"-" or "+".)
@@ -613,7 +612,7 @@ of the file:
$ git diff v2.5:Makefile HEAD:Makefile.in
-------------------------------------
-You can also use 'git show' to see any such file:
+You can also use `git show` to see any such file:
-------------------------------------
$ git show v2.5:Makefile
@@ -649,7 +648,7 @@ digressions that may be interesting at this point are:
* linkgit:git-bisect[1]: When there is a regression in your
project, one way to track down the bug is by searching through
- the history to find the exact commit that's to blame. Git bisect
+ the history to find the exact commit that's to blame. `git bisect`
can help you perform a binary search for that commit. It is
smart enough to perform a close-to-optimal search even in the
case of complex non-linear history with lots of merged branches.
diff --git a/Documentation/manpage-normal.xsl b/Documentation/manpage-normal.xsl
index a9c7ec69f4..beb5ff8ec2 100644
--- a/Documentation/manpage-normal.xsl
+++ b/Documentation/manpage-normal.xsl
@@ -8,19 +8,7 @@
<xsl:param name="man.output.quietly" select="1"/>
<xsl:param name="refentry.meta.get.quietly" select="1"/>
-<!-- convert asciidoc callouts to man page format -->
-<xsl:template match="co">
- <xsl:value-of select="concat('\fB(',substring-after(@id,'-'),')\fR')"/>
-</xsl:template>
-<xsl:template match="calloutlist">
- <xsl:text>.sp&#10;</xsl:text>
- <xsl:apply-templates/>
- <xsl:text>&#10;</xsl:text>
-</xsl:template>
-<xsl:template match="callout">
- <xsl:value-of select="concat('\fB',substring-after(@arearefs,'-'),'. \fR')"/>
- <xsl:apply-templates/>
- <xsl:text>.br&#10;</xsl:text>
-</xsl:template>
+<!-- unset maximum length of title -->
+<xsl:param name="man.th.title.max.length"/>
</xsl:stylesheet>
diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt
index 9aa58052bc..b42a2bb30a 100644
--- a/Documentation/revisions.txt
+++ b/Documentation/revisions.txt
@@ -32,8 +32,9 @@ characters and to avoid word splitting.
first match in the following rules:
. If '$GIT_DIR/<refname>' exists, that is what you mean (this is usually
- useful only for `HEAD`, `FETCH_HEAD`, `ORIG_HEAD`, `MERGE_HEAD`
- and `CHERRY_PICK_HEAD`);
+ useful only for `HEAD`, `FETCH_HEAD`, `ORIG_HEAD`, `MERGE_HEAD`,
+ `REBASE_HEAD`, `REVERT_HEAD`, `CHERRY_PICK_HEAD`, `BISECT_HEAD`
+ and `AUTO_MERGE`);
. otherwise, 'refs/<refname>' if it exists;
@@ -55,8 +56,18 @@ you can easily change the tip of the branch back to the state before you ran
them.
`MERGE_HEAD` records the commit(s) which you are merging into your branch
when you run `git merge`.
+`REBASE_HEAD`, during a rebase, records the commit at which the
+operation is currently stopped, either because of conflicts or an `edit`
+command in an interactive rebase.
+`REVERT_HEAD` records the commit which you are reverting when you
+run `git revert`.
`CHERRY_PICK_HEAD` records the commit which you are cherry-picking
when you run `git cherry-pick`.
+`BISECT_HEAD` records the current commit to be tested when you
+run `git bisect --no-checkout`.
+`AUTO_MERGE` records a tree object corresponding to the state the
+'ort' merge strategy wrote to the working tree when a merge operation
+resulted in conflicts.
+
Note that any of the 'refs/*' cases above may come either from
the `$GIT_DIR/refs` directory or from the `$GIT_DIR/packed-refs` file.
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index dc9c6a663a..99e5f652e9 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -1343,6 +1343,33 @@ $ git diff -3 file.txt # diff against stage 3
$ git diff --theirs file.txt # same as the above.
-------------------------------------------------
+When using the 'ort' merge strategy (the default), before updating the working
+tree with the result of the merge, Git writes a special ref named AUTO_MERGE
+reflecting the state of the tree it is about to write. Conflicted paths that
+could not be automatically merged are written to this tree with conflict
+markers, just as in the working tree. AUTO_MERGE can thus be used with
+linkgit:git-diff[1] to show the changes you've made so far to resolve
+conflicts. Using the same example as above, after resolving the conflict we
+get:
+
+-------------------------------------------------
+$ git diff AUTO_MERGE
+diff --git a/file.txt b/file.txt
+index cd10406..8bf5ae7 100644
+--- a/file.txt
++++ b/file.txt
+@@ -1,5 +1 @@
+-<<<<<<< HEAD:file.txt
+-Hello world
+-=======
+-Goodbye
+->>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:file.txt
++Goodbye world
+-------------------------------------------------
+
+Notice that the diff shows we deleted the conflict markers and both versions,
+and wrote "Goodbye world" instead.
+
The linkgit:git-log[1] and linkgit:gitk[1] commands also provide special help
for merges:
diff --git a/abspath.c b/abspath.c
index d032f5dce5..1202cde23d 100644
--- a/abspath.c
+++ b/abspath.c
@@ -289,3 +289,39 @@ char *prefix_filename_except_for_dash(const char *pfx, const char *arg)
return xstrdup(arg);
return prefix_filename(pfx, arg);
}
+
+void strbuf_add_absolute_path(struct strbuf *sb, const char *path)
+{
+ if (!*path)
+ die("The empty string is not a valid path");
+ if (!is_absolute_path(path)) {
+ struct stat cwd_stat, pwd_stat;
+ size_t orig_len = sb->len;
+ char *cwd = xgetcwd();
+ char *pwd = getenv("PWD");
+ if (pwd && strcmp(pwd, cwd) &&
+ !stat(cwd, &cwd_stat) &&
+ (cwd_stat.st_dev || cwd_stat.st_ino) &&
+ !stat(pwd, &pwd_stat) &&
+ pwd_stat.st_dev == cwd_stat.st_dev &&
+ pwd_stat.st_ino == cwd_stat.st_ino)
+ strbuf_addstr(sb, pwd);
+ else
+ strbuf_addstr(sb, cwd);
+ if (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1]))
+ strbuf_addch(sb, '/');
+ free(cwd);
+ }
+ strbuf_addstr(sb, path);
+}
+
+void strbuf_add_real_path(struct strbuf *sb, const char *path)
+{
+ if (sb->len) {
+ struct strbuf resolved = STRBUF_INIT;
+ strbuf_realpath(&resolved, path, 1);
+ strbuf_addbuf(sb, &resolved);
+ strbuf_release(&resolved);
+ } else
+ strbuf_realpath(sb, path, 1);
+}
diff --git a/abspath.h b/abspath.h
index 7cd3de5e9d..4653080d5e 100644
--- a/abspath.h
+++ b/abspath.h
@@ -30,4 +30,25 @@ static inline int is_absolute_path(const char *path)
return is_dir_sep(path[0]) || has_dos_drive_prefix(path);
}
+/**
+ * Add a path to a buffer, converting a relative path to an
+ * absolute one in the process. Symbolic links are not
+ * resolved.
+ */
+void strbuf_add_absolute_path(struct strbuf *sb, const char *path);
+
+/**
+ * Canonize `path` (make it absolute, resolve symlinks, remove extra
+ * slashes) and append it to `sb`. Die with an informative error
+ * message if there is a problem.
+ *
+ * The directory part of `path` (i.e., everything up to the last
+ * dir_sep) must denote a valid, existing directory, but the last
+ * component need not exist.
+ *
+ * Callers that don't mind links should use the more lightweight
+ * strbuf_add_absolute_path() instead.
+ */
+void strbuf_add_real_path(struct strbuf *sb, const char *path);
+
#endif /* ABSPATH_H */
diff --git a/add-interactive.c b/add-interactive.c
index 757a9929d4..de877ca052 100644
--- a/add-interactive.c
+++ b/add-interactive.c
@@ -12,6 +12,7 @@
#include "dir.h"
#include "run-command.h"
#include "prompt.h"
+#include "tree.h"
static void init_color(struct repository *r, struct add_i_state *s,
const char *section_and_slot, char *dst,
diff --git a/add-patch.c b/add-patch.c
index 8d770d203f..9702c1aabd 100644
--- a/add-patch.c
+++ b/add-patch.c
@@ -1105,10 +1105,11 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)
size_t i;
strbuf_reset(&s->buf);
- strbuf_commented_addf(&s->buf, _("Manual hunk edit mode -- see bottom for "
- "a quick guide.\n"));
+ strbuf_commented_addf(&s->buf, comment_line_char,
+ _("Manual hunk edit mode -- see bottom for "
+ "a quick guide.\n"));
render_hunk(s, hunk, 0, 0, &s->buf);
- strbuf_commented_addf(&s->buf,
+ strbuf_commented_addf(&s->buf, comment_line_char,
_("---\n"
"To remove '%c' lines, make them ' ' lines "
"(context).\n"
@@ -1117,12 +1118,13 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)
s->mode->is_reverse ? '+' : '-',
s->mode->is_reverse ? '-' : '+',
comment_line_char);
- strbuf_commented_addf(&s->buf, "%s", _(s->mode->edit_hunk_hint));
+ strbuf_commented_addf(&s->buf, comment_line_char, "%s",
+ _(s->mode->edit_hunk_hint));
/*
* TRANSLATORS: 'it' refers to the patch mentioned in the previous
* messages.
*/
- strbuf_commented_addf(&s->buf,
+ strbuf_commented_addf(&s->buf, comment_line_char,
_("If it does not apply cleanly, you will be "
"given an opportunity to\n"
"edit again. If all lines of the hunk are "
diff --git a/alloc.c b/alloc.c
index 2886aa9354..377e80f5dd 100644
--- a/alloc.c
+++ b/alloc.c
@@ -13,6 +13,7 @@
#include "blob.h"
#include "tree.h"
#include "commit.h"
+#include "repository.h"
#include "tag.h"
#include "alloc.h"
diff --git a/apply.c b/apply.c
index 3636bc14c2..6212ab3a1b 100644
--- a/apply.c
+++ b/apply.c
@@ -10,6 +10,7 @@
#include "cache.h"
#include "abspath.h"
#include "alloc.h"
+#include "base85.h"
#include "config.h"
#include "object-store.h"
#include "blob.h"
@@ -30,6 +31,8 @@
#include "apply.h"
#include "entry.h"
#include "setup.h"
+#include "symlinks.h"
+#include "ws.h"
#include "wrapper.h"
struct gitdiff_data {
diff --git a/apply.h b/apply.h
index b9f18ce87d..7cd38b1443 100644
--- a/apply.h
+++ b/apply.h
@@ -1,7 +1,7 @@
#ifndef APPLY_H
#define APPLY_H
-#include "hash.h"
+#include "hash-ll.h"
#include "lockfile.h"
#include "string-list.h"
#include "strmap.h"
diff --git a/archive-zip.c b/archive-zip.c
index ef538a90df..d0d065a312 100644
--- a/archive-zip.c
+++ b/archive-zip.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2006 Rene Scharfe
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
#include "archive.h"
#include "gettext.h"
diff --git a/archive.c b/archive.c
index 8570cf37ff..2ea9cbef92 100644
--- a/archive.c
+++ b/archive.c
@@ -6,10 +6,12 @@
#include "environment.h"
#include "gettext.h"
#include "hex.h"
+#include "pretty.h"
#include "setup.h"
#include "refs.h"
#include "object-store.h"
#include "commit.h"
+#include "tree.h"
#include "tree-walk.h"
#include "attr.h"
#include "archive.h"
@@ -128,7 +130,7 @@ static const struct attr_check *get_archive_attrs(struct index_state *istate,
static struct attr_check *check;
if (!check)
check = attr_check_initl("export-ignore", "export-subst", NULL);
- git_check_attr(istate, NULL, path, check);
+ git_check_attr(istate, path, check);
return check;
}
diff --git a/attr.c b/attr.c
index 2d8aeb8b58..d45d34058d 100644
--- a/attr.c
+++ b/attr.c
@@ -20,6 +20,8 @@
#include "object-store.h"
#include "setup.h"
#include "thread-utils.h"
+#include "tree-walk.h"
+#include "object-name.h"
const char git_attr__true[] = "(builtin)true";
const char git_attr__false[] = "\0(builtin)false";
@@ -1169,11 +1171,42 @@ static void collect_some_attrs(struct index_state *istate,
fill(path, pathlen, basename_offset, check->stack, check->all_attrs, rem);
}
+static const char *default_attr_source_tree_object_name;
+
+void set_git_attr_source(const char *tree_object_name)
+{
+ default_attr_source_tree_object_name = xstrdup(tree_object_name);
+}
+
+static void compute_default_attr_source(struct object_id *attr_source)
+{
+ if (!default_attr_source_tree_object_name)
+ default_attr_source_tree_object_name = getenv(GIT_ATTR_SOURCE_ENVIRONMENT);
+
+ if (!default_attr_source_tree_object_name || !is_null_oid(attr_source))
+ return;
+
+ if (repo_get_oid_treeish(the_repository, default_attr_source_tree_object_name, attr_source))
+ die(_("bad --attr-source or GIT_ATTR_SOURCE"));
+}
+
+static struct object_id *default_attr_source(void)
+{
+ static struct object_id attr_source;
+
+ if (is_null_oid(&attr_source))
+ compute_default_attr_source(&attr_source);
+ if (is_null_oid(&attr_source))
+ return NULL;
+ return &attr_source;
+}
+
void git_check_attr(struct index_state *istate,
- const struct object_id *tree_oid, const char *path,
+ const char *path,
struct attr_check *check)
{
int i;
+ const struct object_id *tree_oid = default_attr_source();
collect_some_attrs(istate, tree_oid, path, check);
@@ -1186,10 +1219,11 @@ void git_check_attr(struct index_state *istate,
}
}
-void git_all_attrs(struct index_state *istate, const struct object_id *tree_oid,
+void git_all_attrs(struct index_state *istate,
const char *path, struct attr_check *check)
{
int i;
+ const struct object_id *tree_oid = default_attr_source();
attr_check_reset(check);
collect_some_attrs(istate, tree_oid, path, check);
diff --git a/attr.h b/attr.h
index 9884ea2bc6..676bd17ce2 100644
--- a/attr.h
+++ b/attr.h
@@ -45,7 +45,7 @@
* const char *path;
*
* setup_check();
- * git_check_attr(&the_index, tree_oid, path, check);
+ * git_check_attr(&the_index, path, check);
* ------------
*
* - Act on `.value` member of the result, left in `check->items[]`:
@@ -120,7 +120,6 @@
#define ATTR_MAX_FILE_SIZE (100 * 1024 * 1024)
struct index_state;
-struct object_id;
/**
* An attribute is an opaque object that is identified by its name. Pass the
@@ -136,6 +135,12 @@ struct all_attrs_item;
struct attr_stack;
/*
+ * The textual object name for the tree-ish used by git_check_attr()
+ * to read attributes from (instead of from the working tree).
+ */
+void set_git_attr_source(const char *);
+
+/*
* Given a string, return the gitattribute object that
* corresponds to it.
*/
@@ -203,14 +208,14 @@ void attr_check_free(struct attr_check *check);
const char *git_attr_name(const struct git_attr *);
void git_check_attr(struct index_state *istate,
- const struct object_id *tree_oid, const char *path,
+ const char *path,
struct attr_check *check);
/*
* Retrieve all attributes that apply to the specified path.
* check holds the attributes and their values.
*/
-void git_all_attrs(struct index_state *istate, const struct object_id *tree_oid,
+void git_all_attrs(struct index_state *istate,
const char *path, struct attr_check *check);
enum git_attr_direction {
diff --git a/banned.h b/banned.h
index 6ccf46bc19..44e76bd90a 100644
--- a/banned.h
+++ b/banned.h
@@ -18,6 +18,10 @@
#define strncpy(x,y,n) BANNED(strncpy)
#undef strncat
#define strncat(x,y,n) BANNED(strncat)
+#undef strtok
+#define strtok(x,y) BANNED(strtok)
+#undef strtok_r
+#define strtok_r(x,y,z) BANNED(strtok_r)
#undef sprintf
#undef vsprintf
diff --git a/base85.c b/base85.c
index 5ca601ee14..bbacdca31b 100644
--- a/base85.c
+++ b/base85.c
@@ -1,4 +1,5 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "base85.h"
#undef DEBUG_85
diff --git a/base85.h b/base85.h
new file mode 100644
index 0000000000..c835086e09
--- /dev/null
+++ b/base85.h
@@ -0,0 +1,7 @@
+#ifndef BASE85_H
+#define BASE85_H
+
+int decode_85(char *dst, const char *line, int linelen);
+void encode_85(char *buf, const unsigned char *data, int bytes);
+
+#endif /* BASE85_H */
diff --git a/blame.c b/blame.c
index 58dd58b6c9..b830654062 100644
--- a/blame.c
+++ b/blame.c
@@ -208,8 +208,12 @@ static struct commit *fake_working_tree_commit(struct repository *r,
origin = make_origin(commit, path);
- ident = fmt_ident("Not Committed Yet", "not.committed.yet",
- WANT_BLANK_IDENT, NULL, 0);
+ if (contents_from)
+ ident = fmt_ident("External file (--contents)", "external.file",
+ WANT_BLANK_IDENT, NULL, 0);
+ else
+ ident = fmt_ident("Not Committed Yet", "not.committed.yet",
+ WANT_BLANK_IDENT, NULL, 0);
strbuf_addstr(&msg, "tree 0000000000000000000000000000000000000000\n");
for (parent = commit->parents; parent; parent = parent->next)
strbuf_addf(&msg, "parent %s\n",
diff --git a/bloom.c b/bloom.c
index d0730525da..aef6b5fea2 100644
--- a/bloom.c
+++ b/bloom.c
@@ -6,6 +6,7 @@
#include "hashmap.h"
#include "commit-graph.h"
#include "commit.h"
+#include "commit-slab.h"
define_commit_slab(bloom_filter_slab, struct bloom_filter);
diff --git a/branch.c b/branch.c
index 7df982693a..ba3914adf5 100644
--- a/branch.c
+++ b/branch.c
@@ -9,6 +9,7 @@
#include "refs.h"
#include "refspec.h"
#include "remote.h"
+#include "repository.h"
#include "sequencer.h"
#include "commit.h"
#include "worktree.h"
@@ -839,30 +840,3 @@ void die_if_checked_out(const char *branch, int ignore_current_worktree)
free_worktrees(worktrees);
}
-
-int replace_each_worktree_head_symref(const char *oldref, const char *newref,
- const char *logmsg)
-{
- int ret = 0;
- struct worktree **worktrees = get_worktrees();
- int i;
-
- for (i = 0; worktrees[i]; i++) {
- struct ref_store *refs;
-
- if (worktrees[i]->is_detached)
- continue;
- if (!worktrees[i]->head_ref)
- continue;
- if (strcmp(oldref, worktrees[i]->head_ref))
- continue;
-
- refs = get_worktree_ref_store(worktrees[i]);
- if (refs_create_symref(refs, "HEAD", newref, logmsg))
- ret = error(_("HEAD of working tree %s is not updated"),
- worktrees[i]->path);
- }
-
- free_worktrees(worktrees);
- return ret;
-}
diff --git a/branch.h b/branch.h
index ef56103c05..30c01aed73 100644
--- a/branch.h
+++ b/branch.h
@@ -155,12 +155,4 @@ int read_branch_desc(struct strbuf *, const char *branch_name);
*/
void die_if_checked_out(const char *branch, int ignore_current_worktree);
-/*
- * Update all per-worktree HEADs pointing at the old ref to point the new ref.
- * This will be used when renaming a branch. Returns 0 if successful, non-zero
- * otherwise.
- */
-int replace_each_worktree_head_symref(const char *oldref, const char *newref,
- const char *logmsg);
-
#endif
diff --git a/builtin/am.c b/builtin/am.c
index 5c83f2e003..9ece2e3066 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1283,7 +1283,7 @@ static int parse_mail(struct am_state *state, const char *mail)
strbuf_addstr(&msg, "\n\n");
strbuf_addbuf(&msg, &mi.log_message);
- strbuf_stripspace(&msg, 0);
+ strbuf_stripspace(&msg, '\0');
assert(!state->author_name);
state->author_name = strbuf_detach(&author_name, NULL);
diff --git a/builtin/apply.c b/builtin/apply.c
index fe72c0ec3e..e3ff02a09e 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -2,6 +2,7 @@
#include "builtin.h"
#include "gettext.h"
#include "parse-options.h"
+#include "repository.h"
#include "apply.h"
static const char * const apply_usage[] = {
diff --git a/builtin/archive.c b/builtin/archive.c
index d13934f1a8..b0eaa3c14a 100644
--- a/builtin/archive.c
+++ b/builtin/archive.c
@@ -9,6 +9,7 @@
#include "transport.h"
#include "parse-options.h"
#include "pkt-line.h"
+#include "repository.h"
#include "sideband.h"
static void create_output_file(const char *output_file)
diff --git a/builtin/bisect.c b/builtin/bisect.c
index 4b2143d455..4812450c39 100644
--- a/builtin/bisect.c
+++ b/builtin/bisect.c
@@ -1,5 +1,6 @@
#include "builtin.h"
#include "cache.h"
+#include "copy.h"
#include "environment.h"
#include "gettext.h"
#include "hex.h"
diff --git a/builtin/branch.c b/builtin/branch.c
index 501c47657c..40a79e60f5 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -512,9 +512,9 @@ static void print_current_branch_name(void)
die(_("HEAD (%s) points outside of refs/heads/"), refname);
}
-static void reject_rebase_or_bisect_branch(const char *target)
+static void reject_rebase_or_bisect_branch(struct worktree **worktrees,
+ const char *target)
{
- struct worktree **worktrees = get_worktrees();
int i;
for (i = 0; worktrees[i]; i++) {
@@ -531,17 +531,50 @@ static void reject_rebase_or_bisect_branch(const char *target)
die(_("Branch %s is being bisected at %s"),
target, wt->path);
}
+}
- free_worktrees(worktrees);
+/*
+ * Update all per-worktree HEADs pointing at the old ref to point the new ref.
+ * This will be used when renaming a branch. Returns 0 if successful, non-zero
+ * otherwise.
+ */
+static int replace_each_worktree_head_symref(struct worktree **worktrees,
+ const char *oldref, const char *newref,
+ const char *logmsg)
+{
+ int ret = 0;
+ int i;
+
+ for (i = 0; worktrees[i]; i++) {
+ struct ref_store *refs;
+
+ if (worktrees[i]->is_detached)
+ continue;
+ if (!worktrees[i]->head_ref)
+ continue;
+ if (strcmp(oldref, worktrees[i]->head_ref))
+ continue;
+
+ refs = get_worktree_ref_store(worktrees[i]);
+ if (refs_create_symref(refs, "HEAD", newref, logmsg))
+ ret = error(_("HEAD of working tree %s is not updated"),
+ worktrees[i]->path);
+ }
+
+ return ret;
}
+#define IS_HEAD 1
+#define IS_ORPHAN 2
+
static void copy_or_rename_branch(const char *oldname, const char *newname, int copy, int force)
{
struct strbuf oldref = STRBUF_INIT, newref = STRBUF_INIT, logmsg = STRBUF_INIT;
struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT;
const char *interpreted_oldname = NULL;
const char *interpreted_newname = NULL;
- int recovery = 0;
+ int recovery = 0, oldref_usage = 0;
+ struct worktree **worktrees = get_worktrees();
if (strbuf_check_branch_ref(&oldref, oldname)) {
/*
@@ -554,8 +587,19 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
die(_("Invalid branch name: '%s'"), oldname);
}
- if ((copy || strcmp(head, oldname)) && !ref_exists(oldref.buf)) {
- if (copy && !strcmp(head, oldname))
+ for (int i = 0; worktrees[i]; i++) {
+ struct worktree *wt = worktrees[i];
+
+ if (wt->head_ref && !strcmp(oldref.buf, wt->head_ref)) {
+ oldref_usage |= IS_HEAD;
+ if (is_null_oid(&wt->head_oid))
+ oldref_usage |= IS_ORPHAN;
+ break;
+ }
+ }
+
+ if ((copy || !(oldref_usage & IS_HEAD)) && !ref_exists(oldref.buf)) {
+ if (oldref_usage & IS_HEAD)
die(_("No commit on branch '%s' yet."), oldname);
else
die(_("No branch named '%s'."), oldname);
@@ -570,7 +614,7 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
else
validate_new_branchname(newname, &newref, force);
- reject_rebase_or_bisect_branch(oldref.buf);
+ reject_rebase_or_bisect_branch(worktrees, oldref.buf);
if (!skip_prefix(oldref.buf, "refs/heads/", &interpreted_oldname) ||
!skip_prefix(newref.buf, "refs/heads/", &interpreted_newname)) {
@@ -584,8 +628,7 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
strbuf_addf(&logmsg, "Branch: renamed %s to %s",
oldref.buf, newref.buf);
- if (!copy &&
- (!head || strcmp(oldname, head) || !is_null_oid(&head_oid)) &&
+ if (!copy && !(oldref_usage & IS_ORPHAN) &&
rename_ref(oldref.buf, newref.buf, logmsg.buf))
die(_("Branch rename failed"));
if (copy && copy_existing_ref(oldref.buf, newref.buf, logmsg.buf))
@@ -600,8 +643,9 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
interpreted_oldname);
}
- if (!copy &&
- replace_each_worktree_head_symref(oldref.buf, newref.buf, logmsg.buf))
+ if (!copy && (oldref_usage & IS_HEAD) &&
+ replace_each_worktree_head_symref(worktrees, oldref.buf, newref.buf,
+ logmsg.buf))
die(_("Branch renamed to %s, but HEAD is not updated!"), newname);
strbuf_release(&logmsg);
@@ -616,6 +660,7 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
strbuf_release(&newref);
strbuf_release(&oldsection);
strbuf_release(&newsection);
+ free_worktrees(worktrees);
}
static GIT_PATH_FUNC(edit_description, "EDIT_DESCRIPTION")
@@ -629,7 +674,7 @@ static int edit_branch_description(const char *branch_name)
exists = !read_branch_desc(&buf, branch_name);
if (!buf.len || buf.buf[buf.len-1] != '\n')
strbuf_addch(&buf, '\n');
- strbuf_commented_addf(&buf,
+ strbuf_commented_addf(&buf, comment_line_char,
_("Please edit the description for the branch\n"
" %s\n"
"Lines starting with '%c' will be stripped.\n"),
@@ -640,7 +685,7 @@ static int edit_branch_description(const char *branch_name)
strbuf_release(&buf);
return -1;
}
- strbuf_stripspace(&buf, 1);
+ strbuf_stripspace(&buf, comment_line_char);
strbuf_addf(&name, "branch.%s.description", branch_name);
if (buf.len || exists)
@@ -834,7 +879,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
strbuf_addf(&branch_ref, "refs/heads/%s", branch_name);
if (!ref_exists(branch_ref.buf))
- error((!argc || !strcmp(head, branch_name))
+ error((!argc || branch_checked_out(branch_ref.buf))
? _("No commit on branch '%s' yet.")
: _("No branch named '%s'."),
branch_name);
@@ -879,7 +924,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
}
if (!ref_exists(branch->refname)) {
- if (!argc || !strcmp(head, branch->name))
+ if (!argc || branch_checked_out(branch->refname))
die(_("No commit on branch '%s' yet."), branch->name);
die(_("branch '%s' does not exist"), branch->name);
}
diff --git a/builtin/bundle.c b/builtin/bundle.c
index e68fc83d94..44113389d7 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -4,6 +4,8 @@
#include "setup.h"
#include "strvec.h"
#include "parse-options.h"
+#include "pkt-line.h"
+#include "repository.h"
#include "cache.h"
#include "bundle.h"
diff --git a/builtin/check-attr.c b/builtin/check-attr.c
index 037bf1aaa2..e27b86d150 100644
--- a/builtin/check-attr.c
+++ b/builtin/check-attr.c
@@ -7,6 +7,7 @@
#include "gettext.h"
#include "object-name.h"
#include "quote.h"
+#include "repository.h"
#include "setup.h"
#include "parse-options.h"
#include "write-or-die.h"
@@ -63,7 +64,7 @@ static void output_attr(struct attr_check *check, const char *file)
}
static void check_attr(const char *prefix, struct attr_check *check,
- const struct object_id *tree_oid, int collect_all,
+ int collect_all,
const char *file)
{
@@ -71,9 +72,9 @@ static void check_attr(const char *prefix, struct attr_check *check,
prefix_path(prefix, prefix ? strlen(prefix) : 0, file);
if (collect_all) {
- git_all_attrs(&the_index, tree_oid, full_path, check);
+ git_all_attrs(&the_index, full_path, check);
} else {
- git_check_attr(&the_index, tree_oid, full_path, check);
+ git_check_attr(&the_index, full_path, check);
}
output_attr(check, file);
@@ -81,7 +82,7 @@ static void check_attr(const char *prefix, struct attr_check *check,
}
static void check_attr_stdin_paths(const char *prefix, struct attr_check *check,
- const struct object_id *tree_oid, int collect_all)
+ int collect_all)
{
struct strbuf buf = STRBUF_INIT;
struct strbuf unquoted = STRBUF_INIT;
@@ -95,7 +96,7 @@ static void check_attr_stdin_paths(const char *prefix, struct attr_check *check,
die("line is badly quoted");
strbuf_swap(&buf, &unquoted);
}
- check_attr(prefix, check, tree_oid, collect_all, buf.buf);
+ check_attr(prefix, check, collect_all, buf.buf);
maybe_flush_or_die(stdout, "attribute to stdout");
}
strbuf_release(&buf);
@@ -111,7 +112,6 @@ static NORETURN void error_with_usage(const char *msg)
int cmd_check_attr(int argc, const char **argv, const char *prefix)
{
struct attr_check *check;
- struct object_id *tree_oid = NULL;
struct object_id initialized_oid;
int cnt, i, doubledash, filei;
@@ -187,14 +187,14 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)
if (source) {
if (repo_get_oid_tree(the_repository, source, &initialized_oid))
die("%s: not a valid tree-ish source", source);
- tree_oid = &initialized_oid;
+ set_git_attr_source(source);
}
if (stdin_paths)
- check_attr_stdin_paths(prefix, check, tree_oid, all_attrs);
+ check_attr_stdin_paths(prefix, check, all_attrs);
else {
for (i = filei; i < argc; i++)
- check_attr(prefix, check, tree_oid, all_attrs, argv[i]);
+ check_attr(prefix, check, all_attrs, argv[i]);
maybe_flush_or_die(stdout, "attribute to stdout");
}
diff --git a/builtin/check-ignore.c b/builtin/check-ignore.c
index 9401dad007..e4b78782a3 100644
--- a/builtin/check-ignore.c
+++ b/builtin/check-ignore.c
@@ -7,6 +7,7 @@
#include "quote.h"
#include "pathspec.h"
#include "parse-options.h"
+#include "repository.h"
#include "submodule.h"
#include "write-or-die.h"
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index 7df673e3e7..9375a05539 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -11,6 +11,7 @@
#include "gettext.h"
#include "lockfile.h"
#include "quote.h"
+#include "repository.h"
#include "cache-tree.h"
#include "parse-options.h"
#include "entry.h"
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 6f5d82ed3d..715eeb5048 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -28,6 +28,7 @@
#include "setup.h"
#include "submodule.h"
#include "submodule-config.h"
+#include "symlinks.h"
#include "trace2.h"
#include "tree.h"
#include "tree-walk.h"
diff --git a/builtin/clean.c b/builtin/clean.c
index 14c0d555ea..78852d28ce 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -14,6 +14,7 @@
#include "dir.h"
#include "gettext.h"
#include "parse-options.h"
+#include "repository.h"
#include "setup.h"
#include "string-list.h"
#include "quote.h"
diff --git a/builtin/clone.c b/builtin/clone.c
index 186845ef0b..15f9912b4c 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -13,6 +13,7 @@
#include "abspath.h"
#include "advice.h"
#include "config.h"
+#include "copy.h"
#include "environment.h"
#include "gettext.h"
#include "hex.h"
@@ -38,6 +39,7 @@
#include "setup.h"
#include "connected.h"
#include "packfile.h"
+#include "pkt-line.h"
#include "list-objects-filter-options.h"
#include "hook.h"
#include "bundle.h"
diff --git a/builtin/commit.c b/builtin/commit.c
index e67c4be221..e002ebf070 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -893,7 +893,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
s->hints = 0;
if (clean_message_contents)
- strbuf_stripspace(&sb, 0);
+ strbuf_stripspace(&sb, '\0');
if (signoff)
append_signoff(&sb, ignore_non_trailer(sb.buf, sb.len), 0);
diff --git a/builtin/config.c b/builtin/config.c
index 9401f1e5e3..ff2fe8ef12 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -9,6 +9,7 @@
#include "ident.h"
#include "parse-options.h"
#include "urlmatch.h"
+#include "path.h"
#include "quote.h"
#include "setup.h"
#include "worktree.h"
diff --git a/builtin/credential-cache--daemon.c b/builtin/credential-cache--daemon.c
index 4e571d9951..756c5f02ae 100644
--- a/builtin/credential-cache--daemon.c
+++ b/builtin/credential-cache--daemon.c
@@ -134,6 +134,9 @@ static void serve_one_client(FILE *in, FILE *out)
if (e->item.password_expiry_utc != TIME_MAX)
fprintf(out, "password_expiry_utc=%"PRItime"\n",
e->item.password_expiry_utc);
+ if (e->item.oauth_refresh_token)
+ fprintf(out, "oauth_refresh_token=%s\n",
+ e->item.oauth_refresh_token);
}
}
else if (!strcmp(action.buf, "exit")) {
diff --git a/builtin/credential-cache.c b/builtin/credential-cache.c
index 508da4c6e4..0ffacfdd83 100644
--- a/builtin/credential-cache.c
+++ b/builtin/credential-cache.c
@@ -1,6 +1,7 @@
#include "builtin.h"
#include "gettext.h"
#include "parse-options.h"
+#include "path.h"
#include "wrapper.h"
#include "write-or-die.h"
diff --git a/builtin/credential-store.c b/builtin/credential-store.c
index 8977604eb9..5eea5bdb58 100644
--- a/builtin/credential-store.c
+++ b/builtin/credential-store.c
@@ -3,6 +3,7 @@
#include "gettext.h"
#include "lockfile.h"
#include "credential.h"
+#include "path.h"
#include "string-list.h"
#include "parse-options.h"
#include "write-or-die.h"
@@ -73,6 +74,25 @@ static void rewrite_credential_file(const char *fn, struct credential *c,
die_errno("unable to write credential store");
}
+static int is_rfc3986_unreserved(char ch)
+{
+ return isalnum(ch) ||
+ ch == '-' || ch == '_' || ch == '.' || ch == '~';
+}
+
+static int is_rfc3986_reserved_or_unreserved(char ch)
+{
+ if (is_rfc3986_unreserved(ch))
+ return 1;
+ switch (ch) {
+ case '!': case '*': case '\'': case '(': case ')': case ';':
+ case ':': case '@': case '&': case '=': case '+': case '$':
+ case ',': case '/': case '?': case '#': case '[': case ']':
+ return 1;
+ }
+ return 0;
+}
+
static void store_credential_file(const char *fn, struct credential *c)
{
struct strbuf buf = STRBUF_INIT;
diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index dc991f753b..360464e6ef 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -27,6 +27,10 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
usage(diff_files_usage);
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
+
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+
repo_init_revisions(the_repository, &rev, prefix);
rev.abbrev = 0;
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index 385c2d0230..0b02c62b85 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -9,6 +9,7 @@
#include "builtin.h"
#include "submodule.h"
#include "repository.h"
+#include "tree.h"
static struct rev_info log_tree_opt;
diff --git a/builtin/diff.c b/builtin/diff.c
index 5a6a5d7f4b..7b64659fe7 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -22,6 +22,7 @@
#include "setup.h"
#include "submodule.h"
#include "oid-array.h"
+#include "tree.h"
#define DIFF_NO_INDEX_EXPLICIT 1
#define DIFF_NO_INDEX_IMPLICIT 2
diff --git a/builtin/difftool.c b/builtin/difftool.c
index f09d24d37f..0049342f5c 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -15,6 +15,7 @@
#include "cache.h"
#include "abspath.h"
#include "config.h"
+#include "copy.h"
#include "builtin.h"
#include "run-command.h"
#include "environment.h"
diff --git a/builtin/fetch.c b/builtin/fetch.c
index ab623f41b4..849a9be421 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -29,6 +29,7 @@
#include "utf8.h"
#include "packfile.h"
#include "pager.h"
+#include "pkt-line.h"
#include "list-objects-filter-options.h"
#include "commit-reach.h"
#include "branch.h"
@@ -56,11 +57,18 @@ enum {
TAGS_SET = 2
};
+enum display_format {
+ DISPLAY_FORMAT_UNKNOWN = 0,
+ DISPLAY_FORMAT_FULL,
+ DISPLAY_FORMAT_COMPACT,
+ DISPLAY_FORMAT_PORCELAIN,
+};
+
struct display_state {
struct strbuf buf;
int refcol_width;
- int compact_format;
+ enum display_format format;
char *url;
int url_len, shown_url;
@@ -77,13 +85,12 @@ static int fetch_prune_tags_config = -1; /* unspecified */
static int prune_tags = -1; /* unspecified */
#define PRUNE_TAGS_BY_DEFAULT 0 /* do we prune tags by default? */
-static int all, append, dry_run, force, keep, multiple, update_head_ok;
+static int append, dry_run, force, keep, update_head_ok;
static int write_fetch_head = 1;
static int verbosity, deepen_relative, set_upstream, refetch;
static int progress = -1;
-static int enable_auto_gc = 1;
-static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;
-static int max_jobs = -1, submodule_fetch_jobs_config = -1;
+static int tags = TAGS_DEFAULT, update_shallow, deepen;
+static int submodule_fetch_jobs_config = -1;
static int fetch_parallel_config = 1;
static int atomic_fetch;
static enum transport_family family;
@@ -94,20 +101,20 @@ static struct string_list deepen_not = STRING_LIST_INIT_NODUP;
static struct strbuf default_rla = STRBUF_INIT;
static struct transport *gtransport;
static struct transport *gsecondary;
-static const char *submodule_prefix = "";
static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
-static int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;
-static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;
static struct refspec refmap = REFSPEC_INIT_FETCH;
static struct list_objects_filter_options filter_options = LIST_OBJECTS_FILTER_INIT;
static struct string_list server_options = STRING_LIST_INIT_DUP;
static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
-static int fetch_write_commit_graph = -1;
-static int stdin_refspecs = 0;
-static int negotiate_only;
+
+struct fetch_config {
+ enum display_format display_format;
+};
static int git_fetch_config(const char *k, const char *v, void *cb)
{
+ struct fetch_config *fetch_config = cb;
+
if (!strcmp(k, "fetch.prune")) {
fetch_prune_config = git_config_bool(k, v);
return 0;
@@ -146,6 +153,18 @@ static int git_fetch_config(const char *k, const char *v, void *cb)
return 0;
}
+ if (!strcmp(k, "fetch.output")) {
+ if (!v)
+ return config_error_nonbool(k);
+ else if (!strcasecmp(v, "full"))
+ fetch_config->display_format = DISPLAY_FORMAT_FULL;
+ else if (!strcasecmp(v, "compact"))
+ fetch_config->display_format = DISPLAY_FORMAT_COMPACT;
+ else
+ die(_("invalid value for '%s': '%s'"),
+ "fetch.output", v);
+ }
+
return git_default_config(k, v, cb);
}
@@ -162,92 +181,6 @@ static int parse_refmap_arg(const struct option *opt, const char *arg, int unset
return 0;
}
-static struct option builtin_fetch_options[] = {
- OPT__VERBOSITY(&verbosity),
- OPT_BOOL(0, "all", &all,
- N_("fetch from all remotes")),
- OPT_BOOL(0, "set-upstream", &set_upstream,
- N_("set upstream for git pull/fetch")),
- OPT_BOOL('a', "append", &append,
- N_("append to .git/FETCH_HEAD instead of overwriting")),
- OPT_BOOL(0, "atomic", &atomic_fetch,
- N_("use atomic transaction to update references")),
- OPT_STRING(0, "upload-pack", &upload_pack, N_("path"),
- N_("path to upload pack on remote end")),
- OPT__FORCE(&force, N_("force overwrite of local reference"), 0),
- OPT_BOOL('m', "multiple", &multiple,
- N_("fetch from multiple remotes")),
- OPT_SET_INT('t', "tags", &tags,
- N_("fetch all tags and associated objects"), TAGS_SET),
- OPT_SET_INT('n', NULL, &tags,
- N_("do not fetch all tags (--no-tags)"), TAGS_UNSET),
- OPT_INTEGER('j', "jobs", &max_jobs,
- N_("number of submodules fetched in parallel")),
- OPT_BOOL(0, "prefetch", &prefetch,
- N_("modify the refspec to place all refs within refs/prefetch/")),
- OPT_BOOL('p', "prune", &prune,
- N_("prune remote-tracking branches no longer on remote")),
- OPT_BOOL('P', "prune-tags", &prune_tags,
- N_("prune local tags no longer on remote and clobber changed tags")),
- OPT_CALLBACK_F(0, "recurse-submodules", &recurse_submodules_cli, N_("on-demand"),
- N_("control recursive fetching of submodules"),
- PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules),
- OPT_BOOL(0, "dry-run", &dry_run,
- N_("dry run")),
- OPT_BOOL(0, "write-fetch-head", &write_fetch_head,
- N_("write fetched references to the FETCH_HEAD file")),
- OPT_BOOL('k', "keep", &keep, N_("keep downloaded pack")),
- OPT_BOOL('u', "update-head-ok", &update_head_ok,
- N_("allow updating of HEAD ref")),
- OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
- OPT_STRING(0, "depth", &depth, N_("depth"),
- N_("deepen history of shallow clone")),
- OPT_STRING(0, "shallow-since", &deepen_since, N_("time"),
- N_("deepen history of shallow repository based on time")),
- OPT_STRING_LIST(0, "shallow-exclude", &deepen_not, N_("revision"),
- N_("deepen history of shallow clone, excluding rev")),
- OPT_INTEGER(0, "deepen", &deepen_relative,
- N_("deepen history of shallow clone")),
- OPT_SET_INT_F(0, "unshallow", &unshallow,
- N_("convert to a complete repository"),
- 1, PARSE_OPT_NONEG),
- OPT_SET_INT_F(0, "refetch", &refetch,
- N_("re-fetch without negotiating common commits"),
- 1, PARSE_OPT_NONEG),
- { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
- N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
- OPT_CALLBACK_F(0, "recurse-submodules-default",
- &recurse_submodules_default, N_("on-demand"),
- N_("default for recursive fetching of submodules "
- "(lower priority than config files)"),
- PARSE_OPT_HIDDEN, option_fetch_parse_recurse_submodules),
- OPT_BOOL(0, "update-shallow", &update_shallow,
- N_("accept refs that update .git/shallow")),
- OPT_CALLBACK_F(0, "refmap", NULL, N_("refmap"),
- N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg),
- OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")),
- OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
- TRANSPORT_FAMILY_IPV4),
- OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
- TRANSPORT_FAMILY_IPV6),
- OPT_STRING_LIST(0, "negotiation-tip", &negotiation_tip, N_("revision"),
- N_("report that we have only objects reachable from this object")),
- OPT_BOOL(0, "negotiate-only", &negotiate_only,
- N_("do not fetch a packfile; instead, print ancestors of negotiation tips")),
- OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
- OPT_BOOL(0, "auto-maintenance", &enable_auto_gc,
- N_("run 'maintenance --auto' after fetching")),
- OPT_BOOL(0, "auto-gc", &enable_auto_gc,
- N_("run 'maintenance --auto' after fetching")),
- OPT_BOOL(0, "show-forced-updates", &fetch_show_forced_updates,
- N_("check for forced-updates on all updated branches")),
- OPT_BOOL(0, "write-commit-graph", &fetch_write_commit_graph,
- N_("write the commit-graph after fetching")),
- OPT_BOOL(0, "stdin", &stdin_refspecs,
- N_("accept refspecs from stdin")),
- OPT_END()
-};
-
static void unlock_pack(unsigned int flags)
{
if (gtransport)
@@ -759,46 +692,56 @@ out:
return ret;
}
-static int refcol_width(const struct ref *ref, int compact_format)
+static int refcol_width(const struct ref *ref_map, int compact_format)
{
- int max, rlen, llen, len;
+ const struct ref *ref;
+ int max, width = 10;
- /* uptodate lines are only shown on high verbosity level */
- if (verbosity <= 0 && oideq(&ref->peer_ref->old_oid, &ref->old_oid))
- return 0;
+ max = term_columns();
+ if (compact_format)
+ max = max * 2 / 3;
- max = term_columns();
- rlen = utf8_strwidth(prettify_refname(ref->name));
+ for (ref = ref_map; ref; ref = ref->next) {
+ int rlen, llen = 0, len;
- llen = utf8_strwidth(prettify_refname(ref->peer_ref->name));
+ if (ref->status == REF_STATUS_REJECT_SHALLOW ||
+ !ref->peer_ref ||
+ !strcmp(ref->name, "HEAD"))
+ continue;
- /*
- * rough estimation to see if the output line is too long and
- * should not be counted (we can't do precise calculation
- * anyway because we don't know if the error explanation part
- * will be printed in update_local_ref)
- */
- if (compact_format) {
- llen = 0;
- max = max * 2 / 3;
+ /* uptodate lines are only shown on high verbosity level */
+ if (verbosity <= 0 && oideq(&ref->peer_ref->old_oid, &ref->old_oid))
+ continue;
+
+ rlen = utf8_strwidth(prettify_refname(ref->name));
+ if (!compact_format)
+ llen = utf8_strwidth(prettify_refname(ref->peer_ref->name));
+
+ /*
+ * rough estimation to see if the output line is too long and
+ * should not be counted (we can't do precise calculation
+ * anyway because we don't know if the error explanation part
+ * will be printed in update_local_ref)
+ */
+ len = 21 /* flag and summary */ + rlen + 4 /* -> */ + llen;
+ if (len >= max)
+ continue;
+
+ if (width < rlen)
+ width = rlen;
}
- len = 21 /* flag and summary */ + rlen + 4 /* -> */ + llen;
- if (len >= max)
- return 0;
- return rlen;
+ return width;
}
static void display_state_init(struct display_state *display_state, struct ref *ref_map,
- const char *raw_url)
+ const char *raw_url, enum display_format format)
{
- struct ref *rm;
- const char *format = "full";
int i;
memset(display_state, 0, sizeof(*display_state));
-
strbuf_init(&display_state->buf, 0);
+ display_state->format = format;
if (raw_url)
display_state->url = transport_anonymize_url(raw_url);
@@ -815,33 +758,17 @@ static void display_state_init(struct display_state *display_state, struct ref *
if (verbosity < 0)
return;
- git_config_get_string_tmp("fetch.output", &format);
- if (!strcasecmp(format, "full"))
- display_state->compact_format = 0;
- else if (!strcasecmp(format, "compact"))
- display_state->compact_format = 1;
- else
- die(_("invalid value for '%s': '%s'"),
- "fetch.output", format);
-
- display_state->refcol_width = 10;
- for (rm = ref_map; rm; rm = rm->next) {
- int width;
-
- if (rm->status == REF_STATUS_REJECT_SHALLOW ||
- !rm->peer_ref ||
- !strcmp(rm->name, "HEAD"))
- continue;
-
- width = refcol_width(rm, display_state->compact_format);
-
- /*
- * Not precise calculation for compact mode because '*' can
- * appear on the left hand side of '->' and shrink the column
- * back.
- */
- if (display_state->refcol_width < width)
- display_state->refcol_width = width;
+ switch (display_state->format) {
+ case DISPLAY_FORMAT_FULL:
+ case DISPLAY_FORMAT_COMPACT:
+ display_state->refcol_width = refcol_width(ref_map,
+ display_state->format == DISPLAY_FORMAT_COMPACT);
+ break;
+ case DISPLAY_FORMAT_PORCELAIN:
+ /* We don't need to precompute anything here. */
+ break;
+ default:
+ BUG("unexpected display format %d", display_state->format);
}
}
@@ -910,39 +837,61 @@ static void print_compact(struct display_state *display_state,
static void display_ref_update(struct display_state *display_state, char code,
const char *summary, const char *error,
const char *remote, const char *local,
+ const struct object_id *old_oid,
+ const struct object_id *new_oid,
int summary_width)
{
- int width;
+ FILE *f = stderr;
if (verbosity < 0)
return;
strbuf_reset(&display_state->buf);
- if (!display_state->shown_url) {
- strbuf_addf(&display_state->buf, _("From %.*s\n"),
- display_state->url_len, display_state->url);
- display_state->shown_url = 1;
- }
+ switch (display_state->format) {
+ case DISPLAY_FORMAT_FULL:
+ case DISPLAY_FORMAT_COMPACT: {
+ int width;
- width = (summary_width + strlen(summary) - gettext_width(summary));
+ if (!display_state->shown_url) {
+ strbuf_addf(&display_state->buf, _("From %.*s\n"),
+ display_state->url_len, display_state->url);
+ display_state->shown_url = 1;
+ }
- strbuf_addf(&display_state->buf, " %c %-*s ", code, width, summary);
- if (!display_state->compact_format)
- print_remote_to_local(display_state, remote, prettify_refname(local));
- else
- print_compact(display_state, remote, prettify_refname(local));
- if (error)
- strbuf_addf(&display_state->buf, " (%s)", error);
+ width = (summary_width + strlen(summary) - gettext_width(summary));
+ remote = prettify_refname(remote);
+ local = prettify_refname(local);
+
+ strbuf_addf(&display_state->buf, " %c %-*s ", code, width, summary);
+
+ if (display_state->format != DISPLAY_FORMAT_COMPACT)
+ print_remote_to_local(display_state, remote, local);
+ else
+ print_compact(display_state, remote, local);
+
+ if (error)
+ strbuf_addf(&display_state->buf, " (%s)", error);
+
+ break;
+ }
+ case DISPLAY_FORMAT_PORCELAIN:
+ strbuf_addf(&display_state->buf, "%c %s %s %s", code,
+ oid_to_hex(old_oid), oid_to_hex(new_oid), local);
+ f = stdout;
+ break;
+ default:
+ BUG("unexpected display format %d", display_state->format);
+ };
strbuf_addch(&display_state->buf, '\n');
- fputs(display_state->buf.buf, stderr);
+ fputs(display_state->buf.buf, f);
}
static int update_local_ref(struct ref *ref,
struct ref_transaction *transaction,
struct display_state *display_state,
- const char *remote, const struct ref *remote_ref,
+ const struct ref *remote_ref,
int summary_width)
{
struct commit *current = NULL, *updated;
@@ -954,7 +903,8 @@ static int update_local_ref(struct ref *ref,
if (oideq(&ref->old_oid, &ref->new_oid)) {
if (verbosity > 0)
display_ref_update(display_state, '=', _("[up to date]"), NULL,
- remote, ref->name, summary_width);
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
return 0;
}
@@ -967,7 +917,8 @@ static int update_local_ref(struct ref *ref,
*/
display_ref_update(display_state, '!', _("[rejected]"),
_("can't fetch into checked-out branch"),
- remote, ref->name, summary_width);
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
return 1;
}
@@ -978,12 +929,14 @@ static int update_local_ref(struct ref *ref,
r = s_update_ref("updating tag", ref, transaction, 0);
display_ref_update(display_state, r ? '!' : 't', _("[tag update]"),
r ? _("unable to update local ref") : NULL,
- remote, ref->name, summary_width);
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
return r;
} else {
display_ref_update(display_state, '!', _("[rejected]"),
_("would clobber existing tag"),
- remote, ref->name, summary_width);
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
return 1;
}
}
@@ -1016,7 +969,8 @@ static int update_local_ref(struct ref *ref,
r = s_update_ref(msg, ref, transaction, 0);
display_ref_update(display_state, r ? '!' : '*', what,
r ? _("unable to update local ref") : NULL,
- remote, ref->name, summary_width);
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
return r;
}
@@ -1039,7 +993,8 @@ static int update_local_ref(struct ref *ref,
r = s_update_ref("fast-forward", ref, transaction, 1);
display_ref_update(display_state, r ? '!' : ' ', quickref.buf,
r ? _("unable to update local ref") : NULL,
- remote, ref->name, summary_width);
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
strbuf_release(&quickref);
return r;
} else if (force || ref->force) {
@@ -1051,12 +1006,14 @@ static int update_local_ref(struct ref *ref,
r = s_update_ref("forced-update", ref, transaction, 1);
display_ref_update(display_state, r ? '!' : '+', quickref.buf,
r ? _("unable to update local ref") : _("forced update"),
- remote, ref->name, summary_width);
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
strbuf_release(&quickref);
return r;
} else {
display_ref_update(display_state, '!', _("[rejected]"), _("non-fast-forward"),
- remote, ref->name, summary_width);
+ remote_ref->name, ref->name,
+ &ref->old_oid, &ref->new_oid, summary_width);
return 1;
}
}
@@ -1261,14 +1218,13 @@ static int store_updated_refs(struct display_state *display_state,
if (!strcmp(rm->name, "HEAD")) {
kind = "";
what = "";
- }
- else if (skip_prefix(rm->name, "refs/heads/", &what))
+ } else if (skip_prefix(rm->name, "refs/heads/", &what)) {
kind = "branch";
- else if (skip_prefix(rm->name, "refs/tags/", &what))
+ } else if (skip_prefix(rm->name, "refs/tags/", &what)) {
kind = "tag";
- else if (skip_prefix(rm->name, "refs/remotes/", &what))
+ } else if (skip_prefix(rm->name, "refs/remotes/", &what)) {
kind = "remote-tracking branch";
- else {
+ } else {
kind = "";
what = rm->name;
}
@@ -1286,7 +1242,7 @@ static int store_updated_refs(struct display_state *display_state,
display_state->url_len);
if (ref) {
- rc |= update_local_ref(ref, transaction, display_state, what,
+ rc |= update_local_ref(ref, transaction, display_state,
rm, summary_width);
free(ref);
} else if (write_fetch_head || dry_run) {
@@ -1297,8 +1253,10 @@ static int store_updated_refs(struct display_state *display_state,
*/
display_ref_update(display_state, '*',
*kind ? kind : "branch", NULL,
- *what ? what : "HEAD",
- "FETCH_HEAD", summary_width);
+ rm->name,
+ "FETCH_HEAD",
+ &rm->new_oid, &rm->old_oid,
+ summary_width);
}
}
}
@@ -1438,6 +1396,7 @@ static int prune_refs(struct display_state *display_state,
for (ref = stale_refs; ref; ref = ref->next) {
display_ref_update(display_state, '-', _("[deleted]"), NULL,
_("(none)"), ref->name,
+ &ref->new_oid, &ref->old_oid,
summary_width);
warn_dangling_symref(stderr, dangling_msg, ref->name);
}
@@ -1595,7 +1554,8 @@ static int backfill_tags(struct display_state *display_state,
}
static int do_fetch(struct transport *transport,
- struct refspec *rs)
+ struct refspec *rs,
+ enum display_format display_format)
{
struct ref_transaction *transaction = NULL;
struct ref *ref_map = NULL;
@@ -1681,7 +1641,7 @@ static int do_fetch(struct transport *transport,
if (retcode)
goto cleanup;
- display_state_init(&display_state, ref_map, transport->url);
+ display_state_init(&display_state, ref_map, transport->url, display_format);
if (atomic_fetch) {
transaction = ref_transaction_begin(&err);
@@ -1869,7 +1829,8 @@ static int add_remote_or_group(const char *name, struct string_list *list)
return 1;
}
-static void add_options_to_argv(struct strvec *argv)
+static void add_options_to_argv(struct strvec *argv,
+ enum display_format format)
{
if (dry_run)
strvec_push(argv, "--dry-run");
@@ -1885,6 +1846,8 @@ static void add_options_to_argv(struct strvec *argv)
strvec_push(argv, "--keep");
if (recurse_submodules == RECURSE_SUBMODULES_ON)
strvec_push(argv, "--recurse-submodules");
+ else if (recurse_submodules == RECURSE_SUBMODULES_OFF)
+ strvec_push(argv, "--no-recurse-submodules");
else if (recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)
strvec_push(argv, "--recurse-submodules=on-demand");
if (tags == TAGS_SET)
@@ -1903,6 +1866,8 @@ static void add_options_to_argv(struct strvec *argv)
strvec_push(argv, "--ipv6");
if (!write_fetch_head)
strvec_push(argv, "--no-write-fetch-head");
+ if (format == DISPLAY_FORMAT_PORCELAIN)
+ strvec_pushf(argv, "--porcelain");
}
/* Fetch multiple remotes in parallel */
@@ -1911,6 +1876,7 @@ struct parallel_fetch_state {
const char **argv;
struct string_list *remotes;
int next, result;
+ enum display_format format;
};
static int fetch_next_remote(struct child_process *cp,
@@ -1930,7 +1896,7 @@ static int fetch_next_remote(struct child_process *cp,
strvec_push(&cp->args, remote);
cp->git_cmd = 1;
- if (verbosity >= 0)
+ if (verbosity >= 0 && state->format != DISPLAY_FORMAT_PORCELAIN)
printf(_("Fetching %s\n"), remote);
return 1;
@@ -1962,7 +1928,8 @@ static int fetch_finished(int result, struct strbuf *out,
return 0;
}
-static int fetch_multiple(struct string_list *list, int max_children)
+static int fetch_multiple(struct string_list *list, int max_children,
+ enum display_format format)
{
int i, result = 0;
struct strvec argv = STRVEC_INIT;
@@ -1980,10 +1947,10 @@ static int fetch_multiple(struct string_list *list, int max_children)
strvec_pushl(&argv, "-c", "fetch.bundleURI=",
"fetch", "--append", "--no-auto-gc",
"--no-write-commit-graph", NULL);
- add_options_to_argv(&argv);
+ add_options_to_argv(&argv, format);
if (max_children != 1 && list->nr != 1) {
- struct parallel_fetch_state state = { argv.v, list, 0, 0 };
+ struct parallel_fetch_state state = { argv.v, list, 0, 0, format };
const struct run_process_parallel_opts opts = {
.tr2_category = "fetch",
.tr2_label = "parallel/fetch",
@@ -2007,7 +1974,7 @@ static int fetch_multiple(struct string_list *list, int max_children)
strvec_pushv(&cmd.args, argv.v);
strvec_push(&cmd.args, name);
- if (verbosity >= 0)
+ if (verbosity >= 0 && format != DISPLAY_FORMAT_PORCELAIN)
printf(_("Fetching %s\n"), name);
cmd.git_cmd = 1;
if (run_command(&cmd)) {
@@ -2062,7 +2029,8 @@ static inline void fetch_one_setup_partial(struct remote *remote)
}
static int fetch_one(struct remote *remote, int argc, const char **argv,
- int prune_tags_ok, int use_stdin_refspecs)
+ int prune_tags_ok, int use_stdin_refspecs,
+ enum display_format display_format)
{
struct refspec rs = REFSPEC_INIT_FETCH;
int i;
@@ -2129,7 +2097,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
sigchain_push_common(unlock_pack_on_signal);
atexit(unlock_pack_atexit);
sigchain_push(SIGPIPE, SIG_IGN);
- exit_code = do_fetch(gtransport, &rs);
+ exit_code = do_fetch(gtransport, &rs, display_format);
sigchain_pop(SIGPIPE);
refspec_clear(&rs);
transport_disconnect(gtransport);
@@ -2139,12 +2107,113 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
int cmd_fetch(int argc, const char **argv, const char *prefix)
{
- int i;
+ struct fetch_config config = {
+ .display_format = DISPLAY_FORMAT_FULL,
+ };
+ const char *submodule_prefix = "";
const char *bundle_uri;
struct string_list list = STRING_LIST_INIT_DUP;
struct remote *remote = NULL;
+ int all = 0, multiple = 0;
int result = 0;
int prune_tags_ok = 1;
+ int enable_auto_gc = 1;
+ int unshallow = 0;
+ int max_jobs = -1;
+ int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;
+ int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;
+ int fetch_write_commit_graph = -1;
+ int stdin_refspecs = 0;
+ int negotiate_only = 0;
+ int porcelain = 0;
+ int i;
+
+ struct option builtin_fetch_options[] = {
+ OPT__VERBOSITY(&verbosity),
+ OPT_BOOL(0, "all", &all,
+ N_("fetch from all remotes")),
+ OPT_BOOL(0, "set-upstream", &set_upstream,
+ N_("set upstream for git pull/fetch")),
+ OPT_BOOL('a', "append", &append,
+ N_("append to .git/FETCH_HEAD instead of overwriting")),
+ OPT_BOOL(0, "atomic", &atomic_fetch,
+ N_("use atomic transaction to update references")),
+ OPT_STRING(0, "upload-pack", &upload_pack, N_("path"),
+ N_("path to upload pack on remote end")),
+ OPT__FORCE(&force, N_("force overwrite of local reference"), 0),
+ OPT_BOOL('m', "multiple", &multiple,
+ N_("fetch from multiple remotes")),
+ OPT_SET_INT('t', "tags", &tags,
+ N_("fetch all tags and associated objects"), TAGS_SET),
+ OPT_SET_INT('n', NULL, &tags,
+ N_("do not fetch all tags (--no-tags)"), TAGS_UNSET),
+ OPT_INTEGER('j', "jobs", &max_jobs,
+ N_("number of submodules fetched in parallel")),
+ OPT_BOOL(0, "prefetch", &prefetch,
+ N_("modify the refspec to place all refs within refs/prefetch/")),
+ OPT_BOOL('p', "prune", &prune,
+ N_("prune remote-tracking branches no longer on remote")),
+ OPT_BOOL('P', "prune-tags", &prune_tags,
+ N_("prune local tags no longer on remote and clobber changed tags")),
+ OPT_CALLBACK_F(0, "recurse-submodules", &recurse_submodules_cli, N_("on-demand"),
+ N_("control recursive fetching of submodules"),
+ PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules),
+ OPT_BOOL(0, "dry-run", &dry_run,
+ N_("dry run")),
+ OPT_BOOL(0, "porcelain", &porcelain, N_("machine-readable output")),
+ OPT_BOOL(0, "write-fetch-head", &write_fetch_head,
+ N_("write fetched references to the FETCH_HEAD file")),
+ OPT_BOOL('k', "keep", &keep, N_("keep downloaded pack")),
+ OPT_BOOL('u', "update-head-ok", &update_head_ok,
+ N_("allow updating of HEAD ref")),
+ OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
+ OPT_STRING(0, "depth", &depth, N_("depth"),
+ N_("deepen history of shallow clone")),
+ OPT_STRING(0, "shallow-since", &deepen_since, N_("time"),
+ N_("deepen history of shallow repository based on time")),
+ OPT_STRING_LIST(0, "shallow-exclude", &deepen_not, N_("revision"),
+ N_("deepen history of shallow clone, excluding rev")),
+ OPT_INTEGER(0, "deepen", &deepen_relative,
+ N_("deepen history of shallow clone")),
+ OPT_SET_INT_F(0, "unshallow", &unshallow,
+ N_("convert to a complete repository"),
+ 1, PARSE_OPT_NONEG),
+ OPT_SET_INT_F(0, "refetch", &refetch,
+ N_("re-fetch without negotiating common commits"),
+ 1, PARSE_OPT_NONEG),
+ { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
+ N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
+ OPT_CALLBACK_F(0, "recurse-submodules-default",
+ &recurse_submodules_default, N_("on-demand"),
+ N_("default for recursive fetching of submodules "
+ "(lower priority than config files)"),
+ PARSE_OPT_HIDDEN, option_fetch_parse_recurse_submodules),
+ OPT_BOOL(0, "update-shallow", &update_shallow,
+ N_("accept refs that update .git/shallow")),
+ OPT_CALLBACK_F(0, "refmap", NULL, N_("refmap"),
+ N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg),
+ OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")),
+ OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
+ TRANSPORT_FAMILY_IPV4),
+ OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
+ TRANSPORT_FAMILY_IPV6),
+ OPT_STRING_LIST(0, "negotiation-tip", &negotiation_tip, N_("revision"),
+ N_("report that we have only objects reachable from this object")),
+ OPT_BOOL(0, "negotiate-only", &negotiate_only,
+ N_("do not fetch a packfile; instead, print ancestors of negotiation tips")),
+ OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
+ OPT_BOOL(0, "auto-maintenance", &enable_auto_gc,
+ N_("run 'maintenance --auto' after fetching")),
+ OPT_BOOL(0, "auto-gc", &enable_auto_gc,
+ N_("run 'maintenance --auto' after fetching")),
+ OPT_BOOL(0, "show-forced-updates", &fetch_show_forced_updates,
+ N_("check for forced-updates on all updated branches")),
+ OPT_BOOL(0, "write-commit-graph", &fetch_write_commit_graph,
+ N_("write the commit-graph after fetching")),
+ OPT_BOOL(0, "stdin", &stdin_refspecs,
+ N_("accept refspecs from stdin")),
+ OPT_END()
+ };
packet_trace_identity("fetch");
@@ -2158,7 +2227,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
free(anon);
}
- git_config(git_fetch_config, NULL);
+ git_config(git_fetch_config, &config);
if (the_repository->gitdir) {
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
@@ -2197,6 +2266,26 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
fetch_config_from_gitmodules(sfjc, rs);
}
+
+ if (porcelain) {
+ switch (recurse_submodules_cli) {
+ case RECURSE_SUBMODULES_OFF:
+ case RECURSE_SUBMODULES_DEFAULT:
+ /*
+ * Reference updates in submodules would be ambiguous
+ * in porcelain mode, so we reject this combination.
+ */
+ recurse_submodules = RECURSE_SUBMODULES_OFF;
+ break;
+
+ default:
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--porcelain", "--recurse-submodules");
+ }
+
+ config.display_format = DISPLAY_FORMAT_PORCELAIN;
+ }
+
if (negotiate_only && !negotiation_tip.nr)
die(_("--negotiate-only needs one or more --negotiation-tip=*"));
@@ -2295,7 +2384,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
} else if (remote) {
if (filter_options.choice || repo_has_promisor_remote(the_repository))
fetch_one_setup_partial(remote);
- result = fetch_one(remote, argc, argv, prune_tags_ok, stdin_refspecs);
+ result = fetch_one(remote, argc, argv, prune_tags_ok, stdin_refspecs,
+ config.display_format);
} else {
int max_children = max_jobs;
@@ -2315,10 +2405,9 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
max_children = fetch_parallel_config;
/* TODO should this also die if we have a previous partial-clone? */
- result = fetch_multiple(&list, max_children);
+ result = fetch_multiple(&list, max_children, config.display_format);
}
-
/*
* This is only needed after fetch_one(), which does not fetch
* submodules by itself.
@@ -2337,7 +2426,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
if (max_children < 0)
max_children = fetch_parallel_config;
- add_options_to_argv(&options);
+ add_options_to_argv(&options, config.display_format);
result = fetch_submodules(the_repository,
&options,
submodule_prefix,
diff --git a/builtin/for-each-repo.c b/builtin/for-each-repo.c
index 598ca16c46..37daf7bec1 100644
--- a/builtin/for-each-repo.c
+++ b/builtin/for-each-repo.c
@@ -3,6 +3,8 @@
#include "builtin.h"
#include "gettext.h"
#include "parse-options.h"
+#include "path.h"
+#include "repository.h"
#include "run-command.h"
#include "string-list.h"
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 35a6de3cdb..dcc165bf0c 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -26,6 +26,8 @@
#include "resolve-undo.h"
#include "run-command.h"
#include "worktree.h"
+#include "pack-revindex.h"
+#include "pack-bitmap.h"
#define REACHABLE 0x0001
#define SEEN 0x0002
@@ -55,6 +57,8 @@ static int name_objects;
#define ERROR_REFS 010
#define ERROR_COMMIT_GRAPH 020
#define ERROR_MULTI_PACK_INDEX 040
+#define ERROR_PACK_REV_INDEX 0100
+#define ERROR_BITMAP 0200
static const char *describe_object(const struct object_id *oid)
{
@@ -858,6 +862,38 @@ static int mark_packed_for_connectivity(const struct object_id *oid,
return 0;
}
+static int check_pack_rev_indexes(struct repository *r, int show_progress)
+{
+ struct progress *progress = NULL;
+ uint32_t pack_count = 0;
+ int res = 0;
+
+ if (show_progress) {
+ for (struct packed_git *p = get_all_packs(r); p; p = p->next)
+ pack_count++;
+ progress = start_delayed_progress("Verifying reverse pack-indexes", pack_count);
+ pack_count = 0;
+ }
+
+ for (struct packed_git *p = get_all_packs(r); p; p = p->next) {
+ int load_error = load_pack_revindex_from_disk(p);
+
+ if (load_error < 0) {
+ error(_("unable to load rev-index for pack '%s'"), p->pack_name);
+ res = ERROR_PACK_REV_INDEX;
+ } else if (!load_error &&
+ !load_pack_revindex(r, p) &&
+ verify_pack_revindex(p)) {
+ error(_("invalid rev-index for pack '%s'"), p->pack_name);
+ res = ERROR_PACK_REV_INDEX;
+ }
+ display_progress(progress, ++pack_count);
+ }
+ stop_progress(&progress);
+
+ return res;
+}
+
static char const * const fsck_usage[] = {
N_("git fsck [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]\n"
" [--[no-]full] [--strict] [--verbose] [--lost-found]\n"
@@ -1021,6 +1057,10 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
free_worktrees(worktrees);
}
+ errors_found |= check_pack_rev_indexes(the_repository, show_progress);
+ if (verify_bitmap_files(the_repository))
+ errors_found |= ERROR_BITMAP;
+
check_connectivity();
if (the_repository->settings.core_commit_graph) {
diff --git a/builtin/gc.c b/builtin/gc.c
index f8569bfacc..f3942188a6 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -12,6 +12,7 @@
#include "builtin.h"
#include "abspath.h"
+#include "date.h"
#include "environment.h"
#include "hex.h"
#include "repository.h"
@@ -50,7 +51,7 @@ static const char * const builtin_gc_usage[] = {
static int pack_refs = 1;
static int prune_reflogs = 1;
-static int cruft_packs = -1;
+static int cruft_packs = 1;
static int aggressive_depth = 50;
static int aggressive_window = 250;
static int gc_auto_threshold = 6700;
@@ -221,7 +222,7 @@ static struct packed_git *find_base_packs(struct string_list *packs,
struct packed_git *p, *base = NULL;
for (p = get_all_packs(the_repository); p; p = p->next) {
- if (!p->pack_local)
+ if (!p->pack_local || p->is_cruft)
continue;
if (limit) {
if (p->pack_size >= limit)
@@ -610,10 +611,6 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
if (prune_expire && parse_expiry_date(prune_expire, &dummy))
die(_("failed to parse prune expiry value %s"), prune_expire);
- prepare_repo_settings(the_repository);
- if (cruft_packs < 0)
- cruft_packs = the_repository->settings.gc_cruft_packs;
-
if (aggressive) {
strvec_push(&repack, "-f");
if (aggressive_depth > 0)
@@ -1689,11 +1686,11 @@ static int get_schedule_cmd(const char **cmd, int *is_available)
if (is_available)
*is_available = 0;
- string_list_split_in_place(&list, testing, ',', -1);
+ string_list_split_in_place(&list, testing, ",", -1);
for_each_string_list_item(item, &list) {
struct string_list pair = STRING_LIST_INIT_NODUP;
- if (string_list_split_in_place(&pair, item->string, ':', 2) != 2)
+ if (string_list_split_in_place(&pair, item->string, ":", 2) != 2)
continue;
if (!strcmp(*cmd, pair.items[0].string)) {
diff --git a/builtin/help.c b/builtin/help.c
index 128aa83099..d3cf4af3f6 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -8,6 +8,7 @@
#include "gettext.h"
#include "pager.h"
#include "parse-options.h"
+#include "path.h"
#include "run-command.h"
#include "config-list.h"
#include "help.h"
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 0f59cf8aa0..bb67e16655 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1756,12 +1756,13 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
fsck_options.walk = mark_link;
reset_pack_idx_option(&opts);
+ opts.flags |= WRITE_REV;
git_config(git_index_pack_config, &opts);
if (prefix && chdir(prefix))
die(_("Cannot come back to cwd"));
- if (git_env_bool(GIT_TEST_WRITE_REV_INDEX, 0))
- rev_index = 1;
+ if (git_env_bool(GIT_TEST_NO_WRITE_REV_INDEX, 0))
+ rev_index = 0;
else
rev_index = !!(opts.flags & (WRITE_REV_VERIFY | WRITE_REV));
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 6183f3fb3f..aef4036105 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -6,6 +6,7 @@
#include "cache.h"
#include "abspath.h"
#include "config.h"
+#include "copy.h"
#include "environment.h"
#include "gettext.h"
#include "refs.h"
@@ -13,6 +14,7 @@
#include "exec-cmd.h"
#include "object-file.h"
#include "parse-options.h"
+#include "path.h"
#include "setup.h"
#include "worktree.h"
#include "wrapper.h"
diff --git a/builtin/log.c b/builtin/log.c
index 4f162ff4d0..676de107d6 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -44,6 +44,7 @@
#include "commit-reach.h"
#include "range-diff.h"
#include "tmp-objdir.h"
+#include "tree.h"
#include "write-or-die.h"
#define MAIL_DEFAULT_WRAP 72
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index 3c74c4a104..cb6cb77e08 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -3,6 +3,7 @@
#include "gettext.h"
#include "hex.h"
#include "transport.h"
+#include "pkt-line.h"
#include "ref-filter.h"
#include "remote.h"
#include "refs.h"
diff --git a/builtin/merge-index.c b/builtin/merge-index.c
index b747b4ed98..ab16e70f23 100644
--- a/builtin/merge-index.c
+++ b/builtin/merge-index.c
@@ -1,6 +1,7 @@
#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "hex.h"
+#include "repository.h"
#include "run-command.h"
static const char *pgm;
diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c
index 708a8ffabe..b9e980384a 100644
--- a/builtin/merge-recursive.c
+++ b/builtin/merge-recursive.c
@@ -3,9 +3,11 @@
#include "advice.h"
#include "commit.h"
#include "gettext.h"
+#include "hash.h"
#include "tag.h"
#include "merge-recursive.h"
#include "object-name.h"
+#include "repository.h"
#include "xdiff-interface.h"
static const char builtin_merge_recursive_usage[] =
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index 6b9f006ec1..b8f8a8b5d9 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -16,6 +16,8 @@
#include "exec-cmd.h"
#include "merge-blobs.h"
#include "quote.h"
+#include "tree.h"
+#include "config.h"
static int line_termination = '\n';
@@ -627,6 +629,8 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
if (argc != expected_remaining_argc)
usage_with_options(merge_tree_usage, mt_options);
+ git_config(git_default_config, NULL);
+
/* Do the relevant type of merge */
if (o.mode == MODE_REAL)
return real_merge(&o, merge_base, argv[0], argv[1], prefix);
diff --git a/builtin/merge.c b/builtin/merge.c
index 8da3e46abb..1d14767c0c 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -879,13 +879,15 @@ static void prepare_to_commit(struct commit_list *remoteheads)
strbuf_addch(&msg, '\n');
if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
wt_status_append_cut_line(&msg);
- strbuf_commented_addf(&msg, "\n");
+ strbuf_commented_addf(&msg, comment_line_char, "\n");
}
- strbuf_commented_addf(&msg, _(merge_editor_comment));
+ strbuf_commented_addf(&msg, comment_line_char,
+ _(merge_editor_comment));
if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
- strbuf_commented_addf(&msg, _(scissors_editor_comment));
+ strbuf_commented_addf(&msg, comment_line_char,
+ _(scissors_editor_comment));
else
- strbuf_commented_addf(&msg,
+ strbuf_commented_addf(&msg, comment_line_char,
_(no_scissors_editor_comment), comment_line_char);
}
if (signoff)
diff --git a/builtin/mv.c b/builtin/mv.c
index 32935af48e..665bd27448 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -18,6 +18,7 @@
#include "cache-tree.h"
#include "string-list.h"
#include "parse-options.h"
+#include "repository.h"
#include "setup.h"
#include "submodule.h"
#include "entry.h"
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 593f0506a1..4d15a23fc4 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -573,7 +573,11 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
N_("ignore refs matching <pattern>")),
OPT_GROUP(""),
OPT_BOOL(0, "all", &all, N_("list all commits reachable from all refs")),
- OPT_BOOL(0, "stdin", &transform_stdin, N_("deprecated: use --annotate-stdin instead")),
+ OPT_BOOL_F(0,
+ "stdin",
+ &transform_stdin,
+ N_("deprecated: use --annotate-stdin instead"),
+ PARSE_OPT_HIDDEN),
OPT_BOOL(0, "annotate-stdin", &annotate_stdin, N_("annotate text from stdin")),
OPT_BOOL(0, "undefined", &allow_undefined, N_("allow to print `undefined` names (default)")),
OPT_BOOL(0, "always", &always,
diff --git a/builtin/notes.c b/builtin/notes.c
index d5788352b6..12d966618b 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -8,9 +8,11 @@
*/
#include "cache.h"
+#include "alloc.h"
#include "config.h"
#include "builtin.h"
#include "editor.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "notes.h"
@@ -29,11 +31,12 @@
#include "worktree.h"
#include "write-or-die.h"
+static char *separator = "\n";
static const char * const git_notes_usage[] = {
N_("git notes [--ref <notes-ref>] [list [<object>]]"),
- N_("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+ N_("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--separator=<paragraph-break>] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
N_("git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"),
- N_("git notes [--ref <notes-ref>] append [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+ N_("git notes [--ref <notes-ref>] append [--allow-empty] [--separator=<paragraph-break>] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
N_("git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"),
N_("git notes [--ref <notes-ref>] show [<object>]"),
N_("git notes [--ref <notes-ref>] merge [-v | -q] [-s <strategy>] <notes-ref>"),
@@ -101,11 +104,26 @@ static const char * const git_notes_get_ref_usage[] = {
static const char note_template[] =
N_("Write/edit the notes for the following object:");
+enum notes_stripspace {
+ UNSPECIFIED = -1,
+ NO_STRIPSPACE = 0,
+ STRIPSPACE = 1,
+};
+
+struct note_msg {
+ enum notes_stripspace stripspace;
+ struct strbuf buf;
+};
+
struct note_data {
int given;
int use_editor;
+ int stripspace;
char *edit_path;
struct strbuf buf;
+ struct note_msg **messages;
+ size_t msg_nr;
+ size_t msg_alloc;
};
static void free_note_data(struct note_data *d)
@@ -115,6 +133,12 @@ static void free_note_data(struct note_data *d)
free(d->edit_path);
}
strbuf_release(&d->buf);
+
+ while (d->msg_nr--) {
+ strbuf_release(&d->messages[d->msg_nr]->buf);
+ free(d->messages[d->msg_nr]);
+ }
+ free(d->messages);
}
static int list_each_note(const struct object_id *object_oid,
@@ -157,7 +181,7 @@ static void write_commented_object(int fd, const struct object_id *object)
if (strbuf_read(&buf, show.out, 0) < 0)
die_errno(_("could not read 'show' output"));
- strbuf_add_commented_lines(&cbuf, buf.buf, buf.len);
+ strbuf_add_commented_lines(&cbuf, buf.buf, buf.len, comment_line_char);
write_or_die(fd, cbuf.buf, cbuf.len);
strbuf_release(&cbuf);
@@ -185,9 +209,10 @@ static void prepare_note_data(const struct object_id *object, struct note_data *
copy_obj_to_fd(fd, old_note);
strbuf_addch(&buf, '\n');
- strbuf_add_commented_lines(&buf, "\n", strlen("\n"));
- strbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)));
- strbuf_add_commented_lines(&buf, "\n", strlen("\n"));
+ strbuf_add_commented_lines(&buf, "\n", strlen("\n"), comment_line_char);
+ strbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)),
+ comment_line_char);
+ strbuf_add_commented_lines(&buf, "\n", strlen("\n"), comment_line_char);
write_or_die(fd, buf.buf, buf.len);
write_commented_object(fd, object);
@@ -199,7 +224,8 @@ static void prepare_note_data(const struct object_id *object, struct note_data *
if (launch_editor(d->edit_path, &d->buf, NULL)) {
die(_("please supply the note contents using either -m or -F option"));
}
- strbuf_stripspace(&d->buf, 1);
+ if (d->stripspace)
+ strbuf_stripspace(&d->buf, comment_line_char);
}
}
@@ -215,66 +241,98 @@ static void write_note_data(struct note_data *d, struct object_id *oid)
}
}
+static void append_separator(struct strbuf *message)
+{
+ if (separator[strlen(separator) - 1] == '\n')
+ strbuf_addstr(message, separator);
+ else
+ strbuf_addf(message, "%s%s", separator, "\n");
+}
+
+static void concat_messages(struct note_data *d)
+{
+ struct strbuf msg = STRBUF_INIT;
+
+ size_t i;
+ for (i = 0; i < d->msg_nr ; i++) {
+ if (d->buf.len)
+ append_separator(&d->buf);
+ strbuf_add(&msg, d->messages[i]->buf.buf, d->messages[i]->buf.len);
+ strbuf_addbuf(&d->buf, &msg);
+ if ((d->stripspace == UNSPECIFIED &&
+ d->messages[i]->stripspace == STRIPSPACE) ||
+ d->stripspace == STRIPSPACE)
+ strbuf_stripspace(&d->buf, 0);
+ strbuf_reset(&msg);
+ }
+ strbuf_release(&msg);
+}
+
static int parse_msg_arg(const struct option *opt, const char *arg, int unset)
{
struct note_data *d = opt->value;
+ struct note_msg *msg = xmalloc(sizeof(*msg));
BUG_ON_OPT_NEG(unset);
- strbuf_grow(&d->buf, strlen(arg) + 2);
- if (d->buf.len)
- strbuf_addch(&d->buf, '\n');
- strbuf_addstr(&d->buf, arg);
- strbuf_stripspace(&d->buf, 0);
-
- d->given = 1;
+ strbuf_init(&msg->buf, strlen(arg));
+ strbuf_addstr(&msg->buf, arg);
+ ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc);
+ d->messages[d->msg_nr - 1] = msg;
+ msg->stripspace = STRIPSPACE;
return 0;
}
static int parse_file_arg(const struct option *opt, const char *arg, int unset)
{
struct note_data *d = opt->value;
+ struct note_msg *msg = xmalloc(sizeof(*msg));
BUG_ON_OPT_NEG(unset);
- if (d->buf.len)
- strbuf_addch(&d->buf, '\n');
+ strbuf_init(&msg->buf , 0);
if (!strcmp(arg, "-")) {
- if (strbuf_read(&d->buf, 0, 1024) < 0)
+ if (strbuf_read(&msg->buf, 0, 1024) < 0)
die_errno(_("cannot read '%s'"), arg);
- } else if (strbuf_read_file(&d->buf, arg, 1024) < 0)
+ } else if (strbuf_read_file(&msg->buf, arg, 1024) < 0)
die_errno(_("could not open or read '%s'"), arg);
- strbuf_stripspace(&d->buf, 0);
- d->given = 1;
+ ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc);
+ d->messages[d->msg_nr - 1] = msg;
+ msg->stripspace = STRIPSPACE;
return 0;
}
static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)
{
struct note_data *d = opt->value;
- char *buf;
+ struct note_msg *msg = xmalloc(sizeof(*msg));
+ char *value;
struct object_id object;
enum object_type type;
unsigned long len;
BUG_ON_OPT_NEG(unset);
- if (d->buf.len)
- strbuf_addch(&d->buf, '\n');
-
+ strbuf_init(&msg->buf, 0);
if (repo_get_oid(the_repository, arg, &object))
die(_("failed to resolve '%s' as a valid ref."), arg);
- if (!(buf = repo_read_object_file(the_repository, &object, &type, &len)))
+ if (!(value = repo_read_object_file(the_repository, &object, &type, &len)))
die(_("failed to read object '%s'."), arg);
if (type != OBJ_BLOB) {
- free(buf);
+ strbuf_release(&msg->buf);
+ free(value);
+ free(msg);
die(_("cannot read note data from non-blob object '%s'."), arg);
}
- strbuf_add(&d->buf, buf, len);
- free(buf);
- d->given = 1;
+ strbuf_add(&msg->buf, value, len);
+ free(value);
+
+ msg->buf.len = len;
+ ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc);
+ d->messages[d->msg_nr - 1] = msg;
+ msg->stripspace = NO_STRIPSPACE;
return 0;
}
@@ -408,7 +466,8 @@ static int add(int argc, const char **argv, const char *prefix)
struct notes_tree *t;
struct object_id object, new_note;
const struct object_id *note;
- struct note_data d = { 0, 0, NULL, STRBUF_INIT };
+ struct note_data d = { .buf = STRBUF_INIT, .stripspace = UNSPECIFIED };
+
struct option options[] = {
OPT_CALLBACK_F('m', "message", &d, N_("message"),
N_("note contents as a string"), PARSE_OPT_NONEG,
@@ -425,6 +484,10 @@ static int add(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "allow-empty", &allow_empty,
N_("allow storing empty note")),
OPT__FORCE(&force, N_("replace existing notes"), PARSE_OPT_NOCOMPLETE),
+ OPT_STRING(0, "separator", &separator, N_("separator"),
+ N_("insert <paragraph-break> between paragraphs")),
+ OPT_BOOL(0, "stripspace", &d.stripspace,
+ N_("remove unnecessary whitespace")),
OPT_END()
};
@@ -436,6 +499,10 @@ static int add(int argc, const char **argv, const char *prefix)
usage_with_options(git_notes_add_usage, options);
}
+ if (d.msg_nr)
+ concat_messages(&d);
+ d.given = !!d.buf.len;
+
object_ref = argc > 1 ? argv[1] : "HEAD";
if (repo_get_oid(the_repository, object_ref, &object))
@@ -574,7 +641,7 @@ static int append_edit(int argc, const char **argv, const char *prefix)
const struct object_id *note;
char *logmsg;
const char * const *usage;
- struct note_data d = { 0, 0, NULL, STRBUF_INIT };
+ struct note_data d = { .buf = STRBUF_INIT, .stripspace = UNSPECIFIED };
struct option options[] = {
OPT_CALLBACK_F('m', "message", &d, N_("message"),
N_("note contents as a string"), PARSE_OPT_NONEG,
@@ -590,6 +657,10 @@ static int append_edit(int argc, const char **argv, const char *prefix)
parse_reuse_arg),
OPT_BOOL(0, "allow-empty", &allow_empty,
N_("allow storing empty note")),
+ OPT_STRING(0, "separator", &separator, N_("separator"),
+ N_("insert <paragraph-break> between paragraphs")),
+ OPT_BOOL(0, "stripspace", &d.stripspace,
+ N_("remove unnecessary whitespace")),
OPT_END()
};
int edit = !strcmp(argv[0], "edit");
@@ -603,6 +674,10 @@ static int append_edit(int argc, const char **argv, const char *prefix)
usage_with_options(usage, options);
}
+ if (d.msg_nr)
+ concat_messages(&d);
+ d.given = !!d.buf.len;
+
if (d.given && edit)
fprintf(stderr, _("The -m/-F/-c/-C options have been deprecated "
"for the 'edit' subcommand.\n"
@@ -622,15 +697,17 @@ static int append_edit(int argc, const char **argv, const char *prefix)
/* Append buf to previous note contents */
unsigned long size;
enum object_type type;
- char *prev_buf = repo_read_object_file(the_repository, note,
- &type, &size);
+ struct strbuf buf = STRBUF_INIT;
+ char *prev_buf = repo_read_object_file(the_repository, note, &type, &size);
- strbuf_grow(&d.buf, size + 1);
- if (d.buf.len && prev_buf && size)
- strbuf_insertstr(&d.buf, 0, "\n");
if (prev_buf && size)
- strbuf_insert(&d.buf, 0, prev_buf, size);
+ strbuf_add(&buf, prev_buf, size);
+ if (d.buf.len && prev_buf && size)
+ append_separator(&buf);
+ strbuf_insert(&d.buf, 0, buf.buf, buf.len);
+
free(prev_buf);
+ strbuf_release(&buf);
}
if (d.buf.len || allow_empty) {
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index bbba1af27b..9cfc8801f9 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1331,7 +1331,7 @@ static int no_try_delta(const char *path)
if (!check)
check = attr_check_initl("delta", NULL);
- git_check_attr(the_repository->index, NULL, path, check);
+ git_check_attr(the_repository->index, path, check);
if (ATTR_FALSE(check->items[0].value))
return 1;
return 0;
@@ -4294,9 +4294,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
}
reset_pack_idx_option(&pack_idx_opts);
+ pack_idx_opts.flags |= WRITE_REV;
git_config(git_pack_config, NULL);
- if (git_env_bool(GIT_TEST_WRITE_REV_INDEX, 0))
- pack_idx_opts.flags |= WRITE_REV;
+ if (git_env_bool(GIT_TEST_NO_WRITE_REV_INDEX, 0))
+ pack_idx_opts.flags &= ~WRITE_REV;
progress = isatty(2);
argc = parse_options(argc, argv, prefix, pack_objects_options,
diff --git a/builtin/pull.c b/builtin/pull.c
index 967368ebc6..0c7bac97b7 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -1047,7 +1047,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
if (!opt_autostash)
require_clean_work_tree(the_repository,
N_("pull with rebase"),
- _("please commit or stash them."), 1, 0);
+ _("Please commit or stash them."), 1, 0);
if (get_rebase_fork_point(&rebase_fork_point, repo, *refspecs))
oidclr(&rebase_fork_point);
diff --git a/builtin/push.c b/builtin/push.c
index 6001e4ae0a..dbdf609daf 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -14,6 +14,8 @@
#include "remote.h"
#include "transport.h"
#include "parse-options.h"
+#include "pkt-line.h"
+#include "repository.h"
#include "submodule.h"
#include "submodule-config.h"
#include "send-pack.h"
@@ -593,11 +595,12 @@ int cmd_push(int argc, const char **argv, const char *prefix)
struct option options[] = {
OPT__VERBOSITY(&verbosity),
OPT_STRING( 0 , "repo", &repo, N_("repository"), N_("repository")),
- OPT_BIT( 0 , "all", &flags, N_("push all refs"), TRANSPORT_PUSH_ALL),
+ OPT_BIT( 0 , "all", &flags, N_("push all branches"), TRANSPORT_PUSH_ALL),
+ OPT_ALIAS( 0 , "branches", "all"),
OPT_BIT( 0 , "mirror", &flags, N_("mirror all refs"),
(TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
OPT_BOOL('d', "delete", &deleterefs, N_("delete refs")),
- OPT_BOOL( 0 , "tags", &tags, N_("push tags (can't be used with --all or --mirror)")),
+ OPT_BOOL( 0 , "tags", &tags, N_("push tags (can't be used with --all or --branches or --mirror)")),
OPT_BIT('n' , "dry-run", &flags, N_("dry run"), TRANSPORT_PUSH_DRY_RUN),
OPT_BIT( 0, "porcelain", &flags, N_("machine-readable output"), TRANSPORT_PUSH_PORCELAIN),
OPT_BIT('f', "force", &flags, N_("force updates"), TRANSPORT_PUSH_FORCE),
@@ -640,7 +643,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
set_push_cert_flags(&flags, push_cert);
if (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR))))
- die(_("options '%s' and '%s' cannot be used together"), "--delete", "--all/--mirror/--tags");
+ die(_("options '%s' and '%s' cannot be used together"), "--delete", "--all/--branches/--mirror/--tags");
if (deleterefs && argc < 2)
die(_("--delete doesn't make sense without any refs"));
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index d61cbad96d..440f19b1b8 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -19,6 +19,7 @@
#include "dir.h"
#include "builtin.h"
#include "parse-options.h"
+#include "repository.h"
#include "resolve-undo.h"
#include "setup.h"
#include "submodule.h"
diff --git a/builtin/rebase.c b/builtin/rebase.c
index ace1d5e8d1..b1ba9fb05d 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -209,7 +209,7 @@ static int edit_todo_file(unsigned flags)
if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)
return error_errno(_("could not read '%s'."), todo_file);
- strbuf_stripspace(&todo_list.buf, 1);
+ strbuf_stripspace(&todo_list.buf, comment_line_char);
res = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags);
if (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file,
NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS)))
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index d22180435c..1a31a58367 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -33,6 +33,7 @@
#include "object-store.h"
#include "protocol.h"
#include "commit-reach.h"
+#include "server-info.h"
#include "trace.h"
#include "trace2.h"
#include "worktree.h"
diff --git a/builtin/repack.c b/builtin/repack.c
index a6902272fc..0541c3ce15 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -7,6 +7,7 @@
#include "hex.h"
#include "parse-options.h"
#include "run-command.h"
+#include "server-info.h"
#include "sigchain.h"
#include "strbuf.h"
#include "string-list.h"
@@ -810,7 +811,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
N_("same as -a, pack unreachable cruft objects separately"),
PACK_CRUFT),
OPT_STRING(0, "cruft-expiration", &cruft_expiration, N_("approxidate"),
- N_("with -C, expire objects older than this")),
+ N_("with --cruft, expire objects older than this")),
OPT_BOOL('d', NULL, &delete_redundant,
N_("remove redundant packs, and run git-prune-packed")),
OPT_BOOL('f', NULL, &po_args.no_reuse_delta,
diff --git a/builtin/rerere.c b/builtin/rerere.c
index d4a03707b1..d4bd52797f 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -4,6 +4,7 @@
#include "dir.h"
#include "gettext.h"
#include "parse-options.h"
+#include "repository.h"
#include "string-list.h"
#include "rerere.h"
#include "wrapper.h"
diff --git a/builtin/rm.c b/builtin/rm.c
index d36072252e..b4589c824c 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -12,9 +12,11 @@
#include "dir.h"
#include "cache-tree.h"
#include "gettext.h"
+#include "hash.h"
#include "tree-walk.h"
#include "object-name.h"
#include "parse-options.h"
+#include "repository.h"
#include "string-list.h"
#include "setup.h"
#include "submodule.h"
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index 20030b75e3..7ef4a642c1 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -2,6 +2,7 @@
#include "config.h"
#include "environment.h"
#include "gettext.h"
+#include "hash.h"
#include "hex.h"
#include "pretty.h"
#include "refs.h"
@@ -10,6 +11,7 @@
#include "strvec.h"
#include "object-name.h"
#include "parse-options.h"
+#include "repository.h"
#include "dir.h"
#include "commit-slab.h"
#include "date.h"
diff --git a/builtin/show-index.c b/builtin/show-index.c
index d4bbbbcd6c..d839e55335 100644
--- a/builtin/show-index.c
+++ b/builtin/show-index.c
@@ -1,9 +1,11 @@
#include "builtin.h"
#include "cache.h"
#include "gettext.h"
+#include "hash.h"
#include "hex.h"
#include "pack.h"
#include "parse-options.h"
+#include "repository.h"
static const char *const show_index_usage[] = {
"git show-index [--object-format=<hash-algorithm>]",
diff --git a/builtin/stripspace.c b/builtin/stripspace.c
index 9451eb69ff..1987752359 100644
--- a/builtin/stripspace.c
+++ b/builtin/stripspace.c
@@ -1,6 +1,7 @@
#include "builtin.h"
#include "cache.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "parse-options.h"
#include "setup.h"
@@ -13,7 +14,7 @@ static void comment_lines(struct strbuf *buf)
size_t len;
msg = strbuf_detach(buf, &len);
- strbuf_add_commented_lines(buf, msg, len);
+ strbuf_add_commented_lines(buf, msg, len, comment_line_char);
free(msg);
}
@@ -58,7 +59,8 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix)
die_errno("could not read the input");
if (mode == STRIP_DEFAULT || mode == STRIP_COMMENTS)
- strbuf_stripspace(&buf, mode == STRIP_COMMENTS);
+ strbuf_stripspace(&buf,
+ mode == STRIP_COMMENTS ? comment_line_char : '\0');
else
comment_lines(&buf);
diff --git a/builtin/tag.c b/builtin/tag.c
index 1850a6a6fd..b79e0a88e6 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -311,9 +311,11 @@ static void create_tag(const struct object_id *object, const char *object_ref,
struct strbuf buf = STRBUF_INIT;
strbuf_addch(&buf, '\n');
if (opt->cleanup_mode == CLEANUP_ALL)
- strbuf_commented_addf(&buf, _(tag_template), tag, comment_line_char);
+ strbuf_commented_addf(&buf, comment_line_char,
+ _(tag_template), tag, comment_line_char);
else
- strbuf_commented_addf(&buf, _(tag_template_nocleanup), tag, comment_line_char);
+ strbuf_commented_addf(&buf, comment_line_char,
+ _(tag_template_nocleanup), tag, comment_line_char);
write_or_die(fd, buf.buf, buf.len);
strbuf_release(&buf);
}
@@ -327,7 +329,8 @@ static void create_tag(const struct object_id *object, const char *object_ref,
}
if (opt->cleanup_mode != CLEANUP_NONE)
- strbuf_stripspace(buf, opt->cleanup_mode == CLEANUP_ALL);
+ strbuf_stripspace(buf,
+ opt->cleanup_mode == CLEANUP_ALL ? comment_line_char : '\0');
if (!opt->message_given && !buf->len)
die(_("no tag message?"));
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 33b00cef15..5fab9ad2ec 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -9,6 +9,7 @@
#include "config.h"
#include "environment.h"
#include "gettext.h"
+#include "hash.h"
#include "hex.h"
#include "lockfile.h"
#include "quote.h"
@@ -21,8 +22,10 @@
#include "parse-options.h"
#include "pathspec.h"
#include "dir.h"
+#include "repository.h"
#include "setup.h"
#include "split-index.h"
+#include "symlinks.h"
#include "fsmonitor.h"
#include "write-or-die.h"
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 6ca85420c3..0c59b1c9ef 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -1,11 +1,13 @@
#include "cache.h"
#include "config.h"
#include "gettext.h"
+#include "hash.h"
#include "refs.h"
#include "builtin.h"
#include "object-name.h"
#include "parse-options.h"
#include "quote.h"
+#include "repository.h"
#include "strvec.h"
static const char * const git_update_ref_usage[] = {
diff --git a/builtin/update-server-info.c b/builtin/update-server-info.c
index e7bff27ae4..19dce3c065 100644
--- a/builtin/update-server-info.c
+++ b/builtin/update-server-info.c
@@ -3,6 +3,7 @@
#include "builtin.h"
#include "gettext.h"
#include "parse-options.h"
+#include "server-info.h"
static const char * const update_server_info_usage[] = {
"git update-server-info [-f | --force]",
diff --git a/builtin/upload-archive.c b/builtin/upload-archive.c
index 7f9320ac6d..44ad400e18 100644
--- a/builtin/upload-archive.c
+++ b/builtin/upload-archive.c
@@ -6,6 +6,7 @@
#include "archive.h"
#include "pkt-line.h"
#include "sideband.h"
+#include "repository.h"
#include "run-command.h"
#include "strvec.h"
diff --git a/builtin/worktree.c b/builtin/worktree.c
index a61bc32189..f3180463be 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -2,6 +2,7 @@
#include "abspath.h"
#include "checkout.h"
#include "config.h"
+#include "copy.h"
#include "builtin.h"
#include "dir.h"
#include "environment.h"
@@ -13,6 +14,7 @@
#include "strvec.h"
#include "branch.h"
#include "refs.h"
+#include "repository.h"
#include "run-command.h"
#include "hook.h"
#include "sigchain.h"
diff --git a/builtin/write-tree.c b/builtin/write-tree.c
index 32e302a813..84b83318c9 100644
--- a/builtin/write-tree.c
+++ b/builtin/write-tree.c
@@ -13,6 +13,7 @@
#include "tree.h"
#include "cache-tree.h"
#include "parse-options.h"
+#include "repository.h"
static const char * const write_tree_usage[] = {
N_("git write-tree [--missing-ok] [--prefix=<prefix>/]"),
diff --git a/bundle-uri.c b/bundle-uri.c
index e2b267cc02..2a2db1a1d3 100644
--- a/bundle-uri.c
+++ b/bundle-uri.c
@@ -1,6 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "bundle-uri.h"
#include "bundle.h"
+#include "copy.h"
#include "environment.h"
#include "gettext.h"
#include "object-store.h"
@@ -795,10 +796,10 @@ int fetch_bundle_uri(struct repository *r, const char *uri,
init_bundle_list(&list);
/*
- * Do not fetch a NULL or empty bundle URI. An empty bundle URI
+ * Do not fetch an empty bundle URI. An empty bundle URI
* could signal that a configured bundle URI has been disabled.
*/
- if (!uri || !*uri) {
+ if (!*uri) {
result = 0;
goto cleanup;
}
diff --git a/cache.h b/cache.h
index 71e2fe74c4..bdedb87e83 100644
--- a/cache.h
+++ b/cache.h
@@ -4,41 +4,10 @@
#include "git-compat-util.h"
#include "strbuf.h"
#include "hashmap.h"
-#include "gettext.h"
-#include "string-list.h"
#include "pathspec.h"
#include "object.h"
#include "statinfo.h"
-#if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT)
-#define DTYPE(de) ((de)->d_type)
-#else
-#undef DT_UNKNOWN
-#undef DT_DIR
-#undef DT_REG
-#undef DT_LNK
-#define DT_UNKNOWN 0
-#define DT_DIR 1
-#define DT_REG 2
-#define DT_LNK 3
-#define DTYPE(de) DT_UNKNOWN
-#endif
-
-/*
- * Some mode bits are also used internally for computations.
- *
- * They *must* not overlap with any valid modes, and they *must* not be emitted
- * to outside world - i.e. appear on disk or network. In other words, it's just
- * temporary fields, which we internally use, but they have to stay in-house.
- *
- * ( such approach is valid, as standard S_IF* fits into 16 bits, and in Git
- * codebase mode is `unsigned int` which is assumed to be at least 32 bits )
- */
-
-/* used internally in tree-diff */
-#define S_DIFFTREE_IFXMIN_NEQ 0x80000000
-
-
/*
* Basic data structures for the directory cache
*/
@@ -586,64 +555,7 @@ extern int verify_ce_order;
#define DATA_CHANGED 0x0020
#define TYPE_CHANGED 0x0040
-int base_name_compare(const char *name1, size_t len1, int mode1,
- const char *name2, size_t len2, int mode2);
-int df_name_compare(const char *name1, size_t len1, int mode1,
- const char *name2, size_t len2, int mode2);
-int name_compare(const char *name1, size_t len1, const char *name2, size_t len2);
-int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2);
-
-struct cache_def {
- struct strbuf path;
- int flags;
- int track_flags;
- int prefix_len_stat_func;
-};
-#define CACHE_DEF_INIT { \
- .path = STRBUF_INIT, \
-}
-static inline void cache_def_clear(struct cache_def *cache)
-{
- strbuf_release(&cache->path);
-}
-
-int has_symlink_leading_path(const char *name, int len);
-int threaded_has_symlink_leading_path(struct cache_def *, const char *, int);
-int check_leading_path(const char *name, int len, int warn_on_lstat_err);
-int has_dirs_only_path(const char *name, int len, int prefix_len);
-void invalidate_lstat_cache(void);
-void schedule_dir_for_removal(const char *name, int len);
-void remove_scheduled_dirs(void);
-
-struct pack_window {
- struct pack_window *next;
- unsigned char *base;
- off_t offset;
- size_t len;
- unsigned int last_used;
- unsigned int inuse_cnt;
-};
-
-struct pack_entry {
- off_t offset;
- struct packed_git *p;
-};
-
-/* Dumb servers support */
-int update_server_info(int);
-
-#define COPY_READ_ERROR (-2)
-#define COPY_WRITE_ERROR (-3)
-int copy_fd(int ifd, int ofd);
-int copy_file(const char *dst, const char *src, int mode);
-int copy_file_with_time(const char *dst, const char *src, int mode);
-
-/* base85 */
-int decode_85(char *dst, const char *line, int linelen);
-void encode_85(char *buf, const unsigned char *data, int bytes);
-
-/* pkt-line.c */
-void packet_trace_identity(const char *prog);
+int cmp_cache_name_compare(const void *a_, const void *b_);
/* add */
/*
@@ -655,36 +567,6 @@ int add_files_to_cache(const char *prefix, const struct pathspec *pathspec, int
/* diff.c */
extern int diff_auto_refresh_index;
-/* match-trees.c */
-void shift_tree(struct repository *, const struct object_id *, const struct object_id *, struct object_id *, int);
-void shift_tree_by(struct repository *, const struct object_id *, const struct object_id *, struct object_id *, const char *);
-
-/*
- * whitespace rules.
- * used by both diff and apply
- * last two digits are tab width
- */
-#define WS_BLANK_AT_EOL 0100
-#define WS_SPACE_BEFORE_TAB 0200
-#define WS_INDENT_WITH_NON_TAB 0400
-#define WS_CR_AT_EOL 01000
-#define WS_BLANK_AT_EOF 02000
-#define WS_TAB_IN_INDENT 04000
-#define WS_TRAILING_SPACE (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF)
-#define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB|8)
-#define WS_TAB_WIDTH_MASK 077
-/* All WS_* -- when extended, adapt diff.c emit_symbol */
-#define WS_RULE_MASK 07777
-extern unsigned whitespace_rule_cfg;
-unsigned whitespace_rule(struct index_state *, const char *);
-unsigned parse_whitespace_rule(const char *);
-unsigned ws_check(const char *line, int len, unsigned ws_rule);
-void ws_check_emit(const char *line, int len, unsigned ws_rule, FILE *stream, const char *set, const char *reset, const char *ws);
-char *whitespace_error_string(unsigned ws);
-void ws_fix_copy(struct strbuf *, const char *, int, unsigned, int *);
-int ws_blank_line(const char *line, int len);
-#define ws_tab_width(rule) ((rule) & WS_TAB_WIDTH_MASK)
-
/* ls-files */
void overlay_tree_on_index(struct index_state *istate,
const char *tree_name, const char *prefix);
@@ -730,6 +612,4 @@ int stat_validity_check(struct stat_validity *sv, const char *path);
*/
void stat_validity_update(struct stat_validity *sv, int fd);
-int versioncmp(const char *s1, const char *s2);
-
#endif /* CACHE_H */
diff --git a/checkout.c b/checkout.c
index 04238b2713..4256e71a7c 100644
--- a/checkout.c
+++ b/checkout.c
@@ -2,6 +2,7 @@
#include "object-name.h"
#include "remote.h"
#include "refspec.h"
+#include "repository.h"
#include "checkout.h"
#include "config.h"
#include "strbuf.h"
diff --git a/checkout.h b/checkout.h
index 1917f3b323..3c514a5ab4 100644
--- a/checkout.h
+++ b/checkout.h
@@ -1,7 +1,7 @@
#ifndef CHECKOUT_H
#define CHECKOUT_H
-#include "hash.h"
+#include "hash-ll.h"
/*
* Check if the branch name uniquely matches a branch name on a remote
diff --git a/chunk-format.c b/chunk-format.c
index 60a73c1b14..e7d613c907 100644
--- a/chunk-format.c
+++ b/chunk-format.c
@@ -3,6 +3,7 @@
#include "chunk-format.h"
#include "csum-file.h"
#include "gettext.h"
+#include "hash.h"
#include "trace2.h"
/*
diff --git a/chunk-format.h b/chunk-format.h
index 025c38f938..c7794e84ad 100644
--- a/chunk-format.h
+++ b/chunk-format.h
@@ -1,7 +1,7 @@
#ifndef CHUNK_FORMAT_H
#define CHUNK_FORMAT_H
-#include "hash.h"
+#include "hash-ll.h"
struct hashfile;
struct chunkfile;
diff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh
index b098e10f52..a18b13a41d 100755
--- a/ci/run-build-and-tests.sh
+++ b/ci/run-build-and-tests.sh
@@ -27,7 +27,7 @@ linux-TEST-vars)
export GIT_TEST_MULTI_PACK_INDEX=1
export GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=1
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master
- export GIT_TEST_WRITE_REV_INDEX=1
+ export GIT_TEST_NO_WRITE_REV_INDEX=1
export GIT_TEST_CHECKOUT_WORKERS=2
;;
linux-clang)
diff --git a/color.c b/color.c
index 6031998d3e..83abb11eda 100644
--- a/color.c
+++ b/color.c
@@ -1,10 +1,11 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
#include "color.h"
#include "editor.h"
#include "gettext.h"
#include "hex.h"
#include "pager.h"
+#include "strbuf.h"
static int git_use_color_default = GIT_COLOR_AUTO;
int color_stdout_is_tty = -1;
diff --git a/combine-diff.c b/combine-diff.c
index f7e9fb5747..1e3cd7fb17 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "object-store.h"
#include "commit.h"
#include "convert.h"
@@ -13,6 +13,7 @@
#include "xdiff/xmacros.h"
#include "log-tree.h"
#include "refs.h"
+#include "tree.h"
#include "userdiff.h"
#include "oid-array.h"
#include "revision.h"
diff --git a/commit-graph.c b/commit-graph.c
index 43558b4d9b..843bdb458d 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -23,6 +23,7 @@
#include "shallow.h"
#include "json-writer.h"
#include "trace2.h"
+#include "tree.h"
#include "chunk-format.h"
#include "wrapper.h"
diff --git a/commit.c b/commit.c
index 878b4473e4..0fb9316931 100644
--- a/commit.c
+++ b/commit.c
@@ -26,6 +26,7 @@
#include "run-command.h"
#include "setup.h"
#include "shallow.h"
+#include "tree.h"
#include "hook.h"
static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
@@ -96,6 +97,7 @@ struct commit *lookup_commit_reference_by_name(const char *name)
static timestamp_t parse_commit_date(const char *buf, const char *tail)
{
const char *dateptr;
+ const char *eol;
if (buf + 6 >= tail)
return 0;
@@ -107,16 +109,56 @@ static timestamp_t parse_commit_date(const char *buf, const char *tail)
return 0;
if (memcmp(buf, "committer", 9))
return 0;
- while (buf < tail && *buf++ != '>')
- /* nada */;
- if (buf >= tail)
+
+ /*
+ * Jump to end-of-line so that we can walk backwards to find the
+ * end-of-email ">". This is more forgiving of malformed cases
+ * because unexpected characters tend to be in the name and email
+ * fields.
+ */
+ eol = memchr(buf, '\n', tail - buf);
+ if (!eol)
return 0;
- dateptr = buf;
- while (buf < tail && *buf++ != '\n')
- /* nada */;
- if (buf >= tail)
+ dateptr = eol;
+ while (dateptr > buf && dateptr[-1] != '>')
+ dateptr--;
+ if (dateptr == buf)
return 0;
- /* dateptr < buf && buf[-1] == '\n', so parsing will stop at buf-1 */
+
+ /*
+ * Trim leading whitespace, but make sure we have at least one
+ * non-whitespace character, as parse_timestamp() will otherwise walk
+ * right past the newline we found in "eol" when skipping whitespace
+ * itself.
+ *
+ * In theory it would be sufficient to allow any character not matched
+ * by isspace(), but there's a catch: our isspace() does not
+ * necessarily match the behavior of parse_timestamp(), as the latter
+ * is implemented by system routines which match more exotic control
+ * codes, or even locale-dependent sequences.
+ *
+ * Since we expect the timestamp to be a number, we can check for that.
+ * Anything else (e.g., a non-numeric token like "foo") would just
+ * cause parse_timestamp() to return 0 anyway.
+ */
+ while (dateptr < eol && isspace(*dateptr))
+ dateptr++;
+ if (!isdigit(*dateptr) && *dateptr != '-')
+ return 0;
+
+ /*
+ * We know there is at least one digit (or dash), so we'll begin
+ * parsing there and stop at worst case at eol.
+ *
+ * Note that we may feed parse_timestamp() extra characters here if the
+ * commit is malformed, and it will parse as far as it can. For
+ * example, "123foo456" would return "123". That might be questionable
+ * (versus returning "0"), but it would help in a hypothetical case
+ * like "123456+0100", where the whitespace from the timezone is
+ * missing. Since such syntactic errors may be baked into history and
+ * hard to correct now, let's err on trying to make our best guess
+ * here, rather than insist on perfect syntax.
+ */
return parse_timestamp(dateptr, NULL, 10);
}
diff --git a/commit.h b/commit.h
index 69b2f376e9..28928833c5 100644
--- a/commit.h
+++ b/commit.h
@@ -2,13 +2,10 @@
#define COMMIT_H
#include "object.h"
-#include "tree.h"
-#include "strbuf.h"
-#include "decorate.h"
-#include "gpg-interface.h"
-#include "string-list.h"
-#include "pretty.h"
-#include "commit-slab.h"
+
+struct signature_check;
+struct strbuf;
+struct tree;
#define COMMIT_NOT_FROM_GRAPH 0xFFFFFFFF
#define GENERATION_NUMBER_INFINITY ((1ULL << 63) - 1)
diff --git a/common-main.c b/common-main.c
index f319317353..033778b3c5 100644
--- a/common-main.c
+++ b/common-main.c
@@ -1,8 +1,10 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "exec-cmd.h"
#include "gettext.h"
#include "attr.h"
+#include "repository.h"
#include "setup.h"
+#include "strbuf.h"
#include "trace2.h"
/*
diff --git a/compat/fsmonitor/fsm-health-darwin.c b/compat/fsmonitor/fsm-health-darwin.c
index b9f709e854..4c291f8a06 100644
--- a/compat/fsmonitor/fsm-health-darwin.c
+++ b/compat/fsmonitor/fsm-health-darwin.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
#include "fsmonitor.h"
#include "fsm-health.h"
diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c
index eb25123fa1..793073aaa7 100644
--- a/compat/fsmonitor/fsm-ipc-darwin.c
+++ b/compat/fsmonitor/fsm-ipc-darwin.c
@@ -1,6 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
+#include "gettext.h"
#include "hex.h"
+#include "repository.h"
#include "strbuf.h"
#include "fsmonitor.h"
#include "fsmonitor-ipc.h"
diff --git a/compat/fsmonitor/fsm-ipc-win32.c b/compat/fsmonitor/fsm-ipc-win32.c
index c9536dfb66..8928fa93ce 100644
--- a/compat/fsmonitor/fsm-ipc-win32.c
+++ b/compat/fsmonitor/fsm-ipc-win32.c
@@ -1,6 +1,7 @@
#include "git-compat-util.h"
#include "config.h"
#include "fsmonitor-ipc.h"
+#include "path.h"
const char *fsmonitor_ipc__get_path(struct repository *r) {
static char *ret;
diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c
index 5eb6402ab8..23e24b4b37 100644
--- a/compat/fsmonitor/fsm-listen-darwin.c
+++ b/compat/fsmonitor/fsm-listen-darwin.c
@@ -23,12 +23,13 @@
#endif
#endif
-#include "cache.h"
+#include "git-compat-util.h"
#include "fsmonitor.h"
#include "fsm-listen.h"
#include "fsmonitor--daemon.h"
#include "fsmonitor-path-utils.h"
#include "gettext.h"
+#include "string-list.h"
struct fsm_listen_data
{
diff --git a/compat/mingw.c b/compat/mingw.c
index abbc3faf32..d06cdc6254 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -13,6 +13,7 @@
#include "../config.h"
#include "../environment.h"
#include "../trace2.h"
+#include "../symlinks.h"
#include "../wrapper.h"
#include "dir.h"
#include "gettext.h"
diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c
index 8a9881db07..a4d11376ba 100644
--- a/compat/precompose_utf8.c
+++ b/compat/precompose_utf8.c
@@ -9,6 +9,7 @@
#include "config.h"
#include "environment.h"
#include "gettext.h"
+#include "path.h"
#include "utf8.h"
#include "precompose_utf8.h"
diff --git a/compat/win32/trace2_win32_process_info.c b/compat/win32/trace2_win32_process_info.c
index e3e895c78a..a4e33768f4 100644
--- a/compat/win32/trace2_win32_process_info.c
+++ b/compat/win32/trace2_win32_process_info.c
@@ -1,5 +1,6 @@
#include "../../cache.h"
#include "../../json-writer.h"
+#include "../../repository.h"
#include "../../trace2.h"
#include "lazyload.h"
#include <Psapi.h>
diff --git a/config.c b/config.c
index 43b0d3fb57..b79baf83e3 100644
--- a/config.c
+++ b/config.c
@@ -5,7 +5,7 @@
* Copyright (C) Johannes Schindelin, 2005
*
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "abspath.h"
#include "advice.h"
#include "alloc.h"
@@ -35,6 +35,7 @@
#include "setup.h"
#include "trace2.h"
#include "worktree.h"
+#include "ws.h"
#include "wrapper.h"
#include "write-or-die.h"
diff --git a/contrib/coccinelle/tests/unused.c b/contrib/coccinelle/tests/unused.c
deleted file mode 100644
index 8294d734ba..0000000000
--- a/contrib/coccinelle/tests/unused.c
+++ /dev/null
@@ -1,82 +0,0 @@
-void test_strbuf(void)
-{
- struct strbuf sb1 = STRBUF_INIT;
- struct strbuf sb2 = STRBUF_INIT;
- struct strbuf sb3 = STRBUF_INIT;
- struct strbuf sb4 = STRBUF_INIT;
- struct strbuf sb5;
- struct strbuf sb6 = { 0 };
- struct strbuf sb7 = STRBUF_INIT;
- struct strbuf sb8 = STRBUF_INIT;
- struct strbuf *sp1;
- struct strbuf *sp2;
- struct strbuf *sp3;
- struct strbuf *sp4 = xmalloc(sizeof(struct strbuf));
- struct strbuf *sp5 = xmalloc(sizeof(struct strbuf));
- struct strbuf *sp6 = xmalloc(sizeof(struct strbuf));
- struct strbuf *sp7;
-
- strbuf_init(&sb5, 0);
- strbuf_init(sp1, 0);
- strbuf_init(sp2, 0);
- strbuf_init(sp3, 0);
- strbuf_init(sp4, 0);
- strbuf_init(sp5, 0);
- strbuf_init(sp6, 0);
- strbuf_init(sp7, 0);
- sp7 = xmalloc(sizeof(struct strbuf));
-
- use_before(&sb3);
- use_as_str("%s", sb7.buf);
- use_as_str("%s", sp1->buf);
- use_as_str("%s", sp6->buf);
- pass_pp(&sp3);
-
- strbuf_release(&sb1);
- strbuf_reset(&sb2);
- strbuf_release(&sb3);
- strbuf_release(&sb4);
- strbuf_release(&sb5);
- strbuf_release(&sb6);
- strbuf_release(&sb7);
- strbuf_release(sp1);
- strbuf_release(sp2);
- strbuf_release(sp3);
- strbuf_release(sp4);
- strbuf_release(sp5);
- strbuf_release(sp6);
- strbuf_release(sp7);
-
- use_after(&sb4);
-
- if (when_strict())
- return;
- strbuf_release(&sb8);
-}
-
-void test_other(void)
-{
- struct string_list l = STRING_LIST_INIT_DUP;
- struct strbuf sb = STRBUF_INIT;
-
- string_list_clear(&l, 0);
- string_list_clear(&sb, 0);
-}
-
-void test_worktrees(void)
-{
- struct worktree **w1 = get_worktrees();
- struct worktree **w2 = get_worktrees();
- struct worktree **w3;
- struct worktree **w4;
-
- w3 = get_worktrees();
- w4 = get_worktrees();
-
- use_it(w4);
-
- free_worktrees(w1);
- free_worktrees(w2);
- free_worktrees(w3);
- free_worktrees(w4);
-}
diff --git a/contrib/coccinelle/tests/unused.res b/contrib/coccinelle/tests/unused.res
deleted file mode 100644
index 6d3e745683..0000000000
--- a/contrib/coccinelle/tests/unused.res
+++ /dev/null
@@ -1,45 +0,0 @@
-void test_strbuf(void)
-{
- struct strbuf sb3 = STRBUF_INIT;
- struct strbuf sb4 = STRBUF_INIT;
- struct strbuf sb7 = STRBUF_INIT;
- struct strbuf *sp1;
- struct strbuf *sp3;
- struct strbuf *sp6 = xmalloc(sizeof(struct strbuf));
- strbuf_init(sp1, 0);
- strbuf_init(sp3, 0);
- strbuf_init(sp6, 0);
-
- use_before(&sb3);
- use_as_str("%s", sb7.buf);
- use_as_str("%s", sp1->buf);
- use_as_str("%s", sp6->buf);
- pass_pp(&sp3);
-
- strbuf_release(&sb3);
- strbuf_release(&sb4);
- strbuf_release(&sb7);
- strbuf_release(sp1);
- strbuf_release(sp3);
- strbuf_release(sp6);
-
- use_after(&sb4);
-
- if (when_strict())
- return;
-}
-
-void test_other(void)
-{
-}
-
-void test_worktrees(void)
-{
- struct worktree **w4;
-
- w4 = get_worktrees();
-
- use_it(w4);
-
- free_worktrees(w4);
-}
diff --git a/contrib/coccinelle/unused.cocci b/contrib/coccinelle/unused.cocci
deleted file mode 100644
index d84046f82e..0000000000
--- a/contrib/coccinelle/unused.cocci
+++ /dev/null
@@ -1,43 +0,0 @@
-// This rule finds sequences of "unused" declerations and uses of a
-// variable, where "unused" is defined to include only calling the
-// equivalent of alloc, init & free functions on the variable.
-@@
-type T;
-identifier I;
-// STRBUF_INIT, but also e.g. STRING_LIST_INIT_DUP (so no anchoring)
-constant INIT_MACRO =~ "_INIT";
-identifier MALLOC1 =~ "^x?[mc]alloc$";
-identifier INIT_ASSIGN1 =~ "^get_worktrees$";
-identifier INIT_CALL1 =~ "^[a-z_]*_init$";
-identifier REL1 =~ "^[a-z_]*_(release|reset|clear|free)$";
-identifier REL2 =~ "^(release|clear|free)_[a-z_]*$";
-@@
-
-(
-- T I;
-|
-- T I = { 0 };
-|
-- T I = INIT_MACRO;
-|
-- T I = MALLOC1(...);
-|
-- T I = INIT_ASSIGN1(...);
-)
-
-<... when != \( I \| &I \)
-(
-- \( INIT_CALL1 \)( \( I \| &I \), ...);
-|
-- I = \( INIT_ASSIGN1 \)(...);
-|
-- I = MALLOC1(...);
-)
-...>
-
-(
-- \( REL1 \| REL2 \)( \( I \| &I \), ...);
-|
-- \( REL1 \| REL2 \)( \( &I \| I \) );
-)
- ... when != \( I \| &I \)
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index dc95c34cc8..945d2543b0 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -767,7 +767,7 @@ __git_refs ()
track=""
;;
*)
- for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD CHERRY_PICK_HEAD; do
+ for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD CHERRY_PICK_HEAD REVERT_HEAD BISECT_HEAD AUTO_MERGE; do
case "$i" in
$match*|$umatch*)
if [ -e "$dir/$i" ]; then
diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh
index 76ee4ab1e5..2c030050ae 100644
--- a/contrib/completion/git-prompt.sh
+++ b/contrib/completion/git-prompt.sh
@@ -298,7 +298,7 @@ __git_ps1_colorize_gitstring ()
# variable, in that order.
__git_eread ()
{
- test -r "$1" && IFS=$'\r\n' read "$2" <"$1"
+ test -r "$1" && IFS=$'\r\n' read -r "$2" <"$1"
}
# see if a cherry-pick or revert is in progress, if the user has committed a
diff --git a/contrib/credential/gnome-keyring/.gitignore b/contrib/credential/gnome-keyring/.gitignore
deleted file mode 100644
index 88d8fcdbce..0000000000
--- a/contrib/credential/gnome-keyring/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-git-credential-gnome-keyring
diff --git a/contrib/credential/gnome-keyring/Makefile b/contrib/credential/gnome-keyring/Makefile
deleted file mode 100644
index 22c19df94b..0000000000
--- a/contrib/credential/gnome-keyring/Makefile
+++ /dev/null
@@ -1,25 +0,0 @@
-MAIN:=git-credential-gnome-keyring
-all:: $(MAIN)
-
-CC = gcc
-RM = rm -f
-CFLAGS = -g -O2 -Wall
-PKG_CONFIG = pkg-config
-
--include ../../../config.mak.autogen
--include ../../../config.mak
-
-INCS:=$(shell $(PKG_CONFIG) --cflags gnome-keyring-1 glib-2.0)
-LIBS:=$(shell $(PKG_CONFIG) --libs gnome-keyring-1 glib-2.0)
-
-SRCS:=$(MAIN).c
-OBJS:=$(SRCS:.c=.o)
-
-%.o: %.c
- $(CC) $(CFLAGS) $(CPPFLAGS) $(INCS) -o $@ -c $<
-
-$(MAIN): $(OBJS)
- $(CC) -o $@ $(LDFLAGS) $^ $(LIBS)
-
-clean:
- @$(RM) $(MAIN) $(OBJS)
diff --git a/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c b/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c
deleted file mode 100644
index 5927e27ae6..0000000000
--- a/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * Copyright (C) 2011 John Szakmeister <john@szakmeister.net>
- * 2012 Philipp A. Hartmann <pah@qo.cx>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Credits:
- * - GNOME Keyring API handling originally written by John Szakmeister
- * - ported to credential helper API by Philipp A. Hartmann
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <glib.h>
-#include <gnome-keyring.h>
-
-#ifdef GNOME_KEYRING_DEFAULT
-
- /* Modern gnome-keyring */
-
-#include <gnome-keyring-memory.h>
-
-#else
-
- /*
- * Support ancient gnome-keyring, circ. RHEL 5.X.
- * GNOME_KEYRING_DEFAULT seems to have been introduced with Gnome 2.22,
- * and the other features roughly around Gnome 2.20, 6 months before.
- * Ubuntu 8.04 used Gnome 2.22 (I think). Not sure any distro used 2.20.
- * So the existence/non-existence of GNOME_KEYRING_DEFAULT seems like
- * a decent thing to use as an indicator.
- */
-
-#define GNOME_KEYRING_DEFAULT NULL
-
-/*
- * ancient gnome-keyring returns DENIED when an entry is not found.
- * Setting NO_MATCH to DENIED will prevent us from reporting DENIED
- * errors during get and erase operations, but we will still report
- * DENIED errors during a store.
- */
-#define GNOME_KEYRING_RESULT_NO_MATCH GNOME_KEYRING_RESULT_DENIED
-
-#define gnome_keyring_memory_alloc g_malloc
-#define gnome_keyring_memory_free gnome_keyring_free_password
-#define gnome_keyring_memory_strdup g_strdup
-
-static const char *gnome_keyring_result_to_message(GnomeKeyringResult result)
-{
- switch (result) {
- case GNOME_KEYRING_RESULT_OK:
- return "OK";
- case GNOME_KEYRING_RESULT_DENIED:
- return "Denied";
- case GNOME_KEYRING_RESULT_NO_KEYRING_DAEMON:
- return "No Keyring Daemon";
- case GNOME_KEYRING_RESULT_ALREADY_UNLOCKED:
- return "Already UnLocked";
- case GNOME_KEYRING_RESULT_NO_SUCH_KEYRING:
- return "No Such Keyring";
- case GNOME_KEYRING_RESULT_BAD_ARGUMENTS:
- return "Bad Arguments";
- case GNOME_KEYRING_RESULT_IO_ERROR:
- return "IO Error";
- case GNOME_KEYRING_RESULT_CANCELLED:
- return "Cancelled";
- case GNOME_KEYRING_RESULT_ALREADY_EXISTS:
- return "Already Exists";
- default:
- return "Unknown Error";
- }
-}
-
-/*
- * Support really ancient gnome-keyring, circ. RHEL 4.X.
- * Just a guess for the Glib version. Glib 2.8 was roughly Gnome 2.12 ?
- * Which was released with gnome-keyring 0.4.3 ??
- */
-#if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 8
-
-static void gnome_keyring_done_cb(GnomeKeyringResult result, gpointer user_data)
-{
- gpointer *data = (gpointer *)user_data;
- int *done = (int *)data[0];
- GnomeKeyringResult *r = (GnomeKeyringResult *)data[1];
-
- *r = result;
- *done = 1;
-}
-
-static void wait_for_request_completion(int *done)
-{
- GMainContext *mc = g_main_context_default();
- while (!*done)
- g_main_context_iteration(mc, TRUE);
-}
-
-static GnomeKeyringResult gnome_keyring_item_delete_sync(const char *keyring, guint32 id)
-{
- int done = 0;
- GnomeKeyringResult result;
- gpointer data[] = { &done, &result };
-
- gnome_keyring_item_delete(keyring, id, gnome_keyring_done_cb, data,
- NULL);
-
- wait_for_request_completion(&done);
-
- return result;
-}
-
-#endif
-#endif
-
-/*
- * This credential struct and API is simplified from git's credential.{h,c}
- */
-struct credential {
- char *protocol;
- char *host;
- unsigned short port;
- char *path;
- char *username;
- char *password;
-};
-
-#define CREDENTIAL_INIT { 0 }
-
-typedef int (*credential_op_cb)(struct credential *);
-
-struct credential_operation {
- char *name;
- credential_op_cb op;
-};
-
-#define CREDENTIAL_OP_END { NULL, NULL }
-
-/* ----------------- GNOME Keyring functions ----------------- */
-
-/* create a special keyring option string, if path is given */
-static char *keyring_object(struct credential *c)
-{
- if (!c->path)
- return NULL;
-
- if (c->port)
- return g_strdup_printf("%s:%hd/%s", c->host, c->port, c->path);
-
- return g_strdup_printf("%s/%s", c->host, c->path);
-}
-
-static int keyring_get(struct credential *c)
-{
- char *object = NULL;
- GList *entries;
- GnomeKeyringNetworkPasswordData *password_data;
- GnomeKeyringResult result;
-
- if (!c->protocol || !(c->host || c->path))
- return EXIT_FAILURE;
-
- object = keyring_object(c);
-
- result = gnome_keyring_find_network_password_sync(
- c->username,
- NULL /* domain */,
- c->host,
- object,
- c->protocol,
- NULL /* authtype */,
- c->port,
- &entries);
-
- g_free(object);
-
- if (result == GNOME_KEYRING_RESULT_NO_MATCH)
- return EXIT_SUCCESS;
-
- if (result == GNOME_KEYRING_RESULT_CANCELLED)
- return EXIT_SUCCESS;
-
- if (result != GNOME_KEYRING_RESULT_OK) {
- g_critical("%s", gnome_keyring_result_to_message(result));
- return EXIT_FAILURE;
- }
-
- /* pick the first one from the list */
- password_data = (GnomeKeyringNetworkPasswordData *)entries->data;
-
- gnome_keyring_memory_free(c->password);
- c->password = gnome_keyring_memory_strdup(password_data->password);
-
- if (!c->username)
- c->username = g_strdup(password_data->user);
-
- gnome_keyring_network_password_list_free(entries);
-
- return EXIT_SUCCESS;
-}
-
-
-static int keyring_store(struct credential *c)
-{
- guint32 item_id;
- char *object = NULL;
- GnomeKeyringResult result;
-
- /*
- * Sanity check that what we are storing is actually sensible.
- * In particular, we can't make a URL without a protocol field.
- * Without either a host or pathname (depending on the scheme),
- * we have no primary key. And without a username and password,
- * we are not actually storing a credential.
- */
- if (!c->protocol || !(c->host || c->path) ||
- !c->username || !c->password)
- return EXIT_FAILURE;
-
- object = keyring_object(c);
-
- result = gnome_keyring_set_network_password_sync(
- GNOME_KEYRING_DEFAULT,
- c->username,
- NULL /* domain */,
- c->host,
- object,
- c->protocol,
- NULL /* authtype */,
- c->port,
- c->password,
- &item_id);
-
- g_free(object);
-
- if (result != GNOME_KEYRING_RESULT_OK &&
- result != GNOME_KEYRING_RESULT_CANCELLED) {
- g_critical("%s", gnome_keyring_result_to_message(result));
- return EXIT_FAILURE;
- }
-
- return EXIT_SUCCESS;
-}
-
-static int keyring_erase(struct credential *c)
-{
- char *object = NULL;
- GList *entries;
- GnomeKeyringNetworkPasswordData *password_data;
- GnomeKeyringResult result;
-
- /*
- * Sanity check that we actually have something to match
- * against. The input we get is a restrictive pattern,
- * so technically a blank credential means "erase everything".
- * But it is too easy to accidentally send this, since it is equivalent
- * to empty input. So explicitly disallow it, and require that the
- * pattern have some actual content to match.
- */
- if (!c->protocol && !c->host && !c->path && !c->username)
- return EXIT_FAILURE;
-
- object = keyring_object(c);
-
- result = gnome_keyring_find_network_password_sync(
- c->username,
- NULL /* domain */,
- c->host,
- object,
- c->protocol,
- NULL /* authtype */,
- c->port,
- &entries);
-
- g_free(object);
-
- if (result == GNOME_KEYRING_RESULT_NO_MATCH)
- return EXIT_SUCCESS;
-
- if (result == GNOME_KEYRING_RESULT_CANCELLED)
- return EXIT_SUCCESS;
-
- if (result != GNOME_KEYRING_RESULT_OK) {
- g_critical("%s", gnome_keyring_result_to_message(result));
- return EXIT_FAILURE;
- }
-
- /* pick the first one from the list (delete all matches?) */
- password_data = (GnomeKeyringNetworkPasswordData *)entries->data;
-
- result = gnome_keyring_item_delete_sync(
- password_data->keyring, password_data->item_id);
-
- gnome_keyring_network_password_list_free(entries);
-
- if (result != GNOME_KEYRING_RESULT_OK) {
- g_critical("%s", gnome_keyring_result_to_message(result));
- return EXIT_FAILURE;
- }
-
- return EXIT_SUCCESS;
-}
-
-/*
- * Table with helper operation callbacks, used by generic
- * credential helper main function.
- */
-static struct credential_operation const credential_helper_ops[] = {
- { "get", keyring_get },
- { "store", keyring_store },
- { "erase", keyring_erase },
- CREDENTIAL_OP_END
-};
-
-/* ------------------ credential functions ------------------ */
-
-static void credential_init(struct credential *c)
-{
- memset(c, 0, sizeof(*c));
-}
-
-static void credential_clear(struct credential *c)
-{
- g_free(c->protocol);
- g_free(c->host);
- g_free(c->path);
- g_free(c->username);
- gnome_keyring_memory_free(c->password);
-
- credential_init(c);
-}
-
-static int credential_read(struct credential *c)
-{
- char *buf;
- size_t line_len;
- char *key;
- char *value;
-
- key = buf = gnome_keyring_memory_alloc(1024);
-
- while (fgets(buf, 1024, stdin)) {
- line_len = strlen(buf);
-
- if (line_len && buf[line_len-1] == '\n')
- buf[--line_len] = '\0';
-
- if (!line_len)
- break;
-
- value = strchr(buf, '=');
- if (!value) {
- g_warning("invalid credential line: %s", key);
- gnome_keyring_memory_free(buf);
- return -1;
- }
- *value++ = '\0';
-
- if (!strcmp(key, "protocol")) {
- g_free(c->protocol);
- c->protocol = g_strdup(value);
- } else if (!strcmp(key, "host")) {
- g_free(c->host);
- c->host = g_strdup(value);
- value = strrchr(c->host, ':');
- if (value) {
- *value++ = '\0';
- c->port = atoi(value);
- }
- } else if (!strcmp(key, "path")) {
- g_free(c->path);
- c->path = g_strdup(value);
- } else if (!strcmp(key, "username")) {
- g_free(c->username);
- c->username = g_strdup(value);
- } else if (!strcmp(key, "password")) {
- gnome_keyring_memory_free(c->password);
- c->password = gnome_keyring_memory_strdup(value);
- while (*value)
- *value++ = '\0';
- }
- /*
- * Ignore other lines; we don't know what they mean, but
- * this future-proofs us when later versions of git do
- * learn new lines, and the helpers are updated to match.
- */
- }
-
- gnome_keyring_memory_free(buf);
-
- return 0;
-}
-
-static void credential_write_item(FILE *fp, const char *key, const char *value)
-{
- if (!value)
- return;
- fprintf(fp, "%s=%s\n", key, value);
-}
-
-static void credential_write(const struct credential *c)
-{
- /* only write username/password, if set */
- credential_write_item(stdout, "username", c->username);
- credential_write_item(stdout, "password", c->password);
-}
-
-static void usage(const char *name)
-{
- struct credential_operation const *try_op = credential_helper_ops;
- const char *basename = strrchr(name, '/');
-
- basename = (basename) ? basename + 1 : name;
- fprintf(stderr, "usage: %s <", basename);
- while (try_op->name) {
- fprintf(stderr, "%s", (try_op++)->name);
- if (try_op->name)
- fprintf(stderr, "%s", "|");
- }
- fprintf(stderr, "%s", ">\n");
-}
-
-int main(int argc, char *argv[])
-{
- int ret = EXIT_SUCCESS;
-
- struct credential_operation const *try_op = credential_helper_ops;
- struct credential cred = CREDENTIAL_INIT;
-
- if (!argv[1]) {
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
-
- g_set_application_name("Git Credential Helper");
-
- /* lookup operation callback */
- while (try_op->name && strcmp(argv[1], try_op->name))
- try_op++;
-
- /* unsupported operation given -- ignore silently */
- if (!try_op->name || !try_op->op)
- goto out;
-
- ret = credential_read(&cred);
- if (ret)
- goto out;
-
- /* perform credential operation */
- ret = (*try_op->op)(&cred);
-
- credential_write(&cred);
-
-out:
- credential_clear(&cred);
- return ret;
-}
diff --git a/contrib/credential/libsecret/.gitignore b/contrib/credential/libsecret/.gitignore
new file mode 100644
index 0000000000..4fa22359e2
--- /dev/null
+++ b/contrib/credential/libsecret/.gitignore
@@ -0,0 +1 @@
+git-credential-libsecret
diff --git a/contrib/credential/libsecret/git-credential-libsecret.c b/contrib/credential/libsecret/git-credential-libsecret.c
index 2c5d76d789..ef681f29d5 100644
--- a/contrib/credential/libsecret/git-credential-libsecret.c
+++ b/contrib/credential/libsecret/git-credential-libsecret.c
@@ -244,17 +244,16 @@ static void credential_clear(struct credential *c)
static int credential_read(struct credential *c)
{
- char *buf;
- size_t line_len;
+ char *buf = NULL;
+ size_t alloc;
+ ssize_t line_len;
char *key;
char *value;
- key = buf = g_malloc(1024);
+ while ((line_len = getline(&buf, &alloc, stdin)) > 0) {
+ key = buf;
- while (fgets(buf, 1024, stdin)) {
- line_len = strlen(buf);
-
- if (line_len && buf[line_len-1] == '\n')
+ if (buf[line_len-1] == '\n')
buf[--line_len] = '\0';
if (!line_len)
@@ -298,7 +297,7 @@ static int credential_read(struct credential *c)
*/
}
- g_free(buf);
+ free(buf);
return 0;
}
diff --git a/contrib/credential/osxkeychain/git-credential-osxkeychain.c b/contrib/credential/osxkeychain/git-credential-osxkeychain.c
index e29cc28779..5f2e5f16c8 100644
--- a/contrib/credential/osxkeychain/git-credential-osxkeychain.c
+++ b/contrib/credential/osxkeychain/git-credential-osxkeychain.c
@@ -113,14 +113,16 @@ static void add_internet_password(void)
static void read_credential(void)
{
- char buf[1024];
+ char *buf = NULL;
+ size_t alloc;
+ ssize_t line_len;
- while (fgets(buf, sizeof(buf), stdin)) {
+ while ((line_len = getline(&buf, &alloc, stdin)) > 0) {
char *v;
if (!strcmp(buf, "\n"))
break;
- buf[strlen(buf)-1] = '\0';
+ buf[line_len-1] = '\0';
v = strchr(buf, '=');
if (!v)
@@ -165,6 +167,8 @@ static void read_credential(void)
* learn new lines, and the helpers are updated to match.
*/
}
+
+ free(buf);
}
int main(int argc, const char **argv)
diff --git a/contrib/credential/wincred/git-credential-wincred.c b/contrib/credential/wincred/git-credential-wincred.c
index ead6e267c7..96f10613ae 100644
--- a/contrib/credential/wincred/git-credential-wincred.c
+++ b/contrib/credential/wincred/git-credential-wincred.c
@@ -6,6 +6,7 @@
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
+#include <wincred.h>
/* common helpers */
@@ -33,65 +34,8 @@ static void *xmalloc(size_t size)
return ret;
}
-/* MinGW doesn't have wincred.h, so we need to define stuff */
-
-typedef struct _CREDENTIAL_ATTRIBUTEW {
- LPWSTR Keyword;
- DWORD Flags;
- DWORD ValueSize;
- LPBYTE Value;
-} CREDENTIAL_ATTRIBUTEW, *PCREDENTIAL_ATTRIBUTEW;
-
-typedef struct _CREDENTIALW {
- DWORD Flags;
- DWORD Type;
- LPWSTR TargetName;
- LPWSTR Comment;
- FILETIME LastWritten;
- DWORD CredentialBlobSize;
- LPBYTE CredentialBlob;
- DWORD Persist;
- DWORD AttributeCount;
- PCREDENTIAL_ATTRIBUTEW Attributes;
- LPWSTR TargetAlias;
- LPWSTR UserName;
-} CREDENTIALW, *PCREDENTIALW;
-
-#define CRED_TYPE_GENERIC 1
-#define CRED_PERSIST_LOCAL_MACHINE 2
-#define CRED_MAX_ATTRIBUTES 64
-
-typedef BOOL (WINAPI *CredWriteWT)(PCREDENTIALW, DWORD);
-typedef BOOL (WINAPI *CredEnumerateWT)(LPCWSTR, DWORD, DWORD *,
- PCREDENTIALW **);
-typedef VOID (WINAPI *CredFreeT)(PVOID);
-typedef BOOL (WINAPI *CredDeleteWT)(LPCWSTR, DWORD, DWORD);
-
-static HMODULE advapi;
-static CredWriteWT CredWriteW;
-static CredEnumerateWT CredEnumerateW;
-static CredFreeT CredFree;
-static CredDeleteWT CredDeleteW;
-
-static void load_cred_funcs(void)
-{
- /* load DLLs */
- advapi = LoadLibraryExA("advapi32.dll", NULL,
- LOAD_LIBRARY_SEARCH_SYSTEM32);
- if (!advapi)
- die("failed to load advapi32.dll");
-
- /* get function pointers */
- CredWriteW = (CredWriteWT)GetProcAddress(advapi, "CredWriteW");
- CredEnumerateW = (CredEnumerateWT)GetProcAddress(advapi,
- "CredEnumerateW");
- CredFree = (CredFreeT)GetProcAddress(advapi, "CredFree");
- CredDeleteW = (CredDeleteWT)GetProcAddress(advapi, "CredDeleteW");
- if (!CredWriteW || !CredEnumerateW || !CredFree || !CredDeleteW)
- die("failed to load functions");
-}
-
-static WCHAR *wusername, *password, *protocol, *host, *path, target[1024];
+static WCHAR *wusername, *password, *protocol, *host, *path, target[1024],
+ *password_expiry_utc;
static void write_item(const char *what, LPCWSTR wbuf, int wlen)
{
@@ -183,6 +127,7 @@ static void get_credential(void)
CREDENTIALW **creds;
DWORD num_creds;
int i;
+ CREDENTIAL_ATTRIBUTEW *attr;
if (!CredEnumerateW(L"git:*", 0, &num_creds, &creds))
return;
@@ -195,6 +140,14 @@ static void get_credential(void)
write_item("password",
(LPCWSTR)creds[i]->CredentialBlob,
creds[i]->CredentialBlobSize / sizeof(WCHAR));
+ for (int j = 0; j < creds[i]->AttributeCount; j++) {
+ attr = creds[i]->Attributes + j;
+ if (!wcscmp(attr->Keyword, L"git_password_expiry_utc")) {
+ write_item("password_expiry_utc", (LPCWSTR)attr->Value,
+ attr->ValueSize / sizeof(WCHAR));
+ break;
+ }
+ }
break;
}
@@ -204,6 +157,7 @@ static void get_credential(void)
static void store_credential(void)
{
CREDENTIALW cred;
+ CREDENTIAL_ATTRIBUTEW expiry_attr;
if (!wusername || !password)
return;
@@ -217,6 +171,14 @@ static void store_credential(void)
cred.Persist = CRED_PERSIST_LOCAL_MACHINE;
cred.AttributeCount = 0;
cred.Attributes = NULL;
+ if (password_expiry_utc != NULL) {
+ expiry_attr.Keyword = L"git_password_expiry_utc";
+ expiry_attr.Value = (LPVOID)password_expiry_utc;
+ expiry_attr.ValueSize = (wcslen(password_expiry_utc)) * sizeof(WCHAR);
+ expiry_attr.Flags = 0;
+ cred.Attributes = &expiry_attr;
+ cred.AttributeCount = 1;
+ }
cred.TargetAlias = NULL;
cred.UserName = wusername;
@@ -249,17 +211,28 @@ static WCHAR *utf8_to_utf16_dup(const char *str)
return wstr;
}
+#define KB (1024)
+
static void read_credential(void)
{
- char buf[1024];
+ size_t alloc = 100 * KB;
+ char *buf = calloc(alloc, sizeof(*buf));
- while (fgets(buf, sizeof(buf), stdin)) {
+ while (fgets(buf, alloc, stdin)) {
char *v;
- int len = strlen(buf);
+ size_t len = strlen(buf);
+ int ends_in_newline = 0;
/* strip trailing CR / LF */
- while (len && strchr("\r\n", buf[len - 1]))
+ if (len && buf[len - 1] == '\n') {
+ buf[--len] = 0;
+ ends_in_newline = 1;
+ }
+ if (len && buf[len - 1] == '\r')
buf[--len] = 0;
+ if (!ends_in_newline)
+ die("bad input: %s", buf);
+
if (!*buf)
break;
@@ -278,12 +251,16 @@ static void read_credential(void)
wusername = utf8_to_utf16_dup(v);
} else if (!strcmp(buf, "password"))
password = utf8_to_utf16_dup(v);
+ else if (!strcmp(buf, "password_expiry_utc"))
+ password_expiry_utc = utf8_to_utf16_dup(v);
/*
* Ignore other lines; we don't know what they mean, but
* this future-proofs us when later versions of git do
* learn new lines, and the helpers are updated to match.
*/
}
+
+ free(buf);
}
int main(int argc, char *argv[])
@@ -292,7 +269,7 @@ int main(int argc, char *argv[])
"usage: git credential-wincred <get|store|erase>\n";
if (!argv[1])
- die(usage);
+ die("%s", usage);
/* git use binary pipes to avoid CRLF-issues */
_setmode(_fileno(stdin), _O_BINARY);
@@ -300,8 +277,6 @@ int main(int argc, char *argv[])
read_credential();
- load_cred_funcs();
-
if (!protocol || !(host || path))
return 0;
diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 10c9c87839..7db4c45676 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -34,8 +34,8 @@ git subtree pull --prefix=<prefix> <repository> <ref>
git subtree push --prefix=<prefix> <repository> <refspec>
--
h,help show the help
-q quiet
-d show debug messages
+q,quiet quiet
+d,debug show debug messages
P,prefix= the name of the subdir to split out
options for 'split' (also: 'push')
annotate= add a prefix to commit message of new commits
diff --git a/convert.c b/convert.c
index 5a2ea5308d..9ee79fe469 100644
--- a/convert.c
+++ b/convert.c
@@ -2,6 +2,7 @@
#include "advice.h"
#include "config.h"
#include "convert.h"
+#include "copy.h"
#include "gettext.h"
#include "hex.h"
#include "object-store.h"
@@ -1314,7 +1315,7 @@ void convert_attrs(struct index_state *istate,
git_config(read_convert_config, NULL);
}
- git_check_attr(istate, NULL, path, check);
+ git_check_attr(istate, path, check);
ccheck = check->items;
ca->crlf_action = git_path_check_crlf(ccheck + 4);
if (ca->crlf_action == CRLF_UNDEFINED)
diff --git a/convert.h b/convert.h
index 0a6e4086b8..d925589444 100644
--- a/convert.h
+++ b/convert.h
@@ -4,7 +4,7 @@
#ifndef CONVERT_H
#define CONVERT_H
-#include "hash.h"
+#include "hash-ll.h"
#include "string-list.h"
struct index_state;
diff --git a/copy.c b/copy.c
index c3250f0822..882c79cffb 100644
--- a/copy.c
+++ b/copy.c
@@ -1,4 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "copy.h"
+#include "path.h"
#include "wrapper.h"
int copy_fd(int ifd, int ofd)
diff --git a/copy.h b/copy.h
new file mode 100644
index 0000000000..2af77cba86
--- /dev/null
+++ b/copy.h
@@ -0,0 +1,10 @@
+#ifndef COPY_H
+#define COPY_H
+
+#define COPY_READ_ERROR (-2)
+#define COPY_WRITE_ERROR (-3)
+int copy_fd(int ifd, int ofd);
+int copy_file(const char *dst, const char *src, int mode);
+int copy_file_with_time(const char *dst, const char *src, int mode);
+
+#endif /* COPY_H */
diff --git a/credential.c b/credential.c
index e6417bf880..023b59d571 100644
--- a/credential.c
+++ b/credential.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "abspath.h"
#include "config.h"
#include "credential.h"
@@ -8,6 +8,7 @@
#include "url.h"
#include "prompt.h"
#include "sigchain.h"
+#include "strbuf.h"
#include "urlmatch.h"
#include "git-compat-util.h"
@@ -24,6 +25,7 @@ void credential_clear(struct credential *c)
free(c->path);
free(c->username);
free(c->password);
+ free(c->oauth_refresh_token);
string_list_clear(&c->helpers, 0);
strvec_clear(&c->wwwauth_headers);
@@ -238,11 +240,16 @@ int credential_read(struct credential *c, FILE *fp)
} else if (!strcmp(key, "path")) {
free(c->path);
c->path = xstrdup(value);
+ } else if (!strcmp(key, "wwwauth[]")) {
+ strvec_push(&c->wwwauth_headers, value);
} else if (!strcmp(key, "password_expiry_utc")) {
errno = 0;
c->password_expiry_utc = parse_timestamp(value, NULL, 10);
if (c->password_expiry_utc == 0 || errno == ERANGE)
c->password_expiry_utc = TIME_MAX;
+ } else if (!strcmp(key, "oauth_refresh_token")) {
+ free(c->oauth_refresh_token);
+ c->oauth_refresh_token = xstrdup(value);
} else if (!strcmp(key, "url")) {
credential_from_url(c, value);
} else if (!strcmp(key, "quit")) {
@@ -278,6 +285,7 @@ void credential_write(const struct credential *c, FILE *fp)
credential_write_item(fp, "path", c->path, 0);
credential_write_item(fp, "username", c->username, 0);
credential_write_item(fp, "password", c->password, 0);
+ credential_write_item(fp, "oauth_refresh_token", c->oauth_refresh_token, 0);
if (c->password_expiry_utc != TIME_MAX) {
char *s = xstrfmt("%"PRItime, c->password_expiry_utc);
credential_write_item(fp, "password_expiry_utc", s, 0);
@@ -403,6 +411,7 @@ void credential_reject(struct credential *c)
FREE_AND_NULL(c->username);
FREE_AND_NULL(c->password);
+ FREE_AND_NULL(c->oauth_refresh_token);
c->password_expiry_utc = TIME_MAX;
c->approved = 0;
}
diff --git a/credential.h b/credential.h
index 2b5958cd43..b8e2936d1d 100644
--- a/credential.h
+++ b/credential.h
@@ -141,6 +141,7 @@ struct credential {
char *protocol;
char *host;
char *path;
+ char *oauth_refresh_token;
timestamp_t password_expiry_utc;
};
diff --git a/csum-file.c b/csum-file.c
index 82ae2973d3..daf9b06dff 100644
--- a/csum-file.c
+++ b/csum-file.c
@@ -10,6 +10,7 @@
#include "git-compat-util.h"
#include "progress.h"
#include "csum-file.h"
+#include "hash.h"
#include "wrapper.h"
static void verify_buffer_or_die(struct hashfile *f,
diff --git a/csum-file.h b/csum-file.h
index 566e05cbd2..bc5bec27ac 100644
--- a/csum-file.h
+++ b/csum-file.h
@@ -1,7 +1,7 @@
#ifndef CSUM_FILE_H
#define CSUM_FILE_H
-#include "hash.h"
+#include "hash-ll.h"
#include "write-or-die.h"
struct progress;
diff --git a/daemon.c b/daemon.c
index 75c3c06457..7139cc201d 100644
--- a/daemon.c
+++ b/daemon.c
@@ -1,8 +1,9 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "abspath.h"
#include "alloc.h"
#include "config.h"
#include "environment.h"
+#include "path.h"
#include "pkt-line.h"
#include "protocol.h"
#include "run-command.h"
diff --git a/date.c b/date.c
index e867ebf6b7..619ada5b20 100644
--- a/date.c
+++ b/date.c
@@ -4,10 +4,11 @@
* Copyright (C) Linus Torvalds, 2005
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "date.h"
#include "gettext.h"
#include "pager.h"
+#include "strbuf.h"
/*
* This is like mktime, but without normalization of tm_wday and tm_yday.
diff --git a/detect-compiler b/detect-compiler
index 50087f5670..a87650b71b 100755
--- a/detect-compiler
+++ b/detect-compiler
@@ -17,7 +17,15 @@ get_family() {
}
get_version() {
- get_version_line | sed 's/^.* version \([0-9][^ ]*\).*/\1/'
+ # A string that begins with a digit up to the next SP
+ ver=$(get_version_line | sed 's/^.* version \([0-9][^ ]*\).*/\1/')
+
+ # There are known -variant suffixes that do not affect the
+ # meaning of the main version number. Strip them.
+ ver=${ver%-win32}
+ ver=${ver%-posix}
+
+ echo "$ver"
}
print_flags() {
diff --git a/diagnose.c b/diagnose.c
index f1aebf0b50..c8c7ebcfa3 100644
--- a/diagnose.c
+++ b/diagnose.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "diagnose.h"
#include "compat/disk.h"
#include "archive.h"
diff --git a/diff-lib.c b/diff-lib.c
index d292405a26..60e979dc1b 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -14,6 +14,7 @@
#include "unpack-trees.h"
#include "refs.h"
#include "submodule.h"
+#include "symlinks.h"
#include "trace.h"
#include "dir.h"
#include "fsmonitor.h"
diff --git a/diff.c b/diff.c
index 067846b13c..3c88c37908 100644
--- a/diff.c
+++ b/diff.c
@@ -4,6 +4,7 @@
#include "cache.h"
#include "abspath.h"
#include "alloc.h"
+#include "base85.h"
#include "config.h"
#include "convert.h"
#include "environment.h"
@@ -40,6 +41,7 @@
#include "object-name.h"
#include "setup.h"
#include "strmap.h"
+#include "ws.h"
#include "wrapper.h"
#ifdef NO_FAST_WORKING_DIRECTORY
@@ -139,7 +141,7 @@ static int parse_dirstat_params(struct diff_options *options, const char *params
int i;
if (*params_copy)
- string_list_split_in_place(&params, params_copy, ',', -1);
+ string_list_split_in_place(&params, params_copy, ",", -1);
for (i = 0; i < params.nr; i++) {
const char *p = params.items[i].string;
if (!strcmp(p, "changes")) {
@@ -3005,6 +3007,24 @@ static int dirstat_compare(const void *_a, const void *_b)
return strcmp(a->name, b->name);
}
+static void conclude_dirstat(struct diff_options *options,
+ struct dirstat_dir *dir,
+ unsigned long changed)
+{
+ struct dirstat_file *to_free = dir->files;
+
+ if (!changed) {
+ /* This can happen even with many files, if everything was renames */
+ ;
+ } else {
+ /* Show all directories with more than x% of the changes */
+ QSORT(dir->files, dir->nr, dirstat_compare);
+ gather_dirstat(options, dir, changed, "", 0);
+ }
+
+ free(to_free);
+}
+
static void show_dirstat(struct diff_options *options)
{
int i;
@@ -3094,13 +3114,7 @@ found_damage:
dir.nr++;
}
- /* This can happen even with many files, if everything was renames */
- if (!changed)
- return;
-
- /* Show all directories with more than x% of the changes */
- QSORT(dir.files, dir.nr, dirstat_compare);
- gather_dirstat(options, &dir, changed, "", 0);
+ conclude_dirstat(options, &dir, changed);
}
static void show_dirstat_by_line(struct diffstat_t *data, struct diff_options *options)
@@ -3138,13 +3152,7 @@ static void show_dirstat_by_line(struct diffstat_t *data, struct diff_options *o
dir.nr++;
}
- /* This can happen even with many files, if everything was renames */
- if (!changed)
- return;
-
- /* Show all directories with more than x% of the changes */
- QSORT(dir.files, dir.nr, dirstat_compare);
- gather_dirstat(options, &dir, changed, "", 0);
+ conclude_dirstat(options, &dir, changed);
}
static void free_diffstat_file(struct diffstat_file *f)
diff --git a/diff.h b/diff.h
index 6a0737b9c3..3a7a9e8b88 100644
--- a/diff.h
+++ b/diff.h
@@ -4,7 +4,6 @@
#ifndef DIFF_H
#define DIFF_H
-#include "tree-walk.h"
#include "pathspec.h"
#include "oidset.h"
#include "strbuf.h"
diff --git a/diffcore.h b/diffcore.h
index 1701ed50b9..5ffe4ec788 100644
--- a/diffcore.h
+++ b/diffcore.h
@@ -4,7 +4,7 @@
#ifndef DIFFCORE_H
#define DIFFCORE_H
-#include "hash.h"
+#include "hash-ll.h"
struct diff_options;
struct mem_pool;
diff --git a/dir.c b/dir.c
index aa840995c4..a7469df3ac 100644
--- a/dir.c
+++ b/dir.c
@@ -25,7 +25,9 @@
#include "fsmonitor.h"
#include "setup.h"
#include "submodule-config.h"
+#include "symlinks.h"
#include "trace2.h"
+#include "tree.h"
#include "wrapper.h"
/*
diff --git a/dir.h b/dir.h
index 3d6c87387e..bb0b4fb9b6 100644
--- a/dir.h
+++ b/dir.h
@@ -6,6 +6,8 @@
#include "statinfo.h"
#include "strbuf.h"
+struct repository;
+
/**
* The directory listing API is used to enumerate paths in the work tree,
* optionally taking `.git/info/exclude` and `.gitignore` files per directory
@@ -640,4 +642,19 @@ static inline int starts_with_dot_dot_slash_native(const char *const path)
return path_match_flags(path, what | PATH_MATCH_NATIVE);
}
+
+#if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT)
+#define DTYPE(de) ((de)->d_type)
+#else
+#undef DT_UNKNOWN
+#undef DT_DIR
+#undef DT_REG
+#undef DT_LNK
+#define DT_UNKNOWN 0
+#define DT_DIR 1
+#define DT_REG 2
+#define DT_LNK 3
+#define DTYPE(de) DT_UNKNOWN
+#endif
+
#endif
diff --git a/editor.c b/editor.c
index b34e10606d..38c5dbbb79 100644
--- a/editor.c
+++ b/editor.c
@@ -6,6 +6,7 @@
#include "environment.h"
#include "gettext.h"
#include "pager.h"
+#include "path.h"
#include "strbuf.h"
#include "strvec.h"
#include "run-command.h"
diff --git a/entry.c b/entry.c
index d89e61fa64..91a540bd29 100644
--- a/entry.c
+++ b/entry.c
@@ -7,6 +7,7 @@
#include "hex.h"
#include "streaming.h"
#include "submodule.h"
+#include "symlinks.h"
#include "progress.h"
#include "fsmonitor.h"
#include "entry.h"
diff --git a/environment.c b/environment.c
index 8a96997539..28d18eaca8 100644
--- a/environment.c
+++ b/environment.c
@@ -7,7 +7,7 @@
* even if you might want to know where the git directory etc
* are.
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "abspath.h"
#include "branch.h"
#include "convert.h"
@@ -67,7 +67,6 @@ int read_replace_refs = 1;
enum eol core_eol = EOL_UNSET;
int global_conv_flags_eol = CONV_EOL_RNDTRP_WARN;
char *check_roundtrip_encoding = "SHIFT-JIS";
-unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
enum branch_track git_branch_track = BRANCH_TRACK_REMOTE;
enum rebase_setup_type autorebase = AUTOREBASE_NEVER;
enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;
diff --git a/environment.h b/environment.h
index a63f0c6a24..30cb7e0fa3 100644
--- a/environment.h
+++ b/environment.h
@@ -55,6 +55,7 @@ const char *getenv_safe(struct strvec *argv, const char *name);
#define GIT_QUARANTINE_ENVIRONMENT "GIT_QUARANTINE_PATH"
#define GIT_OPTIONAL_LOCKS_ENVIRONMENT "GIT_OPTIONAL_LOCKS"
#define GIT_TEXT_DOMAIN_DIR_ENVIRONMENT "GIT_TEXTDOMAINDIR"
+#define GIT_ATTR_SOURCE_ENVIRONMENT "GIT_ATTR_SOURCE"
/*
* Environment variable used in handshaking the wire protocol.
diff --git a/exec-cmd.c b/exec-cmd.c
index 6f61846389..1e34e48c0e 100644
--- a/exec-cmd.c
+++ b/exec-cmd.c
@@ -3,6 +3,7 @@
#include "environment.h"
#include "exec-cmd.h"
#include "gettext.h"
+#include "path.h"
#include "quote.h"
#include "strvec.h"
#include "trace.h"
diff --git a/fetch-pack.c b/fetch-pack.c
index 6fa6e8af9a..0f71054fba 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -2,6 +2,7 @@
#include "alloc.h"
#include "repository.h"
#include "config.h"
+#include "date.h"
#include "environment.h"
#include "gettext.h"
#include "hex.h"
diff --git a/fmt-merge-msg.c b/fmt-merge-msg.c
index 5af0d4715b..5d15e2387d 100644
--- a/fmt-merge-msg.c
+++ b/fmt-merge-msg.c
@@ -508,7 +508,8 @@ static void fmt_tag_signature(struct strbuf *tagbuf,
strbuf_complete_line(tagbuf);
if (sig->len) {
strbuf_addch(tagbuf, '\n');
- strbuf_add_commented_lines(tagbuf, sig->buf, sig->len);
+ strbuf_add_commented_lines(tagbuf, sig->buf, sig->len,
+ comment_line_char);
}
}
@@ -554,7 +555,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
strbuf_addch(&tagline, '\n');
strbuf_add_commented_lines(&tagline,
origins.items[first_tag].string,
- strlen(origins.items[first_tag].string));
+ strlen(origins.items[first_tag].string),
+ comment_line_char);
strbuf_insert(&tagbuf, 0, tagline.buf,
tagline.len);
strbuf_release(&tagline);
@@ -562,7 +564,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
strbuf_addch(&tagbuf, '\n');
strbuf_add_commented_lines(&tagbuf,
origins.items[i].string,
- strlen(origins.items[i].string));
+ strlen(origins.items[i].string),
+ comment_line_char);
fmt_tag_signature(&tagbuf, &sig, buf, len);
}
strbuf_release(&payload);
diff --git a/fsck.c b/fsck.c
index adbe8bf59e..3261ef9ec2 100644
--- a/fsck.c
+++ b/fsck.c
@@ -1,5 +1,6 @@
#include "git-compat-util.h"
#include "alloc.h"
+#include "date.h"
#include "hex.h"
#include "object-store.h"
#include "repository.h"
diff --git a/fsmonitor--daemon.h b/fsmonitor--daemon.h
index e24838f9a8..70d776c54f 100644
--- a/fsmonitor--daemon.h
+++ b/fsmonitor--daemon.h
@@ -3,7 +3,6 @@
#ifdef HAVE_FSMONITOR_DAEMON_BACKEND
-#include "cache.h"
#include "dir.h"
#include "run-command.h"
#include "simple-ipc.h"
diff --git a/fsmonitor-ipc.c b/fsmonitor-ipc.c
index 866828e299..6a6a89764a 100644
--- a/fsmonitor-ipc.c
+++ b/fsmonitor-ipc.c
@@ -3,6 +3,7 @@
#include "gettext.h"
#include "simple-ipc.h"
#include "fsmonitor-ipc.h"
+#include "repository.h"
#include "run-command.h"
#include "strbuf.h"
#include "trace2.h"
diff --git a/git-send-email.perl b/git-send-email.perl
index 66c9171109..affbb88509 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -87,8 +87,10 @@ git send-email --dump-aliases
Automating:
--identity <str> * Use the sendemail.<id> options.
- --to-cmd <str> * Email To: via `<str> \$patch_path`
- --cc-cmd <str> * Email Cc: via `<str> \$patch_path`
+ --to-cmd <str> * Email To: via `<str> \$patch_path`.
+ --cc-cmd <str> * Email Cc: via `<str> \$patch_path`.
+ --header-cmd <str> * Add headers via `<str> \$patch_path`.
+ --no-header-cmd * Disable any header command in use.
--suppress-cc <str> * author, self, sob, cc, cccmd, body, bodycc, misc-by, all.
--[no-]cc-cover * Email Cc: addresses in the cover letter.
--[no-]to-cover * Email To: addresses in the cover letter.
@@ -202,7 +204,7 @@ my (@to,@cc,@xh,$envelope_sender,
$author,$sender,$smtp_authpass,$annotate,$compose,$time);
# Things we either get from config, *or* are overridden on the
# command-line.
-my ($no_cc, $no_to, $no_bcc, $no_identity);
+my ($no_cc, $no_to, $no_bcc, $no_identity, $no_header_cmd);
my (@config_to, @getopt_to);
my (@config_cc, @getopt_cc);
my (@config_bcc, @getopt_bcc);
@@ -269,7 +271,7 @@ sub do_edit {
# Variables with corresponding config settings
my ($suppress_from, $signed_off_by_cc);
my ($cover_cc, $cover_to);
-my ($to_cmd, $cc_cmd);
+my ($to_cmd, $cc_cmd, $header_cmd);
my ($smtp_server, $smtp_server_port, @smtp_server_options);
my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);
my ($batch_size, $relogin_delay);
@@ -318,6 +320,7 @@ my %config_settings = (
"tocmd" => \$to_cmd,
"cc" => \@config_cc,
"cccmd" => \$cc_cmd,
+ "headercmd" => \$header_cmd,
"aliasfiletype" => \$aliasfiletype,
"bcc" => \@config_bcc,
"suppresscc" => \@suppress_cc,
@@ -519,6 +522,8 @@ my %options = (
"compose" => \$compose,
"quiet" => \$quiet,
"cc-cmd=s" => \$cc_cmd,
+ "header-cmd=s" => \$header_cmd,
+ "no-header-cmd" => \$no_header_cmd,
"suppress-from!" => \$suppress_from,
"no-suppress-from" => sub {$suppress_from = 0},
"suppress-cc=s" => \@suppress_cc,
@@ -792,7 +797,19 @@ if (@rev_list_opts) {
@rev_list_opts);
}
-@files = handle_backup_files(@files);
+if (defined $sender) {
+ $sender =~ s/^\s+|\s+$//g;
+ ($sender) = expand_aliases($sender);
+} else {
+ $sender = $repoauthor->() || $repocommitter->() || '';
+}
+
+# $sender could be an already sanitized address
+# (e.g. sendemail.from could be manually sanitized by user).
+# But it's a no-op to run sanitize_address on an already sanitized address.
+$sender = sanitize_address($sender);
+
+$time = time - scalar $#files;
if ($validate) {
# FIFOs can only be read once, exclude them from validation.
@@ -810,6 +827,7 @@ if ($validate) {
$ENV{GIT_SENDEMAIL_FILE_TOTAL} = "$num_files";
foreach my $r (@real_files) {
$ENV{GIT_SENDEMAIL_FILE_COUNTER} = "$num";
+ pre_process_file($r, 1);
validate_patch($r, $target_xfer_encoding);
$num += 1;
}
@@ -817,6 +835,8 @@ if ($validate) {
delete $ENV{GIT_SENDEMAIL_FILE_TOTAL};
}
+@files = handle_backup_files(@files);
+
if (@files) {
unless ($quiet) {
print $_,"\n" for (@files);
@@ -1065,18 +1085,6 @@ if (!$force) {
}
}
-if (defined $sender) {
- $sender =~ s/^\s+|\s+$//g;
- ($sender) = expand_aliases($sender);
-} else {
- $sender = $repoauthor->() || $repocommitter->() || '';
-}
-
-# $sender could be an already sanitized address
-# (e.g. sendemail.from could be manually sanitized by user).
-# But it's a no-op to run sanitize_address on an already sanitized address.
-$sender = sanitize_address($sender);
-
my $to_whom = __("To whom should the emails be sent (if anyone)?");
my $prompting = 0;
if (!@initial_to && !defined $to_cmd) {
@@ -1236,10 +1244,6 @@ sub make_message_id {
#print "new message id = $message_id\n"; # Was useful for debugging
}
-
-
-$time = time - scalar $#files;
-
sub unquote_rfc2047 {
local ($_) = @_;
my $charset;
@@ -1517,16 +1521,7 @@ sub file_name_is_absolute {
return File::Spec::Functions::file_name_is_absolute($path);
}
-# Prepares the email, then asks the user what to do.
-#
-# If the user chooses to send the email, it's sent and 1 is returned.
-# If the user chooses not to send the email, 0 is returned.
-# If the user decides they want to make further edits, -1 is returned and the
-# caller is expected to call send_message again after the edits are performed.
-#
-# If an error occurs sending the email, this just dies.
-
-sub send_message {
+sub gen_header {
my @recipients = unique_email_list(@to);
@cc = (grep { my $cc = extract_valid_address_or_die($_);
not grep { $cc eq $_ || $_ =~ /<\Q${cc}\E>$/ } @recipients
@@ -1568,6 +1563,22 @@ Message-ID: $message_id
if (@xh) {
$header .= join("\n", @xh) . "\n";
}
+ my $recipients_ref = \@recipients;
+ return ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header);
+}
+
+# Prepares the email, then asks the user what to do.
+#
+# If the user chooses to send the email, it's sent and 1 is returned.
+# If the user chooses not to send the email, 0 is returned.
+# If the user decides they want to make further edits, -1 is returned and the
+# caller is expected to call send_message again after the edits are performed.
+#
+# If an error occurs sending the email, this just dies.
+
+sub send_message {
+ my ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header) = gen_header();
+ my @recipients = @$recipients_ref;
my @sendmail_parameters = ('-i', @recipients);
my $raw_from = $sender;
@@ -1757,11 +1768,8 @@ $in_reply_to = $initial_in_reply_to;
$references = $initial_in_reply_to || '';
$message_num = 0;
-# Prepares the email, prompts the user, sends it out
-# Returns 0 if an edit was done and the function should be called again, or 1
-# otherwise.
-sub process_file {
- my ($t) = @_;
+sub pre_process_file {
+ my ($t, $quiet) = @_;
open my $fh, "<", $t or die sprintf(__("can't open file %s"), $t);
@@ -1780,16 +1788,17 @@ sub process_file {
$subject = $initial_subject;
$message = "";
$message_num++;
- # First unfold multiline header fields
+ undef $message_id;
+ # Retrieve and unfold header fields.
+ my @header_lines = ();
while(<$fh>) {
last if /^\s*$/;
- if (/^\s+\S/ and @header) {
- chomp($header[$#header]);
- s/^\s+/ /;
- $header[$#header] .= $_;
- } else {
- push(@header, $_);
- }
+ push(@header_lines, $_);
+ }
+ @header = unfold_headers(@header_lines);
+ # Add computed headers, if applicable.
+ unless ($no_header_cmd || ! $header_cmd) {
+ push @header, invoke_header_cmd($header_cmd, $t);
}
# Now parse the header
foreach(@header) {
@@ -1915,9 +1924,9 @@ sub process_file {
}
close $fh;
- push @to, recipients_cmd("to-cmd", "to", $to_cmd, $t)
+ push @to, recipients_cmd("to-cmd", "to", $to_cmd, $t, $quiet)
if defined $to_cmd;
- push @cc, recipients_cmd("cc-cmd", "cc", $cc_cmd, $t)
+ push @cc, recipients_cmd("cc-cmd", "cc", $cc_cmd, $t, $quiet)
if defined $cc_cmd && !$suppress_cc{'cccmd'};
if ($broken_encoding{$t} && !$has_content_type) {
@@ -1976,6 +1985,15 @@ sub process_file {
@initial_to = @to;
}
}
+}
+
+# Prepares the email, prompts the user, and sends it out
+# Returns 0 if an edit was done and the function should be called again, or 1
+# on the email being successfully sent out.
+sub process_file {
+ my ($t) = @_;
+
+ pre_process_file($t, $quiet);
my $message_was_sent = send_message();
if ($message_was_sent == -1) {
@@ -2021,15 +2039,64 @@ foreach my $t (@files) {
}
}
+# Execute a command and return its output lines as an array. Blank
+# lines which do not appear at the end of the output are reported as
+# errors.
+sub execute_cmd {
+ my ($prefix, $cmd, $file) = @_;
+ my @lines = ();
+ my $seen_blank_line = 0;
+ open my $fh, "-|", "$cmd \Q$file\E"
+ or die sprintf(__("(%s) Could not execute '%s'"), $prefix, $cmd);
+ while (my $line = <$fh>) {
+ die sprintf(__("(%s) Malformed output from '%s'"), $prefix, $cmd)
+ if $seen_blank_line;
+ if ($line =~ /^$/) {
+ $seen_blank_line = $line =~ /^$/;
+ next;
+ }
+ push @lines, $line;
+ }
+ close $fh
+ or die sprintf(__("(%s) failed to close pipe to '%s'"), $prefix, $cmd);
+ return @lines;
+}
+
+# Process headers lines, unfolding multiline headers as defined by RFC
+# 2822.
+sub unfold_headers {
+ my @headers;
+ foreach(@_) {
+ last if /^\s*$/;
+ if (/^\s+\S/ and @headers) {
+ chomp($headers[$#headers]);
+ s/^\s+/ /;
+ $headers[$#headers] .= $_;
+ } else {
+ push(@headers, $_);
+ }
+ }
+ return @headers;
+}
+
+# Invoke the provided CMD with FILE as an argument, which should
+# output RFC 2822 email headers. Fold multiline headers and return the
+# headers as an array.
+sub invoke_header_cmd {
+ my ($cmd, $file) = @_;
+ my @lines = execute_cmd("header-cmd", $header_cmd, $file);
+ return unfold_headers(@lines);
+}
+
# Execute a command (e.g. $to_cmd) to get a list of email addresses
# and return a results array
sub recipients_cmd {
- my ($prefix, $what, $cmd, $file) = @_;
-
+ my ($prefix, $what, $cmd, $file, $quiet) = @_;
+ my @lines = ();
my @addresses = ();
- open my $fh, "-|", "$cmd \Q$file\E"
- or die sprintf(__("(%s) Could not execute '%s'"), $prefix, $cmd);
- while (my $address = <$fh>) {
+
+ @lines = execute_cmd($prefix, $cmd, $file);
+ for my $address (@lines) {
$address =~ s/^\s*//g;
$address =~ s/\s*$//g;
$address = sanitize_address($address);
@@ -2038,8 +2105,6 @@ sub recipients_cmd {
printf(__("(%s) Adding %s: %s from: '%s'\n"),
$prefix, $what, $address, $cmd) unless $quiet;
}
- close $fh
- or die sprintf(__("(%s) failed to close pipe to '%s'"), $prefix, $cmd);
return @addresses;
}
@@ -2110,10 +2175,21 @@ sub validate_patch {
chdir($repo->wc_path() or $repo->repo_path())
or die("chdir: $!");
local $ENV{"GIT_DIR"} = $repo->repo_path();
+
+ my ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header) = gen_header();
+
+ require File::Temp;
+ my ($header_filehandle, $header_filename) = File::Temp::tempfile(
+ TEMPLATE => ".gitsendemail.header.XXXXXX",
+ DIR => $repo->repo_path(),
+ UNLINK => 1,
+ );
+ print $header_filehandle $header;
+
my @cmd = ("git", "hook", "run", "--ignore-missing",
$hook_name, "--");
- my @cmd_msg = (@cmd, "<patch>");
- my @cmd_run = (@cmd, $target);
+ my @cmd_msg = (@cmd, "<patch>", "<header>");
+ my @cmd_run = (@cmd, $target, $header_filename);
$hook_error = system_or_msg(\@cmd_run, undef, "@cmd_msg");
chdir($cwd_save) or die("chdir: $!");
}
diff --git a/git.c b/git.c
index 45899be826..2f42da20f4 100644
--- a/git.c
+++ b/git.c
@@ -9,6 +9,7 @@
#include "alias.h"
#include "replace-object.h"
#include "setup.h"
+#include "attr.h"
#include "shallow.h"
#include "trace.h"
#include "trace2.h"
@@ -314,6 +315,21 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
} else {
exit(list_cmds(cmd));
}
+ } else if (!strcmp(cmd, "--attr-source")) {
+ if (*argc < 2) {
+ fprintf(stderr, _("no attribute source given for --attr-source\n" ));
+ usage(git_usage_string);
+ }
+ setenv(GIT_ATTR_SOURCE_ENVIRONMENT, (*argv)[1], 1);
+ if (envchanged)
+ *envchanged = 1;
+ (*argv)++;
+ (*argc)--;
+ } else if (skip_prefix(cmd, "--attr-source=", &cmd)) {
+ set_git_attr_source(cmd);
+ setenv(GIT_ATTR_SOURCE_ENVIRONMENT, cmd, 1);
+ if (envchanged)
+ *envchanged = 1;
} else {
fprintf(stderr, _("unknown option: %s\n"), cmd);
usage(git_usage_string);
diff --git a/gitk-git/gitk b/gitk-git/gitk
index 0ae7d68590..df3ba2ea99 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -353,6 +353,16 @@ proc parseviewrevs {view revs} {
return $ret
}
+# Escapes a list of filter paths to be passed to git log via stdin. Note that
+# paths must not be quoted.
+proc escape_filter_paths {paths} {
+ set escaped [list]
+ foreach path $paths {
+ lappend escaped [string map {\\ \\\\ "\ " "\\\ "} $path]
+ }
+ return $escaped
+}
+
# Start off a git log process and arrange to read its output
proc start_rev_list {view} {
global startmsecs commitidx viewcomplete curview
@@ -405,14 +415,17 @@ proc start_rev_list {view} {
if {$revs eq {}} {
return 0
}
- set args [concat $vflags($view) $revs]
+ set args $vflags($view)
} else {
+ set revs {}
set args $vorigargs($view)
}
if {[catch {
set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \
- --parents --boundary $args "--" $files] r]
+ --parents --boundary $args --stdin \
+ "<<[join [concat $revs "--" \
+ [escape_filter_paths $files]] "\\n"]"] r]
} err]} {
error_popup "[mc "Error executing git log:"] $err"
return 0
@@ -554,13 +567,20 @@ proc updatecommits {} {
set revs $newrevs
set vposids($view) [lsort -unique [concat $oldpos $vposids($view)]]
}
- set args [concat $vflags($view) $revs --not $oldpos]
+ set args $vflags($view)
+ foreach r $oldpos {
+ lappend revs "^$r"
+ }
} else {
+ set revs {}
set args $vorigargs($view)
}
if {[catch {
set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \
- --parents --boundary $args "--" $vfilelimit($view)] r]
+ --parents --boundary $args --stdin \
+ "<<[join [concat $revs "--" \
+ [escape_filter_paths \
+ $vfilelimit($view)]] "\\n"]"] r]
} err]} {
error_popup "[mc "Error executing git log:"] $err"
return
@@ -10231,10 +10251,16 @@ proc getallcommits {} {
foreach id $seeds {
lappend ids "^$id"
}
+ lappend ids "--"
}
}
if {$ids ne {}} {
- set fd [open [concat $cmd $ids] r]
+ if {$ids eq "--all"} {
+ set cmd [concat $cmd "--all"]
+ } else {
+ set cmd [concat $cmd --stdin "<<[join $ids "\\n"]"]
+ }
+ set fd [open $cmd r]
fconfigure $fd -blocking 0
incr allcommits
nowbusy allcommits
diff --git a/gpg-interface.c b/gpg-interface.c
index aceeb08336..6a3817bbca 100644
--- a/gpg-interface.c
+++ b/gpg-interface.c
@@ -1,16 +1,19 @@
#include "git-compat-util.h"
#include "commit.h"
#include "config.h"
+#include "date.h"
#include "gettext.h"
#include "run-command.h"
#include "strbuf.h"
#include "dir.h"
#include "ident.h"
#include "gpg-interface.h"
+#include "path.h"
#include "sigchain.h"
#include "tempfile.h"
#include "alias.h"
#include "wrapper.h"
+#include "environment.h"
static int git_gpg_config(const char *, const char *, void *);
@@ -584,8 +587,8 @@ static int verify_ssh_signed_buffer(struct signature_check *sigc,
}
}
- strbuf_stripspace(&ssh_keygen_out, 0);
- strbuf_stripspace(&ssh_keygen_err, 0);
+ strbuf_stripspace(&ssh_keygen_out, '\0');
+ strbuf_stripspace(&ssh_keygen_err, '\0');
/* Add stderr outputs to show the user actual ssh-keygen errors */
strbuf_add(&ssh_keygen_out, ssh_principals_err.buf, ssh_principals_err.len);
strbuf_add(&ssh_keygen_out, ssh_keygen_err.buf, ssh_keygen_err.len);
@@ -650,7 +653,7 @@ int check_signature(struct signature_check *sigc,
gpg_interface_lazy_init();
sigc->result = 'N';
- sigc->trust_level = -1;
+ sigc->trust_level = TRUST_UNDEFINED;
fmt = get_format_by_sig(signature);
if (!fmt)
diff --git a/grep.c b/grep.c
index 073559f2cd..f00986c451 100644
--- a/grep.c
+++ b/grep.c
@@ -4,6 +4,7 @@
#include "grep.h"
#include "hex.h"
#include "object-store.h"
+#include "pretty.h"
#include "userdiff.h"
#include "xdiff-interface.h"
#include "diff.h"
diff --git a/hash-ll.h b/hash-ll.h
new file mode 100644
index 0000000000..8050925137
--- /dev/null
+++ b/hash-ll.h
@@ -0,0 +1,276 @@
+#ifndef HASH_LL_H
+#define HASH_LL_H
+
+#if defined(SHA1_APPLE)
+#include <CommonCrypto/CommonDigest.h>
+#elif defined(SHA1_OPENSSL)
+#include <openssl/sha.h>
+#elif defined(SHA1_DC)
+#include "sha1dc_git.h"
+#else /* SHA1_BLK */
+#include "block-sha1/sha1.h"
+#endif
+
+#if defined(SHA256_NETTLE)
+#include "sha256/nettle.h"
+#elif defined(SHA256_GCRYPT)
+#define SHA256_NEEDS_CLONE_HELPER
+#include "sha256/gcrypt.h"
+#elif defined(SHA256_OPENSSL)
+#include <openssl/sha.h>
+#else
+#include "sha256/block/sha256.h"
+#endif
+
+#ifndef platform_SHA_CTX
+/*
+ * platform's underlying implementation of SHA-1; could be OpenSSL,
+ * blk_SHA, Apple CommonCrypto, etc... Note that the relevant
+ * SHA-1 header may have already defined platform_SHA_CTX for our
+ * own implementations like block-sha1, so we list
+ * the default for OpenSSL compatible SHA-1 implementations here.
+ */
+#define platform_SHA_CTX SHA_CTX
+#define platform_SHA1_Init SHA1_Init
+#define platform_SHA1_Update SHA1_Update
+#define platform_SHA1_Final SHA1_Final
+#endif
+
+#define git_SHA_CTX platform_SHA_CTX
+#define git_SHA1_Init platform_SHA1_Init
+#define git_SHA1_Update platform_SHA1_Update
+#define git_SHA1_Final platform_SHA1_Final
+
+#ifndef platform_SHA256_CTX
+#define platform_SHA256_CTX SHA256_CTX
+#define platform_SHA256_Init SHA256_Init
+#define platform_SHA256_Update SHA256_Update
+#define platform_SHA256_Final SHA256_Final
+#endif
+
+#define git_SHA256_CTX platform_SHA256_CTX
+#define git_SHA256_Init platform_SHA256_Init
+#define git_SHA256_Update platform_SHA256_Update
+#define git_SHA256_Final platform_SHA256_Final
+
+#ifdef platform_SHA256_Clone
+#define git_SHA256_Clone platform_SHA256_Clone
+#endif
+
+#ifdef SHA1_MAX_BLOCK_SIZE
+#include "compat/sha1-chunked.h"
+#undef git_SHA1_Update
+#define git_SHA1_Update git_SHA1_Update_Chunked
+#endif
+
+static inline void git_SHA1_Clone(git_SHA_CTX *dst, const git_SHA_CTX *src)
+{
+ memcpy(dst, src, sizeof(*dst));
+}
+
+#ifndef SHA256_NEEDS_CLONE_HELPER
+static inline void git_SHA256_Clone(git_SHA256_CTX *dst, const git_SHA256_CTX *src)
+{
+ memcpy(dst, src, sizeof(*dst));
+}
+#endif
+
+/*
+ * Note that these constants are suitable for indexing the hash_algos array and
+ * comparing against each other, but are otherwise arbitrary, so they should not
+ * be exposed to the user or serialized to disk. To know whether a
+ * git_hash_algo struct points to some usable hash function, test the format_id
+ * field for being non-zero. Use the name field for user-visible situations and
+ * the format_id field for fixed-length fields on disk.
+ */
+/* An unknown hash function. */
+#define GIT_HASH_UNKNOWN 0
+/* SHA-1 */
+#define GIT_HASH_SHA1 1
+/* SHA-256 */
+#define GIT_HASH_SHA256 2
+/* Number of algorithms supported (including unknown). */
+#define GIT_HASH_NALGOS (GIT_HASH_SHA256 + 1)
+
+/* "sha1", big-endian */
+#define GIT_SHA1_FORMAT_ID 0x73686131
+
+/* The length in bytes and in hex digits of an object name (SHA-1 value). */
+#define GIT_SHA1_RAWSZ 20
+#define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ)
+/* The block size of SHA-1. */
+#define GIT_SHA1_BLKSZ 64
+
+/* "s256", big-endian */
+#define GIT_SHA256_FORMAT_ID 0x73323536
+
+/* The length in bytes and in hex digits of an object name (SHA-256 value). */
+#define GIT_SHA256_RAWSZ 32
+#define GIT_SHA256_HEXSZ (2 * GIT_SHA256_RAWSZ)
+/* The block size of SHA-256. */
+#define GIT_SHA256_BLKSZ 64
+
+/* The length in byte and in hex digits of the largest possible hash value. */
+#define GIT_MAX_RAWSZ GIT_SHA256_RAWSZ
+#define GIT_MAX_HEXSZ GIT_SHA256_HEXSZ
+/* The largest possible block size for any supported hash. */
+#define GIT_MAX_BLKSZ GIT_SHA256_BLKSZ
+
+struct object_id {
+ unsigned char hash[GIT_MAX_RAWSZ];
+ int algo; /* XXX requires 4-byte alignment */
+};
+
+#define GET_OID_QUIETLY 01
+#define GET_OID_COMMIT 02
+#define GET_OID_COMMITTISH 04
+#define GET_OID_TREE 010
+#define GET_OID_TREEISH 020
+#define GET_OID_BLOB 040
+#define GET_OID_FOLLOW_SYMLINKS 0100
+#define GET_OID_RECORD_PATH 0200
+#define GET_OID_ONLY_TO_DIE 04000
+#define GET_OID_REQUIRE_PATH 010000
+
+#define GET_OID_DISAMBIGUATORS \
+ (GET_OID_COMMIT | GET_OID_COMMITTISH | \
+ GET_OID_TREE | GET_OID_TREEISH | \
+ GET_OID_BLOB)
+
+enum get_oid_result {
+ FOUND = 0,
+ MISSING_OBJECT = -1, /* The requested object is missing */
+ SHORT_NAME_AMBIGUOUS = -2,
+ /* The following only apply when symlinks are followed */
+ DANGLING_SYMLINK = -4, /*
+ * The initial symlink is there, but
+ * (transitively) points to a missing
+ * in-tree file
+ */
+ SYMLINK_LOOP = -5,
+ NOT_DIR = -6, /*
+ * Somewhere along the symlink chain, a path is
+ * requested which contains a file as a
+ * non-final element.
+ */
+};
+
+/* A suitably aligned type for stack allocations of hash contexts. */
+union git_hash_ctx {
+ git_SHA_CTX sha1;
+ git_SHA256_CTX sha256;
+};
+typedef union git_hash_ctx git_hash_ctx;
+
+typedef void (*git_hash_init_fn)(git_hash_ctx *ctx);
+typedef void (*git_hash_clone_fn)(git_hash_ctx *dst, const git_hash_ctx *src);
+typedef void (*git_hash_update_fn)(git_hash_ctx *ctx, const void *in, size_t len);
+typedef void (*git_hash_final_fn)(unsigned char *hash, git_hash_ctx *ctx);
+typedef void (*git_hash_final_oid_fn)(struct object_id *oid, git_hash_ctx *ctx);
+
+struct git_hash_algo {
+ /*
+ * The name of the algorithm, as appears in the config file and in
+ * messages.
+ */
+ const char *name;
+
+ /* A four-byte version identifier, used in pack indices. */
+ uint32_t format_id;
+
+ /* The length of the hash in binary. */
+ size_t rawsz;
+
+ /* The length of the hash in hex characters. */
+ size_t hexsz;
+
+ /* The block size of the hash. */
+ size_t blksz;
+
+ /* The hash initialization function. */
+ git_hash_init_fn init_fn;
+
+ /* The hash context cloning function. */
+ git_hash_clone_fn clone_fn;
+
+ /* The hash update function. */
+ git_hash_update_fn update_fn;
+
+ /* The hash finalization function. */
+ git_hash_final_fn final_fn;
+
+ /* The hash finalization function for object IDs. */
+ git_hash_final_oid_fn final_oid_fn;
+
+ /* The OID of the empty tree. */
+ const struct object_id *empty_tree;
+
+ /* The OID of the empty blob. */
+ const struct object_id *empty_blob;
+
+ /* The all-zeros OID. */
+ const struct object_id *null_oid;
+};
+extern const struct git_hash_algo hash_algos[GIT_HASH_NALGOS];
+
+/*
+ * Return a GIT_HASH_* constant based on the name. Returns GIT_HASH_UNKNOWN if
+ * the name doesn't match a known algorithm.
+ */
+int hash_algo_by_name(const char *name);
+/* Identical, except based on the format ID. */
+int hash_algo_by_id(uint32_t format_id);
+/* Identical, except based on the length. */
+int hash_algo_by_length(int len);
+/* Identical, except for a pointer to struct git_hash_algo. */
+static inline int hash_algo_by_ptr(const struct git_hash_algo *p)
+{
+ return p - hash_algos;
+}
+
+const struct object_id *null_oid(void);
+
+static inline int hashcmp_algop(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop)
+{
+ /*
+ * Teach the compiler that there are only two possibilities of hash size
+ * here, so that it can optimize for this case as much as possible.
+ */
+ if (algop->rawsz == GIT_MAX_RAWSZ)
+ return memcmp(sha1, sha2, GIT_MAX_RAWSZ);
+ return memcmp(sha1, sha2, GIT_SHA1_RAWSZ);
+}
+
+static inline int hasheq_algop(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop)
+{
+ /*
+ * We write this here instead of deferring to hashcmp so that the
+ * compiler can properly inline it and avoid calling memcmp.
+ */
+ if (algop->rawsz == GIT_MAX_RAWSZ)
+ return !memcmp(sha1, sha2, GIT_MAX_RAWSZ);
+ return !memcmp(sha1, sha2, GIT_SHA1_RAWSZ);
+}
+
+static inline void oidcpy(struct object_id *dst, const struct object_id *src)
+{
+ memcpy(dst->hash, src->hash, GIT_MAX_RAWSZ);
+ dst->algo = src->algo;
+}
+
+static inline struct object_id *oiddup(const struct object_id *src)
+{
+ struct object_id *dst = xmalloc(sizeof(struct object_id));
+ oidcpy(dst, src);
+ return dst;
+}
+
+static inline void oid_set_algo(struct object_id *oid, const struct git_hash_algo *algop)
+{
+ oid->algo = hash_algo_by_ptr(algop);
+}
+
+const char *empty_tree_oid_hex(void);
+const char *empty_blob_oid_hex(void);
+
+#endif
diff --git a/hash-lookup.c b/hash-lookup.c
index b98ed5e11e..bb54dfde9c 100644
--- a/hash-lookup.c
+++ b/hash-lookup.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include "hash.h"
#include "hash-lookup.h"
static uint32_t take2(const struct object_id *oid, size_t ofs)
diff --git a/hash.h b/hash.h
index d39f73618c..615ae0691d 100644
--- a/hash.h
+++ b/hash.h
@@ -1,250 +1,11 @@
#ifndef HASH_H
#define HASH_H
+#include "hash-ll.h"
#include "repository.h"
-#if defined(SHA1_APPLE)
-#include <CommonCrypto/CommonDigest.h>
-#elif defined(SHA1_OPENSSL)
-#include <openssl/sha.h>
-#elif defined(SHA1_DC)
-#include "sha1dc_git.h"
-#else /* SHA1_BLK */
-#include "block-sha1/sha1.h"
-#endif
-
-#if defined(SHA256_NETTLE)
-#include "sha256/nettle.h"
-#elif defined(SHA256_GCRYPT)
-#define SHA256_NEEDS_CLONE_HELPER
-#include "sha256/gcrypt.h"
-#elif defined(SHA256_OPENSSL)
-#include <openssl/sha.h>
-#else
-#include "sha256/block/sha256.h"
-#endif
-
-#ifndef platform_SHA_CTX
-/*
- * platform's underlying implementation of SHA-1; could be OpenSSL,
- * blk_SHA, Apple CommonCrypto, etc... Note that the relevant
- * SHA-1 header may have already defined platform_SHA_CTX for our
- * own implementations like block-sha1, so we list
- * the default for OpenSSL compatible SHA-1 implementations here.
- */
-#define platform_SHA_CTX SHA_CTX
-#define platform_SHA1_Init SHA1_Init
-#define platform_SHA1_Update SHA1_Update
-#define platform_SHA1_Final SHA1_Final
-#endif
-
-#define git_SHA_CTX platform_SHA_CTX
-#define git_SHA1_Init platform_SHA1_Init
-#define git_SHA1_Update platform_SHA1_Update
-#define git_SHA1_Final platform_SHA1_Final
-
-#ifndef platform_SHA256_CTX
-#define platform_SHA256_CTX SHA256_CTX
-#define platform_SHA256_Init SHA256_Init
-#define platform_SHA256_Update SHA256_Update
-#define platform_SHA256_Final SHA256_Final
-#endif
-
-#define git_SHA256_CTX platform_SHA256_CTX
-#define git_SHA256_Init platform_SHA256_Init
-#define git_SHA256_Update platform_SHA256_Update
-#define git_SHA256_Final platform_SHA256_Final
-
-#ifdef platform_SHA256_Clone
-#define git_SHA256_Clone platform_SHA256_Clone
-#endif
-
-#ifdef SHA1_MAX_BLOCK_SIZE
-#include "compat/sha1-chunked.h"
-#undef git_SHA1_Update
-#define git_SHA1_Update git_SHA1_Update_Chunked
-#endif
-
-static inline void git_SHA1_Clone(git_SHA_CTX *dst, const git_SHA_CTX *src)
-{
- memcpy(dst, src, sizeof(*dst));
-}
-
-#ifndef SHA256_NEEDS_CLONE_HELPER
-static inline void git_SHA256_Clone(git_SHA256_CTX *dst, const git_SHA256_CTX *src)
-{
- memcpy(dst, src, sizeof(*dst));
-}
-#endif
-
-/*
- * Note that these constants are suitable for indexing the hash_algos array and
- * comparing against each other, but are otherwise arbitrary, so they should not
- * be exposed to the user or serialized to disk. To know whether a
- * git_hash_algo struct points to some usable hash function, test the format_id
- * field for being non-zero. Use the name field for user-visible situations and
- * the format_id field for fixed-length fields on disk.
- */
-/* An unknown hash function. */
-#define GIT_HASH_UNKNOWN 0
-/* SHA-1 */
-#define GIT_HASH_SHA1 1
-/* SHA-256 */
-#define GIT_HASH_SHA256 2
-/* Number of algorithms supported (including unknown). */
-#define GIT_HASH_NALGOS (GIT_HASH_SHA256 + 1)
-
-/* "sha1", big-endian */
-#define GIT_SHA1_FORMAT_ID 0x73686131
-
-/* The length in bytes and in hex digits of an object name (SHA-1 value). */
-#define GIT_SHA1_RAWSZ 20
-#define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ)
-/* The block size of SHA-1. */
-#define GIT_SHA1_BLKSZ 64
-
-/* "s256", big-endian */
-#define GIT_SHA256_FORMAT_ID 0x73323536
-
-/* The length in bytes and in hex digits of an object name (SHA-256 value). */
-#define GIT_SHA256_RAWSZ 32
-#define GIT_SHA256_HEXSZ (2 * GIT_SHA256_RAWSZ)
-/* The block size of SHA-256. */
-#define GIT_SHA256_BLKSZ 64
-
-/* The length in byte and in hex digits of the largest possible hash value. */
-#define GIT_MAX_RAWSZ GIT_SHA256_RAWSZ
-#define GIT_MAX_HEXSZ GIT_SHA256_HEXSZ
-/* The largest possible block size for any supported hash. */
-#define GIT_MAX_BLKSZ GIT_SHA256_BLKSZ
-
-struct object_id {
- unsigned char hash[GIT_MAX_RAWSZ];
- int algo; /* XXX requires 4-byte alignment */
-};
-
-#define GET_OID_QUIETLY 01
-#define GET_OID_COMMIT 02
-#define GET_OID_COMMITTISH 04
-#define GET_OID_TREE 010
-#define GET_OID_TREEISH 020
-#define GET_OID_BLOB 040
-#define GET_OID_FOLLOW_SYMLINKS 0100
-#define GET_OID_RECORD_PATH 0200
-#define GET_OID_ONLY_TO_DIE 04000
-#define GET_OID_REQUIRE_PATH 010000
-
-#define GET_OID_DISAMBIGUATORS \
- (GET_OID_COMMIT | GET_OID_COMMITTISH | \
- GET_OID_TREE | GET_OID_TREEISH | \
- GET_OID_BLOB)
-
-enum get_oid_result {
- FOUND = 0,
- MISSING_OBJECT = -1, /* The requested object is missing */
- SHORT_NAME_AMBIGUOUS = -2,
- /* The following only apply when symlinks are followed */
- DANGLING_SYMLINK = -4, /*
- * The initial symlink is there, but
- * (transitively) points to a missing
- * in-tree file
- */
- SYMLINK_LOOP = -5,
- NOT_DIR = -6, /*
- * Somewhere along the symlink chain, a path is
- * requested which contains a file as a
- * non-final element.
- */
-};
-
-/* A suitably aligned type for stack allocations of hash contexts. */
-union git_hash_ctx {
- git_SHA_CTX sha1;
- git_SHA256_CTX sha256;
-};
-typedef union git_hash_ctx git_hash_ctx;
-
-typedef void (*git_hash_init_fn)(git_hash_ctx *ctx);
-typedef void (*git_hash_clone_fn)(git_hash_ctx *dst, const git_hash_ctx *src);
-typedef void (*git_hash_update_fn)(git_hash_ctx *ctx, const void *in, size_t len);
-typedef void (*git_hash_final_fn)(unsigned char *hash, git_hash_ctx *ctx);
-typedef void (*git_hash_final_oid_fn)(struct object_id *oid, git_hash_ctx *ctx);
-
-struct git_hash_algo {
- /*
- * The name of the algorithm, as appears in the config file and in
- * messages.
- */
- const char *name;
-
- /* A four-byte version identifier, used in pack indices. */
- uint32_t format_id;
-
- /* The length of the hash in binary. */
- size_t rawsz;
-
- /* The length of the hash in hex characters. */
- size_t hexsz;
-
- /* The block size of the hash. */
- size_t blksz;
-
- /* The hash initialization function. */
- git_hash_init_fn init_fn;
-
- /* The hash context cloning function. */
- git_hash_clone_fn clone_fn;
-
- /* The hash update function. */
- git_hash_update_fn update_fn;
-
- /* The hash finalization function. */
- git_hash_final_fn final_fn;
-
- /* The hash finalization function for object IDs. */
- git_hash_final_oid_fn final_oid_fn;
-
- /* The OID of the empty tree. */
- const struct object_id *empty_tree;
-
- /* The OID of the empty blob. */
- const struct object_id *empty_blob;
-
- /* The all-zeros OID. */
- const struct object_id *null_oid;
-};
-extern const struct git_hash_algo hash_algos[GIT_HASH_NALGOS];
-
-/*
- * Return a GIT_HASH_* constant based on the name. Returns GIT_HASH_UNKNOWN if
- * the name doesn't match a known algorithm.
- */
-int hash_algo_by_name(const char *name);
-/* Identical, except based on the format ID. */
-int hash_algo_by_id(uint32_t format_id);
-/* Identical, except based on the length. */
-int hash_algo_by_length(int len);
-/* Identical, except for a pointer to struct git_hash_algo. */
-static inline int hash_algo_by_ptr(const struct git_hash_algo *p)
-{
- return p - hash_algos;
-}
-
#define the_hash_algo the_repository->hash_algo
-const struct object_id *null_oid(void);
-
-static inline int hashcmp_algop(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop)
-{
- /*
- * Teach the compiler that there are only two possibilities of hash size
- * here, so that it can optimize for this case as much as possible.
- */
- if (algop->rawsz == GIT_MAX_RAWSZ)
- return memcmp(sha1, sha2, GIT_MAX_RAWSZ);
- return memcmp(sha1, sha2, GIT_SHA1_RAWSZ);
-}
-
static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2)
{
return hashcmp_algop(sha1, sha2, the_hash_algo);
@@ -260,17 +21,6 @@ static inline int oidcmp(const struct object_id *oid1, const struct object_id *o
return hashcmp_algop(oid1->hash, oid2->hash, algop);
}
-static inline int hasheq_algop(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop)
-{
- /*
- * We write this here instead of deferring to hashcmp so that the
- * compiler can properly inline it and avoid calling memcmp.
- */
- if (algop->rawsz == GIT_MAX_RAWSZ)
- return !memcmp(sha1, sha2, GIT_MAX_RAWSZ);
- return !memcmp(sha1, sha2, GIT_SHA1_RAWSZ);
-}
-
static inline int hasheq(const unsigned char *sha1, const unsigned char *sha2)
{
return hasheq_algop(sha1, sha2, the_hash_algo);
@@ -296,12 +46,6 @@ static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src)
memcpy(sha_dst, sha_src, the_hash_algo->rawsz);
}
-static inline void oidcpy(struct object_id *dst, const struct object_id *src)
-{
- memcpy(dst->hash, src->hash, GIT_MAX_RAWSZ);
- dst->algo = src->algo;
-}
-
/* Like oidcpy() but zero-pads the unused bytes in dst's hash array. */
static inline void oidcpy_with_padding(struct object_id *dst,
const struct object_id *src)
@@ -318,13 +62,6 @@ static inline void oidcpy_with_padding(struct object_id *dst,
dst->algo = src->algo;
}
-static inline struct object_id *oiddup(const struct object_id *src)
-{
- struct object_id *dst = xmalloc(sizeof(struct object_id));
- oidcpy(dst, src);
- return dst;
-}
-
static inline void hashclr(unsigned char *hash)
{
memset(hash, 0, the_hash_algo->rawsz);
@@ -362,12 +99,4 @@ static inline int is_empty_tree_oid(const struct object_id *oid)
return oideq(oid, the_hash_algo->empty_tree);
}
-static inline void oid_set_algo(struct object_id *oid, const struct git_hash_algo *algop)
-{
- oid->algo = hash_algo_by_ptr(algop);
-}
-
-const char *empty_tree_oid_hex(void);
-const char *empty_blob_oid_hex(void);
-
#endif
diff --git a/hashmap.h b/hashmap.h
index e2cf9c78d8..2695f3d3a6 100644
--- a/hashmap.h
+++ b/hashmap.h
@@ -1,7 +1,7 @@
#ifndef HASHMAP_H
#define HASHMAP_H
-#include "hash.h"
+#include "hash-ll.h"
/*
* Generic implementation of hash-based key-value mappings.
diff --git a/hex.c b/hex.c
index 0a1bddc128..7bb440e794 100644
--- a/hex.c
+++ b/hex.c
@@ -1,4 +1,5 @@
#include "git-compat-util.h"
+#include "hash.h"
#include "hex.h"
const signed char hexval_table[256] = {
diff --git a/hex.h b/hex.h
index e2abfc56fa..7df4b3c460 100644
--- a/hex.h
+++ b/hex.h
@@ -1,7 +1,7 @@
#ifndef HEX_H
#define HEX_H
-#include "hash.h"
+#include "hash-ll.h"
extern const signed char hexval_table[256];
static inline unsigned int hexval(unsigned char c)
diff --git a/hook.c b/hook.c
index 76e322f580..f6306d72b3 100644
--- a/hook.c
+++ b/hook.c
@@ -1,7 +1,9 @@
#include "git-compat-util.h"
+#include "abspath.h"
#include "advice.h"
#include "gettext.h"
#include "hook.h"
+#include "path.h"
#include "run-command.h"
#include "config.h"
#include "strbuf.h"
diff --git a/http-push.c b/http-push.c
index 76ab5dbb09..29cf9db34e 100644
--- a/http-push.c
+++ b/http-push.c
@@ -15,6 +15,8 @@
#include "setup.h"
#include "sigchain.h"
#include "strvec.h"
+#include "tree.h"
+#include "tree-walk.h"
#include "packfile.h"
#include "object-store.h"
#include "commit-reach.h"
diff --git a/imap-send.c b/imap-send.c
index a62424e90a..7f5426177a 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -29,6 +29,7 @@
#include "run-command.h"
#include "parse-options.h"
#include "setup.h"
+#include "strbuf.h"
#include "wrapper.h"
#if defined(NO_OPENSSL) && !defined(HAVE_OPENSSL_CSPRNG)
typedef void *SSL;
diff --git a/khash.h b/khash.h
index 85362718c5..56241e6a5c 100644
--- a/khash.h
+++ b/khash.h
@@ -27,6 +27,7 @@
#define __AC_KHASH_H
#include "hashmap.h"
+#include "hash.h"
#define AC_VERSION_KHASH_H "0.2.8"
diff --git a/line-log.c b/line-log.c
index 10c19daec4..6a7ac312a4 100644
--- a/line-log.c
+++ b/line-log.c
@@ -18,6 +18,7 @@
#include "setup.h"
#include "strvec.h"
#include "bloom.h"
+#include "tree-walk.h"
static void range_set_grow(struct range_set *rs, size_t extra)
{
diff --git a/ll-merge.c b/ll-merge.c
index 28bc94c45d..07ec16e8e5 100644
--- a/ll-merge.c
+++ b/ll-merge.c
@@ -4,7 +4,7 @@
* Copyright (c) 2007 Junio C Hamano
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
#include "convert.h"
#include "attr.h"
@@ -12,6 +12,7 @@
#include "run-command.h"
#include "ll-merge.h"
#include "quote.h"
+#include "strbuf.h"
#include "wrapper.h"
struct ll_merge_driver;
@@ -393,7 +394,7 @@ enum ll_merge_result ll_merge(mmbuffer_t *result_buf,
normalize_file(theirs, path, istate);
}
- git_check_attr(istate, NULL, path, check);
+ git_check_attr(istate, path, check);
ll_driver_name = check->items[0].value;
if (check->items[1].value) {
marker_size = atoi(check->items[1].value);
@@ -421,7 +422,7 @@ int ll_merge_marker_size(struct index_state *istate, const char *path)
if (!check)
check = attr_check_initl("conflict-marker-size", NULL);
- git_check_attr(istate, NULL, path, check);
+ git_check_attr(istate, path, check);
if (check->items[0].value) {
marker_size = atoi(check->items[0].value);
if (marker_size <= 0)
diff --git a/log-tree.c b/log-tree.c
index 143b86fecf..f4b22a60cc 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -24,6 +24,7 @@
#include "help.h"
#include "range-diff.h"
#include "strmap.h"
+#include "tree.h"
#include "write-or-die.h"
static struct decoration name_decoration = { "object names" };
diff --git a/ls-refs.c b/ls-refs.c
index b9f3e08ec3..f385938b64 100644
--- a/ls-refs.c
+++ b/ls-refs.c
@@ -1,6 +1,7 @@
#include "git-compat-util.h"
#include "environment.h"
#include "gettext.h"
+#include "hash.h"
#include "hex.h"
#include "repository.h"
#include "refs.h"
diff --git a/match-trees.c b/match-trees.c
index 5877fc64a8..6bc8eb7647 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -1,5 +1,6 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "hex.h"
+#include "match-trees.h"
#include "tree.h"
#include "tree-walk.h"
#include "object-store.h"
diff --git a/match-trees.h b/match-trees.h
new file mode 100644
index 0000000000..e3877acd58
--- /dev/null
+++ b/match-trees.h
@@ -0,0 +1,10 @@
+#ifndef MATCH_TREES_H
+#define MATCH_TREES_H
+
+struct object_id;
+struct repository;
+
+void shift_tree(struct repository *, const struct object_id *, const struct object_id *, struct object_id *, int);
+void shift_tree_by(struct repository *, const struct object_id *, const struct object_id *, struct object_id *, const char *);
+
+#endif /* MATCH_TREES_H */
diff --git a/merge-ort-wrappers.c b/merge-ort-wrappers.c
index c00dfbab1c..a550753300 100644
--- a/merge-ort-wrappers.c
+++ b/merge-ort-wrappers.c
@@ -1,7 +1,9 @@
#include "cache.h"
#include "gettext.h"
+#include "hash.h"
#include "merge-ort.h"
#include "merge-ort-wrappers.h"
+#include "tree.h"
#include "commit.h"
diff --git a/merge-ort.c b/merge-ort.c
index 2c6a9ed9a4..a50b095c47 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -31,6 +31,7 @@
#include "hex.h"
#include "entry.h"
#include "ll-merge.h"
+#include "match-trees.h"
#include "mem-pool.h"
#include "object-name.h"
#include "object-store.h"
@@ -4722,14 +4723,14 @@ void merge_switch_to_result(struct merge_options *opt,
void merge_finalize(struct merge_options *opt,
struct merge_result *result)
{
- struct merge_options_internal *opti = result->priv;
-
if (opt->renormalize)
git_attr_set_direction(GIT_ATTR_CHECKIN);
assert(opt->priv == NULL);
- clear_or_reinit_internal_opts(opti, 0);
- FREE_AND_NULL(opti);
+ if (result->priv) {
+ clear_or_reinit_internal_opts(result->priv, 0);
+ FREE_AND_NULL(result->priv);
+ }
}
/*** Function Grouping: helper functions for merge_incore_*() ***/
diff --git a/merge-ort.h b/merge-ort.h
index a994c9a5fc..ce56ec1a78 100644
--- a/merge-ort.h
+++ b/merge-ort.h
@@ -2,7 +2,7 @@
#define MERGE_ORT_H
#include "merge-recursive.h"
-#include "hash.h"
+#include "hash-ll.h"
struct commit;
struct tree;
diff --git a/merge-recursive.c b/merge-recursive.c
index 9875bdb11c..8e87b6386d 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -22,6 +22,7 @@
#include "hex.h"
#include "ll-merge.h"
#include "lockfile.h"
+#include "match-trees.h"
#include "object-file.h"
#include "object-name.h"
#include "object-store.h"
@@ -30,6 +31,7 @@
#include "string-list.h"
#include "submodule-config.h"
#include "submodule.h"
+#include "symlinks.h"
#include "tag.h"
#include "tree-walk.h"
#include "unpack-trees.h"
diff --git a/merge.c b/merge.c
index da7fa652c2..10aaec3a6c 100644
--- a/merge.c
+++ b/merge.c
@@ -7,6 +7,7 @@
#include "commit.h"
#include "run-command.h"
#include "resolve-undo.h"
+#include "tree.h"
#include "tree-walk.h"
#include "unpack-trees.h"
#include "dir.h"
diff --git a/midx.c b/midx.c
index 281a1406a8..b500174d1f 100644
--- a/midx.c
+++ b/midx.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "abspath.h"
#include "alloc.h"
#include "config.h"
diff --git a/negotiator/default.c b/negotiator/default.c
index f4b78eb47d..9a5b696327 100644
--- a/negotiator/default.c
+++ b/negotiator/default.c
@@ -4,6 +4,7 @@
#include "../fetch-negotiator.h"
#include "../prio-queue.h"
#include "../refs.h"
+#include "../repository.h"
#include "../tag.h"
/* Remember to update object flag allocation in object.h */
@@ -55,30 +56,49 @@ static int clear_marks(const char *refname, const struct object_id *oid,
static void mark_common(struct negotiation_state *ns, struct commit *commit,
int ancestors_only, int dont_parse)
{
- if (commit != NULL && !(commit->object.flags & COMMON)) {
- struct object *o = (struct object *)commit;
+ struct prio_queue queue = { NULL };
+
+ if (!commit || (commit->object.flags & COMMON))
+ return;
+
+ prio_queue_put(&queue, commit);
+ if (!ancestors_only) {
+ commit->object.flags |= COMMON;
- if (!ancestors_only)
- o->flags |= COMMON;
+ if ((commit->object.flags & SEEN) && !(commit->object.flags & POPPED))
+ ns->non_common_revs--;
+ }
+ while ((commit = prio_queue_get(&queue))) {
+ struct object *o = (struct object *)commit;
if (!(o->flags & SEEN))
rev_list_push(ns, commit, SEEN);
else {
struct commit_list *parents;
- if (!ancestors_only && !(o->flags & POPPED))
- ns->non_common_revs--;
if (!o->parsed && !dont_parse)
if (repo_parse_commit(the_repository, commit))
- return;
+ continue;
for (parents = commit->parents;
parents;
- parents = parents->next)
- mark_common(ns, parents->item, 0,
- dont_parse);
+ parents = parents->next) {
+ struct commit *p = parents->item;
+
+ if (p->object.flags & COMMON)
+ continue;
+
+ p->object.flags |= COMMON;
+
+ if ((p->object.flags & SEEN) && !(p->object.flags & POPPED))
+ ns->non_common_revs--;
+
+ prio_queue_put(&queue, parents->item);
+ }
}
}
+
+ clear_prio_queue(&queue);
}
/*
diff --git a/negotiator/skipping.c b/negotiator/skipping.c
index c7d6ab39bc..5b91520430 100644
--- a/negotiator/skipping.c
+++ b/negotiator/skipping.c
@@ -5,6 +5,7 @@
#include "../hex.h"
#include "../prio-queue.h"
#include "../refs.h"
+#include "../repository.h"
#include "../tag.h"
/* Remember to update object flag allocation in object.h */
@@ -85,29 +86,37 @@ static int clear_marks(const char *refname, const struct object_id *oid,
}
/*
- * Mark this SEEN commit and all its SEEN ancestors as COMMON.
+ * Mark this SEEN commit and all its parsed SEEN ancestors as COMMON.
*/
static void mark_common(struct data *data, struct commit *seen_commit)
{
struct prio_queue queue = { NULL };
struct commit *c;
+ if (seen_commit->object.flags & COMMON)
+ return;
+
prio_queue_put(&queue, seen_commit);
+ seen_commit->object.flags |= COMMON;
while ((c = prio_queue_get(&queue))) {
struct commit_list *p;
- if (c->object.flags & COMMON)
- return;
- c->object.flags |= COMMON;
+
if (!(c->object.flags & POPPED))
data->non_common_revs--;
if (!c->object.parsed)
- return;
+ continue;
for (p = c->parents; p; p = p->next) {
- if (p->item->object.flags & SEEN)
- prio_queue_put(&queue, p->item);
+ if (!(p->item->object.flags & SEEN) ||
+ (p->item->object.flags & COMMON))
+ continue;
+
+ p->item->object.flags |= COMMON;
+ prio_queue_put(&queue, p->item);
}
}
+
+ clear_prio_queue(&queue);
}
/*
diff --git a/notes-cache.c b/notes-cache.c
index fbcdfd0dfe..14288caf98 100644
--- a/notes-cache.c
+++ b/notes-cache.c
@@ -1,6 +1,7 @@
#include "git-compat-util.h"
#include "notes-cache.h"
#include "object-store.h"
+#include "pretty.h"
#include "repository.h"
#include "commit.h"
#include "refs.h"
diff --git a/notes-utils.c b/notes-utils.c
index cb88171b7b..4a793eb347 100644
--- a/notes-utils.c
+++ b/notes-utils.c
@@ -6,6 +6,7 @@
#include "refs.h"
#include "notes-utils.h"
#include "repository.h"
+#include "strbuf.h"
void create_notes_commit(struct repository *r,
struct notes_tree *t,
diff --git a/notes.c b/notes.c
index 02f1aa39ae..f51a2d3630 100644
--- a/notes.c
+++ b/notes.c
@@ -964,7 +964,7 @@ void string_list_add_refs_from_colon_sep(struct string_list *list,
char *globs_copy = xstrdup(globs);
int i;
- string_list_split_in_place(&split, globs_copy, ':', -1);
+ string_list_split_in_place(&split, globs_copy, ":", -1);
string_list_remove_empty_items(&split, 0);
for (i = 0; i < split.nr; i++)
@@ -1020,13 +1020,13 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
t->root = (struct int_node *) xcalloc(1, sizeof(struct int_node));
t->first_non_note = NULL;
t->prev_non_note = NULL;
- t->ref = xstrdup_or_null(notes_ref);
+ t->ref = xstrdup(notes_ref);
t->update_ref = (flags & NOTES_INIT_WRITABLE) ? t->ref : NULL;
t->combine_notes = combine_notes;
t->initialized = 1;
t->dirty = 0;
- if (flags & NOTES_INIT_EMPTY || !notes_ref ||
+ if (flags & NOTES_INIT_EMPTY ||
repo_get_oid_treeish(the_repository, notes_ref, &object_oid))
return;
if (flags & NOTES_INIT_WRITABLE && read_ref(notes_ref, &object_oid))
diff --git a/object-file.c b/object-file.c
index af18e38527..7c1af5c8db 100644
--- a/object-file.c
+++ b/object-file.c
@@ -6,7 +6,7 @@
* This handles basic git object files - packing, unpacking,
* creation etc.
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "abspath.h"
#include "alloc.h"
#include "config.h"
@@ -38,6 +38,7 @@
#include "packfile.h"
#include "object-file.h"
#include "object-store.h"
+#include "oidtree.h"
#include "promisor-remote.h"
#include "setup.h"
#include "submodule.h"
diff --git a/object-file.h b/object-file.h
index e0cfc3a5db..d6414610f8 100644
--- a/object-file.h
+++ b/object-file.h
@@ -4,6 +4,8 @@
#include "git-zlib.h"
#include "object.h"
+struct index_state;
+
/*
* Set this to 0 to prevent oid_object_info_extended() from fetching missing
* blobs. This has a difference only if extensions.partialClone is set.
diff --git a/object-name.c b/object-name.c
index 538e8a8f62..34e0f56703 100644
--- a/object-name.c
+++ b/object-name.c
@@ -14,7 +14,9 @@
#include "remote.h"
#include "dir.h"
#include "oid-array.h"
+#include "oidtree.h"
#include "packfile.h"
+#include "pretty.h"
#include "object-store.h"
#include "repository.h"
#include "setup.h"
@@ -766,6 +768,21 @@ static void find_abbrev_len_packed(struct min_abbrev_data *mad)
find_abbrev_len_for_pack(p, mad);
}
+void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,
+ const struct object_id *oid, int abbrev_len)
+{
+ int r;
+ strbuf_grow(sb, GIT_MAX_HEXSZ + 1);
+ r = repo_find_unique_abbrev_r(repo, sb->buf + sb->len, oid, abbrev_len);
+ strbuf_setlen(sb, sb->len + r);
+}
+
+void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,
+ int abbrev_len)
+{
+ strbuf_repo_add_unique_abbrev(sb, the_repository, oid, abbrev_len);
+}
+
int repo_find_unique_abbrev_r(struct repository *r, char *hex,
const struct object_id *oid, int len)
{
diff --git a/object-name.h b/object-name.h
index 1d63698f42..9ae5223071 100644
--- a/object-name.h
+++ b/object-name.h
@@ -40,6 +40,15 @@ struct object_context {
const char *repo_find_unique_abbrev(struct repository *r, const struct object_id *oid, int len);
int repo_find_unique_abbrev_r(struct repository *r, char *hex, const struct object_id *oid, int len);
+/**
+ * Add the abbreviation, as generated by repo_find_unique_abbrev(), of `sha1` to
+ * the strbuf `sb`.
+ */
+void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,
+ const struct object_id *oid, int abbrev_len);
+void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,
+ int abbrev_len);
+
int repo_get_oid(struct repository *r, const char *str, struct object_id *oid);
__attribute__((format (printf, 2, 3)))
int get_oidf(struct object_id *oid, const char *fmt, ...);
diff --git a/object-store.h b/object-store.h
index 4ac91e375d..12415e5ea7 100644
--- a/object-store.h
+++ b/object-store.h
@@ -2,16 +2,16 @@
#define OBJECT_STORE_H
#include "object.h"
-#include "oidmap.h"
#include "list.h"
-#include "oid-array.h"
-#include "strbuf.h"
#include "thread-utils.h"
#include "khash.h"
#include "dir.h"
-#include "oidtree.h"
#include "oidset.h"
+struct oidmap;
+struct oidtree;
+struct strbuf;
+
struct object_directory {
struct object_directory *next;
diff --git a/object.h b/object.h
index 96e52e24fb..5871615fee 100644
--- a/object.h
+++ b/object.h
@@ -1,9 +1,10 @@
#ifndef OBJECT_H
#define OBJECT_H
-#include "hash.h"
+#include "hash-ll.h"
struct buffer_slab;
+struct repository;
struct parsed_object_pool {
struct object **obj_hash;
diff --git a/oidmap.c b/oidmap.c
index 8c1a139c97..8b1bc4dec9 100644
--- a/oidmap.c
+++ b/oidmap.c
@@ -1,4 +1,5 @@
#include "git-compat-util.h"
+#include "hash.h"
#include "oidmap.h"
static int oidmap_neq(const void *hashmap_cmp_fn_data UNUSED,
diff --git a/oidtree.h b/oidtree.h
index 77898f510a..55c83513fd 100644
--- a/oidtree.h
+++ b/oidtree.h
@@ -2,7 +2,7 @@
#define OIDTREE_H
#include "cbtree.h"
-#include "hash.h"
+#include "hash-ll.h"
#include "mem-pool.h"
struct oidtree {
diff --git a/pack-bitmap-write.c b/pack-bitmap-write.c
index faf67c94d3..cdffe2ce47 100644
--- a/pack-bitmap-write.c
+++ b/pack-bitmap-write.c
@@ -18,6 +18,8 @@
#include "commit-reach.h"
#include "prio-queue.h"
#include "trace2.h"
+#include "tree.h"
+#include "tree-walk.h"
struct bitmapped_commit {
struct commit *commit;
diff --git a/pack-bitmap.c b/pack-bitmap.c
index 295b8abc19..999f962602 100644
--- a/pack-bitmap.c
+++ b/pack-bitmap.c
@@ -381,7 +381,7 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git,
goto cleanup;
}
- if (load_midx_revindex(bitmap_git->midx) < 0) {
+ if (load_midx_revindex(bitmap_git->midx)) {
warning(_("multi-pack bitmap is missing required reverse index"));
goto cleanup;
}
@@ -465,7 +465,7 @@ static int open_pack_bitmap_1(struct bitmap_index *bitmap_git, struct packed_git
return 0;
}
-static int load_reverse_index(struct bitmap_index *bitmap_git)
+static int load_reverse_index(struct repository *r, struct bitmap_index *bitmap_git)
{
if (bitmap_is_midx(bitmap_git)) {
uint32_t i;
@@ -479,23 +479,23 @@ static int load_reverse_index(struct bitmap_index *bitmap_git)
* since we will need to make use of them in pack-objects.
*/
for (i = 0; i < bitmap_git->midx->num_packs; i++) {
- ret = load_pack_revindex(bitmap_git->midx->packs[i]);
+ ret = load_pack_revindex(r, bitmap_git->midx->packs[i]);
if (ret)
return ret;
}
return 0;
}
- return load_pack_revindex(bitmap_git->pack);
+ return load_pack_revindex(r, bitmap_git->pack);
}
-static int load_bitmap(struct bitmap_index *bitmap_git)
+static int load_bitmap(struct repository *r, struct bitmap_index *bitmap_git)
{
assert(bitmap_git->map);
bitmap_git->bitmaps = kh_init_oid_map();
bitmap_git->ext_index.positions = kh_init_oid_pos();
- if (load_reverse_index(bitmap_git))
+ if (load_reverse_index(r, bitmap_git))
goto failed;
if (!(bitmap_git->commits = read_bitmap_1(bitmap_git)) ||
@@ -582,7 +582,7 @@ struct bitmap_index *prepare_bitmap_git(struct repository *r)
{
struct bitmap_index *bitmap_git = xcalloc(1, sizeof(*bitmap_git));
- if (!open_bitmap(r, bitmap_git) && !load_bitmap(bitmap_git))
+ if (!open_bitmap(r, bitmap_git) && !load_bitmap(r, bitmap_git))
return bitmap_git;
free_bitmap_index(bitmap_git);
@@ -591,9 +591,10 @@ struct bitmap_index *prepare_bitmap_git(struct repository *r)
struct bitmap_index *prepare_midx_bitmap_git(struct multi_pack_index *midx)
{
+ struct repository *r = the_repository;
struct bitmap_index *bitmap_git = xcalloc(1, sizeof(*bitmap_git));
- if (!open_midx_bitmap_1(bitmap_git, midx) && !load_bitmap(bitmap_git))
+ if (!open_midx_bitmap_1(bitmap_git, midx) && !load_bitmap(r, bitmap_git))
return bitmap_git;
free_bitmap_index(bitmap_git);
@@ -1594,7 +1595,7 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs,
* from disk. this is the point of no return; after this the rev_list
* becomes invalidated and we must perform the revwalk through bitmaps
*/
- if (load_bitmap(bitmap_git) < 0)
+ if (load_bitmap(revs->repo, bitmap_git) < 0)
goto cleanup;
object_array_clear(&revs->pending);
@@ -1744,6 +1745,7 @@ int reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git,
uint32_t *entries,
struct bitmap **reuse_out)
{
+ struct repository *r = the_repository;
struct packed_git *pack;
struct bitmap *result = bitmap_git->result;
struct bitmap *reuse;
@@ -1754,7 +1756,7 @@ int reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git,
assert(result);
- load_reverse_index(bitmap_git);
+ load_reverse_index(r, bitmap_git);
if (bitmap_is_midx(bitmap_git))
pack = bitmap_git->midx->packs[midx_preferred_pack(bitmap_git)];
@@ -2134,12 +2136,13 @@ int rebuild_bitmap(const uint32_t *reposition,
uint32_t *create_bitmap_mapping(struct bitmap_index *bitmap_git,
struct packing_data *mapping)
{
+ struct repository *r = the_repository;
uint32_t i, num_objects;
uint32_t *reposition;
if (!bitmap_is_midx(bitmap_git))
- load_reverse_index(bitmap_git);
- else if (load_midx_revindex(bitmap_git->midx) < 0)
+ load_reverse_index(r, bitmap_git);
+ else if (load_midx_revindex(bitmap_git->midx))
BUG("rebuild_existing_bitmaps: missing required rev-cache "
"extension");
@@ -2343,3 +2346,48 @@ int bitmap_is_preferred_refname(struct repository *r, const char *refname)
return 0;
}
+
+static int verify_bitmap_file(const char *name)
+{
+ struct stat st;
+ unsigned char *data;
+ int fd = git_open(name);
+ int res = 0;
+
+ /* It is OK to not have the file. */
+ if (fd < 0 || fstat(fd, &st)) {
+ if (fd >= 0)
+ close(fd);
+ return 0;
+ }
+
+ data = xmmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ close(fd);
+ if (!hashfile_checksum_valid(data, st.st_size))
+ res = error(_("bitmap file '%s' has invalid checksum"),
+ name);
+
+ munmap(data, st.st_size);
+ return res;
+}
+
+int verify_bitmap_files(struct repository *r)
+{
+ int res = 0;
+
+ for (struct multi_pack_index *m = get_multi_pack_index(r);
+ m; m = m->next) {
+ char *midx_bitmap_name = midx_bitmap_filename(m);
+ res |= verify_bitmap_file(midx_bitmap_name);
+ free(midx_bitmap_name);
+ }
+
+ for (struct packed_git *p = get_all_packs(r);
+ p; p = p->next) {
+ char *pack_bitmap_name = pack_bitmap_filename(p);
+ res |= verify_bitmap_file(pack_bitmap_name);
+ free(pack_bitmap_name);
+ }
+
+ return res;
+}
diff --git a/pack-bitmap.h b/pack-bitmap.h
index f0180b5276..84591f041b 100644
--- a/pack-bitmap.h
+++ b/pack-bitmap.h
@@ -111,4 +111,6 @@ int bitmap_is_midx(struct bitmap_index *bitmap_git);
const struct string_list *bitmap_preferred_tips(struct repository *r);
int bitmap_is_preferred_refname(struct repository *r, const char *refname);
+int verify_bitmap_files(struct repository *r);
+
#endif
diff --git a/pack-revindex.c b/pack-revindex.c
index 4d9bb41b4d..1f51b712e8 100644
--- a/pack-revindex.c
+++ b/pack-revindex.c
@@ -7,6 +7,7 @@
#include "trace2.h"
#include "config.h"
#include "midx.h"
+#include "csum-file.h"
struct revindex_entry {
off_t offset;
@@ -207,10 +208,14 @@ static int load_revindex_from_disk(char *revindex_name,
size_t revindex_size;
struct revindex_header *hdr;
+ if (git_env_bool(GIT_TEST_REV_INDEX_DIE_ON_DISK, 0))
+ die("dying as requested by '%s'", GIT_TEST_REV_INDEX_DIE_ON_DISK);
+
fd = git_open(revindex_name);
if (fd < 0) {
- ret = -1;
+ /* "No file" means return 1. */
+ ret = 1;
goto cleanup;
}
if (fstat(fd, &st)) {
@@ -262,7 +267,7 @@ cleanup:
return ret;
}
-static int load_pack_revindex_from_disk(struct packed_git *p)
+int load_pack_revindex_from_disk(struct packed_git *p)
{
char *revindex_name;
int ret;
@@ -285,18 +290,58 @@ cleanup:
return ret;
}
-int load_pack_revindex(struct packed_git *p)
+int load_pack_revindex(struct repository *r, struct packed_git *p)
{
if (p->revindex || p->revindex_data)
return 0;
- if (!load_pack_revindex_from_disk(p))
+ prepare_repo_settings(r);
+
+ if (r->settings.pack_read_reverse_index &&
+ !load_pack_revindex_from_disk(p))
return 0;
else if (!create_pack_revindex_in_memory(p))
return 0;
return -1;
}
+/*
+ * verify_pack_revindex verifies that the on-disk rev-index for the given
+ * pack-file is the same that would be created if written from scratch.
+ *
+ * A negative number is returned on error.
+ */
+int verify_pack_revindex(struct packed_git *p)
+{
+ int res = 0;
+
+ /* Do not bother checking if not initialized. */
+ if (!p->revindex_map || !p->revindex_data)
+ return res;
+
+ if (!hashfile_checksum_valid((const unsigned char *)p->revindex_map, p->revindex_size)) {
+ error(_("invalid checksum"));
+ res = -1;
+ }
+
+ /* This may fail due to a broken .idx. */
+ if (create_pack_revindex_in_memory(p))
+ return res;
+
+ for (size_t i = 0; i < p->num_objects; i++) {
+ uint32_t nr = p->revindex[i].nr;
+ uint32_t rev_val = get_be32(p->revindex_data + i);
+
+ if (nr != rev_val) {
+ error(_("invalid rev-index position at %"PRIu64": %"PRIu32" != %"PRIu32""),
+ (uint64_t)i, nr, rev_val);
+ res = -1;
+ }
+ }
+
+ return res;
+}
+
int load_midx_revindex(struct multi_pack_index *m)
{
struct strbuf revindex_name = STRBUF_INIT;
@@ -358,7 +403,7 @@ int offset_to_pack_pos(struct packed_git *p, off_t ofs, uint32_t *pos)
{
unsigned lo, hi;
- if (load_pack_revindex(p) < 0)
+ if (load_pack_revindex(the_repository, p) < 0)
return -1;
lo = 0;
diff --git a/pack-revindex.h b/pack-revindex.h
index 4974e75eb4..6dd47efea1 100644
--- a/pack-revindex.h
+++ b/pack-revindex.h
@@ -34,11 +34,13 @@
#define RIDX_SIGNATURE 0x52494458 /* "RIDX" */
#define RIDX_VERSION 1
-#define GIT_TEST_WRITE_REV_INDEX "GIT_TEST_WRITE_REV_INDEX"
+#define GIT_TEST_NO_WRITE_REV_INDEX "GIT_TEST_NO_WRITE_REV_INDEX"
#define GIT_TEST_REV_INDEX_DIE_IN_MEMORY "GIT_TEST_REV_INDEX_DIE_IN_MEMORY"
+#define GIT_TEST_REV_INDEX_DIE_ON_DISK "GIT_TEST_REV_INDEX_DIE_ON_DISK"
struct packed_git;
struct multi_pack_index;
+struct repository;
/*
* load_pack_revindex populates the revindex's internal data-structures for the
@@ -47,7 +49,23 @@ struct multi_pack_index;
* If a '.rev' file is present it is mmap'd, and pointers are assigned into it
* (instead of using the in-memory variant).
*/
-int load_pack_revindex(struct packed_git *p);
+int load_pack_revindex(struct repository *r, struct packed_git *p);
+
+/*
+ * Specifically load a pack revindex from disk.
+ *
+ * Returns 0 on success, 1 on "no .rev file", and -1 when there is an
+ * error parsing the .rev file.
+ */
+int load_pack_revindex_from_disk(struct packed_git *p);
+
+/*
+ * verify_pack_revindex verifies that the on-disk rev-index for the given
+ * pack-file is the same that would be created if written from scratch.
+ *
+ * A negative number is returned on error.
+ */
+int verify_pack_revindex(struct packed_git *p);
/*
* load_midx_revindex loads the '.rev' file corresponding to the given
diff --git a/pack-write.c b/pack-write.c
index 9c37121be3..3b3ce89de6 100644
--- a/pack-write.c
+++ b/pack-write.c
@@ -314,13 +314,13 @@ static void write_mtimes_trailer(struct hashfile *f, const unsigned char *hash)
hashwrite(f, hash, the_hash_algo->rawsz);
}
-static const char *write_mtimes_file(struct packing_data *to_pack,
- struct pack_idx_entry **objects,
- uint32_t nr_objects,
- const unsigned char *hash)
+static char *write_mtimes_file(struct packing_data *to_pack,
+ struct pack_idx_entry **objects,
+ uint32_t nr_objects,
+ const unsigned char *hash)
{
struct strbuf tmp_file = STRBUF_INIT;
- const char *mtimes_name;
+ char *mtimes_name;
struct hashfile *f;
int fd;
@@ -546,7 +546,7 @@ void stage_tmp_packfiles(struct strbuf *name_buffer,
char **idx_tmp_name)
{
const char *rev_tmp_name = NULL;
- const char *mtimes_tmp_name = NULL;
+ char *mtimes_tmp_name = NULL;
if (adjust_shared_perm(pack_tmp_name))
die_errno("unable to make temporary pack file readable");
@@ -570,6 +570,9 @@ void stage_tmp_packfiles(struct strbuf *name_buffer,
rename_tmp_packfile(name_buffer, rev_tmp_name, "rev");
if (mtimes_tmp_name)
rename_tmp_packfile(name_buffer, mtimes_tmp_name, "mtimes");
+
+ free((char *)rev_tmp_name);
+ free(mtimes_tmp_name);
}
void write_promisor_file(const char *promisor_name, struct ref **sought, int nr_sought)
diff --git a/packfile.c b/packfile.c
index 9ae2278c22..fd083c86e0 100644
--- a/packfile.c
+++ b/packfile.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "alloc.h"
#include "environment.h"
#include "gettext.h"
@@ -2154,7 +2154,7 @@ int for_each_object_in_pack(struct packed_git *p,
int r = 0;
if (flags & FOR_EACH_OBJECT_PACK_ORDER) {
- if (load_pack_revindex(p))
+ if (load_pack_revindex(the_repository, p))
return -1;
}
diff --git a/packfile.h b/packfile.h
index 665603b696..c3692308b8 100644
--- a/packfile.h
+++ b/packfile.h
@@ -6,10 +6,22 @@
/* in object-store.h */
struct packed_git;
-struct pack_entry;
-struct pack_window;
struct object_info;
+struct pack_window {
+ struct pack_window *next;
+ unsigned char *base;
+ off_t offset;
+ size_t len;
+ unsigned int last_used;
+ unsigned int inuse_cnt;
+};
+
+struct pack_entry {
+ off_t offset;
+ struct packed_git *p;
+};
+
/*
* Generate the filename to be used for a pack file with checksum "sha1" and
* extension "ext". The result is written into the strbuf "buf", overwriting
diff --git a/parallel-checkout.c b/parallel-checkout.c
index 50fd7fe31e..69d569f352 100644
--- a/parallel-checkout.c
+++ b/parallel-checkout.c
@@ -3,6 +3,7 @@
#include "config.h"
#include "entry.h"
#include "gettext.h"
+#include "hash.h"
#include "hex.h"
#include "parallel-checkout.h"
#include "pkt-line.h"
@@ -10,6 +11,7 @@
#include "run-command.h"
#include "sigchain.h"
#include "streaming.h"
+#include "symlinks.h"
#include "thread-utils.h"
#include "trace2.h"
#include "wrapper.h"
diff --git a/parse-options-cb.c b/parse-options-cb.c
index 298decf48f..a24521dee0 100644
--- a/parse-options-cb.c
+++ b/parse-options-cb.c
@@ -3,6 +3,7 @@
#include "branch.h"
#include "commit.h"
#include "color.h"
+#include "date.h"
#include "environment.h"
#include "gettext.h"
#include "object-name.h"
diff --git a/parse-options.c b/parse-options.c
index b6803647d0..f8a155ee13 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -5,6 +5,7 @@
#include "commit.h"
#include "color.h"
#include "gettext.h"
+#include "strbuf.h"
#include "utf8.h"
static int disallow_abbreviated_options;
diff --git a/path.c b/path.c
index 7c1cd8182a..e17a2613c5 100644
--- a/path.c
+++ b/path.c
@@ -1213,6 +1213,26 @@ int normalize_path_copy(char *dst, const char *src)
return normalize_path_copy_len(dst, src, NULL);
}
+int strbuf_normalize_path(struct strbuf *src)
+{
+ struct strbuf dst = STRBUF_INIT;
+
+ strbuf_grow(&dst, src->len);
+ if (normalize_path_copy(dst.buf, src->buf) < 0) {
+ strbuf_release(&dst);
+ return -1;
+ }
+
+ /*
+ * normalize_path does not tell us the new length, so we have to
+ * compute it by looking for the new NUL it placed
+ */
+ strbuf_setlen(&dst, strlen(dst.buf));
+ strbuf_swap(src, &dst);
+ strbuf_release(&dst);
+ return 0;
+}
+
/*
* path = Canonical absolute path
* prefixes = string_list containing normalized, absolute paths without
diff --git a/path.h b/path.h
index 60e83a49a9..639372edd9 100644
--- a/path.h
+++ b/path.h
@@ -191,6 +191,11 @@ const char *remove_leading_path(const char *in, const char *prefix);
const char *relative_path(const char *in, const char *prefix, struct strbuf *sb);
int normalize_path_copy_len(char *dst, const char *src, int *prefix_len);
int normalize_path_copy(char *dst, const char *src);
+/**
+ * Normalize in-place the path contained in the strbuf. If an error occurs,
+ * the contents of "sb" are left untouched, and -1 is returned.
+ */
+int strbuf_normalize_path(struct strbuf *src);
int longest_ancestor_length(const char *path, struct string_list *prefixes);
char *strip_path_suffix(const char *path, const char *suffix);
int daemon_avoid_alias(const char *path);
diff --git a/pathspec.c b/pathspec.c
index 6972d515f0..6966b265d3 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -6,8 +6,10 @@
#include "gettext.h"
#include "pathspec.h"
#include "attr.h"
+#include "repository.h"
#include "setup.h"
#include "strvec.h"
+#include "symlinks.h"
#include "quote.h"
/*
@@ -734,7 +736,7 @@ int match_pathspec_attrs(struct index_state *istate,
if (name[namelen])
name = to_free = xmemdupz(name, namelen);
- git_check_attr(istate, NULL, name, item->attr_check);
+ git_check_attr(istate, name, item->attr_check);
free(to_free);
diff --git a/pkt-line.c b/pkt-line.c
index 3561d85358..62b4208b66 100644
--- a/pkt-line.c
+++ b/pkt-line.c
@@ -1,4 +1,5 @@
-#include "cache.h"
+#include "git-compat-util.h"
+#include "copy.h"
#include "pkt-line.h"
#include "gettext.h"
#include "hex.h"
diff --git a/pkt-line.h b/pkt-line.h
index 8e9846f315..7c23a4bfaf 100644
--- a/pkt-line.h
+++ b/pkt-line.h
@@ -246,4 +246,6 @@ void packet_writer_error(struct packet_writer *writer, const char *fmt, ...);
void packet_writer_delim(struct packet_writer *writer);
void packet_writer_flush(struct packet_writer *writer);
+void packet_trace_identity(const char *prog);
+
#endif
diff --git a/preload-index.c b/preload-index.c
index 4abf9c983b..7a26b08c21 100644
--- a/preload-index.c
+++ b/preload-index.c
@@ -11,6 +11,7 @@
#include "progress.h"
#include "thread-utils.h"
#include "repository.h"
+#include "symlinks.h"
#include "trace2.h"
/*
diff --git a/pretty.c b/pretty.c
index 0bb938021b..78bac2d818 100644
--- a/pretty.c
+++ b/pretty.c
@@ -18,6 +18,7 @@
#include "gpg-interface.h"
#include "trailer.h"
#include "run-command.h"
+#include "object-name.h"
/*
* The limit for formatting directives, which enable the caller to append
diff --git a/progress.c b/progress.c
index 72d5e0c73c..f695798aca 100644
--- a/progress.c
+++ b/progress.c
@@ -12,6 +12,7 @@
#include "git-compat-util.h"
#include "pager.h"
#include "progress.h"
+#include "repository.h"
#include "strbuf.h"
#include "trace.h"
#include "trace2.h"
diff --git a/protocol-caps.c b/protocol-caps.c
index 94c51862c5..a90c48852e 100644
--- a/protocol-caps.c
+++ b/protocol-caps.c
@@ -4,7 +4,7 @@
#include "hex.h"
#include "pkt-line.h"
#include "strvec.h"
-#include "hash.h"
+#include "hash-ll.h"
#include "hex.h"
#include "object.h"
#include "object-store.h"
diff --git a/range-diff.c b/range-diff.c
index a1e0cffb9f..6a704e6f47 100644
--- a/range-diff.c
+++ b/range-diff.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "environment.h"
#include "gettext.h"
#include "range-diff.h"
diff --git a/read-cache.c b/read-cache.c
index e919af3c77..f4c31a68c8 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -6,6 +6,7 @@
#include "cache.h"
#include "alloc.h"
#include "config.h"
+#include "date.h"
#include "diff.h"
#include "diffcore.h"
#include "hex.h"
@@ -30,6 +31,7 @@
#include "trace2.h"
#include "varint.h"
#include "split-index.h"
+#include "symlinks.h"
#include "utf8.h"
#include "fsmonitor.h"
#include "thread-utils.h"
@@ -498,87 +500,30 @@ int ie_modified(struct index_state *istate,
return 0;
}
-int base_name_compare(const char *name1, size_t len1, int mode1,
- const char *name2, size_t len2, int mode2)
+static int cache_name_stage_compare(const char *name1, int len1, int stage1,
+ const char *name2, int len2, int stage2)
{
- unsigned char c1, c2;
- size_t len = len1 < len2 ? len1 : len2;
int cmp;
- cmp = memcmp(name1, name2, len);
- if (cmp)
- return cmp;
- c1 = name1[len];
- c2 = name2[len];
- if (!c1 && S_ISDIR(mode1))
- c1 = '/';
- if (!c2 && S_ISDIR(mode2))
- c2 = '/';
- return (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0;
-}
-
-/*
- * df_name_compare() is identical to base_name_compare(), except it
- * compares conflicting directory/file entries as equal. Note that
- * while a directory name compares as equal to a regular file, they
- * then individually compare _differently_ to a filename that has
- * a dot after the basename (because '\0' < '.' < '/').
- *
- * This is used by routines that want to traverse the git namespace
- * but then handle conflicting entries together when possible.
- */
-int df_name_compare(const char *name1, size_t len1, int mode1,
- const char *name2, size_t len2, int mode2)
-{
- unsigned char c1, c2;
- size_t len = len1 < len2 ? len1 : len2;
- int cmp;
-
- cmp = memcmp(name1, name2, len);
+ cmp = name_compare(name1, len1, name2, len2);
if (cmp)
return cmp;
- /* Directories and files compare equal (same length, same name) */
- if (len1 == len2)
- return 0;
- c1 = name1[len];
- if (!c1 && S_ISDIR(mode1))
- c1 = '/';
- c2 = name2[len];
- if (!c2 && S_ISDIR(mode2))
- c2 = '/';
- if (c1 == '/' && !c2)
- return 0;
- if (c2 == '/' && !c1)
- return 0;
- return c1 - c2;
-}
-int name_compare(const char *name1, size_t len1, const char *name2, size_t len2)
-{
- size_t min_len = (len1 < len2) ? len1 : len2;
- int cmp = memcmp(name1, name2, min_len);
- if (cmp)
- return cmp;
- if (len1 < len2)
+ if (stage1 < stage2)
return -1;
- if (len1 > len2)
+ if (stage1 > stage2)
return 1;
return 0;
}
-int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2)
+int cmp_cache_name_compare(const void *a_, const void *b_)
{
- int cmp;
+ const struct cache_entry *ce1, *ce2;
- cmp = name_compare(name1, len1, name2, len2);
- if (cmp)
- return cmp;
-
- if (stage1 < stage2)
- return -1;
- if (stage1 > stage2)
- return 1;
- return 0;
+ ce1 = *((const struct cache_entry **)a_);
+ ce2 = *((const struct cache_entry **)b_);
+ return cache_name_stage_compare(ce1->name, ce1->ce_namelen, ce_stage(ce1),
+ ce2->name, ce2->ce_namelen, ce_stage(ce2));
}
static int index_name_stage_pos(struct index_state *istate,
diff --git a/rebase-interactive.c b/rebase-interactive.c
index 789f407361..f286404d4b 100644
--- a/rebase-interactive.c
+++ b/rebase-interactive.c
@@ -5,6 +5,7 @@
#include "gettext.h"
#include "sequencer.h"
#include "rebase-interactive.h"
+#include "repository.h"
#include "strbuf.h"
#include "commit-slab.h"
#include "config.h"
@@ -71,13 +72,14 @@ void append_todo_help(int command_count,
if (!edit_todo) {
strbuf_addch(buf, '\n');
- strbuf_commented_addf(buf, Q_("Rebase %s onto %s (%d command)",
- "Rebase %s onto %s (%d commands)",
- command_count),
+ strbuf_commented_addf(buf, comment_line_char,
+ Q_("Rebase %s onto %s (%d command)",
+ "Rebase %s onto %s (%d commands)",
+ command_count),
shortrevisions, shortonto, command_count);
}
- strbuf_add_commented_lines(buf, msg, strlen(msg));
+ strbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);
if (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)
msg = _("\nDo not remove any line. Use 'drop' "
@@ -86,7 +88,7 @@ void append_todo_help(int command_count,
msg = _("\nIf you remove a line here "
"THAT COMMIT WILL BE LOST.\n");
- strbuf_add_commented_lines(buf, msg, strlen(msg));
+ strbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);
if (edit_todo)
msg = _("\nYou are editing the todo file "
@@ -97,7 +99,7 @@ void append_todo_help(int command_count,
msg = _("\nHowever, if you remove everything, "
"the rebase will be aborted.\n\n");
- strbuf_add_commented_lines(buf, msg, strlen(msg));
+ strbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);
}
int edit_todo_list(struct repository *r, struct todo_list *todo_list,
@@ -129,7 +131,7 @@ int edit_todo_list(struct repository *r, struct todo_list *todo_list,
if (launch_sequence_editor(todo_file, &new_todo->buf, NULL))
return -2;
- strbuf_stripspace(&new_todo->buf, 1);
+ strbuf_stripspace(&new_todo->buf, comment_line_char);
if (initial && new_todo->buf.len == 0)
return -3;
diff --git a/ref-filter.c b/ref-filter.c
index 10aab14f03..4991cd4f7a 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1,7 +1,8 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "alloc.h"
#include "environment.h"
#include "gettext.h"
+#include "gpg-interface.h"
#include "hex.h"
#include "parse-options.h"
#include "refs.h"
@@ -19,6 +20,7 @@
#include "revision.h"
#include "utf8.h"
#include "version.h"
+#include "versioncmp.h"
#include "trailer.h"
#include "wt-status.h"
#include "commit-slab.h"
diff --git a/reflog.c b/reflog.c
index 9c09443088..ee1bf5d032 100644
--- a/reflog.c
+++ b/reflog.c
@@ -4,6 +4,8 @@
#include "reflog.h"
#include "refs.h"
#include "revision.h"
+#include "tree.h"
+#include "tree-walk.h"
#include "worktree.h"
/* Remember to update object flag allocation in object.h */
diff --git a/refs/debug.c b/refs/debug.c
index adc34c836f..6f11e6de46 100644
--- a/refs/debug.c
+++ b/refs/debug.c
@@ -1,6 +1,7 @@
#include "git-compat-util.h"
#include "hex.h"
#include "refs-internal.h"
+#include "string-list.h"
#include "trace.h"
static struct trace_key trace_refs = TRACE_KEY_INIT(REFS);
diff --git a/refs/files-backend.c b/refs/files-backend.c
index d0581ee41a..bca7b851c5 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -1,7 +1,9 @@
#include "../cache.h"
#include "../config.h"
+#include "../copy.h"
#include "../environment.h"
#include "../gettext.h"
+#include "../hash.h"
#include "../hex.h"
#include "../refs.h"
#include "refs-internal.h"
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index 2333ed5a1f..5b412a133b 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -2,6 +2,7 @@
#include "../alloc.h"
#include "../config.h"
#include "../gettext.h"
+#include "../hash.h"
#include "../hex.h"
#include "../refs.h"
#include "refs-internal.h"
@@ -651,7 +652,7 @@ static struct snapshot *create_snapshot(struct packed_ref_store *refs)
snapshot->buf,
snapshot->eof - snapshot->buf);
- string_list_split_in_place(&traits, p, ' ', -1);
+ string_list_split_in_place(&traits, p, " ", -1);
if (unsorted_string_list_has_string(&traits, "fully-peeled"))
snapshot->peeled = PEELED_FULLY;
diff --git a/refs/ref-cache.c b/refs/ref-cache.c
index dc1ca49c85..2294c4564f 100644
--- a/refs/ref-cache.c
+++ b/refs/ref-cache.c
@@ -1,6 +1,8 @@
#include "../git-compat-util.h"
#include "../alloc.h"
+#include "../hash.h"
#include "../refs.h"
+#include "../repository.h"
#include "refs-internal.h"
#include "ref-cache.h"
#include "../iterator.h"
diff --git a/refs/ref-cache.h b/refs/ref-cache.h
index cf4ad9070b..95c76e27c8 100644
--- a/refs/ref-cache.h
+++ b/refs/ref-cache.h
@@ -1,10 +1,11 @@
#ifndef REFS_REF_CACHE_H
#define REFS_REF_CACHE_H
-#include "hash.h"
+#include "hash-ll.h"
struct ref_dir;
struct ref_store;
+struct repository;
/*
* If this ref_cache is filled lazily, this function is used to load
diff --git a/refspec.c b/refspec.c
index 7b5c305514..57f6c2aaf9 100644
--- a/refspec.c
+++ b/refspec.c
@@ -1,10 +1,12 @@
#include "git-compat-util.h"
#include "alloc.h"
#include "gettext.h"
+#include "hash.h"
#include "hex.h"
#include "strvec.h"
#include "refs.h"
#include "refspec.h"
+#include "strbuf.h"
static struct refspec_item s_tag_refspec = {
.force = 0,
diff --git a/reftable/dump.c b/reftable/dump.c
index 155953d1b8..ce936b4e18 100644
--- a/reftable/dump.c
+++ b/reftable/dump.c
@@ -7,7 +7,7 @@ https://developers.google.com/open-source/licenses/bsd
*/
#include "git-compat-util.h"
-#include "hash.h"
+#include "hash-ll.h"
#include "reftable-blocksource.h"
#include "reftable-error.h"
diff --git a/reftable/error.c b/reftable/error.c
index 93941f2145..0d1766735e 100644
--- a/reftable/error.c
+++ b/reftable/error.c
@@ -6,6 +6,7 @@ license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd
*/
+#include "system.h"
#include "reftable-error.h"
#include <stdio.h>
diff --git a/reftable/publicbasics.c b/reftable/publicbasics.c
index 0ad7d5c0ff..bcb82530d6 100644
--- a/reftable/publicbasics.c
+++ b/reftable/publicbasics.c
@@ -6,10 +6,10 @@ license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd
*/
+#include "system.h"
#include "reftable-malloc.h"
#include "basics.h"
-#include "system.h"
static void *(*reftable_malloc_ptr)(size_t sz);
static void *(*reftable_realloc_ptr)(void *, size_t);
diff --git a/reftable/system.h b/reftable/system.h
index 18f9207dfe..6b74a81514 100644
--- a/reftable/system.h
+++ b/reftable/system.h
@@ -13,7 +13,7 @@ https://developers.google.com/open-source/licenses/bsd
#include "git-compat-util.h"
#include "strbuf.h"
-#include "hash.h" /* hash ID, sizes.*/
+#include "hash-ll.h" /* hash ID, sizes.*/
#include "dir.h" /* remove_dir_recursively, for tests.*/
int hash_size(uint32_t id);
diff --git a/reftable/tree.c b/reftable/tree.c
index b8899e060a..a5bf880985 100644
--- a/reftable/tree.c
+++ b/reftable/tree.c
@@ -6,10 +6,10 @@ license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd
*/
+#include "system.h"
#include "tree.h"
#include "basics.h"
-#include "system.h"
struct tree_node *tree_search(void *key, struct tree_node **rootp,
int (*compare)(const void *, const void *),
diff --git a/reftable/tree_test.c b/reftable/tree_test.c
index cbff125588..ac3a045ad4 100644
--- a/reftable/tree_test.c
+++ b/reftable/tree_test.c
@@ -6,6 +6,7 @@ license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd
*/
+#include "system.h"
#include "tree.h"
#include "basics.h"
diff --git a/repo-settings.c b/repo-settings.c
index 0a6c0b381f..d220c5dd9f 100644
--- a/repo-settings.c
+++ b/repo-settings.c
@@ -41,10 +41,8 @@ void prepare_repo_settings(struct repository *r)
repo_cfg_bool(r, "feature.experimental", &experimental, 0);
/* Defaults modified by feature.* */
- if (experimental) {
+ if (experimental)
r->settings.fetch_negotiation_algorithm = FETCH_NEGOTIATION_SKIPPING;
- r->settings.gc_cruft_packs = 1;
- }
if (manyfiles) {
r->settings.index_version = 4;
r->settings.index_skip_hash = 1;
@@ -63,6 +61,7 @@ void prepare_repo_settings(struct repository *r)
repo_cfg_bool(r, "core.multipackindex", &r->settings.core_multi_pack_index, 1);
repo_cfg_bool(r, "index.sparse", &r->settings.sparse_index, 0);
repo_cfg_bool(r, "index.skiphash", &r->settings.index_skip_hash, r->settings.index_skip_hash);
+ repo_cfg_bool(r, "pack.readreverseindex", &r->settings.pack_read_reverse_index, 1);
/*
* The GIT_TEST_MULTI_PACK_INDEX variable is special in that
diff --git a/repository.h b/repository.h
index 15a8afc5fb..1a13ff2867 100644
--- a/repository.h
+++ b/repository.h
@@ -33,10 +33,10 @@ struct repo_settings {
int commit_graph_generation_version;
int commit_graph_read_changed_paths;
int gc_write_commit_graph;
- int gc_cruft_packs;
int fetch_write_commit_graph;
int command_requires_full_index;
int sparse_index;
+ int pack_read_reverse_index;
struct fsmonitor_settings *fsmonitor; /* lazily loaded */
diff --git a/rerere.c b/rerere.c
index 7abc94bf44..e968d413d6 100644
--- a/rerere.c
+++ b/rerere.c
@@ -2,6 +2,7 @@
#include "abspath.h"
#include "alloc.h"
#include "config.h"
+#include "copy.h"
#include "gettext.h"
#include "hex.h"
#include "lockfile.h"
diff --git a/reset.h b/reset.h
index a28f81829d..10708d8ddc 100644
--- a/reset.h
+++ b/reset.h
@@ -1,7 +1,7 @@
#ifndef RESET_H
#define RESET_H
-#include "hash.h"
+#include "hash-ll.h"
#include "repository.h"
#define GIT_REFLOG_ACTION_ENVIRONMENT "GIT_REFLOG_ACTION"
diff --git a/resolve-undo.c b/resolve-undo.c
index e81096e2d4..70a6db526d 100644
--- a/resolve-undo.c
+++ b/resolve-undo.c
@@ -1,5 +1,6 @@
#include "cache.h"
#include "dir.h"
+#include "hash.h"
#include "resolve-undo.h"
#include "string-list.h"
diff --git a/resolve-undo.h b/resolve-undo.h
index d1ea972771..c5deafc92f 100644
--- a/resolve-undo.h
+++ b/resolve-undo.h
@@ -6,7 +6,7 @@ struct index_state;
struct pathspec;
struct string_list;
-#include "hash.h"
+#include "hash-ll.h"
struct resolve_undo_info {
unsigned int mode[3];
diff --git a/revision.h b/revision.h
index e8f6de9684..31828748dc 100644
--- a/revision.h
+++ b/revision.h
@@ -7,6 +7,7 @@
#include "pretty.h"
#include "diff.h"
#include "commit-slab-decl.h"
+#include "decorate.h"
#include "ident.h"
#include "list-objects-filter-options.h"
diff --git a/run-command.c b/run-command.c
index e64bb08a5b..60c9419866 100644
--- a/run-command.c
+++ b/run-command.c
@@ -5,6 +5,7 @@
#include "gettext.h"
#include "sigchain.h"
#include "strvec.h"
+#include "symlinks.h"
#include "thread-utils.h"
#include "strbuf.h"
#include "string-list.h"
@@ -15,6 +16,7 @@
#include "packfile.h"
#include "hook.h"
#include "compat/nonblock.h"
+#include "alloc.h"
void child_process_init(struct child_process *child)
{
diff --git a/send-pack.c b/send-pack.c
index 2089143555..0c7ccaef68 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -1,6 +1,7 @@
#include "git-compat-util.h"
#include "config.h"
#include "commit.h"
+#include "date.h"
#include "gettext.h"
#include "hex.h"
#include "refs.h"
diff --git a/sequencer.c b/sequencer.c
index c88d1d9553..c9f8b5d4ba 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -3,6 +3,7 @@
#include "advice.h"
#include "alloc.h"
#include "config.h"
+#include "copy.h"
#include "environment.h"
#include "gettext.h"
#include "hex.h"
@@ -659,11 +660,12 @@ void append_conflicts_hint(struct index_state *istate,
}
strbuf_addch(msgbuf, '\n');
- strbuf_commented_addf(msgbuf, "Conflicts:\n");
+ strbuf_commented_addf(msgbuf, comment_line_char, "Conflicts:\n");
for (i = 0; i < istate->cache_nr;) {
const struct cache_entry *ce = istate->cache[i++];
if (ce_stage(ce)) {
- strbuf_commented_addf(msgbuf, "\t%s\n", ce->name);
+ strbuf_commented_addf(msgbuf, comment_line_char,
+ "\t%s\n", ce->name);
while (i < istate->cache_nr &&
!strcmp(ce->name, istate->cache[i]->name))
i++;
@@ -1142,7 +1144,8 @@ void cleanup_message(struct strbuf *msgbuf,
cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
strbuf_setlen(msgbuf, wt_status_locate_end(msgbuf->buf, msgbuf->len));
if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
- strbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
+ strbuf_stripspace(msgbuf,
+ cleanup_mode == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\0');
}
/*
@@ -1173,7 +1176,8 @@ int template_untouched(const struct strbuf *sb, const char *template_file,
if (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)
return 0;
- strbuf_stripspace(&tmpl, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
+ strbuf_stripspace(&tmpl,
+ cleanup_mode == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\0');
if (!skip_prefix(sb->buf, tmpl.buf, &start))
start = sb->buf;
strbuf_release(&tmpl);
@@ -1545,7 +1549,8 @@ static int try_to_commit(struct repository *r,
cleanup = opts->default_msg_cleanup;
if (cleanup != COMMIT_MSG_CLEANUP_NONE)
- strbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL);
+ strbuf_stripspace(msg,
+ cleanup == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\0');
if ((flags & EDIT_MSG) && message_is_empty(msg, cleanup)) {
res = 1; /* run 'git commit' to display error message */
goto out;
@@ -1839,7 +1844,7 @@ static void add_commented_lines(struct strbuf *buf, const void *str, size_t len)
s += count;
len -= count;
}
- strbuf_add_commented_lines(buf, s, len);
+ strbuf_add_commented_lines(buf, s, len, comment_line_char);
}
/* Does the current fixup chain contain a squash command? */
@@ -1938,7 +1943,7 @@ static int append_squash_message(struct strbuf *buf, const char *body,
strbuf_addf(buf, _(nth_commit_msg_fmt),
++opts->current_fixup_count + 1);
strbuf_addstr(buf, "\n\n");
- strbuf_add_commented_lines(buf, body, commented_len);
+ strbuf_add_commented_lines(buf, body, commented_len, comment_line_char);
/* buf->buf may be reallocated so store an offset into the buffer */
fixup_off = buf->len;
strbuf_addstr(buf, body + commented_len);
@@ -2028,7 +2033,8 @@ static int update_squash_messages(struct repository *r,
_(first_commit_msg_str));
strbuf_addstr(&buf, "\n\n");
if (is_fixup_flag(command, flag))
- strbuf_add_commented_lines(&buf, body, strlen(body));
+ strbuf_add_commented_lines(&buf, body, strlen(body),
+ comment_line_char);
else
strbuf_addstr(&buf, body);
@@ -2047,7 +2053,8 @@ static int update_squash_messages(struct repository *r,
strbuf_addf(&buf, _(skip_nth_commit_msg_fmt),
++opts->current_fixup_count + 1);
strbuf_addstr(&buf, "\n\n");
- strbuf_add_commented_lines(&buf, body, strlen(body));
+ strbuf_add_commented_lines(&buf, body, strlen(body),
+ comment_line_char);
} else
return error(_("unknown command: %d"), command);
repo_unuse_commit_buffer(r, commit, message);
@@ -3625,14 +3632,14 @@ static int do_exec(struct repository *r, const char *command_line)
" git rebase --continue\n"
"\n"),
command_line,
- dirty ? N_("and made changes to the index and/or the "
- "working tree\n") : "");
+ dirty ? _("and made changes to the index and/or the "
+ "working tree.\n") : "");
if (status == 127)
/* command not found */
status = 1;
} else if (dirty) {
warning(_("execution succeeded: %s\nbut "
- "left changes to the index and/or the working tree\n"
+ "left changes to the index and/or the working tree.\n"
"Commit or stash your changes, and then run\n"
"\n"
" git rebase --continue\n"
diff --git a/server-info.c b/server-info.c
index 68098ddd1a..55aa04f00a 100644
--- a/server-info.c
+++ b/server-info.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "alloc.h"
#include "dir.h"
#include "environment.h"
@@ -11,6 +11,7 @@
#include "packfile.h"
#include "object-file.h"
#include "object-store.h"
+#include "server-info.h"
#include "strbuf.h"
#include "wrapper.h"
diff --git a/server-info.h b/server-info.h
new file mode 100644
index 0000000000..13bbde2c55
--- /dev/null
+++ b/server-info.h
@@ -0,0 +1,7 @@
+#ifndef SERVER_INFO_H
+#define SERVER_INFO_H
+
+/* Dumb servers support */
+int update_server_info(int);
+
+#endif /* SERVER_INFO_H */
diff --git a/setup.c b/setup.c
index 59abc16ba6..458582207e 100644
--- a/setup.c
+++ b/setup.c
@@ -1352,6 +1352,7 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
}
if (is_git_directory(dir->buf)) {
+ trace2_data_string("setup", NULL, "implicit-bare-repository", dir->buf);
if (get_allowed_bare_repo() == ALLOWED_BARE_REPO_EXPLICIT)
return GIT_DIR_DISALLOWED_BARE;
if (!ensure_valid_ownership(NULL, NULL, dir->buf, report))
diff --git a/split-index.c b/split-index.c
index 5602b74994..40e54760b3 100644
--- a/split-index.c
+++ b/split-index.c
@@ -1,8 +1,10 @@
#include "cache.h"
#include "alloc.h"
#include "gettext.h"
+#include "hash.h"
#include "mem-pool.h"
#include "split-index.h"
+#include "strbuf.h"
#include "ewah/ewok.h"
struct split_index *init_split_index(struct index_state *istate)
diff --git a/split-index.h b/split-index.h
index 1a153f47ba..15a29cd08c 100644
--- a/split-index.h
+++ b/split-index.h
@@ -1,7 +1,7 @@
#ifndef SPLIT_INDEX_H
#define SPLIT_INDEX_H
-#include "hash.h"
+#include "hash-ll.h"
struct index_state;
struct strbuf;
diff --git a/strbuf.c b/strbuf.c
index 729378ec82..b38d32325d 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -1,11 +1,9 @@
#include "git-compat-util.h"
-#include "abspath.h"
#include "alloc.h"
-#include "environment.h"
#include "gettext.h"
#include "hex.h"
-#include "object-name.h"
-#include "refs.h"
+#include "repository.h"
+#include "strbuf.h"
#include "string-list.h"
#include "utf8.h"
#include "date.h"
@@ -364,7 +362,8 @@ static void add_lines(struct strbuf *out,
strbuf_complete_line(out);
}
-void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size)
+void strbuf_add_commented_lines(struct strbuf *out, const char *buf,
+ size_t size, char comment_line_char)
{
static char prefix1[3];
static char prefix2[2];
@@ -376,7 +375,8 @@ void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size
add_lines(out, prefix1, prefix2, buf, size);
}
-void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)
+void strbuf_commented_addf(struct strbuf *sb, char comment_line_char,
+ const char *fmt, ...)
{
va_list params;
struct strbuf buf = STRBUF_INIT;
@@ -386,7 +386,7 @@ void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)
strbuf_vaddf(&buf, fmt, params);
va_end(params);
- strbuf_add_commented_lines(sb, buf.buf, buf.len);
+ strbuf_add_commented_lines(sb, buf.buf, buf.len, comment_line_char);
if (incomplete_line)
sb->buf[--sb->len] = '\0';
@@ -810,25 +810,6 @@ void strbuf_addstr_xml_quoted(struct strbuf *buf, const char *s)
}
}
-int is_rfc3986_reserved_or_unreserved(char ch)
-{
- if (is_rfc3986_unreserved(ch))
- return 1;
- switch (ch) {
- case '!': case '*': case '\'': case '(': case ')': case ';':
- case ':': case '@': case '&': case '=': case '+': case '$':
- case ',': case '/': case '?': case '#': case '[': case ']':
- return 1;
- }
- return 0;
-}
-
-int is_rfc3986_unreserved(char ch)
-{
- return isalnum(ch) ||
- ch == '-' || ch == '_' || ch == '.' || ch == '~';
-}
-
static void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len,
char_predicate allow_unencoded_fn)
{
@@ -899,42 +880,6 @@ void strbuf_humanise_rate(struct strbuf *buf, off_t bytes)
strbuf_humanise(buf, bytes, 1);
}
-void strbuf_add_absolute_path(struct strbuf *sb, const char *path)
-{
- if (!*path)
- die("The empty string is not a valid path");
- if (!is_absolute_path(path)) {
- struct stat cwd_stat, pwd_stat;
- size_t orig_len = sb->len;
- char *cwd = xgetcwd();
- char *pwd = getenv("PWD");
- if (pwd && strcmp(pwd, cwd) &&
- !stat(cwd, &cwd_stat) &&
- (cwd_stat.st_dev || cwd_stat.st_ino) &&
- !stat(pwd, &pwd_stat) &&
- pwd_stat.st_dev == cwd_stat.st_dev &&
- pwd_stat.st_ino == cwd_stat.st_ino)
- strbuf_addstr(sb, pwd);
- else
- strbuf_addstr(sb, cwd);
- if (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1]))
- strbuf_addch(sb, '/');
- free(cwd);
- }
- strbuf_addstr(sb, path);
-}
-
-void strbuf_add_real_path(struct strbuf *sb, const char *path)
-{
- if (sb->len) {
- struct strbuf resolved = STRBUF_INIT;
- strbuf_realpath(&resolved, path, 1);
- strbuf_addbuf(sb, &resolved);
- strbuf_release(&resolved);
- } else
- strbuf_realpath(sb, path, 1);
-}
-
int printf_ln(const char *fmt, ...)
{
int ret;
@@ -1079,21 +1024,6 @@ void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm,
strbuf_setlen(sb, sb->len + len);
}
-void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,
- const struct object_id *oid, int abbrev_len)
-{
- int r;
- strbuf_grow(sb, GIT_MAX_HEXSZ + 1);
- r = repo_find_unique_abbrev_r(repo, sb->buf + sb->len, oid, abbrev_len);
- strbuf_setlen(sb, sb->len + r);
-}
-
-void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,
- int abbrev_len)
-{
- strbuf_repo_add_unique_abbrev(sb, the_repository, oid, abbrev_len);
-}
-
/*
* Returns the length of a line, without trailing spaces.
*
@@ -1123,10 +1053,10 @@ static size_t cleanup(char *line, size_t len)
*
* If last line does not have a newline at the end, one is added.
*
- * Enable skip_comments to skip every line starting with comment
- * character.
+ * Pass a non-NUL comment_line_char to skip every line starting
+ * with it.
*/
-void strbuf_stripspace(struct strbuf *sb, int skip_comments)
+void strbuf_stripspace(struct strbuf *sb, char comment_line_char)
{
size_t empties = 0;
size_t i, j, len, newlen;
@@ -1139,7 +1069,8 @@ void strbuf_stripspace(struct strbuf *sb, int skip_comments)
eol = memchr(sb->buf + i, '\n', sb->len - i);
len = eol ? eol - (sb->buf + i) + 1 : sb->len - i;
- if (skip_comments && len && sb->buf[i] == comment_line_char) {
+ if (comment_line_char && len &&
+ sb->buf[i] == comment_line_char) {
newlen = 0;
continue;
}
@@ -1160,26 +1091,6 @@ void strbuf_stripspace(struct strbuf *sb, int skip_comments)
strbuf_setlen(sb, j);
}
-int strbuf_normalize_path(struct strbuf *src)
-{
- struct strbuf dst = STRBUF_INIT;
-
- strbuf_grow(&dst, src->len);
- if (normalize_path_copy(dst.buf, src->buf) < 0) {
- strbuf_release(&dst);
- return -1;
- }
-
- /*
- * normalize_path does not tell us the new length, so we have to
- * compute it by looking for the new NUL it placed
- */
- strbuf_setlen(&dst, strlen(dst.buf));
- strbuf_swap(src, &dst);
- strbuf_release(&dst);
- return 0;
-}
-
void strbuf_strip_file_from_path(struct strbuf *sb)
{
char *path_sep = find_last_dir_sep(sb->buf);
diff --git a/strbuf.h b/strbuf.h
index 3dfeadb44c..da91c17257 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -1,6 +1,14 @@
#ifndef STRBUF_H
#define STRBUF_H
+/*
+ * NOTE FOR STRBUF DEVELOPERS
+ *
+ * strbuf is a low-level primitive; as such it should interact only
+ * with other low-level primitives. Do not introduce new functions
+ * which interact with higher-level APIs.
+ */
+
struct string_list;
/**
@@ -283,7 +291,8 @@ void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
* by a comment character and a blank.
*/
void strbuf_add_commented_lines(struct strbuf *out,
- const char *buf, size_t size);
+ const char *buf, size_t size,
+ char comment_line_char);
/**
@@ -412,8 +421,8 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
* Add a formatted string prepended by a comment character and a
* blank to the buffer.
*/
-__attribute__((format (printf, 2, 3)))
-void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...);
+__attribute__((format (printf, 3, 4)))
+void strbuf_commented_addf(struct strbuf *sb, char comment_line_char, const char *fmt, ...);
__attribute__((format (printf,2,0)))
void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);
@@ -528,28 +537,6 @@ int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term);
int strbuf_getcwd(struct strbuf *sb);
/**
- * Add a path to a buffer, converting a relative path to an
- * absolute one in the process. Symbolic links are not
- * resolved.
- */
-void strbuf_add_absolute_path(struct strbuf *sb, const char *path);
-
-/**
- * Canonize `path` (make it absolute, resolve symlinks, remove extra
- * slashes) and append it to `sb`. Die with an informative error
- * message if there is a problem.
- *
- * The directory part of `path` (i.e., everything up to the last
- * dir_sep) must denote a valid, existing directory, but the last
- * component need not exist.
- *
- * Callers that don't mind links should use the more lightweight
- * strbuf_add_absolute_path() instead.
- */
-void strbuf_add_real_path(struct strbuf *sb, const char *path);
-
-
-/**
* Normalize in-place the path contained in the strbuf. See
* normalize_path_copy() for details. If an error occurs, the contents of "sb"
* are left untouched, and -1 is returned.
@@ -557,10 +544,11 @@ void strbuf_add_real_path(struct strbuf *sb, const char *path);
int strbuf_normalize_path(struct strbuf *sb);
/**
- * Strip whitespace from a buffer. The second parameter controls if
- * comments are considered contents to be removed or not.
+ * Strip whitespace from a buffer. If comment_line_char is non-NUL,
+ * then lines beginning with that character are considered comments,
+ * thus removed.
*/
-void strbuf_stripspace(struct strbuf *buf, int skip_comments);
+void strbuf_stripspace(struct strbuf *buf, char comment_line_char);
static inline int strbuf_strip_suffix(struct strbuf *sb, const char *suffix)
{
@@ -630,16 +618,6 @@ void strbuf_add_separated_string_list(struct strbuf *str,
*/
void strbuf_list_free(struct strbuf **list);
-/**
- * Add the abbreviation, as generated by repo_find_unique_abbrev(), of `sha1` to
- * the strbuf `sb`.
- */
-struct repository;
-void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,
- const struct object_id *oid, int abbrev_len);
-void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,
- int abbrev_len);
-
/*
* Remove the filename from the provided path string. If the path
* contains a trailing separator, then the path is considered a directory
@@ -704,9 +682,6 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
typedef int (*char_predicate)(char ch);
-int is_rfc3986_unreserved(char ch);
-int is_rfc3986_reserved_or_unreserved(char ch);
-
void strbuf_addstr_urlencode(struct strbuf *sb, const char *name,
char_predicate allow_unencoded_fn);
diff --git a/string-list.c b/string-list.c
index db473f273e..0f8ac117fd 100644
--- a/string-list.c
+++ b/string-list.c
@@ -203,6 +203,15 @@ void string_list_clear_func(struct string_list *list, string_list_clear_func_t c
list->nr = list->alloc = 0;
}
+void string_list_setlen(struct string_list *list, size_t nr)
+{
+ if (list->strdup_strings)
+ BUG("cannot setlen a string_list which owns its entries");
+ if (nr > list->nr)
+ BUG("cannot grow a string_list with setlen");
+ list->nr = nr;
+}
+
struct string_list_item *string_list_append_nodup(struct string_list *list,
char *string)
{
@@ -301,7 +310,7 @@ int string_list_split(struct string_list *list, const char *string,
}
int string_list_split_in_place(struct string_list *list, char *string,
- int delim, int maxsplit)
+ const char *delim, int maxsplit)
{
int count = 0;
char *p = string, *end;
@@ -315,7 +324,7 @@ int string_list_split_in_place(struct string_list *list, char *string,
string_list_append(list, p);
return count;
}
- end = strchr(p, delim);
+ end = strpbrk(p, delim);
if (end) {
*end = '\0';
string_list_append(list, p);
diff --git a/string-list.h b/string-list.h
index c7b0d5d000..122b318641 100644
--- a/string-list.h
+++ b/string-list.h
@@ -134,6 +134,16 @@ typedef void (*string_list_clear_func_t)(void *p, const char *str);
/** Call a custom clear function on each util pointer */
void string_list_clear_func(struct string_list *list, string_list_clear_func_t clearfunc);
+/*
+ * Set the length of a string_list to `nr`, provided that (a) `list`
+ * does not own its own storage, and (b) that `nr` is no larger than
+ * `list->nr`.
+ *
+ * Useful when "shrinking" `list` to write over existing entries that
+ * are no longer used without reallocating.
+ */
+void string_list_setlen(struct string_list *list, size_t nr);
+
/**
* Apply `func` to each item. If `func` returns nonzero, the
* iteration aborts and the return value is propagated.
@@ -270,5 +280,5 @@ int string_list_split(struct string_list *list, const char *string,
* list->strdup_strings must *not* be set.
*/
int string_list_split_in_place(struct string_list *list, char *string,
- int delim, int maxsplit);
+ const char *delim, int maxsplit);
#endif /* STRING_LIST_H */
diff --git a/submodule-config.c b/submodule-config.c
index 7fc0812b64..58dfbde9ae 100644
--- a/submodule-config.c
+++ b/submodule-config.c
@@ -12,6 +12,7 @@
#include "object-name.h"
#include "object-store.h"
#include "parse-options.h"
+#include "thread-utils.h"
#include "tree-walk.h"
/*
diff --git a/symlinks.c b/symlinks.c
index 27ecc93693..b29e340c2d 100644
--- a/symlinks.c
+++ b/symlinks.c
@@ -1,6 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "gettext.h"
#include "setup.h"
+#include "symlinks.h"
static int threaded_check_leading_path(struct cache_def *cache, const char *name,
int len, int warn_on_lstat_err);
diff --git a/symlinks.h b/symlinks.h
new file mode 100644
index 0000000000..7ae3d5b856
--- /dev/null
+++ b/symlinks.h
@@ -0,0 +1,28 @@
+#ifndef SYMLINKS_H
+#define SYMLINKS_H
+
+#include "strbuf.h"
+
+struct cache_def {
+ struct strbuf path;
+ int flags;
+ int track_flags;
+ int prefix_len_stat_func;
+};
+#define CACHE_DEF_INIT { \
+ .path = STRBUF_INIT, \
+}
+static inline void cache_def_clear(struct cache_def *cache)
+{
+ strbuf_release(&cache->path);
+}
+
+int has_symlink_leading_path(const char *name, int len);
+int threaded_has_symlink_leading_path(struct cache_def *, const char *, int);
+int check_leading_path(const char *name, int len, int warn_on_lstat_err);
+int has_dirs_only_path(const char *name, int len, int prefix_len);
+void invalidate_lstat_cache(void);
+void schedule_dir_for_removal(const char *name, int len);
+void remove_scheduled_dirs(void);
+
+#endif /* SYMLINKS_H */
diff --git a/t/README b/t/README
index 29576c3748..bdfac4cceb 100644
--- a/t/README
+++ b/t/README
@@ -475,7 +475,7 @@ GIT_TEST_DEFAULT_HASH=<hash-algo> specifies which hash algorithm to
use in the test scripts. Recognized values for <hash-algo> are "sha1"
and "sha256".
-GIT_TEST_WRITE_REV_INDEX=<boolean>, when true enables the
+GIT_TEST_NO_WRITE_REV_INDEX=<boolean>, when true disables the
'pack.writeReverseIndex' setting.
GIT_TEST_SPARSE_INDEX=<boolean>, when true enables index writes to use the
diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh
index b35be20cf3..2ef70235b1 100644
--- a/t/annotate-tests.sh
+++ b/t/annotate-tests.sh
@@ -72,6 +72,13 @@ test_expect_success 'blame 1 author' '
check_count A 2
'
+test_expect_success 'blame working copy' '
+ test_when_finished "git restore file" &&
+ echo "1A quick brown fox jumps over the" >file &&
+ echo "another lazy dog" >>file &&
+ check_count A 1 "Not Committed Yet" 1
+'
+
test_expect_success 'blame with --contents' '
check_count --contents=file A 2
'
@@ -79,7 +86,7 @@ test_expect_success 'blame with --contents' '
test_expect_success 'blame with --contents changed' '
echo "1A quick brown fox jumps over the" >contents &&
echo "another lazy dog" >>contents &&
- check_count --contents=contents A 1 "Not Committed Yet" 1
+ check_count --contents=contents A 1 "External file (--contents)" 1
'
test_expect_success 'blame in a bare repo without starting commit' '
@@ -109,7 +116,7 @@ test_expect_success 'blame 2 authors' '
'
test_expect_success 'blame with --contents and revision' '
- check_count -h testTag --contents=file A 2 "Not Committed Yet" 2
+ check_count -h testTag --contents=file A 2 "External file (--contents)" 2
'
test_expect_success 'setup B1 lines (branch1)' '
diff --git a/t/helper/test-bloom.c b/t/helper/test-bloom.c
index d2b30d644d..aabe31d724 100644
--- a/t/helper/test-bloom.c
+++ b/t/helper/test-bloom.c
@@ -2,6 +2,7 @@
#include "bloom.h"
#include "hex.h"
#include "commit.h"
+#include "repository.h"
#include "setup.h"
static struct bloom_filter_settings settings = DEFAULT_BLOOM_FILTER_SETTINGS;
diff --git a/t/helper/test-cache-tree.c b/t/helper/test-cache-tree.c
index cdaf5046f5..9507b356e2 100644
--- a/t/helper/test-cache-tree.c
+++ b/t/helper/test-cache-tree.c
@@ -6,6 +6,7 @@
#include "tree.h"
#include "cache-tree.h"
#include "parse-options.h"
+#include "repository.h"
#include "setup.h"
static char const * const test_cache_tree_usage[] = {
diff --git a/t/helper/test-ctype.c b/t/helper/test-ctype.c
index 71a1a5c9b0..e5659df40b 100644
--- a/t/helper/test-ctype.c
+++ b/t/helper/test-ctype.c
@@ -27,6 +27,8 @@ static int is_in(const char *s, int ch)
if (is_in(s, i) != t(i)) \
report_error(#t, i); \
} \
+ if (t(EOF)) \
+ report_error(#t, EOF); \
}
#define DIGIT "0123456789"
diff --git a/t/helper/test-dump-cache-tree.c b/t/helper/test-dump-cache-tree.c
index 2041ca1857..f22f7bd84a 100644
--- a/t/helper/test-dump-cache-tree.c
+++ b/t/helper/test-dump-cache-tree.c
@@ -1,9 +1,11 @@
#define USE_THE_INDEX_VARIABLE
#include "test-tool.h"
#include "cache.h"
+#include "hash.h"
#include "hex.h"
#include "tree.h"
#include "cache-tree.h"
+#include "repository.h"
#include "setup.h"
static void dump_one(struct cache_tree *it, const char *pfx, const char *x)
diff --git a/t/helper/test-dump-fsmonitor.c b/t/helper/test-dump-fsmonitor.c
index 7c6f50158b..9a098a25cb 100644
--- a/t/helper/test-dump-fsmonitor.c
+++ b/t/helper/test-dump-fsmonitor.c
@@ -1,5 +1,6 @@
#include "test-tool.h"
#include "cache.h"
+#include "repository.h"
#include "setup.h"
int cmd__dump_fsmonitor(int ac UNUSED, const char **av UNUSED)
diff --git a/t/helper/test-dump-untracked-cache.c b/t/helper/test-dump-untracked-cache.c
index 9225ced534..df70be549f 100644
--- a/t/helper/test-dump-untracked-cache.c
+++ b/t/helper/test-dump-untracked-cache.c
@@ -3,6 +3,7 @@
#include "cache.h"
#include "dir.h"
#include "hex.h"
+#include "repository.h"
#include "setup.h"
static int compare_untracked(const void *a_, const void *b_)
diff --git a/t/helper/test-example-decorate.c b/t/helper/test-example-decorate.c
index 2cf302ffcb..2ed910adaa 100644
--- a/t/helper/test-example-decorate.c
+++ b/t/helper/test-example-decorate.c
@@ -2,6 +2,7 @@
#include "git-compat-util.h"
#include "object.h"
#include "decorate.h"
+#include "repository.h"
int cmd__example_decorate(int argc UNUSED, const char **argv UNUSED)
{
diff --git a/t/helper/test-fsmonitor-client.c b/t/helper/test-fsmonitor-client.c
index 14522b4c47..9f18c685b7 100644
--- a/t/helper/test-fsmonitor-client.c
+++ b/t/helper/test-fsmonitor-client.c
@@ -7,6 +7,7 @@
#include "cache.h"
#include "parse-options.h"
#include "fsmonitor-ipc.h"
+#include "repository.h"
#include "setup.h"
#include "thread-utils.h"
#include "trace2.h"
diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c
index 36ff07bd4b..0eb0b3d49c 100644
--- a/t/helper/test-hashmap.c
+++ b/t/helper/test-hashmap.c
@@ -2,6 +2,7 @@
#include "git-compat-util.h"
#include "hashmap.h"
#include "strbuf.h"
+#include "string-list.h"
struct test_entry
{
@@ -150,6 +151,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
*/
int cmd__hashmap(int argc, const char **argv)
{
+ struct string_list parts = STRING_LIST_INIT_NODUP;
struct strbuf line = STRBUF_INIT;
int icase;
struct hashmap map = HASHMAP_INIT(test_entry_cmp, &icase);
@@ -159,21 +161,26 @@ int cmd__hashmap(int argc, const char **argv)
/* process commands from stdin */
while (strbuf_getline(&line, stdin) != EOF) {
- char *cmd, *p1 = NULL, *p2 = NULL;
+ char *cmd, *p1, *p2;
unsigned int hash = 0;
struct test_entry *entry;
/* break line into command and up to two parameters */
- cmd = strtok(line.buf, DELIM);
+ string_list_setlen(&parts, 0);
+ string_list_split_in_place(&parts, line.buf, DELIM, 2);
+ string_list_remove_empty_items(&parts, 0);
+
/* ignore empty lines */
- if (!cmd || *cmd == '#')
+ if (!parts.nr)
+ continue;
+ if (!*parts.items[0].string || *parts.items[0].string == '#')
continue;
- p1 = strtok(NULL, DELIM);
- if (p1) {
+ cmd = parts.items[0].string;
+ p1 = parts.nr >= 1 ? parts.items[1].string : NULL;
+ p2 = parts.nr >= 2 ? parts.items[2].string : NULL;
+ if (p1)
hash = icase ? strihash(p1) : strhash(p1);
- p2 = strtok(NULL, DELIM);
- }
if (!strcmp("add", cmd) && p1 && p2) {
@@ -260,6 +267,7 @@ int cmd__hashmap(int argc, const char **argv)
}
}
+ string_list_clear(&parts, 0);
strbuf_release(&line);
hashmap_clear_and_free(&map, struct test_entry, ent);
return 0;
diff --git a/t/helper/test-json-writer.c b/t/helper/test-json-writer.c
index 86887f5320..afe393f597 100644
--- a/t/helper/test-json-writer.c
+++ b/t/helper/test-json-writer.c
@@ -1,5 +1,6 @@
#include "test-tool.h"
#include "json-writer.h"
+#include "string-list.h"
static const char *expect_obj1 = "{\"a\":\"abc\",\"b\":42,\"c\":true}";
static const char *expect_obj2 = "{\"a\":-1,\"b\":2147483647,\"c\":0}";
@@ -394,35 +395,41 @@ static int unit_tests(void)
return 0;
}
-static void get_s(int line_nr, char **s_in)
+struct line {
+ struct string_list *parts;
+ size_t consumed_nr;
+ int nr;
+};
+
+static void get_s(struct line *line, char **s_in)
{
- *s_in = strtok(NULL, " ");
- if (!*s_in)
- die("line[%d]: expected: <s>", line_nr);
+ if (line->consumed_nr > line->parts->nr)
+ die("line[%d]: expected: <s>", line->nr);
+ *s_in = line->parts->items[line->consumed_nr++].string;
}
-static void get_i(int line_nr, intmax_t *s_in)
+static void get_i(struct line *line, intmax_t *s_in)
{
char *s;
char *endptr;
- get_s(line_nr, &s);
+ get_s(line, &s);
*s_in = strtol(s, &endptr, 10);
if (*endptr || errno == ERANGE)
- die("line[%d]: invalid integer value", line_nr);
+ die("line[%d]: invalid integer value", line->nr);
}
-static void get_d(int line_nr, double *s_in)
+static void get_d(struct line *line, double *s_in)
{
char *s;
char *endptr;
- get_s(line_nr, &s);
+ get_s(line, &s);
*s_in = strtod(s, &endptr);
if (*endptr || errno == ERANGE)
- die("line[%d]: invalid float value", line_nr);
+ die("line[%d]: invalid float value", line->nr);
}
static int pretty;
@@ -453,6 +460,7 @@ static char *get_trimmed_line(char *buf, int buf_size)
static int scripted(void)
{
+ struct string_list parts = STRING_LIST_INIT_NODUP;
struct json_writer jw = JSON_WRITER_INIT;
char buf[MAX_LINE_LENGTH];
char *line;
@@ -470,66 +478,77 @@ static int scripted(void)
die("expected first line to be 'object' or 'array'");
while ((line = get_trimmed_line(buf, MAX_LINE_LENGTH)) != NULL) {
+ struct line state = { 0 };
char *verb;
char *key;
char *s_value;
intmax_t i_value;
double d_value;
- line_nr++;
+ state.parts = &parts;
+ state.nr = ++line_nr;
+
+ /* break line into command and zero or more tokens */
+ string_list_setlen(&parts, 0);
+ string_list_split_in_place(&parts, line, " ", -1);
+ string_list_remove_empty_items(&parts, 0);
+
+ /* ignore empty lines */
+ if (!parts.nr || !*parts.items[0].string)
+ continue;
- verb = strtok(line, " ");
+ verb = parts.items[state.consumed_nr++].string;
if (!strcmp(verb, "end")) {
jw_end(&jw);
}
else if (!strcmp(verb, "object-string")) {
- get_s(line_nr, &key);
- get_s(line_nr, &s_value);
+ get_s(&state, &key);
+ get_s(&state, &s_value);
jw_object_string(&jw, key, s_value);
}
else if (!strcmp(verb, "object-int")) {
- get_s(line_nr, &key);
- get_i(line_nr, &i_value);
+ get_s(&state, &key);
+ get_i(&state, &i_value);
jw_object_intmax(&jw, key, i_value);
}
else if (!strcmp(verb, "object-double")) {
- get_s(line_nr, &key);
- get_i(line_nr, &i_value);
- get_d(line_nr, &d_value);
+ get_s(&state, &key);
+ get_i(&state, &i_value);
+ get_d(&state, &d_value);
jw_object_double(&jw, key, i_value, d_value);
}
else if (!strcmp(verb, "object-true")) {
- get_s(line_nr, &key);
+ get_s(&state, &key);
jw_object_true(&jw, key);
}
else if (!strcmp(verb, "object-false")) {
- get_s(line_nr, &key);
+ get_s(&state, &key);
jw_object_false(&jw, key);
}
else if (!strcmp(verb, "object-null")) {
- get_s(line_nr, &key);
+ get_s(&state, &key);
jw_object_null(&jw, key);
}
else if (!strcmp(verb, "object-object")) {
- get_s(line_nr, &key);
+ get_s(&state, &key);
jw_object_inline_begin_object(&jw, key);
}
else if (!strcmp(verb, "object-array")) {
- get_s(line_nr, &key);
+ get_s(&state, &key);
jw_object_inline_begin_array(&jw, key);
}
else if (!strcmp(verb, "array-string")) {
- get_s(line_nr, &s_value);
+ get_s(&state, &s_value);
jw_array_string(&jw, s_value);
}
else if (!strcmp(verb, "array-int")) {
- get_i(line_nr, &i_value);
+ get_i(&state, &i_value);
jw_array_intmax(&jw, i_value);
}
else if (!strcmp(verb, "array-double")) {
- get_i(line_nr, &i_value);
- get_d(line_nr, &d_value);
+ get_i(&state, &i_value);
+ get_d(&state, &d_value);
jw_array_double(&jw, i_value, d_value);
}
else if (!strcmp(verb, "array-true"))
@@ -552,6 +571,7 @@ static int scripted(void)
printf("%s\n", jw.json.buf);
jw_release(&jw);
+ string_list_clear(&parts, 0);
return 0;
}
diff --git a/t/helper/test-lazy-init-name-hash.c b/t/helper/test-lazy-init-name-hash.c
index f23d983c11..b83a75d19f 100644
--- a/t/helper/test-lazy-init-name-hash.c
+++ b/t/helper/test-lazy-init-name-hash.c
@@ -3,6 +3,7 @@
#include "cache.h"
#include "environment.h"
#include "parse-options.h"
+#include "repository.h"
#include "setup.h"
#include "trace.h"
diff --git a/t/helper/test-match-trees.c b/t/helper/test-match-trees.c
index 35a2b8005c..d0db5ff26f 100644
--- a/t/helper/test-match-trees.c
+++ b/t/helper/test-match-trees.c
@@ -1,7 +1,8 @@
#include "test-tool.h"
-#include "cache.h"
#include "hex.h"
+#include "match-trees.h"
#include "object-name.h"
+#include "repository.h"
#include "setup.h"
#include "tree.h"
diff --git a/t/helper/test-mergesort.c b/t/helper/test-mergesort.c
index 737e0c5235..42ccc87051 100644
--- a/t/helper/test-mergesort.c
+++ b/t/helper/test-mergesort.c
@@ -1,7 +1,7 @@
#include "test-tool.h"
-#include "cache.h"
#include "mem-pool.h"
#include "mergesort.h"
+#include "strbuf.h"
static uint32_t minstd_rand(uint32_t *state)
{
diff --git a/t/helper/test-oid-array.c b/t/helper/test-oid-array.c
index 30e1947b90..eef68833b7 100644
--- a/t/helper/test-oid-array.c
+++ b/t/helper/test-oid-array.c
@@ -1,8 +1,8 @@
#include "test-tool.h"
-#include "cache.h"
#include "hex.h"
#include "oid-array.h"
#include "setup.h"
+#include "strbuf.h"
static int print_oid(const struct object_id *oid, void *data)
{
diff --git a/t/helper/test-oidmap.c b/t/helper/test-oidmap.c
index 1b0e7eecb4..bd30244a54 100644
--- a/t/helper/test-oidmap.c
+++ b/t/helper/test-oidmap.c
@@ -2,8 +2,10 @@
#include "hex.h"
#include "object-name.h"
#include "oidmap.h"
+#include "repository.h"
#include "setup.h"
#include "strbuf.h"
+#include "string-list.h"
/* key is an oid and value is a name (could be a refname for example) */
struct test_entry {
@@ -25,6 +27,7 @@ struct test_entry {
*/
int cmd__oidmap(int argc UNUSED, const char **argv UNUSED)
{
+ struct string_list parts = STRING_LIST_INIT_NODUP;
struct strbuf line = STRBUF_INIT;
struct oidmap map = OIDMAP_INIT;
@@ -35,19 +38,24 @@ int cmd__oidmap(int argc UNUSED, const char **argv UNUSED)
/* process commands from stdin */
while (strbuf_getline(&line, stdin) != EOF) {
- char *cmd, *p1 = NULL, *p2 = NULL;
+ char *cmd, *p1, *p2;
struct test_entry *entry;
struct object_id oid;
/* break line into command and up to two parameters */
- cmd = strtok(line.buf, DELIM);
+ string_list_setlen(&parts, 0);
+ string_list_split_in_place(&parts, line.buf, DELIM, 2);
+ string_list_remove_empty_items(&parts, 0);
+
/* ignore empty lines */
- if (!cmd || *cmd == '#')
+ if (!parts.nr)
+ continue;
+ if (!*parts.items[0].string || *parts.items[0].string == '#')
continue;
- p1 = strtok(NULL, DELIM);
- if (p1)
- p2 = strtok(NULL, DELIM);
+ cmd = parts.items[0].string;
+ p1 = parts.nr >= 1 ? parts.items[1].string : NULL;
+ p2 = parts.nr >= 2 ? parts.items[2].string : NULL;
if (!strcmp("put", cmd) && p1 && p2) {
@@ -108,6 +116,7 @@ int cmd__oidmap(int argc UNUSED, const char **argv UNUSED)
}
}
+ string_list_clear(&parts, 0);
strbuf_release(&line);
oidmap_free(&map, 1);
return 0;
diff --git a/t/helper/test-oidtree.c b/t/helper/test-oidtree.c
index 5b98f2f70a..c7a1d4c642 100644
--- a/t/helper/test-oidtree.c
+++ b/t/helper/test-oidtree.c
@@ -1,8 +1,8 @@
#include "test-tool.h"
-#include "cache.h"
#include "hex.h"
#include "oidtree.h"
#include "setup.h"
+#include "strbuf.h"
static enum cb_next print_oid(const struct object_id *oid, void *data UNUSED)
{
diff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c
index b66039e575..00fa281a9c 100644
--- a/t/helper/test-parse-options.c
+++ b/t/helper/test-parse-options.c
@@ -1,6 +1,6 @@
#include "test-tool.h"
-#include "cache.h"
#include "parse-options.h"
+#include "strbuf.h"
#include "string-list.h"
#include "trace2.h"
diff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c
index 6355c9e4b6..2ef53d5f7a 100644
--- a/t/helper/test-path-utils.c
+++ b/t/helper/test-path-utils.c
@@ -2,6 +2,7 @@
#include "cache.h"
#include "abspath.h"
#include "environment.h"
+#include "path.h"
#include "setup.h"
#include "string-list.h"
#include "trace.h"
diff --git a/t/helper/test-read-cache.c b/t/helper/test-read-cache.c
index a4c24d0e42..c1ae276395 100644
--- a/t/helper/test-read-cache.c
+++ b/t/helper/test-read-cache.c
@@ -2,6 +2,7 @@
#include "test-tool.h"
#include "cache.h"
#include "config.h"
+#include "repository.h"
#include "setup.h"
#include "wrapper.h"
diff --git a/t/helper/test-read-midx.c b/t/helper/test-read-midx.c
index 05c4f2b262..211addaa00 100644
--- a/t/helper/test-read-midx.c
+++ b/t/helper/test-read-midx.c
@@ -1,10 +1,10 @@
#include "test-tool.h"
-#include "cache.h"
#include "hex.h"
#include "midx.h"
#include "repository.h"
#include "object-store.h"
#include "pack-bitmap.h"
+#include "packfile.h"
#include "setup.h"
static int read_midx_file(const char *object_dir, int show_objects)
diff --git a/t/helper/test-reftable.c b/t/helper/test-reftable.c
index 1f0a28cbb6..00237ef0d9 100644
--- a/t/helper/test-reftable.c
+++ b/t/helper/test-reftable.c
@@ -1,3 +1,4 @@
+#include "reftable/system.h"
#include "reftable/reftable-tests.h"
#include "test-tool.h"
diff --git a/t/helper/test-scrap-cache-tree.c b/t/helper/test-scrap-cache-tree.c
index 3fecd06d17..6e17f50d22 100644
--- a/t/helper/test-scrap-cache-tree.c
+++ b/t/helper/test-scrap-cache-tree.c
@@ -2,6 +2,7 @@
#include "test-tool.h"
#include "cache.h"
#include "lockfile.h"
+#include "repository.h"
#include "setup.h"
#include "tree.h"
#include "cache-tree.h"
diff --git a/t/helper/test-string-list.c b/t/helper/test-string-list.c
index 2123dda85b..e2aad611d1 100644
--- a/t/helper/test-string-list.c
+++ b/t/helper/test-string-list.c
@@ -1,5 +1,5 @@
#include "test-tool.h"
-#include "cache.h"
+#include "strbuf.h"
#include "string-list.h"
/*
@@ -62,7 +62,7 @@ int cmd__string_list(int argc, const char **argv)
struct string_list list = STRING_LIST_INIT_NODUP;
int i;
char *s = xstrdup(argv[2]);
- int delim = *argv[3];
+ const char *delim = argv[3];
int maxsplit = atoi(argv[4]);
i = string_list_split_in_place(&list, s, delim, maxsplit);
@@ -111,7 +111,7 @@ int cmd__string_list(int argc, const char **argv)
*/
if (sb.len && sb.buf[sb.len - 1] == '\n')
strbuf_setlen(&sb, sb.len - 1);
- string_list_split_in_place(&list, sb.buf, '\n', -1);
+ string_list_split_in_place(&list, sb.buf, "\n", -1);
string_list_sort(&list);
diff --git a/t/helper/test-submodule-config.c b/t/helper/test-submodule-config.c
index 5e462faa9d..9df2f03ac8 100644
--- a/t/helper/test-submodule-config.c
+++ b/t/helper/test-submodule-config.c
@@ -1,6 +1,8 @@
#include "test-tool.h"
#include "config.h"
+#include "hash.h"
#include "object-name.h"
+#include "repository.h"
#include "setup.h"
#include "submodule-config.h"
#include "submodule.h"
diff --git a/t/helper/test-submodule-nested-repo-config.c b/t/helper/test-submodule-nested-repo-config.c
index d31f5e48ab..ecd40ded99 100644
--- a/t/helper/test-submodule-nested-repo-config.c
+++ b/t/helper/test-submodule-nested-repo-config.c
@@ -1,4 +1,5 @@
#include "test-tool.h"
+#include "repository.h"
#include "setup.h"
#include "submodule-config.h"
diff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c
index 7cbd59922a..356e0a26c5 100644
--- a/t/helper/test-submodule.c
+++ b/t/helper/test-submodule.c
@@ -2,6 +2,7 @@
#include "test-tool-utils.h"
#include "parse-options.h"
#include "remote.h"
+#include "repository.h"
#include "setup.h"
#include "submodule-config.h"
#include "submodule.h"
diff --git a/t/helper/test-trace2.c b/t/helper/test-trace2.c
index 98f071452a..20c7495f38 100644
--- a/t/helper/test-trace2.c
+++ b/t/helper/test-trace2.c
@@ -3,6 +3,7 @@
#include "run-command.h"
#include "exec-cmd.h"
#include "config.h"
+#include "repository.h"
#include "trace2.h"
typedef int(fn_unit_test)(int argc, const char **argv);
diff --git a/t/helper/test-write-cache.c b/t/helper/test-write-cache.c
index a93417ed3a..eace08072d 100644
--- a/t/helper/test-write-cache.c
+++ b/t/helper/test-write-cache.c
@@ -2,6 +2,7 @@
#include "test-tool.h"
#include "cache.h"
#include "lockfile.h"
+#include "repository.h"
#include "setup.h"
int cmd__write_cache(int argc, const char **argv)
diff --git a/t/lib-credential.sh b/t/lib-credential.sh
index 5ea8bc9f1d..f1ab92ba35 100644
--- a/t/lib-credential.sh
+++ b/t/lib-credential.sh
@@ -43,6 +43,7 @@ helper_test_clean() {
reject $1 https example.com store-user
reject $1 https example.com user1
reject $1 https example.com user2
+ reject $1 https example.com user4
reject $1 http path.tld user
reject $1 https timeout.tld user
reject $1 https sso.tld
@@ -270,6 +271,35 @@ helper_test() {
password=
EOF
'
+
+ : ${GIT_TEST_LONG_CRED_BUFFER:=1024}
+ # 23 bytes accounts for "wwwauth[]=basic realm=" plus NUL
+ LONG_VALUE_LEN=$((GIT_TEST_LONG_CRED_BUFFER - 23))
+ LONG_VALUE=$(perl -e 'print "a" x shift' $LONG_VALUE_LEN)
+
+ test_expect_success "helper ($HELPER) not confused by long header" '
+ check approve $HELPER <<-\EOF &&
+ protocol=https
+ host=victim.example.com
+ username=user
+ password=to-be-stolen
+ EOF
+
+ check fill $HELPER <<-EOF
+ protocol=https
+ host=badguy.example.com
+ wwwauth[]=basic realm=${LONG_VALUE}host=victim.example.com
+ --
+ protocol=https
+ host=badguy.example.com
+ username=askpass-username
+ password=askpass-password
+ wwwauth[]=basic realm=${LONG_VALUE}host=victim.example.com
+ --
+ askpass: Username for '\''https://badguy.example.com'\'':
+ askpass: Password for '\''https://askpass-username@badguy.example.com'\'':
+ EOF
+ '
}
helper_test_timeout() {
@@ -298,6 +328,35 @@ helper_test_timeout() {
'
}
+helper_test_oauth_refresh_token() {
+ HELPER=$1
+
+ test_expect_success "helper ($HELPER) stores oauth_refresh_token" '
+ check approve $HELPER <<-\EOF
+ protocol=https
+ host=example.com
+ username=user4
+ password=pass
+ oauth_refresh_token=xyzzy
+ EOF
+ '
+
+ test_expect_success "helper ($HELPER) gets oauth_refresh_token" '
+ check fill $HELPER <<-\EOF
+ protocol=https
+ host=example.com
+ username=user4
+ --
+ protocol=https
+ host=example.com
+ username=user4
+ password=pass
+ oauth_refresh_token=xyzzy
+ --
+ EOF
+ '
+}
+
write_script askpass <<\EOF
echo >&2 askpass: $*
what=$(echo $1 | cut -d" " -f1 | tr A-Z a-z | tr -cd a-z)
diff --git a/t/lib-diff-alternative.sh b/t/lib-diff-alternative.sh
index a8f5d3274a..c4dc2d46dc 100644
--- a/t/lib-diff-alternative.sh
+++ b/t/lib-diff-alternative.sh
@@ -112,15 +112,36 @@ EOF
STRATEGY=$1
- test_expect_success "$STRATEGY diff from attributes" '
+ test_expect_success "setup attributes files for tests with $STRATEGY" '
+ git checkout -b master &&
echo "file* diff=driver" >.gitattributes &&
- git config diff.driver.algorithm "$STRATEGY" &&
- test_must_fail git diff --no-index file1 file2 > output &&
- cat expect &&
- cat output &&
+ git add file1 file2 .gitattributes &&
+ git commit -m "adding files" &&
+ git checkout -b branchA &&
+ echo "file* diff=driverA" >.gitattributes &&
+ git add .gitattributes &&
+ git commit -m "adding driverA as diff driver" &&
+ git checkout master &&
+ git clone --bare --no-local . bare.git
+ '
+
+ test_expect_success "$STRATEGY diff from attributes" '
+ test_must_fail git -c diff.driver.algorithm=$STRATEGY diff --no-index file1 file2 > output &&
test_cmp expect output
'
+ test_expect_success "diff from attributes with bare repo with source" '
+ git -C bare.git --attr-source=branchA -c diff.driver.algorithm=myers \
+ -c diff.driverA.algorithm=$STRATEGY \
+ diff HEAD:file1 HEAD:file2 >output &&
+ test_cmp expect output
+ '
+
+ test_expect_success "diff from attributes with bare repo with invalid source" '
+ test_must_fail git -C bare.git --attr-source=invalid-branch diff \
+ HEAD:file1 HEAD:file2
+ '
+
test_expect_success "$STRATEGY diff from attributes has valid diffstat" '
echo "file* diff=driver" >.gitattributes &&
git config diff.driver.algorithm "$STRATEGY" &&
diff --git a/t/perf/p2000-sparse-operations.sh b/t/perf/p2000-sparse-operations.sh
index 60d1de0662..901cc493ef 100755
--- a/t/perf/p2000-sparse-operations.sh
+++ b/t/perf/p2000-sparse-operations.sh
@@ -129,5 +129,7 @@ test_perf_on_all git grep --cached bogus -- "f2/f1/f1/*"
test_perf_on_all git write-tree
test_perf_on_all git describe --dirty
test_perf_on_all 'echo >>new && git describe --dirty'
+test_perf_on_all git diff-files
+test_perf_on_all git diff-files -- $SPARSE_CONE/a
test_done
diff --git a/t/perf/p5312-pack-bitmaps-revs.sh b/t/perf/p5312-pack-bitmaps-revs.sh
index 0684b690af..ceec60656b 100755
--- a/t/perf/p5312-pack-bitmaps-revs.sh
+++ b/t/perf/p5312-pack-bitmaps-revs.sh
@@ -12,8 +12,7 @@ test_lookup_pack_bitmap () {
test_perf_large_repo
test_expect_success 'setup bitmap config' '
- git config pack.writebitmaps true &&
- git config pack.writeReverseIndex true
+ git config pack.writebitmaps true
'
# we need to create the tag up front such that it is covered by the repack and
diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh
index 89b306cb11..26e082f05b 100755
--- a/t/t0003-attributes.sh
+++ b/t/t0003-attributes.sh
@@ -30,8 +30,17 @@ attr_check_quote () {
attr_check_source () {
path="$1" expect="$2" source="$3" git_opts="$4" &&
- git $git_opts check-attr --source $source test -- "$path" >actual 2>err &&
echo "$path: test: $expect" >expect &&
+
+ git $git_opts check-attr --source $source test -- "$path" >actual 2>err &&
+ test_cmp expect actual &&
+ test_must_be_empty err &&
+
+ git $git_opts --attr-source="$source" check-attr test -- "$path" >actual 2>err &&
+ test_cmp expect actual &&
+ test_must_be_empty err
+
+ GIT_ATTR_SOURCE="$source" git $git_opts check-attr test -- "$path" >actual 2>err &&
test_cmp expect actual &&
test_must_be_empty err
}
diff --git a/t/t0020-crlf.sh b/t/t0020-crlf.sh
index 35cc8c3b39..81946e87cc 100755
--- a/t/t0020-crlf.sh
+++ b/t/t0020-crlf.sh
@@ -125,7 +125,7 @@ test_expect_success 'update with autocrlf=input' '
munge_cr append dir/two &&
git update-index -- one dir/two &&
differs=$(git diff-index --cached HEAD) &&
- verbose test -z "$differs"
+ test -z "$differs"
'
@@ -138,7 +138,7 @@ test_expect_success 'update with autocrlf=true' '
munge_cr append dir/two &&
git update-index -- one dir/two &&
differs=$(git diff-index --cached HEAD) &&
- verbose test -z "$differs"
+ test -z "$differs"
'
@@ -153,7 +153,7 @@ test_expect_success 'checkout with autocrlf=true' '
test "$one" = $(git hash-object --stdin <one) &&
test "$two" = $(git hash-object --stdin <dir/two) &&
differs=$(git diff-index --cached HEAD) &&
- verbose test -z "$differs"
+ test -z "$differs"
'
test_expect_success 'checkout with autocrlf=input' '
@@ -167,7 +167,7 @@ test_expect_success 'checkout with autocrlf=input' '
test "$one" = $(git hash-object --stdin <one) &&
test "$two" = $(git hash-object --stdin <dir/two) &&
differs=$(git diff-index --cached HEAD) &&
- verbose test -z "$differs"
+ test -z "$differs"
'
test_expect_success 'apply patch (autocrlf=input)' '
@@ -177,7 +177,7 @@ test_expect_success 'apply patch (autocrlf=input)' '
git read-tree --reset -u HEAD &&
git apply patch.file &&
- verbose test "$patched" = "$(git hash-object --stdin <one)"
+ test "$patched" = "$(git hash-object --stdin <one)"
'
test_expect_success 'apply patch --cached (autocrlf=input)' '
@@ -187,7 +187,7 @@ test_expect_success 'apply patch --cached (autocrlf=input)' '
git read-tree --reset -u HEAD &&
git apply --cached patch.file &&
- verbose test "$patched" = $(git rev-parse :one)
+ test "$patched" = $(git rev-parse :one)
'
test_expect_success 'apply patch --index (autocrlf=input)' '
@@ -197,8 +197,8 @@ test_expect_success 'apply patch --index (autocrlf=input)' '
git read-tree --reset -u HEAD &&
git apply --index patch.file &&
- verbose test "$patched" = $(git rev-parse :one) &&
- verbose test "$patched" = $(git hash-object --stdin <one)
+ test "$patched" = $(git rev-parse :one) &&
+ test "$patched" = $(git hash-object --stdin <one)
'
test_expect_success 'apply patch (autocrlf=true)' '
@@ -208,7 +208,7 @@ test_expect_success 'apply patch (autocrlf=true)' '
git read-tree --reset -u HEAD &&
git apply patch.file &&
- verbose test "$patched" = "$(remove_cr <one | git hash-object --stdin)"
+ test "$patched" = "$(remove_cr <one | git hash-object --stdin)"
'
test_expect_success 'apply patch --cached (autocrlf=true)' '
@@ -218,7 +218,7 @@ test_expect_success 'apply patch --cached (autocrlf=true)' '
git read-tree --reset -u HEAD &&
git apply --cached patch.file &&
- verbose test "$patched" = $(git rev-parse :one)
+ test "$patched" = $(git rev-parse :one)
'
test_expect_success 'apply patch --index (autocrlf=true)' '
@@ -228,8 +228,8 @@ test_expect_success 'apply patch --index (autocrlf=true)' '
git read-tree --reset -u HEAD &&
git apply --index patch.file &&
- verbose test "$patched" = $(git rev-parse :one) &&
- verbose test "$patched" = "$(remove_cr <one | git hash-object --stdin)"
+ test "$patched" = $(git rev-parse :one) &&
+ test "$patched" = "$(remove_cr <one | git hash-object --stdin)"
'
test_expect_success '.gitattributes says two is binary' '
@@ -240,7 +240,7 @@ test_expect_success '.gitattributes says two is binary' '
git read-tree --reset -u HEAD &&
! has_cr dir/two &&
- verbose has_cr one &&
+ has_cr one &&
! has_cr three
'
@@ -259,8 +259,8 @@ test_expect_success '.gitattributes says two and three are text' '
echo "t* crlf" >.gitattributes &&
git read-tree --reset -u HEAD &&
- verbose has_cr dir/two &&
- verbose has_cr three
+ has_cr dir/two &&
+ has_cr three
'
test_expect_success 'in-tree .gitattributes (1)' '
@@ -273,7 +273,7 @@ test_expect_success 'in-tree .gitattributes (1)' '
git read-tree --reset -u HEAD &&
! has_cr one &&
- verbose has_cr three
+ has_cr three
'
test_expect_success 'in-tree .gitattributes (2)' '
@@ -283,7 +283,7 @@ test_expect_success 'in-tree .gitattributes (2)' '
git checkout-index -f -q -u -a &&
! has_cr one &&
- verbose has_cr three
+ has_cr three
'
test_expect_success 'in-tree .gitattributes (3)' '
@@ -294,7 +294,7 @@ test_expect_success 'in-tree .gitattributes (3)' '
git checkout-index -u one dir/two three &&
! has_cr one &&
- verbose has_cr three
+ has_cr three
'
test_expect_success 'in-tree .gitattributes (4)' '
@@ -305,7 +305,7 @@ test_expect_success 'in-tree .gitattributes (4)' '
git checkout-index -u .gitattributes &&
! has_cr one &&
- verbose has_cr three
+ has_cr three
'
test_expect_success 'checkout with existing .gitattributes' '
diff --git a/t/t0035-safe-bare-repository.sh b/t/t0035-safe-bare-repository.sh
index 11c15a48aa..038b8b788d 100755
--- a/t/t0035-safe-bare-repository.sh
+++ b/t/t0035-safe-bare-repository.sh
@@ -7,13 +7,26 @@ TEST_PASSES_SANITIZE_LEAK=true
pwd="$(pwd)"
-expect_accepted () {
- git "$@" rev-parse --git-dir
+expect_accepted_implicit () {
+ test_when_finished 'rm "$pwd/trace.perf"' &&
+ GIT_TRACE2_PERF="$pwd/trace.perf" git "$@" rev-parse --git-dir &&
+ # Note: we're intentionally only checking that the bare repo has a
+ # directory *prefix* of $pwd
+ grep -F "implicit-bare-repository:$pwd" "$pwd/trace.perf"
+}
+
+expect_accepted_explicit () {
+ test_when_finished 'rm "$pwd/trace.perf"' &&
+ GIT_DIR="$1" GIT_TRACE2_PERF="$pwd/trace.perf" git rev-parse --git-dir &&
+ ! grep -F "implicit-bare-repository:$pwd" "$pwd/trace.perf"
}
expect_rejected () {
- test_must_fail git "$@" rev-parse --git-dir 2>err &&
- grep -F "cannot use bare repository" err
+ test_when_finished 'rm "$pwd/trace.perf"' &&
+ test_env GIT_TRACE2_PERF="$pwd/trace.perf" \
+ test_must_fail git "$@" rev-parse --git-dir 2>err &&
+ grep -F "cannot use bare repository" err &&
+ grep -F "implicit-bare-repository:$pwd" "$pwd/trace.perf"
}
test_expect_success 'setup bare repo in worktree' '
@@ -22,12 +35,13 @@ test_expect_success 'setup bare repo in worktree' '
'
test_expect_success 'safe.bareRepository unset' '
- expect_accepted -C outer-repo/bare-repo
+ test_unconfig --global safe.bareRepository &&
+ expect_accepted_implicit -C outer-repo/bare-repo
'
test_expect_success 'safe.bareRepository=all' '
test_config_global safe.bareRepository all &&
- expect_accepted -C outer-repo/bare-repo
+ expect_accepted_implicit -C outer-repo/bare-repo
'
test_expect_success 'safe.bareRepository=explicit' '
@@ -47,7 +61,7 @@ test_expect_success 'safe.bareRepository in the repository' '
test_expect_success 'safe.bareRepository on the command line' '
test_config_global safe.bareRepository explicit &&
- expect_accepted -C outer-repo/bare-repo \
+ expect_accepted_implicit -C outer-repo/bare-repo \
-c safe.bareRepository=all
'
@@ -60,4 +74,8 @@ test_expect_success 'safe.bareRepository in included file' '
expect_rejected -C outer-repo/bare-repo
'
+test_expect_success 'no trace when GIT_DIR is explicitly provided' '
+ expect_accepted_explicit "$pwd/outer-repo/bare-repo"
+'
+
test_done
diff --git a/t/t0063-string-list.sh b/t/t0063-string-list.sh
index 46d4839194..1fee6d9010 100755
--- a/t/t0063-string-list.sh
+++ b/t/t0063-string-list.sh
@@ -18,6 +18,14 @@ test_split () {
"
}
+test_split_in_place() {
+ cat >expected &&
+ test_expect_success "split (in place) $1 at $2, max $3" "
+ test-tool string-list split_in_place '$1' '$2' '$3' >actual &&
+ test_cmp expected actual
+ "
+}
+
test_split "foo:bar:baz" ":" "-1" <<EOF
3
[0]: "foo"
@@ -61,6 +69,49 @@ test_split ":" ":" "-1" <<EOF
[1]: ""
EOF
+test_split_in_place "foo:;:bar:;:baz:;:" ":;" "-1" <<EOF
+10
+[0]: "foo"
+[1]: ""
+[2]: ""
+[3]: "bar"
+[4]: ""
+[5]: ""
+[6]: "baz"
+[7]: ""
+[8]: ""
+[9]: ""
+EOF
+
+test_split_in_place "foo:;:bar:;:baz" ":;" "0" <<EOF
+1
+[0]: "foo:;:bar:;:baz"
+EOF
+
+test_split_in_place "foo:;:bar:;:baz" ":;" "1" <<EOF
+2
+[0]: "foo"
+[1]: ";:bar:;:baz"
+EOF
+
+test_split_in_place "foo:;:bar:;:baz" ":;" "2" <<EOF
+3
+[0]: "foo"
+[1]: ""
+[2]: ":bar:;:baz"
+EOF
+
+test_split_in_place "foo:;:bar:;:" ":;" "-1" <<EOF
+7
+[0]: "foo"
+[1]: ""
+[2]: ""
+[3]: "bar"
+[4]: ""
+[5]: ""
+[6]: ""
+EOF
+
test_expect_success "test filter_string_list" '
test "x-" = "x$(test-tool string-list filter - y)" &&
test "x-" = "x$(test-tool string-list filter no y)" &&
diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh
index c66d91e82d..a4f5bba507 100755
--- a/t/t0300-credentials.sh
+++ b/t/t0300-credentials.sh
@@ -214,6 +214,24 @@ test_expect_success 'credential_approve stores password expiry' '
EOF
'
+test_expect_success 'credential_approve stores oauth refresh token' '
+ check approve useless <<-\EOF
+ protocol=http
+ host=example.com
+ username=foo
+ password=bar
+ oauth_refresh_token=xyzzy
+ --
+ --
+ useless: store
+ useless: protocol=http
+ useless: host=example.com
+ useless: username=foo
+ useless: password=bar
+ useless: oauth_refresh_token=xyzzy
+ EOF
+'
+
test_expect_success 'do not bother storing password-less credential' '
check approve useless <<-\EOF
protocol=http
@@ -808,7 +826,7 @@ test_expect_success 'credential config with partial URLs' '
git -c credential.$partial.helper=yep \
-c credential.with%0anewline.username=uh-oh \
- credential fill <stdin >stdout 2>stderr &&
+ credential fill <stdin 2>stderr &&
test_i18ngrep "skipping credential lookup for key" stderr
'
diff --git a/t/t0301-credential-cache.sh b/t/t0301-credential-cache.sh
index 698b7159f0..c02a3b5969 100755
--- a/t/t0301-credential-cache.sh
+++ b/t/t0301-credential-cache.sh
@@ -29,6 +29,7 @@ test_atexit 'git credential-cache exit'
# test that the daemon works with no special setup
helper_test cache
+helper_test_oauth_refresh_token cache
test_expect_success 'socket defaults to ~/.cache/git/credential/socket' '
test_when_finished "
diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh
index 0c784813f1..e58bfbfcb4 100755
--- a/t/t1092-sparse-checkout-compatibility.sh
+++ b/t/t1092-sparse-checkout-compatibility.sh
@@ -1377,7 +1377,7 @@ test_expect_success 'index.sparse disabled inline uses full index' '
! test_region index ensure_full_index trace2.txt
'
-ensure_not_expanded () {
+run_sparse_index_trace2 () {
rm -f trace2.txt &&
if test -z "$WITHOUT_UNTRACKED_TXT"
then
@@ -1397,7 +1397,16 @@ ensure_not_expanded () {
git -C sparse-index "$@" \
>sparse-index-out \
2>sparse-index-error || return 1
- fi &&
+ fi
+}
+
+ensure_expanded () {
+ run_sparse_index_trace2 "$@" &&
+ test_region index ensure_full_index trace2.txt
+}
+
+ensure_not_expanded () {
+ run_sparse_index_trace2 "$@" &&
test_region ! index ensure_full_index trace2.txt
}
@@ -2108,4 +2117,57 @@ test_expect_success 'sparse-index is not expanded: write-tree' '
ensure_not_expanded write-tree
'
+test_expect_success 'diff-files with pathspec inside sparse definition' '
+ init_repos &&
+
+ write_script edit-contents <<-\EOF &&
+ echo text >>"$1"
+ EOF
+
+ run_on_all ../edit-contents deep/a &&
+
+ test_all_match git diff-files &&
+
+ test_all_match git diff-files -- deep/a &&
+
+ # test wildcard
+ test_all_match git diff-files -- "deep/*"
+'
+
+test_expect_success 'diff-files with pathspec outside sparse definition' '
+ init_repos &&
+
+ test_sparse_match git diff-files -- folder2/a &&
+
+ write_script edit-contents <<-\EOF &&
+ echo text >>"$1"
+ EOF
+
+ # The directory "folder1" is outside the cone of interest
+ # and will not exist in the sparse checkout repositories.
+ # Create it as needed, add file "folder1/a" there with
+ # contents that is different from the staged version.
+ run_on_all mkdir -p folder1 &&
+ run_on_all cp a folder1/a &&
+
+ run_on_all ../edit-contents folder1/a &&
+ test_all_match git diff-files &&
+ test_all_match git diff-files -- folder1/a &&
+ test_all_match git diff-files -- "folder*/a"
+'
+
+test_expect_success 'sparse index is not expanded: diff-files' '
+ init_repos &&
+
+ write_script edit-contents <<-\EOF &&
+ echo text >>"$1"
+ EOF
+
+ run_on_all ../edit-contents deep/a &&
+
+ ensure_not_expanded diff-files &&
+ ensure_not_expanded diff-files -- deep/a &&
+ ensure_not_expanded diff-files -- "deep/*"
+'
+
test_done
diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index f1d42b62b0..86bfbc2b36 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -98,6 +98,23 @@ test_expect_success 'subsections are not canonicalized by git-config' '
test_cmp_config two section.SubSection.key
'
+test_missing_key () {
+ local key="$1" &&
+ local title="$2" &&
+ test_expect_success "value for $title is not printed" '
+ test_must_fail git config "$key" >out 2>err &&
+ test_must_be_empty out &&
+ test_must_be_empty err
+ '
+}
+
+test_missing_key 'missingsection.missingkey' 'missing section and missing key'
+test_missing_key 'missingsection.penguin' 'missing section and existing key'
+test_missing_key 'section.missingkey' 'existing section and missing key'
+test_missing_key 'section.MissingSubSection.missingkey' 'missing subsection and missing key'
+test_missing_key 'section.SubSection.missingkey' 'existing subsection and missing key'
+test_missing_key 'section.MissingSubSection.key' 'missing subsection and existing key'
+
cat > .git/config <<\EOF
[alpha]
bar = foo
@@ -1488,35 +1505,29 @@ test_expect_success 'git config ignores pairs without count' '
test_must_be_empty error
'
-test_expect_success 'git config ignores pairs with zero count' '
- test_must_fail env \
- GIT_CONFIG_COUNT=0 \
- GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \
- git config pair.one
-'
-
test_expect_success 'git config ignores pairs exceeding count' '
GIT_CONFIG_COUNT=1 \
GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \
GIT_CONFIG_KEY_1="pair.two" GIT_CONFIG_VALUE_1="value" \
- git config --get-regexp "pair.*" >actual &&
+ git config --get-regexp "pair.*" >actual 2>error &&
cat >expect <<-EOF &&
pair.one value
EOF
- test_cmp expect actual
+ test_cmp expect actual &&
+ test_must_be_empty error
'
test_expect_success 'git config ignores pairs with zero count' '
test_must_fail env \
GIT_CONFIG_COUNT=0 GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \
- git config pair.one >error &&
+ git config pair.one 2>error &&
test_must_be_empty error
'
test_expect_success 'git config ignores pairs with empty count' '
test_must_fail env \
GIT_CONFIG_COUNT= GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \
- git config pair.one >error &&
+ git config pair.one 2>error &&
test_must_be_empty error
'
@@ -1601,11 +1612,11 @@ test_expect_success 'git config --edit respects core.editor' '
# malformed configuration files
test_expect_success 'barf on syntax error' '
cat >.git/config <<-\EOF &&
- # broken section line
+ # broken key=value
[section]
key garbage
EOF
- test_must_fail git config --get section.key >actual 2>error &&
+ test_must_fail git config --get section.key 2>error &&
test_i18ngrep " line 3 " error
'
@@ -1615,17 +1626,17 @@ test_expect_success 'barf on incomplete section header' '
[section
key = value
EOF
- test_must_fail git config --get section.key >actual 2>error &&
+ test_must_fail git config --get section.key 2>error &&
test_i18ngrep " line 2 " error
'
test_expect_success 'barf on incomplete string' '
cat >.git/config <<-\EOF &&
- # broken section line
+ # broken value string
[section]
key = "value string
EOF
- test_must_fail git config --get section.key >actual 2>error &&
+ test_must_fail git config --get section.key 2>error &&
test_i18ngrep " line 3 " error
'
diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh
index 1b6437ec07..ae5cd3f5a0 100755
--- a/t/t1301-shared-repo.sh
+++ b/t/t1301-shared-repo.sh
@@ -89,7 +89,7 @@ do
rm -f .git/info/refs &&
git update-server-info &&
actual="$(test_modebits .git/info/refs)" &&
- verbose test "x$actual" = "x-$y"
+ test "x$actual" = "x-$y"
'
@@ -99,7 +99,7 @@ do
rm -f .git/info/refs &&
git update-server-info &&
actual="$(test_modebits .git/info/refs)" &&
- verbose test "x$actual" = "x-$x"
+ test "x$actual" = "x-$x"
'
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index bca46378b2..8c442adb1a 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -989,10 +989,7 @@ test_expect_success 'fsck error and recovery on invalid object type' '
garbage_blob=$(git hash-object --stdin -w -t garbage --literally </dev/null) &&
- cat >err.expect <<-\EOF &&
- fatal: invalid object type
- EOF
- test_must_fail git fsck >out 2>err &&
+ test_must_fail git fsck 2>err &&
grep -e "^error" -e "^fatal" err >errors &&
test_line_count = 1 errors &&
grep "$garbage_blob: object is of unknown type '"'"'garbage'"'"':" err
diff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh
index de1d48f3ba..dd811b7fb4 100755
--- a/t/t1502-rev-parse-parseopt.sh
+++ b/t/t1502-rev-parse-parseopt.sh
@@ -302,14 +302,14 @@ test_expect_success 'test --parseopt help output: "wrapped" options normal "or:"
|EOF
END_EXPECT
- test_must_fail git rev-parse --parseopt -- -h >out <spec >actual &&
+ test_must_fail git rev-parse --parseopt -- -h <spec >actual &&
test_cmp expect actual
'
test_expect_success 'test --parseopt invalid opt-spec' '
test_write_lines x -- "=, x" >spec &&
echo "fatal: missing opt-spec before option flags" >expect &&
- test_must_fail git rev-parse --parseopt -- >out <spec 2>err &&
+ test_must_fail git rev-parse --parseopt -- <spec 2>err &&
test_cmp expect err
'
@@ -339,7 +339,7 @@ test_expect_success 'test --parseopt help output: multi-line blurb after empty l
|EOF
END_EXPECT
- test_must_fail git rev-parse --parseopt -- -h >out <spec >actual &&
+ test_must_fail git rev-parse --parseopt -- -h <spec >actual &&
test_cmp expect actual
'
diff --git a/t/t1507-rev-parse-upstream.sh b/t/t1507-rev-parse-upstream.sh
index d94c72c672..cb9ef7e329 100755
--- a/t/t1507-rev-parse-upstream.sh
+++ b/t/t1507-rev-parse-upstream.sh
@@ -97,7 +97,8 @@ test_expect_success 'my-side@{u} resolves to correct commit' '
commit_subject my-side >actual &&
test_cmp expect actual &&
echo 5 >expect &&
- commit_subject my-side@{u} >actual
+ commit_subject my-side@{u} >actual &&
+ test_cmp expect actual
'
test_expect_success 'not-tracking@{u} fails' '
diff --git a/t/t2019-checkout-ambiguous-ref.sh b/t/t2019-checkout-ambiguous-ref.sh
index 2c8c926b4d..9540588664 100755
--- a/t/t2019-checkout-ambiguous-ref.sh
+++ b/t/t2019-checkout-ambiguous-ref.sh
@@ -16,7 +16,7 @@ test_expect_success 'setup ambiguous refs' '
'
test_expect_success 'checkout ambiguous ref succeeds' '
- git checkout ambiguity >stdout 2>stderr
+ git checkout ambiguity 2>stderr
'
test_expect_success 'checkout produces ambiguity warning' '
@@ -37,7 +37,7 @@ test_expect_success 'checkout reports switch to branch' '
'
test_expect_success 'checkout vague ref succeeds' '
- git checkout vagueness >stdout 2>stderr &&
+ git checkout vagueness 2>stderr &&
test_set_prereq VAGUENESS_SUCCESS
'
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 5a8a48287c..98b6c8ac34 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -239,6 +239,21 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou
git worktree prune
'
+test_expect_success 'git branch -M fails if updating any linked working tree fails' '
+ git worktree add -b baz bazdir1 &&
+ git worktree add -f bazdir2 baz &&
+ touch .git/worktrees/bazdir1/HEAD.lock &&
+ test_must_fail git branch -M baz bam &&
+ test $(git -C bazdir2 rev-parse --abbrev-ref HEAD) = bam &&
+ git branch -M bam baz &&
+ rm .git/worktrees/bazdir1/HEAD.lock &&
+ touch .git/worktrees/bazdir2/HEAD.lock &&
+ test_must_fail git branch -M baz bam &&
+ test $(git -C bazdir1 rev-parse --abbrev-ref HEAD) = bam &&
+ rm -rf bazdir1 bazdir2 &&
+ git worktree prune
+'
+
test_expect_success 'git branch -M baz bam should succeed within a worktree in which baz is checked out' '
git checkout -b baz &&
git worktree add -f bazdir baz &&
@@ -283,6 +298,20 @@ test_expect_success 'git branch -M and -C fail on detached HEAD' '
test_cmp expect err
'
+test_expect_success 'git branch -m should work with orphan branches' '
+ test_when_finished git checkout - &&
+ test_when_finished git worktree remove -f wt &&
+ git worktree add wt --detach &&
+ # rename orphan in another worktreee
+ git -C wt checkout --orphan orphan-foo-wt &&
+ git branch -m orphan-foo-wt orphan-bar-wt &&
+ test orphan-bar-wt=$(git -C orphan-worktree branch --show-current) &&
+ # rename orphan in the current worktree
+ git checkout --orphan orphan-foo &&
+ git branch -m orphan-foo orphan-bar &&
+ test orphan-bar=$(git branch --show-current)
+'
+
test_expect_success 'git branch -d on orphan HEAD (merged)' '
test_when_finished git checkout main &&
git checkout --orphan orphan &&
diff --git a/t/t3202-show-branch.sh b/t/t3202-show-branch.sh
index ea7cfd1951..be20ebe1d5 100755
--- a/t/t3202-show-branch.sh
+++ b/t/t3202-show-branch.sh
@@ -221,4 +221,22 @@ test_expect_success 'fatal descriptions on non-existent branch' '
test_cmp expect actual
'
+test_expect_success 'error descriptions on orphan branch' '
+ test_when_finished git worktree remove -f wt &&
+ git worktree add wt --detach &&
+ git -C wt checkout --orphan orphan-branch &&
+ test_branch_op_in_wt() {
+ test_orphan_error() {
+ test_must_fail git $* 2>actual &&
+ test_i18ngrep "No commit on branch .orphan-branch. yet.$" actual
+ } &&
+ test_orphan_error -C wt branch $1 $2 && # implicit branch
+ test_orphan_error -C wt branch $1 orphan-branch $2 && # explicit branch
+ test_orphan_error branch $1 orphan-branch $2 # different worktree
+ } &&
+ test_branch_op_in_wt --edit-description &&
+ test_branch_op_in_wt --set-upstream-to=ne &&
+ test_branch_op_in_wt -c new-branch
+'
+
test_done
diff --git a/t/t3301-notes.sh b/t/t3301-notes.sh
index 3288aaec7d..dbadcf1375 100755
--- a/t/t3301-notes.sh
+++ b/t/t3301-notes.sh
@@ -362,6 +362,7 @@ test_expect_success 'do not create empty note with -m ""' '
'
test_expect_success 'create note with combination of -m and -F' '
+ test_when_finished git notes remove HEAD &&
cat >expect-combine_m_and_F <<-EOF &&
foo
@@ -380,6 +381,25 @@ test_expect_success 'create note with combination of -m and -F' '
test_cmp expect-combine_m_and_F actual
'
+test_expect_success 'create note with combination of -m and -F and --separator' '
+ cat >expect-combine_m_and_F <<-\EOF &&
+ foo
+ -------
+ xyzzy
+ -------
+ bar
+ -------
+ zyxxy
+ -------
+ baz
+ EOF
+ echo "xyzzy" >note_a &&
+ echo "zyxxy" >note_b &&
+ git notes add -m "foo" -F note_a -m "bar" -F note_b -m "baz" --separator "-------" &&
+ git notes show >actual &&
+ test_cmp expect-combine_m_and_F actual
+'
+
test_expect_success 'remove note with "git notes remove"' '
git notes remove HEAD^ &&
git notes remove &&
@@ -521,6 +541,85 @@ test_expect_success 'listing non-existing notes fails' '
test_must_be_empty actual
'
+test_expect_success 'append: specify an empty separator' '
+ test_when_finished git notes remove HEAD &&
+ cat >expect <<-\EOF &&
+ notes-1
+
+ notes-2
+ EOF
+
+ git notes add -m "notes-1" &&
+ git notes append --separator="" -m "notes-2" &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'append: specify separator with line break' '
+ test_when_finished git notes remove HEAD &&
+ cat >expect <<-\EOF &&
+ notes-1
+ -------
+ notes-2
+ EOF
+
+ git notes add -m "notes-1" &&
+ git notes append --separator="-------$LF" -m "notes-2" &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'append: specify separator without line break' '
+ test_when_finished git notes remove HEAD &&
+ cat >expect <<-\EOF &&
+ notes-1
+ -------
+ notes-2
+ EOF
+
+ git notes add -m "notes-1" &&
+ git notes append --separator="-------" -m "notes-2" &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'append: specify separator with multiple messages' '
+ test_when_finished git notes remove HEAD &&
+ cat >expect <<-\EOF &&
+ notes-1
+ -------
+ notes-2
+ -------
+ notes-3
+ EOF
+
+ git notes add -m "notes-1" &&
+ git notes append --separator="-------" -m "notes-2" -m "notes-3" &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'append note with combination of -m and -F and --separator' '
+ test_when_finished git notes remove HEAD &&
+ cat >expect-combine_m_and_F <<-\EOF &&
+ m-notes-1
+ -------
+ f-notes-1
+ -------
+ m-notes-2
+ -------
+ f-notes-2
+ -------
+ m-notes-3
+ EOF
+
+ echo "f-notes-1" >note_a &&
+ echo "f-notes-2" >note_b &&
+ git notes append -m "m-notes-1" -F note_a -m "m-notes-2" -F note_b -m "m-notes-3" --separator "-------" &&
+ git notes show >actual &&
+ test_cmp expect-combine_m_and_F actual
+'
+
test_expect_success 'append to existing note with "git notes append"' '
cat >expect <<-EOF &&
Initial set of notes
@@ -818,6 +917,33 @@ test_expect_success 'create note from blob with "git notes add -C" reuses blob i
test_cmp blob actual
'
+test_expect_success 'create note from blob with "-C", also specify "-m", "-F" and "--separator"' '
+ # 8th will be reuseed in following tests, so rollback when the test is done
+ test_when_finished "git notes remove && git notes add -C $(cat blob)" &&
+ commit=$(git rev-parse HEAD) &&
+ cat >expect <<-EOF &&
+ commit $commit
+ Author: A U Thor <author@example.com>
+ Date: Thu Apr 7 15:20:13 2005 -0700
+
+ ${indent}8th
+
+ Notes:
+ ${indent}This is a blob object
+ ${indent}-------
+ ${indent}This is created by -m
+ ${indent}-------
+ ${indent}This is created by -F
+ EOF
+
+ git notes remove &&
+ echo "This is a blob object" | git hash-object -w --stdin >blob &&
+ echo "This is created by -F" >note_a &&
+ git notes add -C $(cat blob) -m "This is created by -m" -F note_a --separator="-------" &&
+ git log -1 >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'create note from other note with "git notes add -c"' '
test_commit 9th &&
commit=$(git rev-parse HEAD) &&
diff --git a/t/t3321-notes-stripspace.sh b/t/t3321-notes-stripspace.sh
new file mode 100755
index 0000000000..028d825e8f
--- /dev/null
+++ b/t/t3321-notes-stripspace.sh
@@ -0,0 +1,577 @@
+#!/bin/sh
+#
+# Copyright (c) 2023 Teng Long
+#
+
+test_description='Test commit notes with stripspace behavior'
+
+. ./test-lib.sh
+
+MULTI_LF="$LF$LF$LF"
+write_script fake_editor <<\EOF
+echo "$MSG" >"$1"
+echo "$MSG" >&2
+EOF
+GIT_EDITOR=./fake_editor
+export GIT_EDITOR
+
+test_expect_success 'setup the commit' '
+ test_commit 1st
+'
+
+test_expect_success 'add note by editor' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+ EOF
+
+ MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes add &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying single "-m", "--stripspace" is the default behavior' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+ EOF
+
+ git notes add -m "${LF}first-line${MULTI_LF}second-line${LF}" &&
+ git notes show >actual &&
+ test_cmp expect actual &&
+ git notes remove &&
+ git notes add --stripspace -m "${LF}first-line${MULTI_LF}second-line${LF}" &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying single "-m" and "--no-stripspace" ' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ ${LF}first-line${MULTI_LF}second-line
+ EOF
+
+ git notes add --no-stripspace \
+ -m "${LF}first-line${MULTI_LF}second-line${LF}" &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying multiple "-m", "--stripspace" is the default behavior' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+ EOF
+
+ git notes add -m "${LF}" \
+ -m "first-line" \
+ -m "${MULTI_LF}" \
+ -m "second-line" \
+ -m "${LF}" &&
+ git notes show >actual &&
+ test_cmp expect actual &&
+ git notes remove &&
+ git notes add --stripspace -m "${LF}" \
+ -m "first-line" \
+ -m "${MULTI_LF}" \
+ -m "second-line" \
+ -m "${LF}" &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add notes by specifying multiple "-m" and "--no-stripspace"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ ${LF}
+ first-line
+ ${MULTI_LF}
+ second-line${LF}
+ EOF
+
+ git notes add --no-stripspace \
+ -m "${LF}" \
+ -m "first-line" \
+ -m "${MULTI_LF}" \
+ -m "second-line" \
+ -m "${LF}" &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying single "-F", "--stripspace" is the default behavior' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+ EOF
+
+ cat >note-file <<-EOF &&
+ ${LF}
+ first-line
+ ${MULTI_LF}
+ second-line
+ ${LF}
+ EOF
+
+ git notes add -F note-file &&
+ git notes show >actual &&
+ test_cmp expect actual &&
+ git notes remove &&
+ git notes add --stripspace -F note-file &&
+ git notes show >actual
+'
+
+test_expect_success 'add note by specifying single "-F" and "--no-stripspace"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ ${LF}
+ first-line
+ ${MULTI_LF}
+ second-line
+ ${LF}
+ EOF
+
+ cat >note-file <<-EOF &&
+ ${LF}
+ first-line
+ ${MULTI_LF}
+ second-line
+ ${LF}
+ EOF
+
+ git notes add --no-stripspace -F note-file &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying multiple "-F", "--stripspace" is the default behavior' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ file-1-first-line
+
+ file-1-second-line
+
+ file-2-first-line
+
+ file-2-second-line
+ EOF
+
+ cat >note-file-1 <<-EOF &&
+ ${LF}
+ file-1-first-line
+ ${MULTI_LF}
+ file-1-second-line
+ ${LF}
+ EOF
+
+ cat >note-file-2 <<-EOF &&
+ ${LF}
+ file-2-first-line
+ ${MULTI_LF}
+ file-2-second-line
+ ${LF}
+ EOF
+
+ git notes add -F note-file-1 -F note-file-2 &&
+ git notes show >actual &&
+ test_cmp expect actual &&
+ git notes remove &&
+ git notes add --stripspace -F note-file-1 -F note-file-2 &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying multiple "-F" with "--no-stripspace"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ ${LF}
+ file-1-first-line
+ ${MULTI_LF}
+ file-1-second-line
+ ${LF}
+
+ ${LF}
+ file-2-first-line
+ ${MULTI_LF}
+ file-2-second-line
+ ${LF}
+ EOF
+
+ cat >note-file-1 <<-EOF &&
+ ${LF}
+ file-1-first-line
+ ${MULTI_LF}
+ file-1-second-line
+ ${LF}
+ EOF
+
+ cat >note-file-2 <<-EOF &&
+ ${LF}
+ file-2-first-line
+ ${MULTI_LF}
+ file-2-second-line
+ ${LF}
+ EOF
+
+ git notes add --no-stripspace -F note-file-1 -F note-file-2 &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'append note by editor' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+ EOF
+
+ git notes add -m "first-line" &&
+ MSG="${MULTI_LF}second-line${LF}" git notes append &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'append note by specifying single "-m"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+ EOF
+
+ git notes add -m "${LF}first-line" &&
+ git notes append -m "${MULTI_LF}second-line${LF}" &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'append note by specifying multiple "-m"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+ EOF
+
+ git notes add -m "${LF}first-line" &&
+ git notes append -m "${MULTI_LF}" \
+ -m "second-line" \
+ -m "${LF}" &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying single "-F"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+ EOF
+
+ cat >note-file <<-EOF &&
+ ${LF}
+ first-line
+ ${MULTI_LF}
+ second-line
+ ${LF}
+ EOF
+
+ git notes add -F note-file &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add notes by specifying multiple "-F"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ file-1-first-line
+
+ file-1-second-line
+
+ file-2-first-line
+
+ file-2-second-line
+ EOF
+
+ cat >note-file-1 <<-EOF &&
+ ${LF}
+ file-1-first-line
+ ${MULTI_LF}
+ file-1-second-line
+ ${LF}
+ EOF
+
+ cat >note-file-2 <<-EOF &&
+ ${LF}
+ file-2-first-line
+ ${MULTI_LF}
+ file-2-second-line
+ ${LF}
+ EOF
+
+ git notes add -F note-file-1 -F note-file-2 &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'append note by specifying single "-F"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ initial-line
+
+ first-line
+
+ second-line
+ EOF
+
+ cat >note-file <<-EOF &&
+ ${LF}
+ first-line
+ ${MULTI_LF}
+ second-line
+ ${LF}
+ EOF
+
+ git notes add -m "initial-line" &&
+ git notes append -F note-file &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'append notes by specifying multiple "-F"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ initial-line
+
+ file-1-first-line
+
+ file-1-second-line
+
+ file-2-first-line
+
+ file-2-second-line
+ EOF
+
+ cat >note-file-1 <<-EOF &&
+ ${LF}
+ file-1-first-line
+ ${MULTI_LF}
+ file-1-second-line
+ ${LF}
+ EOF
+
+ cat >note-file-2 <<-EOF &&
+ ${LF}
+ file-2-first-line
+ ${MULTI_LF}
+ file-2-second-line
+ ${LF}
+ EOF
+
+ git notes add -m "initial-line" &&
+ git notes append -F note-file-1 -F note-file-2 &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'append note by specifying multiple "-F" with "--no-stripspace"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ initial-line
+ ${LF}${LF}
+ file-1-first-line
+ ${MULTI_LF}
+ file-1-second-line
+ ${LF}
+
+ ${LF}
+ file-2-first-line
+ ${MULTI_LF}
+ file-2-second-line
+ ${LF}
+ EOF
+
+ cat >note-file-1 <<-EOF &&
+ ${LF}
+ file-1-first-line
+ ${MULTI_LF}
+ file-1-second-line
+ ${LF}
+ EOF
+
+ cat >note-file-2 <<-EOF &&
+ ${LF}
+ file-2-first-line
+ ${MULTI_LF}
+ file-2-second-line
+ ${LF}
+ EOF
+
+ git notes add -m "initial-line" &&
+ git notes append --no-stripspace -F note-file-1 -F note-file-2 &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add notes with empty messages' '
+ rev=$(git rev-parse HEAD) &&
+ git notes add -m "${LF}" \
+ -m "${MULTI_LF}" \
+ -m "${LF}" >actual 2>&1 &&
+ test_i18ngrep "Removing note for object" actual
+'
+
+test_expect_success 'add note by specifying "-C", "--no-stripspace" is the default behavior' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ ${LF}
+ first-line
+ ${MULTI_LF}
+ second-line
+ ${LF}
+ EOF
+
+ cat expect | git hash-object -w --stdin >blob &&
+ git notes add -C $(cat blob) &&
+ git notes show >actual &&
+ test_cmp expect actual &&
+ git notes remove &&
+ git notes add --no-stripspace -C $(cat blob) &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'reuse note by specifying "-C" and "--stripspace"' '
+ test_when_finished "git notes remove" &&
+ cat >data <<-EOF &&
+ ${LF}
+ first-line
+ ${MULTI_LF}
+ second-line
+ ${LF}
+ EOF
+
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+ EOF
+
+ cat data | git hash-object -w --stdin >blob &&
+ git notes add --stripspace -C $(cat blob) &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'reuse with "-C" and add note with "-m", "-m" will stripspace all together' '
+ test_when_finished "git notes remove" &&
+ cat >data <<-EOF &&
+ ${LF}
+ first-line
+ ${MULTI_LF}
+ second-line
+ ${LF}
+ EOF
+
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+
+ third-line
+ EOF
+
+ cat data | git hash-object -w --stdin >blob &&
+ git notes add -C $(cat blob) -m "third-line" &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add note with "-m" and reuse note with "-C", "-C" will not stripspace all together' '
+ test_when_finished "git notes remove" &&
+ cat >data <<-EOF &&
+
+ second-line
+ EOF
+
+ cat >expect <<-EOF &&
+ first-line
+ ${LF}
+ second-line
+ EOF
+
+ cat data | git hash-object -w --stdin >blob &&
+ git notes add -m "first-line" -C $(cat blob) &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying "-c", "--stripspace" is the default behavior' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+ EOF
+
+ echo "initial-line" | git hash-object -w --stdin >blob &&
+ MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes add -c $(cat blob) &&
+ git notes show >actual &&
+ test_cmp expect actual &&
+ git notes remove &&
+ MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes add --stripspace -c $(cat blob) &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'add note by specifying "-c" with "--no-stripspace"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ ${LF}first-line${MULTI_LF}second-line${LF}
+ EOF
+
+ echo "initial-line" | git hash-object -w --stdin >blob &&
+ MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes add --no-stripspace -c $(cat blob) &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'edit note by specifying "-c", "--stripspace" is the default behavior' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ first-line
+
+ second-line
+ EOF
+
+ MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes edit &&
+ git notes show >actual &&
+ test_cmp expect actual &&
+ git notes remove &&
+ MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes edit --stripspace &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'edit note by specifying "-c" with "--no-stripspace"' '
+ test_when_finished "git notes remove" &&
+ cat >expect <<-EOF &&
+ ${LF}first-line${MULTI_LF}second-line${LF}
+ EOF
+
+ MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes add --no-stripspace &&
+ git notes show >actual &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t3427-rebase-subtree.sh b/t/t3427-rebase-subtree.sh
index 48b76f8232..1b3e97c875 100755
--- a/t/t3427-rebase-subtree.sh
+++ b/t/t3427-rebase-subtree.sh
@@ -74,9 +74,9 @@ test_expect_success 'Rebase -Xsubtree --empty=ask --onto commit' '
test_must_fail git rebase -Xsubtree=files_subtree --empty=ask --onto files-main main &&
: first pick results in no changes &&
git rebase --skip &&
- verbose test "$(commit_message HEAD~2)" = "topic_4" &&
- verbose test "$(commit_message HEAD~)" = "files_subtree/topic_5" &&
- verbose test "$(commit_message HEAD)" = "Empty commit"
+ test "$(commit_message HEAD~2)" = "topic_4" &&
+ test "$(commit_message HEAD~)" = "files_subtree/topic_5" &&
+ test "$(commit_message HEAD)" = "Empty commit"
'
test_expect_success 'Rebase -Xsubtree --empty=ask --rebase-merges --onto commit' '
@@ -85,9 +85,9 @@ test_expect_success 'Rebase -Xsubtree --empty=ask --rebase-merges --onto commit'
test_must_fail git rebase -Xsubtree=files_subtree --empty=ask --rebase-merges --onto files-main --root &&
: first pick results in no changes &&
git rebase --skip &&
- verbose test "$(commit_message HEAD~2)" = "topic_4" &&
- verbose test "$(commit_message HEAD~)" = "files_subtree/topic_5" &&
- verbose test "$(commit_message HEAD)" = "Empty commit"
+ test "$(commit_message HEAD~2)" = "topic_4" &&
+ test "$(commit_message HEAD~)" = "files_subtree/topic_5" &&
+ test "$(commit_message HEAD)" = "Empty commit"
'
test_done
diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh
index 2f3e3e2416..e2ef619323 100755
--- a/t/t3501-revert-cherry-pick.sh
+++ b/t/t3501-revert-cherry-pick.sh
@@ -1,14 +1,6 @@
#!/bin/sh
-test_description='test cherry-pick and revert with renames
-
- --
- + rename2: renames oops to opos
- + rename1: renames oops to spoo
- + added: adds extra line to oops
- ++ initial: has lines in oops
-
-'
+test_description='miscellaneous basic tests for cherry-pick and revert'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
@@ -63,6 +55,14 @@ test_expect_success 'revert --nonsense' '
test_i18ngrep "[Uu]sage:" msg
'
+# the following two test cherry-pick and revert with renames
+#
+# --
+# + rename2: renames oops to opos
+# + rename1: renames oops to spoo
+# + added: adds extra line to oops
+# ++ initial: has lines in oops
+
test_expect_success 'cherry-pick after renaming branch' '
git checkout rename2 &&
diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh
index 42a2b9a13b..c8d555771d 100755
--- a/t/t4018-diff-funcname.sh
+++ b/t/t4018-diff-funcname.sh
@@ -63,6 +63,25 @@ do
test_i18ngrep ! fatal msg &&
test_i18ngrep ! error msg
'
+
+ test_expect_success "builtin $p pattern compiles on bare repo with --attr-source" '
+ test_when_finished "rm -rf bare.git" &&
+ git checkout -B master &&
+ git add . &&
+ echo "*.java diff=notexist" >.gitattributes &&
+ git add .gitattributes &&
+ git commit -am "changing gitattributes" &&
+ git checkout -B branchA &&
+ echo "*.java diff=$p" >.gitattributes &&
+ git add .gitattributes &&
+ git commit -am "changing gitattributes" &&
+ git clone --bare --no-local . bare.git &&
+ git -C bare.git symbolic-ref HEAD refs/heads/master &&
+ test_expect_code 1 git -C bare.git --attr-source=branchA \
+ diff --exit-code HEAD:A.java HEAD:B.java 2>msg &&
+ test_i18ngrep ! fatal msg &&
+ test_i18ngrep ! error msg
+ '
done
test_expect_success 'last regexp must not be negated' '
diff --git a/t/t4022-diff-rewrite.sh b/t/t4022-diff-rewrite.sh
index 1c89050a97..6fed993ea0 100755
--- a/t/t4022-diff-rewrite.sh
+++ b/t/t4022-diff-rewrite.sh
@@ -24,7 +24,7 @@ test_expect_success setup '
test_expect_success 'detect rewrite' '
actual=$(git diff-files -B --summary test) &&
- verbose expr "$actual" : " rewrite test ([0-9]*%)$"
+ expr "$actual" : " rewrite test ([0-9]*%)$"
'
diff --git a/t/t4047-diff-dirstat.sh b/t/t4047-diff-dirstat.sh
index 7fec2cb9cd..70224c3da1 100755
--- a/t/t4047-diff-dirstat.sh
+++ b/t/t4047-diff-dirstat.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='diff --dirstat tests'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# set up two commits where the second commit has these files
diff --git a/t/t4062-diff-pickaxe.sh b/t/t4062-diff-pickaxe.sh
index 9aaa068ed9..a90b46b678 100755
--- a/t/t4062-diff-pickaxe.sh
+++ b/t/t4062-diff-pickaxe.sh
@@ -24,7 +24,7 @@ test_expect_success '-G matches' '
test_expect_success '-S --pickaxe-regex' '
git diff --name-only -S0 --pickaxe-regex HEAD^ >out &&
- verbose test 4096-zeroes.txt = "$(cat out)"
+ test 4096-zeroes.txt = "$(cat out)"
'
test_done
diff --git a/t/t4212-log-corrupt.sh b/t/t4212-log-corrupt.sh
index e89e1f54b6..85e90acb09 100755
--- a/t/t4212-log-corrupt.sh
+++ b/t/t4212-log-corrupt.sh
@@ -8,8 +8,9 @@ TEST_PASSES_SANITIZE_LEAK=true
test_expect_success 'setup' '
test_commit foo &&
- git cat-file commit HEAD |
- sed "/^author /s/>/>-<>/" >broken_email.commit &&
+ git cat-file commit HEAD >ok.commit &&
+ sed "s/>/>-<>/" <ok.commit >broken_email.commit &&
+
git hash-object --literally -w -t commit broken_email.commit >broken_email.hash &&
git update-ref refs/heads/broken_email $(cat broken_email.hash)
'
@@ -43,6 +44,11 @@ test_expect_success 'git log --format with broken author email' '
test_must_be_empty actual.err
'
+test_expect_success '--until handles broken email' '
+ git rev-list --until=1980-01-01 broken_email >actual &&
+ test_must_be_empty actual
+'
+
munge_author_date () {
git cat-file commit "$1" >commit.orig &&
sed "s/^\(author .*>\) [0-9]*/\1 $2/" <commit.orig >commit.munge &&
@@ -86,4 +92,45 @@ test_expect_success 'absurdly far-in-future date' '
git log -1 --format=%ad $commit
'
+test_expect_success 'create commits with whitespace committer dates' '
+ # It is important that this subject line is numeric, since we want to
+ # be sure we are not confused by skipping whitespace and accidentally
+ # parsing the subject as a timestamp.
+ #
+ # Do not use munge_author_date here. Besides not hitting the committer
+ # line, it leaves the timezone intact, and we want nothing but
+ # whitespace.
+ #
+ # We will make two munged commits here. The first, ws_commit, will
+ # be purely spaces. The second contains a vertical tab, which is
+ # considered a space by strtoumax(), but not by our isspace().
+ test_commit 1234567890 &&
+ git cat-file commit HEAD >commit.orig &&
+ sed "s/>.*/> /" <commit.orig >commit.munge &&
+ ws_commit=$(git hash-object --literally -w -t commit commit.munge) &&
+ sed "s/>.*/> $(printf "\013")/" <commit.orig >commit.munge &&
+ vt_commit=$(git hash-object --literally -w -t commit commit.munge)
+'
+
+test_expect_success '--until treats whitespace date as sentinel' '
+ echo $ws_commit >expect &&
+ git rev-list --until=1980-01-01 $ws_commit >actual &&
+ test_cmp expect actual &&
+
+ echo $vt_commit >expect &&
+ git rev-list --until=1980-01-01 $vt_commit >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'pretty-printer handles whitespace date' '
+ # as with the %ad test above, we will show these as the empty string,
+ # not the 1970 epoch date. This is intentional; see 7d9a281941 (t4212:
+ # test bogus timestamps with git-log, 2014-02-24) for more discussion.
+ echo : >expect &&
+ git log -1 --format="%at:%ct" $ws_commit >actual &&
+ test_cmp expect actual &&
+ git log -1 --format="%at:%ct" $vt_commit >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t4300-merge-tree.sh b/t/t4300-merge-tree.sh
index c52c8a21fa..57c4f26e46 100755
--- a/t/t4300-merge-tree.sh
+++ b/t/t4300-merge-tree.sh
@@ -334,4 +334,22 @@ test_expect_success 'turn tree to file' '
test_cmp expect actual
'
+test_expect_success 'merge-tree respects core.useReplaceRefs=false' '
+ test_commit merge-to &&
+ test_commit valid base &&
+ git reset --hard HEAD^ &&
+ test_commit malicious base &&
+
+ test_when_finished "git replace -d $(git rev-parse valid^0)" &&
+ git replace valid^0 malicious^0 &&
+
+ tree=$(git -c core.useReplaceRefs=true merge-tree --write-tree merge-to valid) &&
+ merged=$(git cat-file -p $tree:base) &&
+ test malicious = $merged &&
+
+ tree=$(git -c core.useReplaceRefs=false merge-tree --write-tree merge-to valid) &&
+ merged=$(git cat-file -p $tree:base) &&
+ test valid = $merged
+'
+
test_done
diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh
index 5500dd0842..f367327441 100755
--- a/t/t5304-prune.sh
+++ b/t/t5304-prune.sh
@@ -16,7 +16,7 @@ add_blob() {
before=$(git count-objects | sed "s/ .*//") &&
BLOB=$(echo aleph_0 | git hash-object -w --stdin) &&
BLOB_FILE=.git/objects/$(echo $BLOB | sed "s/^../&\//") &&
- verbose test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
+ test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
test_path_is_file $BLOB_FILE &&
test-tool chmtime =+0 $BLOB_FILE
}
@@ -51,23 +51,23 @@ test_expect_success 'prune stale packs' '
test_expect_success 'prune --expire' '
add_blob &&
git prune --expire=1.hour.ago &&
- verbose test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
+ test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
test_path_is_file $BLOB_FILE &&
test-tool chmtime =-86500 $BLOB_FILE &&
git prune --expire 1.day &&
- verbose test $before = $(git count-objects | sed "s/ .*//") &&
+ test $before = $(git count-objects | sed "s/ .*//") &&
test_path_is_missing $BLOB_FILE
'
test_expect_success 'gc: implicit prune --expire' '
add_blob &&
test-tool chmtime =-$((2*$week-30)) $BLOB_FILE &&
- git gc &&
- verbose test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
+ git gc --no-cruft &&
+ test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
test_path_is_file $BLOB_FILE &&
test-tool chmtime =-$((2*$week+1)) $BLOB_FILE &&
- git gc &&
- verbose test $before = $(git count-objects | sed "s/ .*//") &&
+ git gc --no-cruft &&
+ test $before = $(git count-objects | sed "s/ .*//") &&
test_path_is_missing $BLOB_FILE
'
@@ -86,7 +86,7 @@ test_expect_success 'gc: refuse to start with invalid gc.pruneExpire' '
test_expect_success 'gc: start with ok gc.pruneExpire' '
git config gc.pruneExpire 2.days.ago &&
- git gc
+ git gc --no-cruft
'
test_expect_success 'prune: prune nonsense parameters' '
@@ -137,44 +137,44 @@ test_expect_success 'gc --no-prune' '
add_blob &&
test-tool chmtime =-$((5001*$day)) $BLOB_FILE &&
git config gc.pruneExpire 2.days.ago &&
- git gc --no-prune &&
- verbose test 1 = $(git count-objects | sed "s/ .*//") &&
+ git gc --no-prune --no-cruft &&
+ test 1 = $(git count-objects | sed "s/ .*//") &&
test_path_is_file $BLOB_FILE
'
test_expect_success 'gc respects gc.pruneExpire' '
git config gc.pruneExpire 5002.days.ago &&
- git gc &&
+ git gc --no-cruft &&
test_path_is_file $BLOB_FILE &&
git config gc.pruneExpire 5000.days.ago &&
- git gc &&
+ git gc --no-cruft &&
test_path_is_missing $BLOB_FILE
'
test_expect_success 'gc --prune=<date>' '
add_blob &&
test-tool chmtime =-$((5001*$day)) $BLOB_FILE &&
- git gc --prune=5002.days.ago &&
+ git gc --prune=5002.days.ago --no-cruft &&
test_path_is_file $BLOB_FILE &&
- git gc --prune=5000.days.ago &&
+ git gc --prune=5000.days.ago --no-cruft &&
test_path_is_missing $BLOB_FILE
'
test_expect_success 'gc --prune=never' '
add_blob &&
- git gc --prune=never &&
+ git gc --prune=never --no-cruft &&
test_path_is_file $BLOB_FILE &&
- git gc --prune=now &&
+ git gc --prune=now --no-cruft &&
test_path_is_missing $BLOB_FILE
'
test_expect_success 'gc respects gc.pruneExpire=never' '
git config gc.pruneExpire never &&
add_blob &&
- git gc &&
+ git gc --no-cruft &&
test_path_is_file $BLOB_FILE &&
git config gc.pruneExpire now &&
- git gc &&
+ git gc --no-cruft &&
test_path_is_missing $BLOB_FILE
'
@@ -192,10 +192,10 @@ test_expect_success 'gc: prune old objects after local clone' '
git clone --no-hardlinks . aclone &&
(
cd aclone &&
- verbose test 1 = $(git count-objects | sed "s/ .*//") &&
+ test 1 = $(git count-objects | sed "s/ .*//") &&
test_path_is_file $BLOB_FILE &&
- git gc --prune &&
- verbose test 0 = $(git count-objects | sed "s/ .*//") &&
+ git gc --prune --no-cruft &&
+ test 0 = $(git count-objects | sed "s/ .*//") &&
test_path_is_missing $BLOB_FILE
)
'
@@ -237,7 +237,7 @@ test_expect_success 'clean pack garbage with gc' '
>.git/objects/pack/fake2.keep &&
>.git/objects/pack/fake2.idx &&
>.git/objects/pack/fake3.keep &&
- git gc &&
+ git gc --no-cruft &&
git count-objects -v 2>stderr &&
grep "^warning:" stderr | sort >actual &&
cat >expected <<\EOF &&
diff --git a/t/t5325-reverse-index.sh b/t/t5325-reverse-index.sh
index d042d26f2b..431a603ca0 100755
--- a/t/t5325-reverse-index.sh
+++ b/t/t5325-reverse-index.sh
@@ -1,17 +1,20 @@
#!/bin/sh
test_description='on-disk reverse index'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# The below tests want control over the 'pack.writeReverseIndex' setting
# themselves to assert various combinations of it with other options.
-sane_unset GIT_TEST_WRITE_REV_INDEX
+sane_unset GIT_TEST_NO_WRITE_REV_INDEX
packdir=.git/objects/pack
test_expect_success 'setup' '
test_commit base &&
+ test_config pack.writeReverseIndex false &&
pack=$(git pack-objects --all $packdir/pack) &&
rev=$packdir/pack-$pack.rev &&
@@ -94,6 +97,17 @@ test_expect_success 'reverse index is not generated when available on disk' '
--batch-check="%(objectsize:disk)" <tip
'
+test_expect_success 'reverse index is ignored when pack.readReverseIndex is false' '
+ test_index_pack true &&
+ test_path_is_file $rev &&
+
+ test_config pack.readReverseIndex false &&
+
+ git rev-parse HEAD >tip &&
+ GIT_TEST_REV_INDEX_DIE_ON_DISK=1 git cat-file \
+ --batch-check="%(objectsize:disk)" <tip
+'
+
test_expect_success 'revindex in-memory vs on-disk' '
git init repo &&
test_when_finished "rm -fr repo" &&
@@ -117,4 +131,78 @@ test_expect_success 'revindex in-memory vs on-disk' '
test_cmp on-disk in-core
)
'
+
+test_expect_success 'fsck succeeds on good rev-index' '
+ test_when_finished rm -fr repo &&
+ git init repo &&
+ (
+ cd repo &&
+
+ test_commit commit &&
+ git -c pack.writeReverseIndex=true repack -ad &&
+ git fsck 2>err &&
+ test_must_be_empty err
+ )
+'
+
+test_expect_success 'set up rev-index corruption tests' '
+ git init corrupt &&
+ (
+ cd corrupt &&
+
+ test_commit commit &&
+ git -c pack.writeReverseIndex=true repack -ad &&
+
+ revfile=$(ls .git/objects/pack/pack-*.rev) &&
+ chmod a+w $revfile &&
+ cp $revfile $revfile.bak
+ )
+'
+
+corrupt_rev_and_verify () {
+ (
+ pos="$1" &&
+ value="$2" &&
+ error="$3" &&
+
+ cd corrupt &&
+ revfile=$(ls .git/objects/pack/pack-*.rev) &&
+
+ # Reset to original rev-file.
+ cp $revfile.bak $revfile &&
+
+ printf "$value" | dd of=$revfile bs=1 seek="$pos" conv=notrunc &&
+ test_must_fail git fsck 2>err &&
+ grep "$error" err
+ )
+}
+
+test_expect_success 'fsck catches invalid checksum' '
+ revfile=$(ls corrupt/.git/objects/pack/pack-*.rev) &&
+ orig_size=$(wc -c <$revfile) &&
+ hashpos=$((orig_size - 10)) &&
+ corrupt_rev_and_verify $hashpos bogus \
+ "invalid checksum"
+'
+
+test_expect_success 'fsck catches invalid row position' '
+ corrupt_rev_and_verify 14 "\07" \
+ "invalid rev-index position"
+'
+
+test_expect_success 'fsck catches invalid header: magic number' '
+ corrupt_rev_and_verify 1 "\07" \
+ "reverse-index file .* has unknown signature"
+'
+
+test_expect_success 'fsck catches invalid header: version' '
+ corrupt_rev_and_verify 7 "\02" \
+ "reverse-index file .* has unsupported version"
+'
+
+test_expect_success 'fsck catches invalid header: hash function' '
+ corrupt_rev_and_verify 11 "\03" \
+ "reverse-index file .* has unsupported hash id"
+'
+
test_done
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index 0882cbb6e4..f771c442d4 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -434,4 +434,48 @@ test_expect_success 'tagged commits are selected for bitmapping' '
)
'
+corrupt_file () {
+ chmod a+w "$1" &&
+ printf "bogus" | dd of="$1" bs=1 seek="12" conv=notrunc
+}
+
+test_expect_success 'git fsck correctly identifies good and bad bitmaps' '
+ git init valid &&
+ test_when_finished rm -rf valid &&
+
+ test_commit_bulk 20 &&
+ git repack -adbf &&
+
+ # Move pack-bitmap aside so it is not deleted
+ # in next repack.
+ packbitmap=$(ls .git/objects/pack/pack-*.bitmap) &&
+ mv "$packbitmap" "$packbitmap.bak" &&
+
+ test_commit_bulk 10 &&
+ git repack -b --write-midx &&
+ midxbitmap=$(ls .git/objects/pack/multi-pack-index-*.bitmap) &&
+
+ # Copy MIDX bitmap to backup. Copy pack bitmap from backup.
+ cp "$midxbitmap" "$midxbitmap.bak" &&
+ cp "$packbitmap.bak" "$packbitmap" &&
+
+ # fsck works at first
+ git fsck 2>err &&
+ test_must_be_empty err &&
+
+ corrupt_file "$packbitmap" &&
+ test_must_fail git fsck 2>err &&
+ grep "bitmap file '\''$packbitmap'\'' has invalid checksum" err &&
+
+ cp "$packbitmap.bak" "$packbitmap" &&
+ corrupt_file "$midxbitmap" &&
+ test_must_fail git fsck 2>err &&
+ grep "bitmap file '\''$midxbitmap'\'' has invalid checksum" err &&
+
+ corrupt_file "$packbitmap" &&
+ test_must_fail git fsck 2>err &&
+ grep "bitmap file '\''$midxbitmap'\'' has invalid checksum" err &&
+ grep "bitmap file '\''$packbitmap'\'' has invalid checksum" err
+'
+
test_done
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index dc44da9c79..4f289063ce 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -1118,59 +1118,6 @@ test_expect_success 'fetching with auto-gc does not lock up' '
)
'
-test_expect_success 'fetch aligned output' '
- git clone . full-output &&
- test_commit looooooooooooong-tag &&
- (
- cd full-output &&
- git -c fetch.output=full fetch origin >actual 2>&1 &&
- grep -e "->" actual | cut -c 22- >../actual
- ) &&
- cat >expect <<-\EOF &&
- main -> origin/main
- looooooooooooong-tag -> looooooooooooong-tag
- EOF
- test_cmp expect actual
-'
-
-test_expect_success 'fetch compact output' '
- git clone . compact &&
- test_commit extraaa &&
- (
- cd compact &&
- git -c fetch.output=compact fetch origin >actual 2>&1 &&
- grep -e "->" actual | cut -c 22- >../actual
- ) &&
- cat >expect <<-\EOF &&
- main -> origin/*
- extraaa -> *
- EOF
- test_cmp expect actual
-'
-
-test_expect_success '--no-show-forced-updates' '
- mkdir forced-updates &&
- (
- cd forced-updates &&
- git init &&
- test_commit 1 &&
- test_commit 2
- ) &&
- git clone forced-updates forced-update-clone &&
- git clone forced-updates no-forced-update-clone &&
- git -C forced-updates reset --hard HEAD~1 &&
- (
- cd forced-update-clone &&
- git fetch --show-forced-updates origin 2>output &&
- test_i18ngrep "(forced update)" output
- ) &&
- (
- cd no-forced-update-clone &&
- git fetch --no-show-forced-updates origin 2>output &&
- test_i18ngrep ! "(forced update)" output
- )
-'
-
for section in fetch transfer
do
test_expect_success "$section.hideRefs affects connectivity check" '
diff --git a/t/t5523-push-upstream.sh b/t/t5523-push-upstream.sh
index c9acc07635..1b8d609879 100755
--- a/t/t5523-push-upstream.sh
+++ b/t/t5523-push-upstream.sh
@@ -61,12 +61,20 @@ test_expect_success 'push -u :topic_2' '
check_config topic_2 upstream refs/heads/other2
'
-test_expect_success 'push -u --all' '
+test_expect_success 'push -u --all(the same behavior with--branches)' '
git branch all1 &&
git branch all2 &&
git push -u --all &&
check_config all1 upstream refs/heads/all1 &&
- check_config all2 upstream refs/heads/all2
+ check_config all2 upstream refs/heads/all2 &&
+ git config --get-regexp branch.all* > expect &&
+ git config --remove-section branch.all1 &&
+ git config --remove-section branch.all2 &&
+ git push -u --branches &&
+ check_config all1 upstream refs/heads/all1 &&
+ check_config all2 upstream refs/heads/all2 &&
+ git config --get-regexp branch.all* > actual &&
+ test_cmp expect actual
'
test_expect_success 'push -u HEAD' '
diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh
index dcdbe26a08..26e933f93a 100755
--- a/t/t5526-fetch-submodules.sh
+++ b/t/t5526-fetch-submodules.sh
@@ -1180,4 +1180,17 @@ test_expect_success 'fetch --all with --recurse-submodules with multiple' '
test_line_count = 2 fetch-subs
'
+test_expect_success "fetch --all with --no-recurse-submodules only fetches superproject" '
+ test_when_finished "rm -rf src_clone" &&
+
+ git clone --recurse-submodules src src_clone &&
+ (
+ cd src_clone &&
+ git remote add secondary ../src &&
+ git config submodule.recurse true &&
+ git fetch --all --no-recurse-submodules 2>../fetch-log
+ ) &&
+ ! grep "Fetching submodule" fetch-log
+'
+
test_done
diff --git a/t/t5543-atomic-push.sh b/t/t5543-atomic-push.sh
index 70431122a4..04b47ad84a 100755
--- a/t/t5543-atomic-push.sh
+++ b/t/t5543-atomic-push.sh
@@ -117,7 +117,10 @@ test_expect_success 'atomic push fails if one branch fails' '
test_commit five &&
git checkout main &&
test_commit six &&
- test_must_fail git push --atomic --all up
+ test_must_fail git push --atomic --all up >output-all 2>&1 &&
+ # --all and --branches have the same behavior when be combined with --atomic
+ test_must_fail git push --atomic --branches up >output-branches 2>&1 &&
+ test_cmp output-all output-branches
) &&
test_refs main HEAD@{7} &&
test_refs second HEAD@{4}
diff --git a/t/t5574-fetch-output.sh b/t/t5574-fetch-output.sh
new file mode 100755
index 0000000000..90e6dcb9a7
--- /dev/null
+++ b/t/t5574-fetch-output.sh
@@ -0,0 +1,293 @@
+#!/bin/sh
+
+test_description='git fetch output format'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+test_expect_success 'fetch with invalid output format configuration' '
+ test_when_finished "rm -rf clone" &&
+ git clone . clone &&
+
+ test_must_fail git -C clone -c fetch.output fetch origin 2>actual.err &&
+ cat >expect <<-EOF &&
+ error: missing value for ${SQ}fetch.output${SQ}
+ fatal: unable to parse ${SQ}fetch.output${SQ} from command-line config
+ EOF
+ test_cmp expect actual.err &&
+
+ test_must_fail git -C clone -c fetch.output= fetch origin 2>actual.err &&
+ cat >expect <<-EOF &&
+ fatal: invalid value for ${SQ}fetch.output${SQ}: ${SQ}${SQ}
+ EOF
+ test_cmp expect actual.err &&
+
+ test_must_fail git -C clone -c fetch.output=garbage fetch origin 2>actual.err &&
+ cat >expect <<-EOF &&
+ fatal: invalid value for ${SQ}fetch.output${SQ}: ${SQ}garbage${SQ}
+ EOF
+ test_cmp expect actual.err
+'
+
+test_expect_success 'fetch aligned output' '
+ git clone . full-output &&
+ test_commit looooooooooooong-tag &&
+ (
+ cd full-output &&
+ git -c fetch.output=full fetch origin >actual 2>&1 &&
+ grep -e "->" actual | cut -c 22- >../actual
+ ) &&
+ cat >expect <<-\EOF &&
+ main -> origin/main
+ looooooooooooong-tag -> looooooooooooong-tag
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'fetch compact output' '
+ git clone . compact &&
+ test_commit extraaa &&
+ (
+ cd compact &&
+ git -c fetch.output=compact fetch origin >actual 2>&1 &&
+ grep -e "->" actual | cut -c 22- >../actual
+ ) &&
+ cat >expect <<-\EOF &&
+ main -> origin/*
+ extraaa -> *
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'fetch porcelain output' '
+ test_when_finished "rm -rf porcelain" &&
+
+ # Set up a bunch of references that we can use to demonstrate different
+ # kinds of flag symbols in the output format.
+ MAIN_OLD=$(git rev-parse HEAD) &&
+ git branch "fast-forward" &&
+ git branch "deleted-branch" &&
+ git checkout -b force-updated &&
+ test_commit --no-tag force-update-old &&
+ FORCE_UPDATED_OLD=$(git rev-parse HEAD) &&
+ git checkout main &&
+
+ # Clone and pre-seed the repositories. We fetch references into two
+ # namespaces so that we can test that rejected and force-updated
+ # references are reported properly.
+ refspecs="refs/heads/*:refs/unforced/* +refs/heads/*:refs/forced/*" &&
+ git clone . porcelain &&
+ git -C porcelain fetch origin $refspecs &&
+
+ # Now that we have set up the client repositories we can change our
+ # local references.
+ git branch new-branch &&
+ git branch -d deleted-branch &&
+ git checkout fast-forward &&
+ test_commit --no-tag fast-forward-new &&
+ FAST_FORWARD_NEW=$(git rev-parse HEAD) &&
+ git checkout force-updated &&
+ git reset --hard HEAD~ &&
+ test_commit --no-tag force-update-new &&
+ FORCE_UPDATED_NEW=$(git rev-parse HEAD) &&
+
+ cat >expect <<-EOF &&
+ - $MAIN_OLD $ZERO_OID refs/forced/deleted-branch
+ - $MAIN_OLD $ZERO_OID refs/unforced/deleted-branch
+ $MAIN_OLD $FAST_FORWARD_NEW refs/unforced/fast-forward
+ ! $FORCE_UPDATED_OLD $FORCE_UPDATED_NEW refs/unforced/force-updated
+ * $ZERO_OID $MAIN_OLD refs/unforced/new-branch
+ $MAIN_OLD $FAST_FORWARD_NEW refs/forced/fast-forward
+ + $FORCE_UPDATED_OLD $FORCE_UPDATED_NEW refs/forced/force-updated
+ * $ZERO_OID $MAIN_OLD refs/forced/new-branch
+ $MAIN_OLD $FAST_FORWARD_NEW refs/remotes/origin/fast-forward
+ + $FORCE_UPDATED_OLD $FORCE_UPDATED_NEW refs/remotes/origin/force-updated
+ * $ZERO_OID $MAIN_OLD refs/remotes/origin/new-branch
+ EOF
+
+ # Execute a dry-run fetch first. We do this to assert that the dry-run
+ # and non-dry-run fetches produces the same output. Execution of the
+ # fetch is expected to fail as we have a rejected reference update.
+ test_must_fail git -C porcelain fetch \
+ --porcelain --dry-run --prune origin $refspecs >actual &&
+ test_cmp expect actual &&
+
+ # And now we perform a non-dry-run fetch.
+ test_must_fail git -C porcelain fetch \
+ --porcelain --prune origin $refspecs >actual 2>stderr &&
+ test_cmp expect actual &&
+ test_must_be_empty stderr
+'
+
+test_expect_success 'fetch porcelain with multiple remotes' '
+ test_when_finished "rm -rf porcelain" &&
+
+ git switch --create multiple-remotes &&
+ git clone . porcelain &&
+ git -C porcelain remote add second-remote "$PWD" &&
+ git -C porcelain fetch second-remote &&
+
+ test_commit --no-tag multi-commit &&
+ old_commit=$(git rev-parse HEAD~) &&
+ new_commit=$(git rev-parse HEAD) &&
+
+ cat >expect <<-EOF &&
+ $old_commit $new_commit refs/remotes/origin/multiple-remotes
+ $old_commit $new_commit refs/remotes/second-remote/multiple-remotes
+ EOF
+
+ git -C porcelain fetch --porcelain --all >actual 2>stderr &&
+ test_cmp expect actual &&
+ test_must_be_empty stderr
+'
+
+test_expect_success 'fetch porcelain refuses to work with submodules' '
+ test_when_finished "rm -rf porcelain" &&
+
+ cat >expect <<-EOF &&
+ fatal: options ${SQ}--porcelain${SQ} and ${SQ}--recurse-submodules${SQ} cannot be used together
+ EOF
+
+ git init porcelain &&
+ test_must_fail git -C porcelain fetch --porcelain --recurse-submodules=yes 2>stderr &&
+ test_cmp expect stderr &&
+
+ test_must_fail git -C porcelain fetch --porcelain --recurse-submodules=on-demand 2>stderr &&
+ test_cmp expect stderr
+'
+
+test_expect_success 'fetch porcelain overrides fetch.output config' '
+ test_when_finished "rm -rf porcelain" &&
+
+ git switch --create config-override &&
+ git clone . porcelain &&
+ test_commit new-commit &&
+ old_commit=$(git rev-parse HEAD~) &&
+ new_commit=$(git rev-parse HEAD) &&
+
+ cat >expect <<-EOF &&
+ $old_commit $new_commit refs/remotes/origin/config-override
+ * $ZERO_OID $new_commit refs/tags/new-commit
+ EOF
+
+ git -C porcelain -c fetch.output=compact fetch --porcelain >stdout 2>stderr &&
+ test_must_be_empty stderr &&
+ test_cmp expect stdout
+'
+
+test_expect_success 'fetch --no-porcelain overrides previous --porcelain' '
+ test_when_finished "rm -rf no-porcelain" &&
+
+ git switch --create no-porcelain &&
+ git clone . no-porcelain &&
+ test_commit --no-tag no-porcelain &&
+ old_commit=$(git rev-parse --short HEAD~) &&
+ new_commit=$(git rev-parse --short HEAD) &&
+
+ cat >expect <<-EOF &&
+ From $(test-tool path-utils real_path .)/.
+ $old_commit..$new_commit no-porcelain -> origin/no-porcelain
+ EOF
+
+ git -C no-porcelain fetch --porcelain --no-porcelain >stdout 2>stderr &&
+ test_cmp expect stderr &&
+ test_must_be_empty stdout
+'
+
+test_expect_success 'fetch output with HEAD' '
+ test_when_finished "rm -rf head" &&
+ git clone . head &&
+
+ git -C head fetch --dry-run origin HEAD >actual.out 2>actual.err &&
+ cat >expect <<-EOF &&
+ From $(test-tool path-utils real_path .)/.
+ * branch HEAD -> FETCH_HEAD
+ EOF
+ test_must_be_empty actual.out &&
+ test_cmp expect actual.err &&
+
+ git -C head fetch origin HEAD >actual.out 2>actual.err &&
+ test_must_be_empty actual.out &&
+ test_cmp expect actual.err &&
+
+ git -C head fetch --dry-run origin HEAD:foo >actual.out 2>actual.err &&
+ cat >expect <<-EOF &&
+ From $(test-tool path-utils real_path .)/.
+ * [new ref] HEAD -> foo
+ EOF
+ test_must_be_empty actual.out &&
+ test_cmp expect actual.err &&
+
+ git -C head fetch origin HEAD:foo >actual.out 2>actual.err &&
+ test_must_be_empty actual.out &&
+ test_cmp expect actual.err
+'
+
+test_expect_success 'fetch porcelain output with HEAD' '
+ test_when_finished "rm -rf head" &&
+ git clone . head &&
+ COMMIT_ID=$(git rev-parse HEAD) &&
+
+ git -C head fetch --porcelain --dry-run origin HEAD >actual &&
+ cat >expect <<-EOF &&
+ * $ZERO_OID $COMMIT_ID FETCH_HEAD
+ EOF
+ test_cmp expect actual &&
+
+ git -C head fetch --porcelain origin HEAD >actual &&
+ test_cmp expect actual &&
+
+ git -C head fetch --porcelain --dry-run origin HEAD:foo >actual &&
+ cat >expect <<-EOF &&
+ * $ZERO_OID $COMMIT_ID refs/heads/foo
+ EOF
+ test_cmp expect actual &&
+
+ git -C head fetch --porcelain origin HEAD:foo >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'fetch output with object ID' '
+ test_when_finished "rm -rf object-id" &&
+ git clone . object-id &&
+ commit=$(git rev-parse HEAD) &&
+
+ git -C object-id fetch --dry-run origin $commit:object-id >actual.out 2>actual.err &&
+ cat >expect <<-EOF &&
+ From $(test-tool path-utils real_path .)/.
+ * [new ref] $commit -> object-id
+ EOF
+ test_must_be_empty actual.out &&
+ test_cmp expect actual.err &&
+
+ git -C object-id fetch origin $commit:object-id >actual.out 2>actual.err &&
+ test_must_be_empty actual.out &&
+ test_cmp expect actual.err
+'
+
+test_expect_success '--no-show-forced-updates' '
+ mkdir forced-updates &&
+ (
+ cd forced-updates &&
+ git init &&
+ test_commit 1 &&
+ test_commit 2
+ ) &&
+ git clone forced-updates forced-update-clone &&
+ git clone forced-updates no-forced-update-clone &&
+ git -C forced-updates reset --hard HEAD~1 &&
+ (
+ cd forced-update-clone &&
+ git fetch --show-forced-updates origin 2>output &&
+ test_i18ngrep "(forced update)" output
+ ) &&
+ (
+ cd no-forced-update-clone &&
+ git fetch --no-show-forced-updates origin 2>output &&
+ test_i18ngrep ! "(forced update)" output
+ )
+'
+
+test_done
diff --git a/t/t5583-push-branches.sh b/t/t5583-push-branches.sh
new file mode 100755
index 0000000000..e7e1b6dab6
--- /dev/null
+++ b/t/t5583-push-branches.sh
@@ -0,0 +1,115 @@
+#!/bin/sh
+
+test_description='check the consisitency of behavior of --all and --branches'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+delete_refs() {
+ dir=$1
+ shift
+ rm -rf deletes
+ for arg in $*
+ do
+ echo "delete ${arg}" >>deletes
+ done
+ git -C $dir update-ref --stdin < deletes
+}
+
+test_expect_success 'setup bare remote' '
+ git init --bare remote-1 &&
+ git -C remote-1 config gc.auto 0 &&
+ test_commit one &&
+ git push remote-1 HEAD
+'
+
+test_expect_success 'setup different types of references' '
+ cat >refs <<-EOF &&
+ update refs/heads/branch-1 HEAD
+ update refs/heads/branch-2 HEAD
+ EOF
+
+ git tag -a -m "annotated" annotated-1 HEAD &&
+ git tag -a -m "annotated" annotated-2 HEAD &&
+ git update-ref --stdin < refs
+'
+
+test_expect_success '--all and --branches have the same behavior' '
+ test_when_finished "delete_refs remote-1 \
+ refs/heads/branch-1 \
+ refs/heads/branch-2" &&
+ git push remote-1 --all &&
+ commit=$(git rev-parse HEAD) &&
+ cat >expect <<-EOF &&
+ $commit refs/heads/branch-1
+ $commit refs/heads/branch-2
+ $commit refs/heads/main
+ EOF
+
+ git -C remote-1 show-ref --heads >actual.all &&
+ delete_refs remote-1 refs/heads/branch-1 refs/heads/branch-2 &&
+ git push remote-1 --branches &&
+ git -C remote-1 show-ref --heads >actual.branches &&
+ test_cmp actual.all actual.branches &&
+ test_cmp expect actual.all
+'
+
+test_expect_success '--all or --branches can not be combined with refspecs' '
+ test_must_fail git push remote-1 --all main >actual.all 2>&1 &&
+ test_must_fail git push remote-1 --branches main >actual.branches 2>&1 &&
+ test_cmp actual.all actual.branches &&
+ grep "be combined with refspecs" actual.all
+'
+
+test_expect_success '--all or --branches can not be combined with --mirror' '
+ test_must_fail git push remote-1 --all --mirror >actual.all 2>&1 &&
+ test_must_fail git push remote-1 --branches --mirror >actual.branches 2>&1 &&
+ test_cmp actual.all actual.branches &&
+ grep "cannot be used together" actual.all
+'
+
+test_expect_success '--all or --branches can not be combined with --tags' '
+ test_must_fail git push remote-1 --all --tags >actual.all 2>&1 &&
+ test_must_fail git push remote-1 --branches --tags >actual.branches 2>&1 &&
+ test_cmp actual.all actual.branches &&
+ grep "cannot be used together" actual.all
+'
+
+
+test_expect_success '--all or --branches can not be combined with --delete' '
+ test_must_fail git push remote-1 --all --delete >actual.all 2>&1 &&
+ test_must_fail git push remote-1 --branches --delete >actual.branches 2>&1 &&
+ test_cmp actual.all actual.branches &&
+ grep "cannot be used together" actual.all
+'
+
+test_expect_success '--all or --branches combines with --follow-tags have same behavior' '
+ test_when_finished "delete_refs remote-1 \
+ refs/heads/branch-1 \
+ refs/heads/branch-2 \
+ refs/tags/annotated-1 \
+ refs/tags/annotated-2" &&
+ git push remote-1 --all --follow-tags &&
+ git -C remote-1 show-ref > actual.all &&
+ cat >expect <<-EOF &&
+ $commit refs/heads/branch-1
+ $commit refs/heads/branch-2
+ $commit refs/heads/main
+ $(git rev-parse annotated-1) refs/tags/annotated-1
+ $(git rev-parse annotated-2) refs/tags/annotated-2
+ EOF
+
+ delete_refs remote-1 \
+ refs/heads/branch-1 \
+ refs/heads/branch-2 \
+ refs/tags/annotated-1 \
+ refs/tags/annotated-2 &&
+ git push remote-1 --branches --follow-tags &&
+ git -C remote-1 show-ref >actual.branches &&
+ test_cmp actual.all actual.branches &&
+ test_cmp expect actual.all
+'
+
+test_done
diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh
index 41d0ca00b1..573eb97a0f 100755
--- a/t/t6006-rev-list-format.sh
+++ b/t/t6006-rev-list-format.sh
@@ -493,7 +493,7 @@ test_expect_success 'empty email' '
test_tick &&
C=$(GIT_AUTHOR_EMAIL= git commit-tree HEAD^{tree} </dev/null) &&
A=$(git show --pretty=format:%an,%ae,%ad%n -s $C) &&
- verbose test "$A" = "$GIT_AUTHOR_NAME,,Thu Apr 7 15:14:13 2005 -0700"
+ test "$A" = "$GIT_AUTHOR_NAME,,Thu Apr 7 15:14:13 2005 -0700"
'
test_expect_success 'del LF before empty (1)' '
diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh
index d9acb63951..69509d0c11 100755
--- a/t/t6500-gc.sh
+++ b/t/t6500-gc.sh
@@ -210,90 +210,95 @@ prepare_cruft_history () {
git reset HEAD^^
}
-assert_cruft_packs () {
- find .git/objects/pack -name "*.mtimes" >mtimes &&
- sed -e 's/\.mtimes$/\.pack/g' mtimes >packs &&
-
- test_file_not_empty packs &&
- while read pack
- do
- test_path_is_file "$pack" || return 1
- done <packs
-}
-
assert_no_cruft_packs () {
find .git/objects/pack -name "*.mtimes" >mtimes &&
test_must_be_empty mtimes
}
-test_expect_success 'gc --cruft generates a cruft pack' '
- test_when_finished "rm -fr crufts" &&
- git init crufts &&
+for argv in \
+ "gc" \
+ "-c gc.cruftPacks=true gc" \
+ "-c gc.cruftPacks=false gc --cruft"
+do
+ test_expect_success "git $argv generates a cruft pack" '
+ test_when_finished "rm -fr repo" &&
+ git init repo &&
+ (
+ cd repo &&
+
+ prepare_cruft_history &&
+ git $argv &&
+
+ find .git/objects/pack -name "*.mtimes" >mtimes &&
+ sed -e 's/\.mtimes$/\.pack/g' mtimes >packs &&
+
+ test_file_not_empty packs &&
+ while read pack
+ do
+ test_path_is_file "$pack" || return 1
+ done <packs
+ )
+ '
+done
+
+for argv in \
+ "gc --no-cruft" \
+ "-c gc.cruftPacks=false gc" \
+ "-c gc.cruftPacks=true gc --no-cruft"
+do
+ test_expect_success "git $argv does not generate a cruft pack" '
+ test_when_finished "rm -fr repo" &&
+ git init repo &&
+ (
+ cd repo &&
+
+ prepare_cruft_history &&
+ git $argv &&
+
+ assert_no_cruft_packs
+ )
+ '
+done
+
+test_expect_success '--keep-largest-pack ignores cruft packs' '
+ test_when_finished "rm -fr repo" &&
+ git init repo &&
(
- cd crufts &&
+ cd repo &&
+ # Generate a pack for reachable objects (of which there
+ # are 3), and one for unreachable objects (of which
+ # there are 6).
prepare_cruft_history &&
git gc --cruft &&
- assert_cruft_packs
- )
-'
-
-test_expect_success 'gc.cruftPacks=true generates a cruft pack' '
- test_when_finished "rm -fr crufts" &&
- git init crufts &&
- (
- cd crufts &&
-
- prepare_cruft_history &&
- git -c gc.cruftPacks=true gc &&
- assert_cruft_packs
- )
-'
-
-test_expect_success 'feature.experimental=true generates a cruft pack' '
- git init crufts &&
- test_when_finished "rm -fr crufts" &&
- (
- cd crufts &&
- prepare_cruft_history &&
- git -c feature.experimental=true gc &&
- assert_cruft_packs
- )
-'
+ mtimes="$(find .git/objects/pack -type f -name "pack-*.mtimes")" &&
+ sz="$(test_file_size "${mtimes%.mtimes}.pack")" &&
-test_expect_success 'feature.experimental=false allows explicit cruft packs' '
- git init crufts &&
- test_when_finished "rm -fr crufts" &&
- (
- cd crufts &&
+ # Ensure that the cruft pack gets removed (due to
+ # `--prune=now`) despite it being the largest pack.
+ git -c gc.bigPackThreshold=$sz gc --cruft --prune=now &&
- prepare_cruft_history &&
- git -c gc.cruftPacks=true -c feature.experimental=false gc &&
- assert_cruft_packs
+ assert_no_cruft_packs
)
'
-test_expect_success 'feature.experimental=true can be overridden' '
- git init crufts &&
- test_when_finished "rm -fr crufts" &&
+test_expect_success 'gc.bigPackThreshold ignores cruft packs' '
+ test_when_finished "rm -fr repo" &&
+ git init repo &&
(
- cd crufts &&
+ cd repo &&
+ # Generate a pack for reachable objects (of which there
+ # are 3), and one for unreachable objects (of which
+ # there are 6).
prepare_cruft_history &&
- git -c feature.expiremental=true -c gc.cruftPacks=false gc &&
- assert_no_cruft_packs
- )
-'
+ git gc --cruft &&
-test_expect_success 'feature.experimental=false avoids cruft packs by default' '
- git init crufts &&
- test_when_finished "rm -fr crufts" &&
- (
- cd crufts &&
+ # Ensure that the cruft pack gets removed (due to
+ # `--prune=now`) despite it being the largest pack.
+ git gc --cruft --prune=now --keep-largest-pack &&
- prepare_cruft_history &&
- git -c feature.experimental=false gc &&
assert_no_cruft_packs
)
'
diff --git a/t/t6501-freshen-objects.sh b/t/t6501-freshen-objects.sh
index 3968b47ed5..4521508b83 100755
--- a/t/t6501-freshen-objects.sh
+++ b/t/t6501-freshen-objects.sh
@@ -101,7 +101,7 @@ do
'
test_expect_success "simultaneous gc ($title)" '
- git gc --prune=12.hours.ago
+ git gc --no-cruft --prune=12.hours.ago
'
test_expect_success "finish writing out commit ($title)" '
@@ -131,7 +131,7 @@ do
'
test_expect_success "simultaneous gc ($title)" '
- git gc --prune=12.hours.ago
+ git gc --no-cruft --prune=12.hours.ago
'
# tree should have been refreshed by write-tree
@@ -151,8 +151,8 @@ test_expect_success 'do not complain about existing broken links (commit)' '
some message
EOF
commit=$(git hash-object -t commit -w broken-commit) &&
- git gc -q 2>stderr &&
- verbose git cat-file -e $commit &&
+ git gc --no-cruft -q 2>stderr &&
+ git cat-file -e $commit &&
test_must_be_empty stderr
'
@@ -161,7 +161,7 @@ test_expect_success 'do not complain about existing broken links (tree)' '
100644 blob $(test_oid 003) foo
EOF
tree=$(git mktree --missing <broken-tree) &&
- git gc -q 2>stderr &&
+ git gc --no-cruft -q 2>stderr &&
git cat-file -e $tree &&
test_must_be_empty stderr
'
@@ -176,7 +176,7 @@ test_expect_success 'do not complain about existing broken links (tag)' '
this is a broken tag
EOF
tag=$(git hash-object -t tag -w broken-tag) &&
- git gc -q 2>stderr &&
+ git gc --no-cruft -q 2>stderr &&
git cat-file -e $tag &&
test_must_be_empty stderr
'
diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh
index d72cef8826..898a920532 100755
--- a/t/t7001-mv.sh
+++ b/t/t7001-mv.sh
@@ -4,6 +4,10 @@ test_description='git mv in subdirs'
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff-data.sh
+index_at_path () {
+ git ls-files --format='%(objectmode) %(objectname) %(stage)' "$@"
+}
+
test_expect_success 'mv -f refreshes updated index entry' '
echo test >bar &&
git add bar &&
@@ -187,7 +191,8 @@ test_expect_success "Michael Cassar's test case" '
git mv papers/unsorted/Thesis.pdf papers/all-papers/moo-blah.pdf &&
T=$(git write-tree) &&
- git ls-tree -r $T | verbose grep partA/outline.txt
+ git ls-tree -r $T >out &&
+ grep partA/outline.txt out
'
rm -fr papers partA path?
@@ -260,12 +265,12 @@ test_expect_success 'git mv should not change sha1 of moved cache entry' '
git init &&
echo 1 >dirty &&
git add dirty &&
- entry="$(git ls-files --stage dirty | cut -f 1)" &&
+ entry="$(index_at_path dirty)" &&
git mv dirty dirty2 &&
- test "$entry" = "$(git ls-files --stage dirty2 | cut -f 1)" &&
+ test "$entry" = "$(index_at_path dirty2)" &&
echo 2 >dirty2 &&
git mv dirty2 dirty &&
- test "$entry" = "$(git ls-files --stage dirty | cut -f 1)"
+ test "$entry" = "$(index_at_path dirty)"
'
rm -f dirty dirty2
@@ -342,7 +347,7 @@ test_expect_success 'git mv cannot move a submodule in a file' '
'
test_expect_success 'git mv moves a submodule with a .git directory and no .gitmodules' '
- entry="$(git ls-files --stage sub | cut -f 1)" &&
+ entry="$(index_at_path sub)" &&
git rm .gitmodules &&
(
cd sub &&
@@ -353,7 +358,7 @@ test_expect_success 'git mv moves a submodule with a .git directory and no .gitm
mkdir mod &&
git mv sub mod/sub &&
test_path_is_missing sub &&
- test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+ test "$entry" = "$(index_at_path mod/sub)" &&
git -C mod/sub status &&
git update-index --refresh &&
git diff-files --quiet
@@ -363,7 +368,7 @@ test_expect_success 'git mv moves a submodule with a .git directory and .gitmodu
rm -rf mod &&
git reset --hard &&
git submodule update &&
- entry="$(git ls-files --stage sub | cut -f 1)" &&
+ entry="$(index_at_path sub)" &&
(
cd sub &&
rm -f .git &&
@@ -373,7 +378,7 @@ test_expect_success 'git mv moves a submodule with a .git directory and .gitmodu
mkdir mod &&
git mv sub mod/sub &&
test_path_is_missing sub &&
- test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+ test "$entry" = "$(index_at_path mod/sub)" &&
git -C mod/sub status &&
echo mod/sub >expected &&
git config -f .gitmodules submodule.sub.path >actual &&
@@ -386,11 +391,11 @@ test_expect_success 'git mv moves a submodule with gitfile' '
rm -rf mod &&
git reset --hard &&
git submodule update &&
- entry="$(git ls-files --stage sub | cut -f 1)" &&
+ entry="$(index_at_path sub)" &&
mkdir mod &&
git -C mod mv ../sub/ . &&
test_path_is_missing sub &&
- test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+ test "$entry" = "$(index_at_path mod/sub)" &&
git -C mod/sub status &&
echo mod/sub >expected &&
git config -f .gitmodules submodule.sub.path >actual &&
@@ -404,12 +409,12 @@ test_expect_success 'mv does not complain when no .gitmodules file is found' '
git reset --hard &&
git submodule update &&
git rm .gitmodules &&
- entry="$(git ls-files --stage sub | cut -f 1)" &&
+ entry="$(index_at_path sub)" &&
mkdir mod &&
git mv sub mod/sub 2>actual.err &&
test_must_be_empty actual.err &&
test_path_is_missing sub &&
- test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+ test "$entry" = "$(index_at_path mod/sub)" &&
git -C mod/sub status &&
git update-index --refresh &&
git diff-files --quiet
@@ -420,7 +425,7 @@ test_expect_success 'mv will error out on a modified .gitmodules file unless sta
git reset --hard &&
git submodule update &&
git config -f .gitmodules foo.bar true &&
- entry="$(git ls-files --stage sub | cut -f 1)" &&
+ entry="$(index_at_path sub)" &&
mkdir mod &&
test_must_fail git mv sub mod/sub 2>actual.err &&
test_file_not_empty actual.err &&
@@ -430,7 +435,7 @@ test_expect_success 'mv will error out on a modified .gitmodules file unless sta
git mv sub mod/sub 2>actual.err &&
test_must_be_empty actual.err &&
test_path_is_missing sub &&
- test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+ test "$entry" = "$(index_at_path mod/sub)" &&
git -C mod/sub status &&
git update-index --refresh &&
git diff-files --quiet
@@ -442,13 +447,13 @@ test_expect_success 'mv issues a warning when section is not found in .gitmodule
git submodule update &&
git config -f .gitmodules --remove-section submodule.sub &&
git add .gitmodules &&
- entry="$(git ls-files --stage sub | cut -f 1)" &&
+ entry="$(index_at_path sub)" &&
echo "warning: Could not find section in .gitmodules where path=sub" >expect.err &&
mkdir mod &&
git mv sub mod/sub 2>actual.err &&
test_cmp expect.err actual.err &&
test_path_is_missing sub &&
- test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
+ test "$entry" = "$(index_at_path mod/sub)" &&
git -C mod/sub status &&
git update-index --refresh &&
git diff-files --quiet
diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh
index c975eb54d2..0ef7b78457 100755
--- a/t/t7300-clean.sh
+++ b/t/t7300-clean.sh
@@ -120,7 +120,7 @@ test_expect_success 'git clean with relative prefix' '
grep part3 |
sed -n -e "s|^Would remove ||p"
) &&
- verbose test "$would_clean" = ../src/part3.c
+ test "$would_clean" = ../src/part3.c
'
test_expect_success 'git clean with absolute path' '
@@ -133,7 +133,7 @@ test_expect_success 'git clean with absolute path' '
grep part3 |
sed -n -e "s|^Would remove ||p"
) &&
- verbose test "$would_clean" = ../src/part3.c
+ test "$would_clean" = ../src/part3.c
'
test_expect_success 'git clean with out of work tree relative path' '
diff --git a/t/t7510-signed-commit.sh b/t/t7510-signed-commit.sh
index 48f86cb367..ccbc416402 100755
--- a/t/t7510-signed-commit.sh
+++ b/t/t7510-signed-commit.sh
@@ -221,84 +221,91 @@ test_expect_success GPG 'amending already signed commit' '
test_expect_success GPG 'show good signature with custom format' '
cat >expect <<-\EOF &&
G
+ ultimate
13B6F51ECDDE430D
C O Mitter <committer@example.com>
73D758744BE721698EC54E8713B6F51ECDDE430D
73D758744BE721698EC54E8713B6F51ECDDE430D
EOF
- git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" sixth-signed >actual &&
+ git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" sixth-signed >actual &&
test_cmp expect actual
'
test_expect_success GPG 'show bad signature with custom format' '
cat >expect <<-\EOF &&
B
+ undefined
13B6F51ECDDE430D
C O Mitter <committer@example.com>
EOF
- git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" $(cat forged1.commit) >actual &&
+ git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" $(cat forged1.commit) >actual &&
test_cmp expect actual
'
test_expect_success GPG 'show untrusted signature with custom format' '
cat >expect <<-\EOF &&
U
+ undefined
65A0EEA02E30CAD7
Eris Discordia <discord@example.net>
F8364A59E07FFE9F4D63005A65A0EEA02E30CAD7
D4BE22311AD3131E5EDA29A461092E85B7227189
EOF
- git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual &&
+ git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual &&
test_cmp expect actual
'
test_expect_success GPG 'show untrusted signature with undefined trust level' '
cat >expect <<-\EOF &&
+ U
undefined
65A0EEA02E30CAD7
Eris Discordia <discord@example.net>
F8364A59E07FFE9F4D63005A65A0EEA02E30CAD7
D4BE22311AD3131E5EDA29A461092E85B7227189
EOF
- git log -1 --format="%GT%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual &&
+ git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual &&
test_cmp expect actual
'
test_expect_success GPG 'show untrusted signature with ultimate trust level' '
cat >expect <<-\EOF &&
+ G
ultimate
13B6F51ECDDE430D
C O Mitter <committer@example.com>
73D758744BE721698EC54E8713B6F51ECDDE430D
73D758744BE721698EC54E8713B6F51ECDDE430D
EOF
- git log -1 --format="%GT%n%GK%n%GS%n%GF%n%GP" sixth-signed >actual &&
+ git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" sixth-signed >actual &&
test_cmp expect actual
'
test_expect_success GPG 'show unknown signature with custom format' '
cat >expect <<-\EOF &&
E
+ undefined
65A0EEA02E30CAD7
EOF
- GNUPGHOME="$GNUPGHOME_NOT_USED" git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual &&
+ GNUPGHOME="$GNUPGHOME_NOT_USED" git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual &&
test_cmp expect actual
'
test_expect_success GPG 'show lack of signature with custom format' '
cat >expect <<-\EOF &&
N
+ undefined
EOF
- git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" seventh-unsigned >actual &&
+ git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" seventh-unsigned >actual &&
test_cmp expect actual
'
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index 6520346246..48bf0af2ee 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -47,7 +47,7 @@ clean_fake_sendmail () {
test_expect_success $PREREQ 'Extract patches' '
patches=$(git format-patch -s --cc="One <one@example.com>" --cc=two@example.com -n HEAD^1) &&
- threaded_patches=$(git format-patch -o threaded -s --in-reply-to="format" HEAD^1)
+ threaded_patches=$(git format-patch -o threaded --thread=shallow -s --in-reply-to="format" HEAD^1)
'
# Test no confirm early to ensure remaining tests will not hang
@@ -374,13 +374,16 @@ test_expect_success $PREREQ,!AUTOIDENT 'broken implicit ident aborts send-email'
)
'
-test_expect_success $PREREQ 'setup tocmd and cccmd scripts' '
+test_expect_success $PREREQ 'setup cmd scripts' '
write_script tocmd-sed <<-\EOF &&
sed -n -e "s/^tocmd--//p" "$1"
EOF
- write_script cccmd-sed <<-\EOF
+ write_script cccmd-sed <<-\EOF &&
sed -n -e "s/^cccmd--//p" "$1"
EOF
+ write_script headercmd-sed <<-\EOF
+ sed -n -e "s/^headercmd--//p" "$1"
+ EOF
'
test_expect_success $PREREQ 'tocmd works' '
@@ -410,6 +413,70 @@ test_expect_success $PREREQ 'cccmd works' '
grep "^ cccmd@example.com" msgtxt1
'
+test_expect_success $PREREQ 'headercmd works' '
+ clean_fake_sendmail &&
+ cp $patches headercmd.patch &&
+ echo "headercmd--X-Debbugs-CC: dummy@example.com" >>headercmd.patch &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --header-cmd=./headercmd-sed \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ headercmd.patch \
+ &&
+ grep "^X-Debbugs-CC: dummy@example.com" msgtxt1
+'
+
+test_expect_success $PREREQ '--no-header-cmd works' '
+ clean_fake_sendmail &&
+ cp $patches headercmd.patch &&
+ echo "headercmd--X-Debbugs-CC: dummy@example.com" >>headercmd.patch &&
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --header-cmd=./headercmd-sed \
+ --no-header-cmd \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ headercmd.patch \
+ &&
+ ! grep "^X-Debbugs-CC: dummy@example.com" msgtxt1
+'
+
+test_expect_success $PREREQ 'multiline fields are correctly unfolded' '
+ clean_fake_sendmail &&
+ cp $patches headercmd.patch &&
+ write_script headercmd-multiline <<-\EOF &&
+ echo "X-Debbugs-CC: someone@example.com
+FoldedField: This is a tale
+ best told using
+ multiple lines."
+ EOF
+ git send-email \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --header-cmd=./headercmd-multiline \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ headercmd.patch &&
+ grep "^FoldedField: This is a tale best told using multiple lines.$" msgtxt1
+'
+
+# Blank lines in the middle of the output of a command are invalid.
+test_expect_success $PREREQ 'malform output reported on blank lines in command output' '
+ clean_fake_sendmail &&
+ cp $patches headercmd.patch &&
+ write_script headercmd-malformed-output <<-\EOF &&
+ echo "X-Debbugs-CC: someone@example.com
+
+SomeOtherField: someone-else@example.com"
+ EOF
+ ! git send-email \
+ --from="Example <nobody@example.com>" \
+ --to=nobody@example.com \
+ --header-cmd=./headercmd-malformed-output \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ headercmd.patch
+'
+
test_expect_success $PREREQ 'reject long lines' '
z8=zzzzzzzz &&
z64=$z8$z8$z8$z8$z8$z8$z8$z8 &&
@@ -540,7 +607,7 @@ test_expect_success $PREREQ "--validate respects relative core.hooksPath path" '
test_path_is_file my-hooks.ran &&
cat >expect <<-EOF &&
fatal: longline.patch: rejected by sendemail-validate hook
- fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch>'"'"' died with exit code 1
+ fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch> <header>'"'"' died with exit code 1
warning: no patches were sent
EOF
test_cmp expect actual
@@ -559,12 +626,50 @@ test_expect_success $PREREQ "--validate respects absolute core.hooksPath path" '
test_path_is_file my-hooks.ran &&
cat >expect <<-EOF &&
fatal: longline.patch: rejected by sendemail-validate hook
- fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch>'"'"' died with exit code 1
+ fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch> <header>'"'"' died with exit code 1
warning: no patches were sent
EOF
test_cmp expect actual
'
+test_expect_success $PREREQ "--validate hook supports header argument" '
+ write_script my-hooks/sendemail-validate <<-\EOF &&
+ if test "$#" -ge 2
+ then
+ grep "X-test-header: v1.0" "$2"
+ else
+ echo "No header arg passed"
+ exit 1
+ fi
+ EOF
+ test_config core.hooksPath "my-hooks" &&
+ rm -fr outdir &&
+ git format-patch \
+ --add-header="X-test-header: v1.0" \
+ -n HEAD^1 -o outdir &&
+ git send-email \
+ --dry-run \
+ --to=nobody@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ --validate \
+ outdir/000?-*.patch
+'
+
+test_expect_success $PREREQ 'clear message-id before parsing a new message' '
+ clean_fake_sendmail &&
+ echo true | write_script my-hooks/sendemail-validate &&
+ test_config core.hooksPath my-hooks &&
+ GIT_SEND_EMAIL_NOTTY=1 \
+ git send-email --validate --to=recipient@example.com \
+ --smtp-server="$(pwd)/fake.sendmail" \
+ $patches $threaded_patches &&
+ id0=$(grep "^Message-ID: " $threaded_patches) &&
+ id1=$(grep "^Message-ID: " msgtxt1) &&
+ id2=$(grep "^Message-ID: " msgtxt2) &&
+ test "z$id0" = "z$id2" &&
+ test "z$id1" != "z$id2"
+'
+
for enc in 7bit 8bit quoted-printable base64
do
test_expect_success $PREREQ "--transfer-encoding=$enc produces correct header" '
diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index aa55b41b9a..ac237a1f90 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -388,9 +388,7 @@ test_expect_success 'B: accept branch name "TEMP_TAG"' '
INPUT_END
- test_when_finished "rm -f .git/TEMP_TAG
- git gc
- git prune" &&
+ test_when_finished "rm -f .git/TEMP_TAG && git gc --prune=now" &&
git fast-import <input &&
test $(test-tool ref-store main resolve-ref TEMP_TAG 0 | cut -f1 -d " " ) != "$ZERO_OID" &&
test $(git rev-parse main) = $(git rev-parse TEMP_TAG^)
@@ -406,8 +404,7 @@ test_expect_success 'B: accept empty committer' '
INPUT_END
test_when_finished "git update-ref -d refs/heads/empty-committer-1
- git gc
- git prune" &&
+ git gc --prune=now" &&
git fast-import <input &&
out=$(git fsck) &&
echo "$out" &&
@@ -452,8 +449,7 @@ test_expect_success 'B: accept and fixup committer with no name' '
INPUT_END
test_when_finished "git update-ref -d refs/heads/empty-committer-2
- git gc
- git prune" &&
+ git gc --prune=now" &&
git fast-import <input &&
out=$(git fsck) &&
echo "$out" &&
@@ -1778,8 +1774,7 @@ test_expect_success 'P: verbatim SHA gitlinks' '
INPUT_END
git branch -D sub &&
- git gc &&
- git prune &&
+ git gc --prune=now &&
git fast-import <input &&
test $(git rev-parse --verify subuse2) = $(git rev-parse --verify subuse1)
'
diff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh
index dc88d0e064..a4b3cb9492 100755
--- a/t/t9800-git-p4-basic.sh
+++ b/t/t9800-git-p4-basic.sh
@@ -330,7 +330,7 @@ test_expect_success 'initial import time from top change time' '
test_when_finished cleanup_git &&
(
cd "$git" &&
- gittime=$(git show -s --raw --pretty=format:%at HEAD) &&
+ gittime=$(git show -s --pretty=format:%at HEAD) &&
echo $p4time $gittime &&
test $p4time = $gittime
)
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index d6c0478d98..8835e16e81 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -405,40 +405,40 @@ test_expect_success '__gitdir - remote as argument' '
test_expect_success '__git_dequote - plain unquoted word' '
__git_dequote unquoted-word &&
- verbose test unquoted-word = "$dequoted_word"
+ test unquoted-word = "$dequoted_word"
'
# input: b\a\c\k\'\\\"s\l\a\s\h\es
# expected: back'\"slashes
test_expect_success '__git_dequote - backslash escaped' '
__git_dequote "b\a\c\k\\'\''\\\\\\\"s\l\a\s\h\es" &&
- verbose test "back'\''\\\"slashes" = "$dequoted_word"
+ test "back'\''\\\"slashes" = "$dequoted_word"
'
# input: sin'gle\' '"quo'ted
# expected: single\ "quoted
test_expect_success '__git_dequote - single quoted' '
__git_dequote "'"sin'gle\\\\' '\\\"quo'ted"'" &&
- verbose test '\''single\ "quoted'\'' = "$dequoted_word"
+ test '\''single\ "quoted'\'' = "$dequoted_word"
'
# input: dou"ble\\" "\"\quot"ed
# expected: double\ "\quoted
test_expect_success '__git_dequote - double quoted' '
__git_dequote '\''dou"ble\\" "\"\quot"ed'\'' &&
- verbose test '\''double\ "\quoted'\'' = "$dequoted_word"
+ test '\''double\ "\quoted'\'' = "$dequoted_word"
'
# input: 'open single quote
test_expect_success '__git_dequote - open single quote' '
__git_dequote "'\''open single quote" &&
- verbose test "open single quote" = "$dequoted_word"
+ test "open single quote" = "$dequoted_word"
'
# input: "open double quote
test_expect_success '__git_dequote - open double quote' '
__git_dequote "\"open double quote" &&
- verbose test "open double quote" = "$dequoted_word"
+ test "open double quote" = "$dequoted_word"
'
@@ -616,7 +616,7 @@ test_expect_success '__git_is_configured_remote' '
test_when_finished "git remote remove remote_2" &&
git remote add remote_2 git://remote_2 &&
(
- verbose __git_is_configured_remote remote_2 &&
+ __git_is_configured_remote remote_2 &&
test_must_fail __git_is_configured_remote non-existent
)
'
@@ -2596,30 +2596,30 @@ test_expect_success 'options with value' '
test_expect_success 'sourcing the completion script clears cached commands' '
(
__git_compute_all_commands &&
- verbose test -n "$__git_all_commands" &&
+ test -n "$__git_all_commands" &&
. "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
- verbose test -z "$__git_all_commands"
+ test -z "$__git_all_commands"
)
'
test_expect_success 'sourcing the completion script clears cached merge strategies' '
(
__git_compute_merge_strategies &&
- verbose test -n "$__git_merge_strategies" &&
+ test -n "$__git_merge_strategies" &&
. "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
- verbose test -z "$__git_merge_strategies"
+ test -z "$__git_merge_strategies"
)
'
test_expect_success 'sourcing the completion script clears cached --options' '
(
__gitcomp_builtin checkout &&
- verbose test -n "$__gitcomp_builtin_checkout" &&
+ test -n "$__gitcomp_builtin_checkout" &&
__gitcomp_builtin notes_edit &&
- verbose test -n "$__gitcomp_builtin_notes_edit" &&
+ test -n "$__gitcomp_builtin_notes_edit" &&
. "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
- verbose test -z "$__gitcomp_builtin_checkout" &&
- verbose test -z "$__gitcomp_builtin_notes_edit"
+ test -z "$__gitcomp_builtin_checkout" &&
+ test -z "$__gitcomp_builtin_notes_edit"
)
'
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 999d46fafe..6e19ebc922 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -1227,15 +1227,6 @@ test_i18ngrep () {
return 1
}
-# Call any command "$@" but be more verbose about its
-# failure. This is handy for commands like "test" which do
-# not output anything when they fail.
-verbose () {
- "$@" && return 0
- echo >&4 "command failed: $(git rev-parse --sq-quote "$@")"
- return 1
-}
-
# Check if the file expected to be empty is indeed empty, and barfs
# otherwise.
diff --git a/tempfile.c b/tempfile.c
index 50c377134c..6c88a63b42 100644
--- a/tempfile.c
+++ b/tempfile.c
@@ -43,6 +43,7 @@
*/
#include "git-compat-util.h"
+#include "abspath.h"
#include "path.h"
#include "tempfile.h"
#include "sigchain.h"
diff --git a/trace2.c b/trace2.c
index 21264df71b..0efc4e7b95 100644
--- a/trace2.c
+++ b/trace2.c
@@ -2,6 +2,7 @@
#include "config.h"
#include "json-writer.h"
#include "quote.h"
+#include "repository.h"
#include "run-command.h"
#include "sigchain.h"
#include "thread-utils.h"
diff --git a/trace2/tr2_tgt_event.c b/trace2/tr2_tgt_event.c
index 9e7aab6d51..2af53e5d4d 100644
--- a/trace2/tr2_tgt_event.c
+++ b/trace2/tr2_tgt_event.c
@@ -1,6 +1,7 @@
#include "git-compat-util.h"
#include "config.h"
#include "json-writer.h"
+#include "repository.h"
#include "run-command.h"
#include "version.h"
#include "trace2/tr2_dst.h"
diff --git a/trace2/tr2_tgt_normal.c b/trace2/tr2_tgt_normal.c
index 8672c2c2d0..1ebfb464d5 100644
--- a/trace2/tr2_tgt_normal.c
+++ b/trace2/tr2_tgt_normal.c
@@ -1,5 +1,6 @@
#include "git-compat-util.h"
#include "config.h"
+#include "repository.h"
#include "run-command.h"
#include "quote.h"
#include "version.h"
diff --git a/trace2/tr2_tgt_perf.c b/trace2/tr2_tgt_perf.c
index 3f2b2d5311..328e483a05 100644
--- a/trace2/tr2_tgt_perf.c
+++ b/trace2/tr2_tgt_perf.c
@@ -1,5 +1,6 @@
#include "git-compat-util.h"
#include "config.h"
+#include "repository.h"
#include "run-command.h"
#include "quote.h"
#include "version.h"
diff --git a/tree-diff.c b/tree-diff.c
index 69031d7cba..20bb15f38d 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -1,10 +1,24 @@
/*
* Helper functions for tree diff generation
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "diff.h"
#include "diffcore.h"
#include "tree.h"
+#include "tree-walk.h"
+
+/*
+ * Some mode bits are also used internally for computations.
+ *
+ * They *must* not overlap with any valid modes, and they *must* not be emitted
+ * to outside world - i.e. appear on disk or network. In other words, it's just
+ * temporary fields, which we internally use, but they have to stay in-house.
+ *
+ * ( such approach is valid, as standard S_IF* fits into 16 bits, and in Git
+ * codebase mode is `unsigned int` which is assumed to be at least 32 bits )
+ */
+
+#define S_DIFFTREE_IFXMIN_NEQ 0x80000000
/*
* internal mode marker, saying a tree entry != entry of tp[imin]
diff --git a/tree-walk.c b/tree-walk.c
index 2993c48c2f..d3c48e06df 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "tree-walk.h"
#include "alloc.h"
#include "dir.h"
diff --git a/tree-walk.h b/tree-walk.h
index 25fe27e352..01a9d8eb44 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -1,9 +1,10 @@
#ifndef TREE_WALK_H
#define TREE_WALK_H
-#include "hash.h"
+#include "hash-ll.h"
struct index_state;
+struct repository;
#define MAX_TRAVERSE_TREES 8
diff --git a/tree.c b/tree.c
index e9d51ce2e0..0dd2029a8a 100644
--- a/tree.c
+++ b/tree.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "cache-tree.h"
#include "hex.h"
#include "tree.h"
@@ -94,14 +94,72 @@ int read_tree(struct repository *r,
return ret;
}
-int cmp_cache_name_compare(const void *a_, const void *b_)
+int base_name_compare(const char *name1, size_t len1, int mode1,
+ const char *name2, size_t len2, int mode2)
{
- const struct cache_entry *ce1, *ce2;
+ unsigned char c1, c2;
+ size_t len = len1 < len2 ? len1 : len2;
+ int cmp;
+
+ cmp = memcmp(name1, name2, len);
+ if (cmp)
+ return cmp;
+ c1 = name1[len];
+ c2 = name2[len];
+ if (!c1 && S_ISDIR(mode1))
+ c1 = '/';
+ if (!c2 && S_ISDIR(mode2))
+ c2 = '/';
+ return (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0;
+}
+
+/*
+ * df_name_compare() is identical to base_name_compare(), except it
+ * compares conflicting directory/file entries as equal. Note that
+ * while a directory name compares as equal to a regular file, they
+ * then individually compare _differently_ to a filename that has
+ * a dot after the basename (because '\0' < '.' < '/').
+ *
+ * This is used by routines that want to traverse the git namespace
+ * but then handle conflicting entries together when possible.
+ */
+int df_name_compare(const char *name1, size_t len1, int mode1,
+ const char *name2, size_t len2, int mode2)
+{
+ unsigned char c1, c2;
+ size_t len = len1 < len2 ? len1 : len2;
+ int cmp;
+
+ cmp = memcmp(name1, name2, len);
+ if (cmp)
+ return cmp;
+ /* Directories and files compare equal (same length, same name) */
+ if (len1 == len2)
+ return 0;
+ c1 = name1[len];
+ if (!c1 && S_ISDIR(mode1))
+ c1 = '/';
+ c2 = name2[len];
+ if (!c2 && S_ISDIR(mode2))
+ c2 = '/';
+ if (c1 == '/' && !c2)
+ return 0;
+ if (c2 == '/' && !c1)
+ return 0;
+ return c1 - c2;
+}
- ce1 = *((const struct cache_entry **)a_);
- ce2 = *((const struct cache_entry **)b_);
- return cache_name_stage_compare(ce1->name, ce1->ce_namelen, ce_stage(ce1),
- ce2->name, ce2->ce_namelen, ce_stage(ce2));
+int name_compare(const char *name1, size_t len1, const char *name2, size_t len2)
+{
+ size_t min_len = (len1 < len2) ? len1 : len2;
+ int cmp = memcmp(name1, name2, min_len);
+ if (cmp)
+ return cmp;
+ if (len1 < len2)
+ return -1;
+ if (len1 > len2)
+ return 1;
+ return 0;
}
struct tree *lookup_tree(struct repository *r, const struct object_id *oid)
diff --git a/tree.h b/tree.h
index 6efff003e2..1b5ecbda6b 100644
--- a/tree.h
+++ b/tree.h
@@ -3,6 +3,7 @@
#include "object.h"
+struct pathspec;
struct repository;
struct strbuf;
@@ -28,7 +29,15 @@ void free_tree_buffer(struct tree *tree);
/* Parses and returns the tree in the given ent, chasing tags and commits. */
struct tree *parse_tree_indirect(const struct object_id *oid);
-int cmp_cache_name_compare(const void *a_, const void *b_);
+/*
+ * Functions for comparing pathnames
+ */
+int base_name_compare(const char *name1, size_t len1, int mode1,
+ const char *name2, size_t len2, int mode2);
+int df_name_compare(const char *name1, size_t len1, int mode1,
+ const char *name2, size_t len2, int mode2);
+int name_compare(const char *name1, size_t len1,
+ const char *name2, size_t len2);
#define READ_TREE_RECURSIVE 1
typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const char *, unsigned int, void *);
diff --git a/unpack-trees.c b/unpack-trees.c
index c0732aa0c2..e8c32a40dc 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -18,6 +18,7 @@
#include "sparse-index.h"
#include "submodule.h"
#include "submodule-config.h"
+#include "symlinks.h"
#include "trace2.h"
#include "fsmonitor.h"
#include "object-store.h"
diff --git a/userdiff.c b/userdiff.c
index eaec6ebb5e..664c7c1402 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -444,7 +444,7 @@ struct userdiff_driver *userdiff_find_by_path(struct index_state *istate,
check = attr_check_initl("diff", NULL);
if (!path)
return NULL;
- git_check_attr(istate, NULL, path, check);
+ git_check_attr(istate, path, check);
if (ATTR_TRUE(check->items[0].value))
return &driver_true;
diff --git a/versioncmp.c b/versioncmp.c
index 7498da96e0..74cc7c43f0 100644
--- a/versioncmp.c
+++ b/versioncmp.c
@@ -1,6 +1,7 @@
-#include "cache.h"
+#include "git-compat-util.h"
#include "config.h"
#include "string-list.h"
+#include "versioncmp.h"
/*
* versioncmp(): copied from string/strverscmp.c in glibc commit
diff --git a/versioncmp.h b/versioncmp.h
new file mode 100644
index 0000000000..879b510e82
--- /dev/null
+++ b/versioncmp.h
@@ -0,0 +1,6 @@
+#ifndef VERSIONCMP_H
+#define VERSIONCMP_H
+
+int versioncmp(const char *s1, const char *s2);
+
+#endif /* VERSIONCMP_H */
diff --git a/wrapper.c b/wrapper.c
index c130d7518b..67f5f5dbe1 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -1,10 +1,13 @@
/*
* Various trivial helper wrappers around standard functions
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "abspath.h"
#include "config.h"
#include "gettext.h"
+#include "object.h"
+#include "repository.h"
+#include "strbuf.h"
#include "trace2.h"
#include "wrapper.h"
diff --git a/ws.c b/ws.c
index da3d0e28cb..9456e2fdbe 100644
--- a/ws.c
+++ b/ws.c
@@ -3,8 +3,12 @@
*
* Copyright (c) 2007 Junio C Hamano
*/
-#include "cache.h"
+#include "git-compat-util.h"
#include "attr.h"
+#include "strbuf.h"
+#include "ws.h"
+
+unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
static struct whitespace_rule {
const char *rule_name;
@@ -79,7 +83,7 @@ unsigned whitespace_rule(struct index_state *istate, const char *pathname)
if (!attr_whitespace_rule)
attr_whitespace_rule = attr_check_initl("whitespace", NULL);
- git_check_attr(istate, NULL, pathname, attr_whitespace_rule);
+ git_check_attr(istate, pathname, attr_whitespace_rule);
value = attr_whitespace_rule->items[0].value;
if (ATTR_TRUE(value)) {
/* true (whitespace) */
diff --git a/ws.h b/ws.h
new file mode 100644
index 0000000000..5ba676c559
--- /dev/null
+++ b/ws.h
@@ -0,0 +1,33 @@
+#ifndef WS_H
+#define WS_H
+
+struct index_state;
+struct strbuf;
+
+/*
+ * whitespace rules.
+ * used by both diff and apply
+ * last two digits are tab width
+ */
+#define WS_BLANK_AT_EOL 0100
+#define WS_SPACE_BEFORE_TAB 0200
+#define WS_INDENT_WITH_NON_TAB 0400
+#define WS_CR_AT_EOL 01000
+#define WS_BLANK_AT_EOF 02000
+#define WS_TAB_IN_INDENT 04000
+#define WS_TRAILING_SPACE (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF)
+#define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB|8)
+#define WS_TAB_WIDTH_MASK 077
+/* All WS_* -- when extended, adapt diff.c emit_symbol */
+#define WS_RULE_MASK 07777
+extern unsigned whitespace_rule_cfg;
+unsigned whitespace_rule(struct index_state *, const char *);
+unsigned parse_whitespace_rule(const char *);
+unsigned ws_check(const char *line, int len, unsigned ws_rule);
+void ws_check_emit(const char *line, int len, unsigned ws_rule, FILE *stream, const char *set, const char *reset, const char *ws);
+char *whitespace_error_string(unsigned ws);
+void ws_fix_copy(struct strbuf *, const char *, int, unsigned, int *);
+int ws_blank_line(const char *line, int len);
+#define ws_tab_width(rule) ((rule) & WS_TAB_WIDTH_MASK)
+
+#endif /* WS_H */
diff --git a/wt-status.c b/wt-status.c
index 97b9c1c035..677465b10c 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -22,6 +22,7 @@
#include "strbuf.h"
#include "trace.h"
#include "trace2.h"
+#include "tree.h"
#include "utf8.h"
#include "worktree.h"
#include "lockfile.h"
@@ -1023,7 +1024,7 @@ static void wt_longstatus_print_submodule_summary(struct wt_status *s, int uncom
if (s->display_comment_prefix) {
size_t len;
summary_content = strbuf_detach(&summary, &len);
- strbuf_add_commented_lines(&summary, summary_content, len);
+ strbuf_add_commented_lines(&summary, summary_content, len, comment_line_char);
free(summary_content);
}
@@ -1098,8 +1099,8 @@ void wt_status_append_cut_line(struct strbuf *buf)
{
const char *explanation = _("Do not modify or remove the line above.\nEverything below it will be ignored.");
- strbuf_commented_addf(buf, "%s", cut_line);
- strbuf_add_commented_lines(buf, explanation, strlen(explanation));
+ strbuf_commented_addf(buf, comment_line_char, "%s", cut_line);
+ strbuf_add_commented_lines(buf, explanation, strlen(explanation), comment_line_char);
}
void wt_status_add_cut_line(FILE *fp)
diff --git a/xdiff-interface.h b/xdiff-interface.h
index 3750794afe..733c364d26 100644
--- a/xdiff-interface.h
+++ b/xdiff-interface.h
@@ -1,7 +1,7 @@
#ifndef XDIFF_INTERFACE_H
#define XDIFF_INTERFACE_H
-#include "hash.h"
+#include "hash-ll.h"
#include "xdiff/xdiff.h"
/*