aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/main.yml6
-rw-r--r--.gitignore4
-rw-r--r--Documentation/CodingGuidelines51
-rw-r--r--Documentation/RelNotes/2.38.2.txt60
-rw-r--r--Documentation/RelNotes/2.39.0.txt167
-rw-r--r--Documentation/SubmittingPatches4
-rwxr-xr-xDocumentation/build-docdep.perl5
-rw-r--r--Documentation/config.txt2
-rw-r--r--Documentation/config/fsmonitor--daemon.txt11
-rw-r--r--Documentation/config/log.txt6
-rw-r--r--Documentation/config/mergetool.txt2
-rw-r--r--Documentation/git-annotate.txt2
-rw-r--r--Documentation/git-clean.txt10
-rw-r--r--Documentation/git-commit-graph.txt5
-rw-r--r--Documentation/git-credential-cache--daemon.txt4
-rw-r--r--Documentation/git-diff-files.txt2
-rw-r--r--Documentation/git-diff.txt8
-rw-r--r--Documentation/git-fast-export.txt2
-rw-r--r--Documentation/git-fsmonitor--daemon.txt37
-rw-r--r--Documentation/git-hash-object.txt3
-rw-r--r--Documentation/git-interpret-trailers.txt5
-rw-r--r--Documentation/git-maintenance.txt6
-rw-r--r--Documentation/git-merge-base.txt4
-rw-r--r--Documentation/git-multi-pack-index.txt7
-rw-r--r--Documentation/git-mv.txt4
-rw-r--r--Documentation/git-pack-redundant.txt2
-rw-r--r--Documentation/git-patch-id.txt24
-rw-r--r--Documentation/git-prune-packed.txt2
-rw-r--r--Documentation/git-read-tree.txt2
-rw-r--r--Documentation/git-receive-pack.txt4
-rw-r--r--Documentation/git-reflog.txt17
-rw-r--r--Documentation/git-rerere.txt2
-rw-r--r--Documentation/git-rev-list.txt2
-rw-r--r--Documentation/git-send-email.txt15
-rw-r--r--Documentation/git-send-pack.txt5
-rw-r--r--Documentation/git-show-branch.txt4
-rw-r--r--Documentation/git-show-ref.txt4
-rw-r--r--Documentation/git-sparse-checkout.txt2
-rw-r--r--Documentation/git-stash.txt17
-rw-r--r--Documentation/git-status.txt2
-rw-r--r--Documentation/git-symbolic-ref.txt11
-rw-r--r--Documentation/git-tag.txt18
-rw-r--r--Documentation/git-update-server-info.txt8
-rw-r--r--Documentation/git-upload-archive.txt4
-rw-r--r--Documentation/git-var.txt2
-rw-r--r--Documentation/git-verify-commit.txt2
-rw-r--r--Documentation/git-verify-pack.txt2
-rw-r--r--Documentation/git-verify-tag.txt2
-rw-r--r--Documentation/git-worktree.txt3
-rw-r--r--Documentation/git.txt43
-rw-r--r--Documentation/revisions.txt2
-rw-r--r--Documentation/technical/bundle-uri.txt8
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--Makefile17
l---------RelNotes2
-rw-r--r--apply.c18
-rw-r--r--archive.c10
-rw-r--r--attr.c41
-rw-r--r--builtin/bisect--helper.c7
-rw-r--r--builtin/blame.c22
-rw-r--r--builtin/branch.c71
-rw-r--r--builtin/bugreport.c3
-rw-r--r--builtin/bundle.c38
-rw-r--r--builtin/cat-file.c2
-rw-r--r--builtin/clean.c2
-rw-r--r--builtin/clone.c3
-rw-r--r--builtin/commit-graph.c10
-rw-r--r--builtin/commit-tree.c5
-rw-r--r--builtin/commit.c15
-rw-r--r--builtin/credential-cache--daemon.c4
-rw-r--r--builtin/describe.c5
-rw-r--r--builtin/diagnose.c3
-rw-r--r--builtin/diff-files.c1
-rw-r--r--builtin/diff-index.c3
-rw-r--r--builtin/diff-tree.c6
-rw-r--r--builtin/diff.c26
-rw-r--r--builtin/fetch.c25
-rw-r--r--builtin/for-each-repo.c2
-rw-r--r--builtin/fsck.c11
-rw-r--r--builtin/fsmonitor--daemon.c15
-rw-r--r--builtin/gc.c111
-rw-r--r--builtin/grep.c48
-rw-r--r--builtin/hash-object.c5
-rw-r--r--builtin/help.c2
-rw-r--r--builtin/init-db.c5
-rw-r--r--builtin/interpret-trailers.c4
-rw-r--r--builtin/log.c2
-rw-r--r--builtin/ls-remote.c2
-rw-r--r--builtin/merge-base.c2
-rw-r--r--builtin/multi-pack-index.c7
-rw-r--r--builtin/pack-objects.c4
-rw-r--r--builtin/pack-redundant.c2
-rw-r--r--builtin/pack-refs.c2
-rw-r--r--builtin/patch-id.c113
-rw-r--r--builtin/push.c4
-rw-r--r--builtin/read-tree.c4
-rw-r--r--builtin/reflog.c3
-rw-r--r--builtin/remote.c50
-rw-r--r--builtin/repack.c127
-rw-r--r--builtin/rerere.c2
-rw-r--r--builtin/rev-list.c3
-rw-r--r--builtin/revert.c9
-rw-r--r--builtin/rm.c4
-rw-r--r--builtin/send-pack.c1
-rw-r--r--builtin/show-branch.c3
-rw-r--r--builtin/show-ref.c4
-rw-r--r--builtin/sparse-checkout.c2
-rw-r--r--builtin/stash.c73
-rw-r--r--builtin/submodule--helper.c34
-rw-r--r--builtin/symbolic-ref.c21
-rw-r--r--builtin/tag.c10
-rw-r--r--builtin/unpack-file.c2
-rw-r--r--builtin/update-index.c6
-rw-r--r--builtin/update-server-info.c2
-rw-r--r--builtin/upload-archive.c2
-rw-r--r--builtin/upload-pack.c3
-rw-r--r--builtin/verify-commit.c2
-rw-r--r--builtin/verify-pack.c2
-rw-r--r--builtin/verify-tag.c2
-rw-r--r--builtin/worktree.c110
-rwxr-xr-xci/lib.sh8
-rw-r--r--common-main.c1
-rw-r--r--compat/fsmonitor/fsm-ipc-darwin.c52
-rw-r--r--compat/fsmonitor/fsm-ipc-win32.c9
-rw-r--r--compat/fsmonitor/fsm-listen-darwin.c14
-rw-r--r--compat/fsmonitor/fsm-path-utils-darwin.c135
-rw-r--r--compat/fsmonitor/fsm-path-utils-win32.c145
-rw-r--r--compat/fsmonitor/fsm-settings-darwin.c77
-rw-r--r--compat/fsmonitor/fsm-settings-win32.c174
-rw-r--r--compat/nonblock.c2
-rw-r--r--config.c30
-rw-r--r--config.mak.dev25
-rw-r--r--contrib/buildsystems/CMakeLists.txt20
-rwxr-xr-xcontrib/credential/netrc/git-credential-netrc.perl5
-rw-r--r--contrib/credential/osxkeychain/git-credential-osxkeychain.c5
-rw-r--r--contrib/credential/wincred/git-credential-wincred.c7
-rw-r--r--convert.c4
-rw-r--r--date.c6
-rw-r--r--diff-merges.c40
-rw-r--r--diff.c120
-rw-r--r--diff.h2
-rw-r--r--diffcore-pickaxe.c4
-rw-r--r--dir.c4
-rw-r--r--exec-cmd.c2
-rw-r--r--fsmonitor--daemon.h3
-rw-r--r--fsmonitor-ipc.c18
-rw-r--r--fsmonitor-ipc.h4
-rw-r--r--fsmonitor-path-utils.h60
-rw-r--r--fsmonitor-settings.c68
-rw-r--r--fsmonitor-settings.h4
-rw-r--r--fsmonitor.c9
-rw-r--r--gettext.c2
-rw-r--r--git-compat-util.h22
-rw-r--r--git.c14
-rw-r--r--gpg-interface.c7
-rw-r--r--grep.c15
-rw-r--r--grep.h1
-rw-r--r--help.c2
-rw-r--r--hook.c23
-rw-r--r--ll-merge.c18
-rw-r--r--mailinfo.c2
-rw-r--r--merge-ort.c96
-rw-r--r--midx.c46
-rw-r--r--object-file.c19
-rw-r--r--object.c3
-rw-r--r--oss-fuzz/.gitignore3
-rw-r--r--oss-fuzz/fuzz-commit-graph.c (renamed from fuzz-commit-graph.c)0
-rw-r--r--oss-fuzz/fuzz-pack-headers.c (renamed from fuzz-pack-headers.c)0
-rw-r--r--oss-fuzz/fuzz-pack-idx.c (renamed from fuzz-pack-idx.c)0
-rw-r--r--pack-bitmap-write.c8
-rw-r--r--patch-ids.c10
-rw-r--r--patch-ids.h2
-rw-r--r--perl/Git.pm36
-rw-r--r--promisor-remote.c23
-rw-r--r--promisor-remote.h11
-rw-r--r--read-cache.c61
-rw-r--r--ref-filter.c2
-rw-r--r--reflog-walk.c2
-rw-r--r--reflog.c13
-rw-r--r--refs.c76
-rw-r--r--refs.h33
-rw-r--r--refs/files-backend.c80
-rw-r--r--refs/packed-backend.c2
-rw-r--r--revision.c12
-rw-r--r--run-command.c236
-rw-r--r--run-command.h71
-rw-r--r--scalar.c5
-rw-r--r--sequencer.c6
-rw-r--r--string-list.c2
-rw-r--r--string-list.h7
-rw-r--r--submodule-config.c2
-rw-r--r--submodule.c18
-rwxr-xr-xt/check-non-portable-shell.pl1
-rw-r--r--t/helper/test-path-utils.c3
-rw-r--r--t/helper/test-proc-receive.c2
-rw-r--r--t/helper/test-run-command.c77
-rw-r--r--t/helper/test-submodule.c22
-rw-r--r--t/lib-httpd/apache.conf2
-rwxr-xr-xt/perf/p2000-sparse-operations.sh1
-rwxr-xr-xt/perf/run4
-rwxr-xr-xt/t0033-safe-directory.sh9
-rwxr-xr-xt/t0035-safe-bare-repository.sh9
-rwxr-xr-xt/t0410-partial-clone.sh14
-rwxr-xr-xt/t0450-txt-doc-vs-help.sh172
-rw-r--r--t/t0450/txt-help-mismatches58
-rwxr-xr-xt/t1002-read-tree-m-u-2way.sh16
-rwxr-xr-xt/t1092-sparse-checkout-compatibility.sh72
-rwxr-xr-xt/t1304-default-acl.sh4
-rwxr-xr-xt/t1401-symbolic-ref.sh14
-rwxr-xr-xt/t3200-branch.sh7
-rwxr-xr-xt/t3202-show-branch.sh46
-rwxr-xr-xt/t3204-branch-name-interpretation.sh24
-rwxr-xr-xt/t3305-notes-fanout.sh2
-rwxr-xr-xt/t3404-rebase-interactive.sh6
-rwxr-xr-xt/t3415-rebase-autosquash.sh13
-rwxr-xr-xt/t3419-rebase-patch-id.sh63
-rwxr-xr-xt/t3435-rebase-gpg-sign.sh8
-rwxr-xr-xt/t3438-rebase-broken-files.sh59
-rwxr-xr-xt/t3700-add.sh2
-rwxr-xr-xt/t3702-add-edit.sh2
-rwxr-xr-xt/t4012-diff-binary.sh14
-rwxr-xr-xt/t4014-format-patch.sh8
-rwxr-xr-xt/t4038-diff-combined.sh10
-rwxr-xr-xt/t4202-log.sh9
-rwxr-xr-xt/t4204-patch-id.sh95
-rwxr-xr-xt/t4301-merge-tree-write-tree.sh9
-rwxr-xr-xt/t5100-mailinfo.sh4
-rwxr-xr-xt/t5319-multi-pack-index.sh94
-rwxr-xr-xt/t5320-delta-islands.sh2
-rwxr-xr-xt/t5326-multi-pack-bitmaps.sh24
-rwxr-xr-xt/t5505-remote.sh11
-rwxr-xr-xt/t5526-fetch-submodules.sh8
-rwxr-xr-xt/t5550-http-fetch-dumb.sh2
-rwxr-xr-xt/t5606-clone-options.sh9
-rwxr-xr-xt/t5702-protocol-v2.sh2
-rwxr-xr-xt/t7003-filter-branch.sh4
-rwxr-xr-xt/t7527-builtin-fsmonitor.sh18
-rwxr-xr-xt/t7700-repack.sh61
-rwxr-xr-xt/t7701-repack-unpack-unreachable.sh4
-rwxr-xr-xt/t7703-repack-geometric.sh6
-rwxr-xr-xt/t7810-grep.sh15
-rwxr-xr-xt/t7900-maintenance.sh11
-rwxr-xr-xt/t9001-send-email.sh8
-rwxr-xr-xt/t9133-git-svn-nested-git-repo.sh6
-rwxr-xr-xt/t9134-git-svn-ignore-paths.sh8
-rwxr-xr-xt/t9140-git-svn-reset.sh4
-rwxr-xr-xt/t9147-git-svn-include-paths.sh8
-rwxr-xr-xt/t9210-scalar.sh5
-rwxr-xr-xt/t9700-perl-git.sh4
-rwxr-xr-xt/t9700/test.pl12
-rwxr-xr-xt/t9814-git-p4-rename.sh2
-rwxr-xr-xt/t9815-git-p4-submit-fail.sh4
-rw-r--r--t/test-lib-functions.sh2
-rw-r--r--t/test-lib.sh14
-rw-r--r--tmp-objdir.c40
-rw-r--r--worktree.c59
-rw-r--r--worktree.h10
-rw-r--r--write-or-die.c1
258 files changed, 3575 insertions, 1581 deletions
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 831f4df56c..bd6f75b8e0 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -251,6 +251,12 @@ jobs:
- jobname: linux-leaks
cc: gcc
pool: ubuntu-latest
+ - jobname: linux-asan
+ cc: gcc
+ pool: ubuntu-latest
+ - jobname: linux-ubsan
+ cc: gcc
+ pool: ubuntu-latest
env:
CC: ${{matrix.vector.cc}}
CC_PACKAGE: ${{matrix.vector.cc_package}}
diff --git a/.gitignore b/.gitignore
index b3dcafcb33..cb0231fb40 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,5 @@
-/fuzz-commit-graph
/fuzz_corpora
-/fuzz-pack-headers
-/fuzz-pack-idx
+/GIT-BUILD-DIR
/GIT-BUILD-OPTIONS
/GIT-CFLAGS
/GIT-LDFLAGS
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index 9fca21cc5f..9d5c27807a 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -162,8 +162,6 @@ For shell scripts specifically (not exhaustive):
- We do not use \{m,n\};
- - We do not use -E;
-
- We do not use ? or + (which are \{0,1\} and \{1,\}
respectively in BRE) but that goes without saying as these
are ERE elements not BRE (note that \? and \+ are not even part
@@ -204,10 +202,19 @@ For C programs:
by e.g. "echo DEVELOPER=1 >>config.mak".
- We try to support a wide range of C compilers to compile Git with,
- including old ones. You should not use features from newer C
+ including old ones. As of Git v2.35.0 Git requires C99 (we check
+ "__STDC_VERSION__"). You should not use features from a newer C
standard, even if your compiler groks them.
- There are a few exceptions to this guideline:
+ New C99 features have been phased in gradually, if something's new
+ in C99 but not used yet don't assume that it's safe to use, some
+ compilers we target have only partial support for it. These are
+ considered safe to use:
+
+ . since around 2007 with 2b6854c863a, we have been using
+ initializer elements which are not computable at load time. E.g.:
+
+ const char *args[] = {"constant", variable, NULL};
. since early 2012 with e1327023ea, we have been using an enum
definition whose last element is followed by a comma. This, like
@@ -223,18 +230,24 @@ For C programs:
. since early 2021 with 765dc168882, we have been using variadic
macros, mostly for printf-like trace and debug macros.
- These used to be forbidden, but we have not heard any breakage
- report, and they are assumed to be safe.
+ . since late 2021 with 44ba10d6, we have had variables declared in
+ the for loop "for (int i = 0; i < 10; i++)".
+
+ New C99 features that we cannot use yet:
+
+ . %z and %zu as a printf() argument for a size_t (the %z being for
+ the POSIX-specific ssize_t). Instead you should use
+ printf("%"PRIuMAX, (uintmax_t)v). These days the MSVC version we
+ rely on supports %z, but the C library used by MinGW does not.
+
+ . Shorthand like ".a.b = *c" in struct initializations is known to
+ trip up an older IBM XLC version, use ".a = { .b = *c }" instead.
+ See the 33665d98 (reftable: make assignments portable to AIX xlc
+ v12.01, 2022-03-28).
- Variables have to be declared at the beginning of the block, before
the first statement (i.e. -Wdeclaration-after-statement).
- - Declaring a variable in the for loop "for (int i = 0; i < 10; i++)"
- is still not allowed in this codebase. We are in the process of
- allowing it by waiting to see that 44ba10d6 (revision: use C99
- declaration of variable in for() loop, 2021-11-14) does not get
- complaints. Let's revisit this around November 2022.
-
- NULL pointers shall be written as NULL, not as 0.
- When declaring pointers, the star sides with the variable
@@ -650,8 +663,8 @@ Writing Documentation:
(One or more of <file>.)
Optional parts are enclosed in square brackets:
- [<extra>]
- (Zero or one <extra>.)
+ [<file>...]
+ (Zero or more of <file>.)
--exec-path[=<path>]
(Option with an optional argument. Note that the "=" is inside the
@@ -665,6 +678,16 @@ Writing Documentation:
[-q | --quiet]
[--utf8 | --no-utf8]
+ Use spacing around "|" token(s), but not immediately after opening or
+ before closing a [] or () pair:
+ Do: [-q | --quiet]
+ Don't: [-q|--quiet]
+
+ Don't use spacing around "|" tokens when they're used to seperate the
+ alternate arguments of an option:
+ Do: --track[=(direct|inherit)]
+ Don't: --track[=(direct | inherit)]
+
Parentheses are used for grouping:
[(<rev> | <range>)...]
(Any number of either <rev> or <range>. Parens are needed to make
diff --git a/Documentation/RelNotes/2.38.2.txt b/Documentation/RelNotes/2.38.2.txt
new file mode 100644
index 0000000000..086b900f6c
--- /dev/null
+++ b/Documentation/RelNotes/2.38.2.txt
@@ -0,0 +1,60 @@
+Git 2.38.2 Release Notes
+========================
+
+This is to backport various fixes accumulated during the development
+towards Git 2.39, the next feature release.
+
+
+Fixes since v2.38.1
+-------------------
+
+ * Update CodingGuidelines to clarify what features to use and avoid
+ in C99.
+
+ * The codepath that reads from the index v4 had unaligned memory
+ accesses, which has been corrected.
+
+ * "git remote rename" failed to rename a remote without fetch
+ refspec, which has been corrected.
+
+ * "git clone" did not like to see the "--bare" and the "--origin"
+ options used together without a good reason.
+
+ * Fix messages incorrectly marked for translation.
+
+ * "git fsck" failed to release contents of tree objects already used
+ from the memory, which has been fixed.
+
+ * "git rebase -i" can mistakenly attempt to apply a fixup to a commit
+ itself, which has been corrected.
+
+ * In read-only repositories, "git merge-tree" tried to come up with a
+ merge result tree object, which it failed (which is not wrong) and
+ led to a segfault (which is bad), which has been corrected.
+
+ * Force C locale while running tests around httpd to make sure we can
+ find expected error messages in the log.
+
+ * Fix a logic in "mailinfo -b" that miscomputed the length of a
+ substring, which lead to an out-of-bounds access.
+
+ * The codepath to sign learned to report errors when it fails to read
+ from "ssh-keygen".
+
+ * "GIT_EDITOR=: git branch --edit-description" resulted in failure,
+ which has been corrected.
+
+ * Documentation on various Boolean GIT_* environment variables have
+ been clarified.
+
+ * "git multi-pack-index repack/expire" used to repack unreachable
+ cruft into a new pack, which have been corrected.
+
+ * The code to clean temporary object directories (used for
+ quarantine) tried to remove them inside its signal handler, which
+ was a no-no.
+
+ * "git branch --edit-description" on an unborh branch misleadingly
+ said that no such branch exists, which has been corrected.
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.39.0.txt b/Documentation/RelNotes/2.39.0.txt
new file mode 100644
index 0000000000..f87c4c442e
--- /dev/null
+++ b/Documentation/RelNotes/2.39.0.txt
@@ -0,0 +1,167 @@
+Git v2.39 Release Notes
+=======================
+
+UI, Workflows & Features
+------------------------
+
+ * "git grep" learned to expand the sparse-index more lazily and on
+ demand in a sparse checkout.
+
+ * By default, use of fsmonitor on a repository on networked
+ filesystem is disabled. Add knobs to make it workable on macOS.
+
+ * After checking out a "branch" that is a symbolic-ref that points at
+ another branch, "git symbolic-ref HEAD" reports the underlying
+ branch, not the symbolic-ref the user gave checkout as argument.
+ The command learned the "--no-recurse" option to stop after
+ dereferencing a symbolic-ref only once.
+
+ * "git branch --edit-description @{-1}" is now a way to edit branch
+ description of the branch you were on before switching to the
+ current branch.
+
+
+Performance, Internal Implementation, Development Support etc.
+--------------------------------------------------------------
+
+ * With a bit of header twiddling, use the native regexp library on
+ macOS instead of the compat/ one.
+
+ * Prepare for GNU [ef]grep that throw warning of their uses.
+
+ * Sources related to fuzz testing have been moved down to their own
+ directory.
+
+ * Most credential helpers ignored unknown entries in a credential
+ description, but a few died upon seeing them. The latter were
+ taught to ignore them, too
+
+ * "scalar unregister" in a repository that is already been
+ unregistered reported an error.
+
+ * Remove error detection from a function that fetches from promisor
+ remotes, and make it die when such a fetch fails to bring all the
+ requested objects, to give an early failure to various operations.
+
+ * Update CodingGuidelines to clarify what features to use and avoid
+ in C99.
+
+ * Avoid false-positive from LSan whose assumption may be broken with
+ higher optimization levels.
+
+ * Enable address and undefined sanitizer tasks at GitHub Actions CI.
+
+ * More UNUSED annotation to help using -Wunused option with the
+ compiler.
+ (merge 4b992f0a24 jk/unused-anno-more later to maint).
+
+
+Fixes since v2.38
+-----------------
+
+ * The codepath that reads from the index v4 had unaligned memory
+ accesses, which has been corrected.
+
+ * Fix messages incorrectly marked for translation.
+
+ * "git fsck" failed to release contents of tree objects already used
+ from the memory, which has been fixed.
+
+ * "git clone" did not like to see the "--bare" and the "--origin"
+ options used together without a good reason.
+
+ * "git remote rename" failed to rename a remote without fetch
+ refspec, which has been corrected.
+
+ * Documentation on various Boolean GIT_* environment variables have
+ been clarified.
+
+ * "git rebase -i" can mistakenly attempt to apply a fixup to a commit
+ itself, which has been corrected.
+
+ * "git multi-pack-index repack/expire" used to repack unreachable
+ cruft into a new pack, which have been corrected.
+
+ * In read-only repositories, "git merge-tree" tried to come up with a
+ merge result tree object, which it failed (which is not wrong) and
+ led to a segfault (which is bad), which has been corrected.
+
+ * Force C locale while running tests around httpd to make sure we can
+ find expected error messages in the log.
+
+ * Fix a logic in "mailinfo -b" that miscomputed the length of a
+ substring, which lead to an out-of-bounds access.
+
+ * The codepath to sign learned to report errors when it fails to read
+ from "ssh-keygen".
+
+ * Code clean-up that results in plugging a leak.
+
+ * "GIT_EDITOR=: git branch --edit-description" resulted in failure,
+ which has been corrected.
+
+ * The code to clean temporary object directories (used for
+ quarantine) tried to remove them inside its signal handler, which
+ was a no-no.
+
+ * Update comment in the Makefile about the RUNTIME_PREFIX config knob.
+
+ * Clarify that "the sentence after <area>: prefix does not begin with
+ a capital letter" rule applies only to the commit title.
+
+ * "git branch --edit-description" on an unborh branch misleadingly
+ said that no such branch exists, which has been corrected.
+
+ * Work around older clang that warns against C99 zero initialization
+ syntax for struct.
+
+ * Giving "--invert-grep" and "--all-match" without "--grep" to the
+ "git log" command resulted in an attempt to access grep pattern
+ expression structure that has not been allocated, which has been
+ corrected.
+ (merge db84376f98 ab/grep-simplify-extended-expression later to maint).
+
+ * "git diff rev^!" did not show combined diff to go to the rev from
+ its parents.
+ (merge a79c6b6081 rs/diff-caret-bang-with-parents later to maint).
+
+ * Allow configuration files in "protected" scopes to include other
+ configuration files.
+ (merge ecec57b3c9 gc/bare-repo-discovery later to maint).
+
+ * Give a bit more diversity to macOS CI by using sha1dc in one of the
+ jobs (the other one tests Apple Common Crypto).
+ (merge 1ad5c3df35 jc/ci-osx-with-sha1dc later to maint).
+
+ * A bugfix with tracing support in midx codepath
+ (merge e9c3839944 tb/midx-bitmap-selection-fix later to maint).
+
+ * When geometric repacking feature is in use together with the
+ --pack-kept-objects option, we lost packs marked with .keep files.
+ (merge 197443e80a tb/save-keep-pack-during-geometric-repack later to maint).
+
+ * Move a global variable added as a hack during regression fixes to
+ its proper place in the API.
+ (merge 0b0ab95f17 ab/run-hook-api-cleanup later to maint).
+
+ * Update to build procedure with VS using CMake/CTest.
+ (merge c858750b41 js/cmake-updates later to maint).
+
+ * The short-help text shown by "git cmd -h" and the synopsis text
+ shown at the beginning of "git help cmd" have been made more
+ consistent.
+
+ * When creating a multi-pack bitmap, remove per-pack bitmap files
+ unconditionally as they will never be consulted.
+ (merge 55d902cd61 tb/remove-unused-pack-bitmap later to maint).
+
+ * Fix a longstanding syntax error in Git.pm error codepath.
+
+ * "git diff --stat" etc. were invented back when everything was ASCII
+ and strlen() was a way to measure the display width of a string;
+ adjust them to compute the display width assuming UTF-8 pathnames.
+ (merge ce8529b2bb tb/diffstat-with-utf8-strwidth later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+ (merge 413bc6d20a ds/cmd-main-reorder later to maint).
+ (merge 8d2863e4ed nw/t1002-cleanup later to maint).
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index 5bd795e5db..927f7329a5 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -153,7 +153,9 @@ files you are modifying to see the current conventions.
[[summary-section]]
The title sentence after the "area:" prefix omits the full stop at the
-end, and its first word is not capitalized unless there is a reason to
+end, and its first word is not capitalized (the omission
+of capitalization applies only to the word after the "area:"
+prefix of the title) unless there is a reason to
capitalize it other than because it is the first word in the sentence.
E.g. "doc: clarify...", not "doc: Clarify...", or "githooks.txt:
improve...", not "githooks.txt: Improve...". But "refs: HEAD is also
diff --git a/Documentation/build-docdep.perl b/Documentation/build-docdep.perl
index ba4205e030..1b3ac8fdd9 100755
--- a/Documentation/build-docdep.perl
+++ b/Documentation/build-docdep.perl
@@ -38,9 +38,10 @@ while ($changed) {
}
}
-while (my ($text, $included) = each %include) {
+foreach my $text (sort keys %include) {
+ my $included = $include{$text};
if (! exists $included{$text} &&
(my $base = $text) =~ s/\.txt$//) {
- print "$base.html $base.xml : ", join(" ", keys %$included), "\n";
+ print "$base.html $base.xml : ", join(" ", sort keys %$included), "\n";
}
}
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5b5b976569..1e20583165 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -423,6 +423,8 @@ include::config/filter.txt[]
include::config/fsck.txt[]
+include::config/fsmonitor--daemon.txt[]
+
include::config/gc.txt[]
include::config/gitcvs.txt[]
diff --git a/Documentation/config/fsmonitor--daemon.txt b/Documentation/config/fsmonitor--daemon.txt
new file mode 100644
index 0000000000..c225c6c9e7
--- /dev/null
+++ b/Documentation/config/fsmonitor--daemon.txt
@@ -0,0 +1,11 @@
+fsmonitor.allowRemote::
+ By default, the fsmonitor daemon refuses to work against network-mounted
+ repositories. Setting `fsmonitor.allowRemote` to `true` overrides this
+ behavior. Only respected when `core.fsmonitor` is set to `true`.
+
+fsmonitor.socketDir::
+ This Mac OS-specific option, if set, specifies the directory in
+ which to create the Unix domain socket used for communication
+ between the fsmonitor daemon and various Git commands. The directory must
+ reside on a native Mac OS filesystem. Only respected when `core.fsmonitor`
+ is set to `true`.
diff --git a/Documentation/config/log.txt b/Documentation/config/log.txt
index bc63bc3939..5f96cf87fb 100644
--- a/Documentation/config/log.txt
+++ b/Documentation/config/log.txt
@@ -34,9 +34,9 @@ log.excludeDecoration::
option.
log.diffMerges::
- Set default diff format to be used for merge commits. See
- `--diff-merges` in linkgit:git-log[1] for details.
- Defaults to `separate`.
+ Set diff format to be used when `--diff-merges=on` is
+ specified, see `--diff-merges` in linkgit:git-log[1] for
+ details. Defaults to `separate`.
log.follow::
If `true`, `git log` will act as if the `--follow` option was used when
diff --git a/Documentation/config/mergetool.txt b/Documentation/config/mergetool.txt
index 90b3809700..e779a122d8 100644
--- a/Documentation/config/mergetool.txt
+++ b/Documentation/config/mergetool.txt
@@ -59,7 +59,7 @@ mergetool.hideResolved::
possible and write the 'MERGED' file containing conflict markers around
any conflicts that it cannot resolve; 'LOCAL' and 'REMOTE' normally
represent the versions of the file from before Git's conflict
- resolution. This flag causes 'LOCAL' and 'REMOTE' to be overwriten so
+ resolution. This flag causes 'LOCAL' and 'REMOTE' to be overwritten so
that only the unresolved conflicts are presented to the merge tool. Can
be configured per-tool via the `mergetool.<tool>.hideResolved`
configuration variable. Defaults to `false`.
diff --git a/Documentation/git-annotate.txt b/Documentation/git-annotate.txt
index e44a831339..5ae8aabe0f 100644
--- a/Documentation/git-annotate.txt
+++ b/Documentation/git-annotate.txt
@@ -8,7 +8,7 @@ git-annotate - Annotate file lines with commit information
SYNOPSIS
--------
[verse]
-'git annotate' [<options>] <file> [<revision>]
+'git annotate' [<options>] [<rev-opts>] [<rev>] [--] <file>
DESCRIPTION
-----------
diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt
index 91742633fa..160d08b86b 100644
--- a/Documentation/git-clean.txt
+++ b/Documentation/git-clean.txt
@@ -8,7 +8,7 @@ git-clean - Remove untracked files from the working tree
SYNOPSIS
--------
[verse]
-'git clean' [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] <path>...
+'git clean' [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] [<pathspec>...]
DESCRIPTION
-----------
@@ -20,16 +20,16 @@ Normally, only files unknown to Git are removed, but if the `-x`
option is specified, ignored files are also removed. This can, for
example, be useful to remove all build products.
-If any optional `<path>...` arguments are given, only those paths
-are affected.
+If any optional `<pathspec>...` arguments are given, only those paths
+that match the pathspec are affected.
OPTIONS
-------
-d::
- Normally, when no <path> is specified, git clean will not
+ Normally, when no <pathspec> is specified, git clean will not
recurse into untracked directories to avoid removing too much.
Specify -d to have it recurse into such directories as well.
- If any paths are specified, -d is irrelevant; all untracked
+ If a <pathspec> is specified, -d is irrelevant; all untracked
files matching the specified paths (with exceptions for nested
git directories mentioned under `--force`) will be removed.
diff --git a/Documentation/git-commit-graph.txt b/Documentation/git-commit-graph.txt
index 36fe56c2c7..c8dbceba01 100644
--- a/Documentation/git-commit-graph.txt
+++ b/Documentation/git-commit-graph.txt
@@ -10,7 +10,10 @@ SYNOPSIS
--------
[verse]
'git commit-graph verify' [--object-dir <dir>] [--shallow] [--[no-]progress]
-'git commit-graph write' <options> [--object-dir <dir>] [--[no-]progress]
+'git commit-graph write' [--object-dir <dir>] [--append]
+ [--split[=<strategy>]] [--reachable | --stdin-packs | --stdin-commits]
+ [--changed-paths] [--[no-]max-new-filters <n>] [--[no-]progress]
+ <split options>
DESCRIPTION
diff --git a/Documentation/git-credential-cache--daemon.txt b/Documentation/git-credential-cache--daemon.txt
index 01e1c214dd..650a15a7ed 100644
--- a/Documentation/git-credential-cache--daemon.txt
+++ b/Documentation/git-credential-cache--daemon.txt
@@ -8,7 +8,7 @@ git-credential-cache--daemon - Temporarily store user credentials in memory
SYNOPSIS
--------
[verse]
-'git credential-cache{litdd}daemon' [--debug] <socket>
+'git credential-cache{litdd}daemon' [--debug] <socket-path>
DESCRIPTION
-----------
@@ -16,7 +16,7 @@ DESCRIPTION
NOTE: You probably don't want to invoke this command yourself; it is
started automatically when you use linkgit:git-credential-cache[1].
-This command listens on the Unix domain socket specified by `<socket>`
+This command listens on the Unix domain socket specified by `<socket-path>`
for `git-credential-cache` clients. Clients may store and retrieve
credentials. Each credential is held for a timeout specified by the
client; once no credentials are held, the daemon exits.
diff --git a/Documentation/git-diff-files.txt b/Documentation/git-diff-files.txt
index bf1febb9ae..591e3801b7 100644
--- a/Documentation/git-diff-files.txt
+++ b/Documentation/git-diff-files.txt
@@ -9,7 +9,7 @@ git-diff-files - Compares files in the working tree and the index
SYNOPSIS
--------
[verse]
-'git diff-files' [-q] [-0|-1|-2|-3|-c|--cc] [<common-diff-options>] [<path>...]
+'git diff-files' [-q] [-0 | -1 | -2 | -3 | -c | --cc] [<common-diff-options>] [<path>...]
DESCRIPTION
-----------
diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt
index 85ae6d6d08..52b679256c 100644
--- a/Documentation/git-diff.txt
+++ b/Documentation/git-diff.txt
@@ -79,10 +79,10 @@ If --merge-base is given, use the merge base of the two commits for the
This form is to view the results of a merge commit. The first
listed <commit> must be the merge itself; the remaining two or
- more commits should be its parents. A convenient way to produce
- the desired set of revisions is to use the `^@` suffix.
- For instance, if `master` names a merge commit, `git diff master
- master^@` gives the same combined diff as `git show master`.
+ more commits should be its parents. Convenient ways to produce
+ the desired set of revisions are to use the suffixes `^@` and
+ `^!`. If A is a merge commit, then `git diff A A^@`,
+ `git diff A^!` and `git show A` all give the same combined diff.
'git diff' [<options>] <commit>..<commit> [--] [<path>...]::
diff --git a/Documentation/git-fast-export.txt b/Documentation/git-fast-export.txt
index 1978dbdc6a..4643ddbe68 100644
--- a/Documentation/git-fast-export.txt
+++ b/Documentation/git-fast-export.txt
@@ -9,7 +9,7 @@ git-fast-export - Git data exporter
SYNOPSIS
--------
[verse]
-'git fast-export [<options>]' | 'git fast-import'
+'git fast-export' [<options>] | 'git fast-import'
DESCRIPTION
-----------
diff --git a/Documentation/git-fsmonitor--daemon.txt b/Documentation/git-fsmonitor--daemon.txt
index cc142fb861..8238eadb0e 100644
--- a/Documentation/git-fsmonitor--daemon.txt
+++ b/Documentation/git-fsmonitor--daemon.txt
@@ -3,7 +3,7 @@ git-fsmonitor{litdd}daemon(1)
NAME
----
-git-fsmonitor--daemon - A Built-in File System Monitor
+git-fsmonitor--daemon - A Built-in Filesystem Monitor
SYNOPSIS
--------
@@ -17,7 +17,7 @@ DESCRIPTION
-----------
A daemon to watch the working directory for file and directory
-changes using platform-specific file system notification facilities.
+changes using platform-specific filesystem notification facilities.
This daemon communicates directly with commands like `git status`
using the link:technical/api-simple-ipc.html[simple IPC] interface
@@ -63,13 +63,44 @@ CAVEATS
-------
The fsmonitor daemon does not currently know about submodules and does
-not know to filter out file system events that happen within a
+not know to filter out filesystem events that happen within a
submodule. If fsmonitor daemon is watching a super repo and a file is
modified within the working directory of a submodule, it will report
the change (as happening against the super repo). However, the client
will properly ignore these extra events, so performance may be affected
but it will not cause an incorrect result.
+By default, the fsmonitor daemon refuses to work against network-mounted
+repositories; this may be overridden by setting `fsmonitor.allowRemote` to
+`true`. Note, however, that the fsmonitor daemon is not guaranteed to work
+correctly with all network-mounted repositories and such use is considered
+experimental.
+
+On Mac OS, the inter-process communication (IPC) between various Git
+commands and the fsmonitor daemon is done via a Unix domain socket (UDS) -- a
+special type of file -- which is supported by native Mac OS filesystems,
+but not on network-mounted filesystems, NTFS, or FAT32. Other filesystems
+may or may not have the needed support; the fsmonitor daemon is not guaranteed
+to work with these filesystems and such use is considered experimental.
+
+By default, the socket is created in the `.git` directory, however, if the
+`.git` directory is on a network-mounted filesystem, it will be instead be
+created at `$HOME/.git-fsmonitor-*` unless `$HOME` itself is on a
+network-mounted filesystem in which case you must set the configuration
+variable `fsmonitor.socketDir` to the path of a directory on a Mac OS native
+filesystem in which to create the socket file.
+
+If none of the above directories (`.git`, `$HOME`, or `fsmonitor.socketDir`)
+is on a native Mac OS file filesystem the fsmonitor daemon will report an
+error that will cause the daemon and the currently running command to exit.
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/fsmonitor--daemon.txt[]
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-hash-object.txt b/Documentation/git-hash-object.txt
index df9e2c58bd..472b5bb995 100644
--- a/Documentation/git-hash-object.txt
+++ b/Documentation/git-hash-object.txt
@@ -9,7 +9,8 @@ git-hash-object - Compute object ID and optionally creates a blob from a file
SYNOPSIS
--------
[verse]
-'git hash-object' [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin [--literally]] [--] <file>...
+'git hash-object' [-t <type>] [-w] [--path=<file> | --no-filters]
+ [--stdin [--literally]] [--] <file>...
'git hash-object' [-t <type>] [-w] --stdin-paths [--no-filters]
DESCRIPTION
diff --git a/Documentation/git-interpret-trailers.txt b/Documentation/git-interpret-trailers.txt
index 6d6197cd0a..22ff3a603e 100644
--- a/Documentation/git-interpret-trailers.txt
+++ b/Documentation/git-interpret-trailers.txt
@@ -8,8 +8,9 @@ git-interpret-trailers - Add or parse structured information in commit messages
SYNOPSIS
--------
[verse]
-'git interpret-trailers' [<options>] [(--trailer <token>[(=|:)<value>])...] [<file>...]
-'git interpret-trailers' [<options>] [--parse] [<file>...]
+'git interpret-trailers' [--in-place] [--trim-empty]
+ [(--trailer <token>[(=|:)<value>])...]
+ [--parse] [<file>...]
DESCRIPTION
-----------
diff --git a/Documentation/git-maintenance.txt b/Documentation/git-maintenance.txt
index 9c630efe19..bb888690e4 100644
--- a/Documentation/git-maintenance.txt
+++ b/Documentation/git-maintenance.txt
@@ -11,7 +11,7 @@ SYNOPSIS
[verse]
'git maintenance' run [<options>]
'git maintenance' start [--scheduler=<scheduler>]
-'git maintenance' (stop|register|unregister)
+'git maintenance' (stop|register|unregister) [<options>]
DESCRIPTION
@@ -79,6 +79,10 @@ unregister::
Remove the current repository from background maintenance. This
only removes the repository from the configured list. It does not
stop the background maintenance processes from running.
++
+The `unregister` subcommand will report an error if the current repository
+is not already registered. Use the `--force` option to return success even
+when the current repository is not registered.
TASKS
-----
diff --git a/Documentation/git-merge-base.txt b/Documentation/git-merge-base.txt
index 2d944e0851..b01ba3d356 100644
--- a/Documentation/git-merge-base.txt
+++ b/Documentation/git-merge-base.txt
@@ -9,8 +9,8 @@ git-merge-base - Find as good common ancestors as possible for a merge
SYNOPSIS
--------
[verse]
-'git merge-base' [-a|--all] <commit> <commit>...
-'git merge-base' [-a|--all] --octopus <commit>...
+'git merge-base' [-a | --all] <commit> <commit>...
+'git merge-base' [-a | --all] --octopus <commit>...
'git merge-base' --is-ancestor <commit> <commit>
'git merge-base' --independent <commit>...
'git merge-base' --fork-point <ref> [<commit>]
diff --git a/Documentation/git-multi-pack-index.txt b/Documentation/git-multi-pack-index.txt
index a48c3d5ea6..3696506eb3 100644
--- a/Documentation/git-multi-pack-index.txt
+++ b/Documentation/git-multi-pack-index.txt
@@ -70,9 +70,10 @@ verify::
Verify the contents of the MIDX file.
expire::
- Delete the pack-files that are tracked by the MIDX file, but
- have no objects referenced by the MIDX. Rewrite the MIDX file
- afterward to remove all references to these pack-files.
+ Delete the pack-files that are tracked by the MIDX file, but
+ have no objects referenced by the MIDX (with the exception of
+ `.keep` packs and cruft packs). Rewrite the MIDX file afterward
+ to remove all references to these pack-files.
repack::
Create a new pack-file containing objects in small pack-files
diff --git a/Documentation/git-mv.txt b/Documentation/git-mv.txt
index 79449bf98f..fb0220fd18 100644
--- a/Documentation/git-mv.txt
+++ b/Documentation/git-mv.txt
@@ -9,7 +9,7 @@ git-mv - Move or rename a file, a directory, or a symlink
SYNOPSIS
--------
[verse]
-'git mv' <options>... <args>...
+'git mv' [<options>] <source>... <destination>
DESCRIPTION
-----------
@@ -30,7 +30,7 @@ OPTIONS
-------
-f::
--force::
- Force renaming or moving of a file even if the target exists
+ Force renaming or moving of a file even if the <destination> exists.
-k::
Skip move or rename actions which would lead to an error
condition. An error happens when a source is neither existing nor
diff --git a/Documentation/git-pack-redundant.txt b/Documentation/git-pack-redundant.txt
index ee7034b5e5..dda80a740c 100644
--- a/Documentation/git-pack-redundant.txt
+++ b/Documentation/git-pack-redundant.txt
@@ -9,7 +9,7 @@ git-pack-redundant - Find redundant pack files
SYNOPSIS
--------
[verse]
-'git pack-redundant' [ --verbose ] [ --alt-odb ] ( --all | <pack-filename>... )
+'git pack-redundant' [--verbose] [--alt-odb] (--all | <pack-filename>...)
DESCRIPTION
-----------
diff --git a/Documentation/git-patch-id.txt b/Documentation/git-patch-id.txt
index 442caff8a9..1d15fa45d5 100644
--- a/Documentation/git-patch-id.txt
+++ b/Documentation/git-patch-id.txt
@@ -8,18 +8,18 @@ git-patch-id - Compute unique ID for a patch
SYNOPSIS
--------
[verse]
-'git patch-id' [--stable | --unstable]
+'git patch-id' [--stable | --unstable | --verbatim]
DESCRIPTION
-----------
Read a patch from the standard input and compute the patch ID for it.
A "patch ID" is nothing but a sum of SHA-1 of the file diffs associated with a
-patch, with whitespace and line numbers ignored. As such, it's "reasonably
-stable", but at the same time also reasonably unique, i.e., two patches that
-have the same "patch ID" are almost guaranteed to be the same thing.
+patch, with line numbers ignored. As such, it's "reasonably stable", but at
+the same time also reasonably unique, i.e., two patches that have the same
+"patch ID" are almost guaranteed to be the same thing.
-IOW, you can use this thing to look for likely duplicate commits.
+The main usecase for this command is to look for likely duplicate commits.
When dealing with 'git diff-tree' output, it takes advantage of
the fact that the patch is prefixed with the object name of the
@@ -30,6 +30,12 @@ This can be used to make a mapping from patch ID to commit ID.
OPTIONS
-------
+--verbatim::
+ Calculate the patch-id of the input as it is given, do not strip
+ any whitespace.
+
+ This is the default if patchid.verbatim is true.
+
--stable::
Use a "stable" sum of hashes as the patch ID. With this option:
- Reordering file diffs that make up a patch does not affect the ID.
@@ -45,14 +51,16 @@ OPTIONS
of "-O<orderfile>", thereby making existing databases storing such
"unstable" or historical patch-ids unusable.
+ - All whitespace within the patch is ignored and does not affect the id.
+
This is the default if patchid.stable is set to true.
--unstable::
Use an "unstable" hash as the patch ID. With this option,
the result produced is compatible with the patch-id value produced
- by git 1.9 and older. Users with pre-existing databases storing
- patch-ids produced by git 1.9 and older (who do not deal with reordered
- patches) may want to use this option.
+ by git 1.9 and older and whitespace is ignored. Users with pre-existing
+ databases storing patch-ids produced by git 1.9 and older (who do not deal
+ with reordered patches) may want to use this option.
This is the default.
diff --git a/Documentation/git-prune-packed.txt b/Documentation/git-prune-packed.txt
index 9fed59a317..844d6f808a 100644
--- a/Documentation/git-prune-packed.txt
+++ b/Documentation/git-prune-packed.txt
@@ -9,7 +9,7 @@ git-prune-packed - Remove extra objects that are already in pack files
SYNOPSIS
--------
[verse]
-'git prune-packed' [-n|--dry-run] [-q|--quiet]
+'git prune-packed' [-n | --dry-run] [-q | --quiet]
DESCRIPTION
diff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt
index b9bfdc0a31..7567955bad 100644
--- a/Documentation/git-read-tree.txt
+++ b/Documentation/git-read-tree.txt
@@ -9,7 +9,7 @@ git-read-tree - Reads tree information into the index
SYNOPSIS
--------
[verse]
-'git read-tree' [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>]
+'git read-tree' [(-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>)
[-u | -i]] [--index-output=<file>] [--no-sparse-checkout]
(--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])
diff --git a/Documentation/git-receive-pack.txt b/Documentation/git-receive-pack.txt
index 014a78409b..65ff518ccf 100644
--- a/Documentation/git-receive-pack.txt
+++ b/Documentation/git-receive-pack.txt
@@ -9,7 +9,7 @@ git-receive-pack - Receive what is pushed into the repository
SYNOPSIS
--------
[verse]
-'git-receive-pack' <directory>
+'git receive-pack' <git-dir>
DESCRIPTION
-----------
@@ -38,7 +38,7 @@ its behavior, see linkgit:git-config[1].
OPTIONS
-------
-<directory>::
+<git-dir>::
The repository to sync into.
--http-backend-info-refs::
diff --git a/Documentation/git-reflog.txt b/Documentation/git-reflog.txt
index db9d46edfa..ec64cbff4c 100644
--- a/Documentation/git-reflog.txt
+++ b/Documentation/git-reflog.txt
@@ -9,15 +9,7 @@ git-reflog - Manage reflog information
SYNOPSIS
--------
[verse]
-'git reflog' <subcommand> <options>
-
-DESCRIPTION
------------
-The command takes various subcommands, and different options
-depending on the subcommand:
-
-[verse]
-'git reflog' ['show'] [<log-options>] [<ref>]
+'git reflog' [show] [<log-options>] [<ref>]
'git reflog expire' [--expire=<time>] [--expire-unreachable=<time>]
[--rewrite] [--updateref] [--stale-fix]
[--dry-run | -n] [--verbose] [--all [--single-worktree] | <refs>...]
@@ -25,6 +17,10 @@ depending on the subcommand:
[--dry-run | -n] [--verbose] <ref>@{<specifier>}...
'git reflog exists' <ref>
+DESCRIPTION
+-----------
+This command manages the information recorded in the reflogs.
+
Reference logs, or "reflogs", record when the tips of branches and
other references were updated in the local repository. Reflogs are
useful in various Git commands, to specify the old value of a
@@ -33,7 +29,8 @@ moves ago", `master@{one.week.ago}` means "where master used to point
to one week ago in this local repository", and so on. See
linkgit:gitrevisions[7] for more details.
-This command manages the information recorded in the reflogs.
+The command takes various subcommands, and different options
+depending on the subcommand:
The "show" subcommand (which is also the default, in the absence of
any subcommands) shows the log of the reference provided in the
diff --git a/Documentation/git-rerere.txt b/Documentation/git-rerere.txt
index 4cfc883378..992b469270 100644
--- a/Documentation/git-rerere.txt
+++ b/Documentation/git-rerere.txt
@@ -8,7 +8,7 @@ git-rerere - Reuse recorded resolution of conflicted merges
SYNOPSIS
--------
[verse]
-'git rerere' ['clear'|'forget' <pathspec>|'diff'|'remaining'|'status'|'gc']
+'git rerere' [clear | forget <pathspec>... | diff | status | remaining | gc]
DESCRIPTION
-----------
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
index 20bb8e8217..51029a2271 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -9,7 +9,7 @@ git-rev-list - Lists commit objects in reverse chronological order
SYNOPSIS
--------
[verse]
-'git rev-list' [<options>] <commit>... [[--] <path>...]
+'git rev-list' [<options>] <commit>... [--] [<path>...]
DESCRIPTION
-----------
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index 3290043053..765b2df853 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -178,9 +178,18 @@ Sending
for `sendmail` in `/usr/sbin`, `/usr/lib` and $PATH.
--smtp-encryption=<encryption>::
- Specify the encryption to use, either 'ssl' or 'tls'. Any other
- value reverts to plain SMTP. Default is the value of
- `sendemail.smtpEncryption`.
+ Specify in what way encrypting begins for the SMTP connection.
+ Valid values are 'ssl' and 'tls'. Any other value reverts to plain
+ (unencrypted) SMTP, which defaults to port 25.
+ Despite the names, both values will use the same newer version of TLS,
+ but for historic reasons have these names. 'ssl' refers to "implicit"
+ encryption (sometimes called SMTPS), that uses port 465 by default.
+ 'tls' refers to "explicit" encryption (often known as STARTTLS),
+ that uses port 25 by default. Other ports might be used by the SMTP
+ server, which are not the default. Commonly found alternative port for
+ 'tls' and unencrypted is 587. You need to check your provider's
+ documentation or your server configuration to make sure
+ for your own case. Default is the value of `sendemail.smtpEncryption`.
--smtp-domain=<FQDN>::
Specifies the Fully Qualified Domain Name (FQDN) used in the
diff --git a/Documentation/git-send-pack.txt b/Documentation/git-send-pack.txt
index be41f11974..595b002152 100644
--- a/Documentation/git-send-pack.txt
+++ b/Documentation/git-send-pack.txt
@@ -9,9 +9,10 @@ git-send-pack - Push objects over Git protocol to another repository
SYNOPSIS
--------
[verse]
-'git send-pack' [--dry-run] [--force] [--receive-pack=<git-receive-pack>]
+'git send-pack' [--mirror] [--dry-run] [--force]
+ [--receive-pack=<git-receive-pack>]
[--verbose] [--thin] [--atomic]
- [--[no-]signed|--signed=(true|false|if-asked)]
+ [--[no-]signed | --signed=(true|false|if-asked)]
[<host>:]<directory> (--all | <ref>...)
DESCRIPTION
diff --git a/Documentation/git-show-branch.txt b/Documentation/git-show-branch.txt
index e5ec6b467f..71f608b1ff 100644
--- a/Documentation/git-show-branch.txt
+++ b/Documentation/git-show-branch.txt
@@ -8,12 +8,12 @@ git-show-branch - Show branches and their commits
SYNOPSIS
--------
[verse]
-'git show-branch' [-a|--all] [-r|--remotes] [--topo-order | --date-order]
+'git show-branch' [-a | --all] [-r | --remotes] [--topo-order | --date-order]
[--current] [--color[=<when>] | --no-color] [--sparse]
[--more=<n> | --list | --independent | --merge-base]
[--no-name | --sha1-name] [--topics]
[(<rev> | <glob>)...]
-'git show-branch' (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]
+'git show-branch' (-g | --reflog)[=<n>[,<base>]] [--list] [<ref>]
DESCRIPTION
-----------
diff --git a/Documentation/git-show-ref.txt b/Documentation/git-show-ref.txt
index ab4d271925..d1d56f68b4 100644
--- a/Documentation/git-show-ref.txt
+++ b/Documentation/git-show-ref.txt
@@ -8,8 +8,8 @@ git-show-ref - List references in a local repository
SYNOPSIS
--------
[verse]
-'git show-ref' [-q|--quiet] [--verify] [--head] [-d|--dereference]
- [-s|--hash[=<n>]] [--abbrev[=<n>]] [--tags]
+'git show-ref' [-q | --quiet] [--verify] [--head] [-d | --dereference]
+ [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]
[--heads] [--] [<pattern>...]
'git show-ref' --exclude-existing[=<pattern>]
diff --git a/Documentation/git-sparse-checkout.txt b/Documentation/git-sparse-checkout.txt
index 3776705bf5..68392d2a56 100644
--- a/Documentation/git-sparse-checkout.txt
+++ b/Documentation/git-sparse-checkout.txt
@@ -9,7 +9,7 @@ git-sparse-checkout - Reduce your working tree to a subset of tracked files
SYNOPSIS
--------
[verse]
-'git sparse-checkout <subcommand> [<options>]'
+'git sparse-checkout' (init | list | set | add | reapply | disable) [<options>]
DESCRIPTION
diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
index c5d7091828..f4bb6114d9 100644
--- a/Documentation/git-stash.txt
+++ b/Documentation/git-stash.txt
@@ -9,17 +9,20 @@ SYNOPSIS
--------
[verse]
'git stash' list [<log-options>]
-'git stash' show [-u|--include-untracked|--only-untracked] [<diff-options>] [<stash>]
-'git stash' drop [-q|--quiet] [<stash>]
-'git stash' ( pop | apply ) [--index] [-q|--quiet] [<stash>]
+'git stash' show [-u | --include-untracked | --only-untracked] [<diff-options>] [<stash>]
+'git stash' drop [-q | --quiet] [<stash>]
+'git stash' pop [--index] [-q | --quiet] [<stash>]
+'git stash' apply [--index] [-q | --quiet] [<stash>]
'git stash' branch <branchname> [<stash>]
-'git stash' [push [-p|--patch] [-S|--staged] [-k|--[no-]keep-index] [-q|--quiet]
- [-u|--include-untracked] [-a|--all] [-m|--message <message>]
+'git stash' [push [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]
+ [-u | --include-untracked] [-a | --all] [(-m | --message) <message>]
[--pathspec-from-file=<file> [--pathspec-file-nul]]
[--] [<pathspec>...]]
+'git stash' save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]
+ [-u | --include-untracked] [-a | --all] [<message>]
'git stash' clear
'git stash' create [<message>]
-'git stash' store [-m|--message <message>] [-q|--quiet] <commit>
+'git stash' store [(-m | --message) <message>] [-q | --quiet] <commit>
DESCRIPTION
-----------
@@ -47,7 +50,7 @@ stash index (e.g. the integer `n` is equivalent to `stash@{n}`).
COMMANDS
--------
-push [-p|--patch] [-S|--staged] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>] [--pathspec-from-file=<file> [--pathspec-file-nul]] [--] [<pathspec>...]::
+push [-p|--patch] [-S|--staged] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [(-m|--message) <message>] [--pathspec-from-file=<file> [--pathspec-file-nul]] [--] [<pathspec>...]::
Save your local modifications to a new 'stash entry' and roll them
back to HEAD (in the working tree and in the index).
diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt
index 54a4b29b47..5e438a7fdc 100644
--- a/Documentation/git-status.txt
+++ b/Documentation/git-status.txt
@@ -9,7 +9,7 @@ git-status - Show the working tree status
SYNOPSIS
--------
[verse]
-'git status' [<options>...] [--] [<pathspec>...]
+'git status' [<options>] [--] [<pathspec>...]
DESCRIPTION
-----------
diff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt
index ef68ad2b71..102c83eb19 100644
--- a/Documentation/git-symbolic-ref.txt
+++ b/Documentation/git-symbolic-ref.txt
@@ -9,7 +9,7 @@ SYNOPSIS
--------
[verse]
'git symbolic-ref' [-m <reason>] <name> <ref>
-'git symbolic-ref' [-q] [--short] <name>
+'git symbolic-ref' [-q] [--short] [--no-recurse] <name>
'git symbolic-ref' --delete [-q] <name>
DESCRIPTION
@@ -46,6 +46,15 @@ OPTIONS
When showing the value of <name> as a symbolic ref, try to shorten the
value, e.g. from `refs/heads/master` to `master`.
+--recurse::
+--no-recurse::
+ When showing the value of <name> as a symbolic ref, if
+ <name> refers to another symbolic ref, follow such a chain
+ of symbolic refs until the result no longer points at a
+ symbolic ref (`--recurse`, which is the default).
+ `--no-recurse` stops after dereferencing only a single level
+ of symbolic ref.
+
-m::
Update the reflog for <name> with <reason>. This is valid only
when creating or updating a symbolic ref.
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 31a97a1b6c..fdc72b5875 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -9,7 +9,7 @@ git-tag - Create, list, delete or verify a tag object signed with GPG
SYNOPSIS
--------
[verse]
-'git tag' [-a | -s | -u <keyid>] [-f] [-m <msg> | -F <file>] [-e]
+'git tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]
<tagname> [<commit> | <object>]
'git tag' -d <tagname>...
'git tag' [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]
@@ -26,19 +26,19 @@ to delete, list or verify tags.
Unless `-f` is given, the named tag must not yet exist.
-If one of `-a`, `-s`, or `-u <keyid>` is passed, the command
+If one of `-a`, `-s`, or `-u <key-id>` is passed, the command
creates a 'tag' object, and requires a tag message. Unless
`-m <msg>` or `-F <file>` is given, an editor is started for the user to type
in the tag message.
-If `-m <msg>` or `-F <file>` is given and `-a`, `-s`, and `-u <keyid>`
+If `-m <msg>` or `-F <file>` is given and `-a`, `-s`, and `-u <key-id>`
are absent, `-a` is implied.
Otherwise, a tag reference that points directly at the given object
(i.e., a lightweight tag) is created.
A GnuPG signed tag object will be created when `-s` or `-u
-<keyid>` is used. When `-u <keyid>` is not used, the
+<key-id>` is used. When `-u <key-id>` is not used, the
committer identity for the current user is used to find the
GnuPG key for signing. The configuration variable `gpg.program`
is used to specify custom GnuPG binary.
@@ -72,8 +72,8 @@ OPTIONS
Override `tag.gpgSign` configuration variable that is
set to force each and every tag to be signed.
--u <keyid>::
---local-user=<keyid>::
+-u <key-id>::
+--local-user=<key-id>::
Make a GPG-signed tag, using the given key.
-f::
@@ -164,14 +164,14 @@ This option is only applicable when listing tags without annotation lines.
Use the given tag message (instead of prompting).
If multiple `-m` options are given, their values are
concatenated as separate paragraphs.
- Implies `-a` if none of `-a`, `-s`, or `-u <keyid>`
+ Implies `-a` if none of `-a`, `-s`, or `-u <key-id>`
is given.
-F <file>::
--file=<file>::
Take the tag message from the given file. Use '-' to
read the message from the standard input.
- Implies `-a` if none of `-a`, `-s`, or `-u <keyid>`
+ Implies `-a` if none of `-a`, `-s`, or `-u <key-id>`
is given.
-e::
@@ -220,7 +220,7 @@ it in the repository configuration as follows:
-------------------------------------
[user]
- signingKey = <gpg-keyid>
+ signingKey = <gpg-key_id>
-------------------------------------
`pager.tag` is only respected when listing tags, i.e., when `-l` is
diff --git a/Documentation/git-update-server-info.txt b/Documentation/git-update-server-info.txt
index 969bb2e15f..17e429dbd0 100644
--- a/Documentation/git-update-server-info.txt
+++ b/Documentation/git-update-server-info.txt
@@ -9,7 +9,7 @@ git-update-server-info - Update auxiliary info file to help dumb servers
SYNOPSIS
--------
[verse]
-'git update-server-info'
+'git update-server-info' [-f | --force]
DESCRIPTION
-----------
@@ -19,6 +19,12 @@ $GIT_OBJECT_DIRECTORY/info directories to help clients discover
what references and packs the server has. This command
generates such auxiliary files.
+OPTIONS
+-------
+-f::
+--force::
+ update the info files from scratch.
+
OUTPUT
------
diff --git a/Documentation/git-upload-archive.txt b/Documentation/git-upload-archive.txt
index fba0f1c1b2..e8eb10baad 100644
--- a/Documentation/git-upload-archive.txt
+++ b/Documentation/git-upload-archive.txt
@@ -9,7 +9,7 @@ git-upload-archive - Send archive back to git-archive
SYNOPSIS
--------
[verse]
-'git upload-archive' <directory>
+'git upload-archive' <repository>
DESCRIPTION
-----------
@@ -54,7 +54,7 @@ access via non-smart-http.
OPTIONS
-------
-<directory>::
+<repository>::
The repository to get a tar archive from.
GIT
diff --git a/Documentation/git-var.txt b/Documentation/git-var.txt
index 387cc1b914..6aa521fab2 100644
--- a/Documentation/git-var.txt
+++ b/Documentation/git-var.txt
@@ -9,7 +9,7 @@ git-var - Show a Git logical variable
SYNOPSIS
--------
[verse]
-'git var' ( -l | <variable> )
+'git var' (-l | <variable>)
DESCRIPTION
-----------
diff --git a/Documentation/git-verify-commit.txt b/Documentation/git-verify-commit.txt
index 92097f6673..aee4c40eac 100644
--- a/Documentation/git-verify-commit.txt
+++ b/Documentation/git-verify-commit.txt
@@ -8,7 +8,7 @@ git-verify-commit - Check the GPG signature of commits
SYNOPSIS
--------
[verse]
-'git verify-commit' <commit>...
+'git verify-commit' [-v | --verbose] [--raw] <commit>...
DESCRIPTION
-----------
diff --git a/Documentation/git-verify-pack.txt b/Documentation/git-verify-pack.txt
index 61ca6d04c2..b8720dce8a 100644
--- a/Documentation/git-verify-pack.txt
+++ b/Documentation/git-verify-pack.txt
@@ -9,7 +9,7 @@ git-verify-pack - Validate packed Git archive files
SYNOPSIS
--------
[verse]
-'git verify-pack' [-v|--verbose] [-s|--stat-only] [--] <pack>.idx ...
+'git verify-pack' [-v | --verbose] [-s | --stat-only] [--] <pack>.idx...
DESCRIPTION
diff --git a/Documentation/git-verify-tag.txt b/Documentation/git-verify-tag.txt
index 0b8075dad9..81d50ecc4c 100644
--- a/Documentation/git-verify-tag.txt
+++ b/Documentation/git-verify-tag.txt
@@ -8,7 +8,7 @@ git-verify-tag - Check the GPG signature of tags
SYNOPSIS
--------
[verse]
-'git verify-tag' [--format=<format>] <tag>...
+'git verify-tag' [-v | --verbose] [--format=<format>] [--raw] <tag>...
DESCRIPTION
-----------
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index ada30c86a7..063d6eeb99 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -9,7 +9,8 @@ git-worktree - Manage multiple working trees
SYNOPSIS
--------
[verse]
-'git worktree add' [-f] [--detach] [--checkout] [--lock [--reason <string>]] [-b <new-branch>] <path> [<commit-ish>]
+'git worktree add' [-f] [--detach] [--checkout] [--lock [--reason <string>]]
+ [-b <new-branch>] <path> [<commit-ish>]
'git worktree list' [-v | --porcelain [-z]]
'git worktree lock' [--reason <string>] <worktree>
'git worktree move' <worktree> <new-path>
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 0c15ef3a8e..1d33e083ab 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -458,7 +458,12 @@ Please see linkgit:gitglossary[7].
Environment Variables
---------------------
-Various Git commands use the following environment variables:
+Various Git commands pay attention to environment variables and change
+their behavior. The environment variables marked as "Boolean" take
+their values the same way as Boolean valued configuration variables, e.g.
+"true", "yes", "on" and positive numbers are taken as "yes".
+
+Here are the variables:
The Git Repository
~~~~~~~~~~~~~~~~~~
@@ -467,13 +472,13 @@ is worth noting that they may be used/overridden by SCMS sitting above
Git so take care if using a foreign front-end.
`GIT_INDEX_FILE`::
- This environment allows the specification of an alternate
+ This environment variable specifies an alternate
index file. If not specified, the default of `$GIT_DIR/index`
is used.
`GIT_INDEX_VERSION`::
- This environment variable allows the specification of an index
- version for new repositories. It won't affect existing index
+ This environment variable specifies what index version is used
+ when writing the index file out. It won't affect existing index
files. By default index file version 2 or 3 is used. See
linkgit:git-update-index[1] for more information.
@@ -530,7 +535,7 @@ double-quotes and respecting backslash escapes. E.g., the value
When run in a directory that does not have ".git" repository
directory, Git tries to find such a directory in the parent
directories to find the top of the working tree, but by default it
- does not cross filesystem boundaries. This environment variable
+ does not cross filesystem boundaries. This Boolean environment variable
can be set to true to tell Git not to stop at filesystem
boundaries. Like `GIT_CEILING_DIRECTORIES`, this will not affect
an explicit repository directory set via `GIT_DIR` or on the
@@ -682,6 +687,11 @@ for further details.
plink or tortoiseplink. This variable overrides the config setting
`ssh.variant` that serves the same purpose.
+`GIT_SSL_NO_VERIFY`::
+ Setting and exporting this environment variable to any value
+ tells Git not to verify the SSL certificate when fetching or
+ pushing over HTTPS.
+
`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)
@@ -690,7 +700,7 @@ for further details.
option in linkgit:git-config[1].
`GIT_TERMINAL_PROMPT`::
- If this environment variable is set to `0`, git will not prompt
+ If this Boolean environment variable is set to false, git will not prompt
on the terminal (e.g., when asking for HTTP authentication).
`GIT_CONFIG_GLOBAL`::
@@ -705,13 +715,14 @@ for further details.
`GIT_CONFIG_NOSYSTEM`::
Whether to skip reading settings from the system-wide
- `$(prefix)/etc/gitconfig` file. This environment variable can
+ `$(prefix)/etc/gitconfig` file. This Boolean environment variable can
be used along with `$HOME` and `$XDG_CONFIG_HOME` to create a
predictable environment for a picky script, or you can set it
- temporarily to avoid using a buggy `/etc/gitconfig` file while
+ to true to temporarily avoid using a buggy `/etc/gitconfig` file while
waiting for someone with sufficient permissions to fix it.
`GIT_FLUSH`::
+// NEEDSWORK: make it into a usual Boolean environment variable
If this environment variable is set to "1", then commands such
as 'git blame' (in incremental mode), 'git rev-list', 'git log',
'git check-attr' and 'git check-ignore' will
@@ -852,11 +863,11 @@ for full details.
`GIT_TRACE_REDACT`::
By default, when tracing is activated, Git redacts the values of
cookies, the "Authorization:" header, the "Proxy-Authorization:"
- header and packfile URIs. Set this variable to `0` to prevent this
+ header and packfile URIs. Set this Boolean environment variable to false to prevent this
redaction.
`GIT_LITERAL_PATHSPECS`::
- Setting this variable to `1` will cause Git to treat all
+ Setting this Boolean environment variable to true will cause Git to treat all
pathspecs literally, rather than as glob patterns. For example,
running `GIT_LITERAL_PATHSPECS=1 git log -- '*.c'` will search
for commits that touch the path `*.c`, not any paths that the
@@ -865,15 +876,15 @@ for full details.
`git ls-tree`, `--raw` diff output, etc).
`GIT_GLOB_PATHSPECS`::
- Setting this variable to `1` will cause Git to treat all
+ Setting this Boolean environment variable to true will cause Git to treat all
pathspecs as glob patterns (aka "glob" magic).
`GIT_NOGLOB_PATHSPECS`::
- Setting this variable to `1` will cause Git to treat all
+ Setting this Boolean environment variable to true will cause Git to treat all
pathspecs as literal (aka "literal" magic).
`GIT_ICASE_PATHSPECS`::
- Setting this variable to `1` will cause Git to treat all
+ Setting this Boolean environment variable to true will cause Git to treat all
pathspecs as case-insensitive.
`GIT_REFLOG_ACTION`::
@@ -887,7 +898,7 @@ for full details.
end user, to be recorded in the body of the reflog.
`GIT_REF_PARANOIA`::
- If set to `0`, ignore broken or badly named refs when iterating
+ If this Boolean environment variable is set to false, ignore broken or badly named refs when iterating
over lists of refs. Normally Git will try to include any such
refs, which may cause some operations to fail. This is usually
preferable, as potentially destructive operations (e.g.,
@@ -906,7 +917,7 @@ for full details.
`protocol.allow` in linkgit:git-config[1] for more details.
`GIT_PROTOCOL_FROM_USER`::
- Set to 0 to prevent protocols used by fetch/push/clone which are
+ Set this Boolean environment variable to false to prevent protocols used by fetch/push/clone which are
configured to the `user` state. This is useful to restrict recursive
submodule initialization from an untrusted repository or for programs
which feed potentially-untrusted URLS to git commands. See
@@ -934,7 +945,7 @@ only affects clones and fetches; it is not yet used for pushes (but may
be in the future).
`GIT_OPTIONAL_LOCKS`::
- If set to `0`, Git will complete any requested operation without
+ If this Boolean environment variable is set to false, Git will complete any requested operation without
performing any optional sub-operations that require taking a lock.
For example, this will prevent `git status` from refreshing the
index as a side effect. This is useful for processes running in
diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt
index e3e350126d..0d2e55d781 100644
--- a/Documentation/revisions.txt
+++ b/Documentation/revisions.txt
@@ -363,7 +363,7 @@ Revision Range Summary
'<rev>{caret}!', e.g. 'HEAD{caret}!'::
A suffix '{caret}' followed by an exclamation mark is the same
- as giving commit '<rev>' and then all its parents prefixed with
+ as giving commit '<rev>' and all its parents prefixed with
'{caret}' to exclude them (and their ancestors).
'<rev>{caret}-<n>', e.g. 'HEAD{caret}-, HEAD{caret}-2'::
diff --git a/Documentation/technical/bundle-uri.txt b/Documentation/technical/bundle-uri.txt
index 18f2dedd40..b78d01d9ad 100644
--- a/Documentation/technical/bundle-uri.txt
+++ b/Documentation/technical/bundle-uri.txt
@@ -153,8 +153,8 @@ bundle.<id>.filter::
bundle.<id>.creationToken::
This value is a nonnegative 64-bit integer used for sorting the bundles
- the list. This is used to download a subset of bundles during a fetch
- when `bundle.heuristic=creationToken`.
+ list. This is used to download a subset of bundles during a fetch when
+ `bundle.heuristic=creationToken`.
bundle.<id>.location::
This string value advertises a real-world location from where the bundle
@@ -234,8 +234,8 @@ will interact with bundle URIs according to the following flow:
making those OIDs present. When all required OIDs are present, the
client unbundles that data using a refspec. The default refspec is
`+refs/heads/*:refs/bundles/*`, but this can be configured. These refs
- are stored so that later `git fetch` negotiations can communicate the
- bundled refs as `have`s, reducing the size of the fetch over the Git
+ are stored so that later `git fetch` negotiations can communicate each
+ bundled ref as a `have`, reducing the size of the fetch over the Git
protocol. To allow pruning refs from this ref namespace, Git may
introduce a numbered namespace (such as `refs/bundles/<i>/*`) such that
stale bundle refs can be deleted.
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 024cbd635e..e3eaeb4926 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.38.1
+DEF_VER=v2.38.GIT
LF='
'
diff --git a/Makefile b/Makefile
index cac3452edb..4659d89275 100644
--- a/Makefile
+++ b/Makefile
@@ -529,8 +529,9 @@ GIT-VERSION-FILE: FORCE
# template_dir
# sysconfdir
# can be specified as a relative path some/where/else;
-# this is interpreted as relative to $(prefix) and "git" at
-# runtime figures out where they are based on the path to the executable.
+# this is interpreted as relative to $(prefix) and "git" built with
+# RUNTIME_PREFIX flag will figure out (at runtime) where they are
+# based on the path to the executable.
# Additionally, the following will be treated as relative by "git" if they
# begin with "$(prefix)/":
# mandir
@@ -688,9 +689,9 @@ SCRIPTS = $(SCRIPT_SH_GEN) \
ETAGS_TARGET = TAGS
-FUZZ_OBJS += fuzz-commit-graph.o
-FUZZ_OBJS += fuzz-pack-headers.o
-FUZZ_OBJS += fuzz-pack-idx.o
+FUZZ_OBJS += oss-fuzz/fuzz-commit-graph.o
+FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o
+FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o
.PHONY: fuzz-objs
fuzz-objs: $(FUZZ_OBJS)
@@ -1338,6 +1339,7 @@ BASIC_CFLAGS += -DSHA1DC_FORCE_ALIGNED_ACCESS
endif
ifneq ($(filter leak,$(SANITIZERS)),)
BASIC_CFLAGS += -DSUPPRESS_ANNOTATED_LEAKS
+BASIC_CFLAGS += -O0
SANITIZE_LEAK = YesCompiledWithIt
endif
ifneq ($(filter address,$(SANITIZERS)),)
@@ -1442,7 +1444,6 @@ ifeq ($(uname_S),Darwin)
APPLE_COMMON_CRYPTO = YesPlease
COMPAT_CFLAGS += -DAPPLE_COMMON_CRYPTO
endif
- NO_REGEX = YesPlease
PTHREAD_LIBS =
endif
@@ -2039,11 +2040,13 @@ ifdef FSMONITOR_DAEMON_BACKEND
COMPAT_CFLAGS += -DHAVE_FSMONITOR_DAEMON_BACKEND
COMPAT_OBJS += compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o
COMPAT_OBJS += compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_BACKEND).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-ipc-$(FSMONITOR_DAEMON_BACKEND).o
endif
ifdef FSMONITOR_OS_SETTINGS
COMPAT_CFLAGS += -DHAVE_FSMONITOR_OS_SETTINGS
COMPAT_OBJS += compat/fsmonitor/fsm-settings-$(FSMONITOR_OS_SETTINGS).o
+ COMPAT_OBJS += compat/fsmonitor/fsm-path-utils-$(FSMONITOR_OS_SETTINGS).o
endif
ifeq ($(TCLTK_PATH),)
@@ -2980,6 +2983,7 @@ GIT-BUILD-OPTIONS: FORCE
@echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@+
@echo NO_PTHREADS=\''$(subst ','\'',$(subst ','\'',$(NO_PTHREADS)))'\' >>$@+
@echo NO_PYTHON=\''$(subst ','\'',$(subst ','\'',$(NO_PYTHON)))'\' >>$@+
+ @echo NO_REGEX=\''$(subst ','\'',$(subst ','\'',$(NO_REGEX)))'\' >>$@+
@echo NO_UNIX_SOCKETS=\''$(subst ','\'',$(subst ','\'',$(NO_UNIX_SOCKETS)))'\' >>$@+
@echo PAGER_ENV=\''$(subst ','\'',$(subst ','\'',$(PAGER_ENV)))'\' >>$@+
@echo DC_SHA1=\''$(subst ','\'',$(subst ','\'',$(DC_SHA1)))'\' >>$@+
@@ -3038,6 +3042,7 @@ else
@echo RUNTIME_PREFIX=\'false\' >>$@+
endif
@if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi
+ @if test -f GIT-BUILD-DIR; then rm GIT-BUILD-DIR; fi
### Detect Python interpreter path changes
ifndef NO_PYTHON
diff --git a/RelNotes b/RelNotes
index 141903f31a..758368388a 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.38.1.txt \ No newline at end of file
+Documentation/RelNotes/2.39.0.txt \ No newline at end of file
diff --git a/apply.c b/apply.c
index 2b7cd930ef..6b4dbe0c88 100644
--- a/apply.c
+++ b/apply.c
@@ -125,7 +125,7 @@ void clear_apply_state(struct apply_state *state)
/* &state->fn_table is cleared at the end of apply_patch() */
}
-static void mute_routine(const char *msg, va_list params)
+static void mute_routine(const char *msg UNUSED, va_list params UNUSED)
{
/* do nothing */
}
@@ -892,9 +892,9 @@ static int parse_traditional_patch(struct apply_state *state,
return 0;
}
-static int gitdiff_hdrend(struct gitdiff_data *state,
- const char *line,
- struct patch *patch)
+static int gitdiff_hdrend(struct gitdiff_data *state UNUSED,
+ const char *line UNUSED,
+ struct patch *patch UNUSED)
{
return 1;
}
@@ -1044,7 +1044,7 @@ static int gitdiff_renamedst(struct gitdiff_data *state,
return 0;
}
-static int gitdiff_similarity(struct gitdiff_data *state,
+static int gitdiff_similarity(struct gitdiff_data *state UNUSED,
const char *line,
struct patch *patch)
{
@@ -1054,7 +1054,7 @@ static int gitdiff_similarity(struct gitdiff_data *state,
return 0;
}
-static int gitdiff_dissimilarity(struct gitdiff_data *state,
+static int gitdiff_dissimilarity(struct gitdiff_data *state UNUSED,
const char *line,
struct patch *patch)
{
@@ -1104,9 +1104,9 @@ static int gitdiff_index(struct gitdiff_data *state,
* This is normal for a diff that doesn't change anything: we'll fall through
* into the next diff. Tell the parser to break out.
*/
-static int gitdiff_unrecognized(struct gitdiff_data *state,
- const char *line,
- struct patch *patch)
+static int gitdiff_unrecognized(struct gitdiff_data *state UNUSED,
+ const char *line UNUSED,
+ struct patch *patch UNUSED)
{
return 1;
}
diff --git a/archive.c b/archive.c
index 61a79e4a22..941495f5d7 100644
--- a/archive.c
+++ b/archive.c
@@ -166,18 +166,16 @@ static int write_archive_entry(const struct object_id *oid, const char *base,
args->convert = check_attr_export_subst(check);
}
+ if (args->verbose)
+ fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
+
if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
- if (args->verbose)
- fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
err = write_entry(args, oid, path.buf, path.len, mode, NULL, 0);
if (err)
return err;
return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
}
- if (args->verbose)
- fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
-
/* Stream it? */
if (S_ISREG(mode) && !args->convert &&
oid_object_info(args->repo, oid, &size) == OBJ_BLOB &&
@@ -500,7 +498,7 @@ static void parse_treeish_arg(const char **argv,
ar_args->time = archive_time;
}
-static void extra_file_info_clear(void *util, const char *str)
+static void extra_file_info_clear(void *util, const char *str UNUSED)
{
struct extra_file_info *info = util;
free(info->base);
diff --git a/attr.c b/attr.c
index 8250b06953..42ad6de8c7 100644
--- a/attr.c
+++ b/attr.c
@@ -23,10 +23,6 @@ static const char git_attr__unknown[] = "(builtin)unknown";
#define ATTR__UNSET NULL
#define ATTR__UNKNOWN git_attr__unknown
-#ifndef DEBUG_ATTR
-#define DEBUG_ATTR 0
-#endif
-
struct git_attr {
int attr_nr; /* unique attribute number */
char name[FLEX_ARRAY]; /* attribute name */
@@ -807,33 +803,6 @@ static struct attr_stack *read_attr(struct index_state *istate,
return res;
}
-#if DEBUG_ATTR
-static void debug_info(const char *what, struct attr_stack *elem)
-{
- fprintf(stderr, "%s: %s\n", what, elem->origin ? elem->origin : "()");
-}
-static void debug_set(const char *what, const char *match, struct git_attr *attr, const void *v)
-{
- const char *value = v;
-
- if (ATTR_TRUE(value))
- value = "set";
- else if (ATTR_FALSE(value))
- value = "unset";
- else if (ATTR_UNSET(value))
- value = "unspecified";
-
- fprintf(stderr, "%s: %s => %s (%s)\n",
- what, attr->name, (char *) value, match);
-}
-#define debug_push(a) debug_info("push", (a))
-#define debug_pop(a) debug_info("pop", (a))
-#else
-#define debug_push(a) do { ; } while (0)
-#define debug_pop(a) do { ; } while (0)
-#define debug_set(a,b,c,d) do { ; } while (0)
-#endif /* DEBUG_ATTR */
-
static const char *git_etc_gitattributes(void)
{
static const char *system_wide;
@@ -954,7 +923,6 @@ static void prepare_attr_stack(struct index_state *istate,
(!namelen || path[namelen] == '/'))
break;
- debug_pop(elem);
*stack = elem->prev;
attr_stack_free(elem);
}
@@ -1028,7 +996,7 @@ static int path_matches(const char *pathname, int pathlen,
static int macroexpand_one(struct all_attrs_item *all_attrs, int nr, int rem);
-static int fill_one(const char *what, struct all_attrs_item *all_attrs,
+static int fill_one(struct all_attrs_item *all_attrs,
const struct match_attr *a, int rem)
{
int i;
@@ -1039,9 +1007,6 @@ static int fill_one(const char *what, struct all_attrs_item *all_attrs,
const char *v = a->state[i].setto;
if (*n == ATTR__UNKNOWN) {
- debug_set(what,
- a->is_macro ? a->u.attr->name : a->u.pat.pattern,
- attr, v);
*n = v;
rem--;
rem = macroexpand_one(all_attrs, attr->attr_nr, rem);
@@ -1064,7 +1029,7 @@ static int fill(const char *path, int pathlen, int basename_offset,
continue;
if (path_matches(path, pathlen, basename_offset,
&a->u.pat, base, stack->originlen))
- rem = fill_one("fill", all_attrs, a, rem);
+ rem = fill_one(all_attrs, a, rem);
}
}
@@ -1076,7 +1041,7 @@ static int macroexpand_one(struct all_attrs_item *all_attrs, int nr, int rem)
const struct all_attrs_item *item = &all_attrs[nr];
if (item->macro && item->value == ATTR__TRUE)
- return fill_one("expand", all_attrs, item->macro, rem);
+ return fill_one(all_attrs, item->macro, rem);
else
return rem;
}
diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 501245fac9..28ef7ec2a4 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -765,11 +765,10 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a
strbuf_read_file(&start_head, git_path_bisect_start(), 0);
strbuf_trim(&start_head);
if (!no_checkout) {
- struct strvec argv = STRVEC_INIT;
+ const char *argv[] = { "checkout", start_head.buf,
+ "--", NULL };
- strvec_pushl(&argv, "checkout", start_head.buf,
- "--", NULL);
- if (run_command_v_opt(argv.v, RUN_GIT_CMD)) {
+ if (run_command_v_opt(argv, RUN_GIT_CMD)) {
res = error(_("checking out '%s' failed."
" Try 'git bisect start "
"<valid-branch>'."),
diff --git a/builtin/blame.c b/builtin/blame.c
index a9fe8cf7a6..71f925e456 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -30,6 +30,7 @@
#include "tag.h"
static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] <file>");
+static char annotate_usage[] = N_("git annotate [<options>] [<rev-opts>] [<rev>] [--] <file>");
static const char *blame_opt_usage[] = {
blame_usage,
@@ -38,6 +39,13 @@ static const char *blame_opt_usage[] = {
NULL
};
+static const char *annotate_opt_usage[] = {
+ annotate_usage,
+ "",
+ N_("<rev-opts> are documented in git-rev-list(1)"),
+ NULL
+};
+
static int longest_file;
static int longest_author;
static int max_orig_digits;
@@ -899,6 +907,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
long anchor;
const int hexsz = the_hash_algo->hexsz;
long num_lines = 0;
+ const char *str_usage = cmd_is_annotate ? annotate_usage : blame_usage;
+ const char **opt_usage = cmd_is_annotate ? annotate_opt_usage : blame_opt_usage;
setup_default_color_by_age();
git_config(git_blame_config, &output_option);
@@ -914,7 +924,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
parse_options_start(&ctx, argc, argv, prefix, options,
PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0);
for (;;) {
- switch (parse_options_step(&ctx, options, blame_opt_usage)) {
+ switch (parse_options_step(&ctx, options, opt_usage)) {
case PARSE_OPT_NON_OPTION:
case PARSE_OPT_UNKNOWN:
break;
@@ -934,7 +944,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
ctx.argv[0] = "--children";
reverse = 1;
}
- parse_revision_opt(&revs, &ctx, options, blame_opt_usage);
+ parse_revision_opt(&revs, &ctx, options, opt_usage);
}
parse_done:
revision_opts_finish(&revs);
@@ -1040,7 +1050,7 @@ parse_done:
switch (argc - dashdash_pos - 1) {
case 2: /* (1b) */
if (argc != 4)
- usage_with_options(blame_opt_usage, options);
+ usage_with_options(opt_usage, options);
/* reorder for the new way: <rev> -- <path> */
argv[1] = argv[3];
argv[3] = argv[2];
@@ -1051,11 +1061,11 @@ parse_done:
argv[argc] = NULL;
break;
default:
- usage_with_options(blame_opt_usage, options);
+ usage_with_options(opt_usage, options);
}
} else {
if (argc < 2)
- usage_with_options(blame_opt_usage, options);
+ usage_with_options(opt_usage, options);
if (argc == 3 && is_a_rev(argv[argc - 1])) { /* (2b) */
path = add_prefix(prefix, argv[1]);
argv[1] = argv[2];
@@ -1113,7 +1123,7 @@ parse_done:
nth_line_cb, &sb, lno, anchor,
&bottom, &top, sb.path,
the_repository->index))
- usage(blame_usage);
+ usage(str_usage);
if ((!lno && (top || bottom)) || lno < bottom)
die(Q_("file %s has only %lu line",
"file %s has only %lu lines",
diff --git a/builtin/branch.c b/builtin/branch.c
index 55cd9a6e99..407517ba68 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -538,6 +538,13 @@ 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))
+ die(_("No commit on branch '%s' yet."), oldname);
+ else
+ die(_("No branch named '%s'."), oldname);
+ }
+
/*
* A command like "git branch -M currentbranch currentbranch" cannot
* cause the worktree to become inconsistent with HEAD, so allow it.
@@ -599,10 +606,11 @@ static GIT_PATH_FUNC(edit_description, "EDIT_DESCRIPTION")
static int edit_branch_description(const char *branch_name)
{
+ int exists;
struct strbuf buf = STRBUF_INIT;
struct strbuf name = STRBUF_INIT;
- read_branch_desc(&buf, 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,
@@ -619,7 +627,8 @@ static int edit_branch_description(const char *branch_name)
strbuf_stripspace(&buf, 1);
strbuf_addf(&name, "branch.%s.description", branch_name);
- git_config_set(name.buf, buf.len ? buf.buf : NULL);
+ if (buf.len || exists)
+ git_config_set(name.buf, buf.len ? buf.buf : NULL);
strbuf_release(&name);
strbuf_release(&buf);
@@ -791,31 +800,33 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
} else if (edit_description) {
const char *branch_name;
struct strbuf branch_ref = STRBUF_INIT;
+ struct strbuf buf = STRBUF_INIT;
+ int ret = 1; /* assume failure */
if (!argc) {
if (filter.detached)
die(_("Cannot give description to detached HEAD"));
branch_name = head;
- } else if (argc == 1)
- branch_name = argv[0];
- else
+ } else if (argc == 1) {
+ strbuf_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
+ branch_name = buf.buf;
+ } else {
die(_("cannot edit description of more than one branch"));
+ }
strbuf_addf(&branch_ref, "refs/heads/%s", branch_name);
- if (!ref_exists(branch_ref.buf)) {
- strbuf_release(&branch_ref);
-
- if (!argc)
- return error(_("No commit on branch '%s' yet."),
- branch_name);
- else
- return error(_("No branch named '%s'."),
- branch_name);
- }
+ if (!ref_exists(branch_ref.buf))
+ ret = error((!argc || !strcmp(head, branch_name))
+ ? _("No commit on branch '%s' yet.")
+ : _("No branch named '%s'."),
+ branch_name);
+ else if (!edit_branch_description(branch_name))
+ ret = 0; /* happy */
+
strbuf_release(&branch_ref);
+ strbuf_release(&buf);
- if (edit_branch_description(branch_name))
- return 1;
+ return ret;
} else if (copy) {
if (!argc)
die(_("branch name required"));
@@ -835,9 +846,15 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
else
die(_("too many arguments for a rename operation"));
} else if (new_upstream) {
- struct branch *branch = branch_get(argv[0]);
+ struct branch *branch;
+ struct strbuf buf = STRBUF_INIT;
- if (argc > 1)
+ if (!argc)
+ branch = branch_get(NULL);
+ else if (argc == 1) {
+ strbuf_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
+ branch = branch_get(buf.buf);
+ } else
die(_("too many arguments to set new upstream"));
if (!branch) {
@@ -848,17 +865,26 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
die(_("no such branch '%s'"), argv[0]);
}
- if (!ref_exists(branch->refname))
+ if (!ref_exists(branch->refname)) {
+ if (!argc || !strcmp(head, branch->name))
+ die(_("No commit on branch '%s' yet."), branch->name);
die(_("branch '%s' does not exist"), branch->name);
+ }
dwim_and_setup_tracking(the_repository, branch->name,
new_upstream, BRANCH_TRACK_OVERRIDE,
quiet);
+ strbuf_release(&buf);
} else if (unset_upstream) {
- struct branch *branch = branch_get(argv[0]);
+ struct branch *branch;
struct strbuf buf = STRBUF_INIT;
- if (argc > 1)
+ if (!argc)
+ branch = branch_get(NULL);
+ else if (argc == 1) {
+ strbuf_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
+ branch = branch_get(buf.buf);
+ } else
die(_("too many arguments to unset upstream"));
if (!branch) {
@@ -871,6 +897,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (!branch_has_merge_config(branch))
die(_("Branch '%s' has no upstream information"), branch->name);
+ strbuf_reset(&buf);
strbuf_addf(&buf, "branch.%s.remote", branch->name);
git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
strbuf_reset(&buf);
diff --git a/builtin/bugreport.c b/builtin/bugreport.c
index 530895be55..96052541cb 100644
--- a/builtin/bugreport.c
+++ b/builtin/bugreport.c
@@ -60,7 +60,8 @@ static void get_populated_hooks(struct strbuf *hook_info, int nongit)
}
static const char * const bugreport_usage[] = {
- N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>] [--diagnose[=<mode>]"),
+ N_("git bugreport [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
+ " [--diagnose[=<mode>]]"),
NULL
};
diff --git a/builtin/bundle.c b/builtin/bundle.c
index e80efce3a4..544c78a5f3 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -11,32 +11,42 @@
* bundle supporting "fetch", "pull", and "ls-remote".
*/
-static const char * const builtin_bundle_usage[] = {
- N_("git bundle create [<options>] <file> <git-rev-list args>"),
- N_("git bundle verify [<options>] <file>"),
- N_("git bundle list-heads <file> [<refname>...]"),
- N_("git bundle unbundle <file> [<refname>...]"),
- NULL
+#define BUILTIN_BUNDLE_CREATE_USAGE \
+ N_("git bundle create [-q | --quiet | --progress | --all-progress] [--all-progress-implied]\n" \
+ " [--version=<version>] <file> <git-rev-list-args>")
+#define BUILTIN_BUNDLE_VERIFY_USAGE \
+ N_("git bundle verify [-q | --quiet] <file>")
+#define BUILTIN_BUNDLE_LIST_HEADS_USAGE \
+ N_("git bundle list-heads <file> [<refname>...]")
+#define BUILTIN_BUNDLE_UNBUNDLE_USAGE \
+ N_("git bundle unbundle [--progress] <file> [<refname>...]")
+
+static char const * const builtin_bundle_usage[] = {
+ BUILTIN_BUNDLE_CREATE_USAGE,
+ BUILTIN_BUNDLE_VERIFY_USAGE,
+ BUILTIN_BUNDLE_LIST_HEADS_USAGE,
+ BUILTIN_BUNDLE_UNBUNDLE_USAGE,
+ NULL,
};
static const char * const builtin_bundle_create_usage[] = {
- N_("git bundle create [<options>] <file> <git-rev-list args>"),
- NULL
+ BUILTIN_BUNDLE_CREATE_USAGE,
+ NULL
};
static const char * const builtin_bundle_verify_usage[] = {
- N_("git bundle verify [<options>] <file>"),
- NULL
+ BUILTIN_BUNDLE_VERIFY_USAGE,
+ NULL
};
static const char * const builtin_bundle_list_heads_usage[] = {
- N_("git bundle list-heads <file> [<refname>...]"),
- NULL
+ BUILTIN_BUNDLE_LIST_HEADS_USAGE,
+ NULL
};
static const char * const builtin_bundle_unbundle_usage[] = {
- N_("git bundle unbundle <file> [<refname>...]"),
- NULL
+ BUILTIN_BUNDLE_UNBUNDLE_USAGE,
+ NULL
};
static int parse_options_cmd_bundle(int argc,
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 989eee0bb4..fa7bd89169 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -893,7 +893,7 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
N_("git cat-file (-t | -s) [--allow-unknown-type] <object>"),
N_("git cat-file (--batch | --batch-check | --batch-command) [--batch-all-objects]\n"
" [--buffer] [--follow-symlinks] [--unordered]\n"
- " [--textconv | --filters]"),
+ " [--textconv | --filters] [-z]"),
N_("git cat-file (--textconv | --filters)\n"
" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"),
NULL
diff --git a/builtin/clean.c b/builtin/clean.c
index 5466636e66..40ff2c578d 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -26,7 +26,7 @@ static struct string_list del_list = STRING_LIST_INIT_DUP;
static unsigned int colopts;
static const char *const builtin_clean_usage[] = {
- N_("git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."),
+ N_("git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] [<pathspec>...]"),
NULL
};
diff --git a/builtin/clone.c b/builtin/clone.c
index 5d7affc29a..547d6464b3 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -931,9 +931,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
option_bare = 1;
if (option_bare) {
- if (option_origin)
- die(_("options '%s' and '%s %s' cannot be used together"),
- "--bare", "--origin", option_origin);
if (real_git_dir)
die(_("options '%s' and '%s' cannot be used together"), "--bare", "--separate-git-dir");
option_no_checkout = 1;
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 51557fe786..e8f77f535f 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -10,13 +10,13 @@
#include "tag.h"
#define BUILTIN_COMMIT_GRAPH_VERIFY_USAGE \
- N_("git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]")
+ N_("git commit-graph verify [--object-dir <dir>] [--shallow] [--[no-]progress]")
#define BUILTIN_COMMIT_GRAPH_WRITE_USAGE \
- N_("git commit-graph write [--object-dir <objdir>] [--append] " \
- "[--split[=<strategy>]] [--reachable|--stdin-packs|--stdin-commits] " \
- "[--changed-paths] [--[no-]max-new-filters <n>] [--[no-]progress] " \
- "<split options>")
+ N_("git commit-graph write [--object-dir <dir>] [--append]\n" \
+ " [--split[=<strategy>]] [--reachable | --stdin-packs | --stdin-commits]\n" \
+ " [--changed-paths] [--[no-]max-new-filters <n>] [--[no-]progress]\n" \
+ " <split options>")
static const char * builtin_commit_graph_verify_usage[] = {
BUILTIN_COMMIT_GRAPH_VERIFY_USAGE,
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index 63ea322933..cc8d584be2 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -15,8 +15,9 @@
#include "parse-options.h"
static const char * const commit_tree_usage[] = {
- N_("git commit-tree [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...] "
- "[(-F <file>)...] <tree>"),
+ N_("git commit-tree <tree> [(-p <parent>)...]"),
+ N_("git commit-tree [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...]\n"
+ " [(-F <file>)...] <tree>"),
NULL
};
diff --git a/builtin/commit.c b/builtin/commit.c
index fcf9c85947..e22bdf23f5 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -40,12 +40,19 @@
#include "pretty.h"
static const char * const builtin_commit_usage[] = {
- N_("git commit [<options>] [--] <pathspec>..."),
+ N_("git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n"
+ " [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>)]\n"
+ " [-F <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
+ " [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n"
+ " [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n"
+ " [-i | -o] [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
+ " [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]\n"
+ " [--] [<pathspec>...]"),
NULL
};
static const char * const builtin_status_usage[] = {
- N_("git status [<options>] [--] <pathspec>..."),
+ N_("git status [<options>] [--] [<pathspec>...]"),
NULL
};
@@ -139,7 +146,7 @@ static int opt_pass_trailer(const struct option *opt, const char *arg, int unset
{
BUG_ON_OPT_NEG(unset);
- strvec_pushl(&trailer_args, "--trailer", arg, NULL);
+ strvec_pushl(opt->value, "--trailer", arg, NULL);
return 0;
}
@@ -1633,7 +1640,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
OPT_STRING(0, "fixup", &fixup_message, N_("[(amend|reword):]commit"), N_("use autosquash formatted message to fixup or amend/reword specified commit")),
OPT_STRING(0, "squash", &squash_message, N_("commit"), N_("use autosquash formatted message to squash specified commit")),
OPT_BOOL(0, "reset-author", &renew_authorship, N_("the commit is authored by me now (used with -C/-c/--amend)")),
- OPT_CALLBACK_F(0, "trailer", NULL, N_("trailer"), N_("add custom trailer(s)"), PARSE_OPT_NONEG, opt_pass_trailer),
+ OPT_CALLBACK_F(0, "trailer", &trailer_args, N_("trailer"), N_("add custom trailer(s)"), PARSE_OPT_NONEG, opt_pass_trailer),
OPT_BOOL('s', "signoff", &signoff, N_("add a Signed-off-by trailer")),
OPT_FILENAME('t', "template", &template_file, N_("use specified template file")),
OPT_BOOL('e', "edit", &edit_flag, N_("force edit of commit")),
diff --git a/builtin/credential-cache--daemon.c b/builtin/credential-cache--daemon.c
index 4c6c89ab0d..f3c89831d4 100644
--- a/builtin/credential-cache--daemon.c
+++ b/builtin/credential-cache--daemon.c
@@ -267,7 +267,7 @@ int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix)
const char *socket_path;
int ignore_sighup = 0;
static const char *usage[] = {
- "git-credential-cache--daemon [opts] <socket_path>",
+ "git credential-cache--daemon [--debug] <socket-path>",
NULL
};
int debug = 0;
@@ -305,7 +305,7 @@ int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix)
int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix)
{
const char * const usage[] = {
- "git credential-cache--daemon [options] <action>",
+ "git credential-cache--daemon [--debug] <socket-path>",
"",
"credential-cache--daemon is disabled in this build of Git",
NULL
diff --git a/builtin/describe.c b/builtin/describe.c
index e17c4b4c69..23e3f05fb1 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -23,8 +23,9 @@
define_commit_slab(commit_names, struct commit_name *);
static const char * const describe_usage[] = {
- N_("git describe [<options>] [<commit-ish>...]"),
- N_("git describe [<options>] --dirty"),
+ N_("git describe [--all] [--tags] [--contains] [--abbrev=<n>] [<commit-ish>...]"),
+ N_("git describe [--all] [--tags] [--contains] [--abbrev=<n>] --dirty[=<mark>]"),
+ N_("git describe <blob>"),
NULL
};
diff --git a/builtin/diagnose.c b/builtin/diagnose.c
index 576e0e8e38..d52015c67a 100644
--- a/builtin/diagnose.c
+++ b/builtin/diagnose.c
@@ -3,7 +3,8 @@
#include "diagnose.h"
static const char * const diagnose_usage[] = {
- N_("git diagnose [-o|--output-directory <path>] [-s|--suffix <format>] [--mode=<mode>]"),
+ N_("git diagnose [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
+ " [--mode=<mode>]"),
NULL
};
diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index 92cf6e1e92..096ea2fedb 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -15,6 +15,7 @@
static const char diff_files_usage[] =
"git diff-files [-q] [-0 | -1 | -2 | -3 | -c | --cc] [<common-diff-options>] [<path>...]"
+"\n"
COMMON_DIFF_OPTIONS_HELP;
int cmd_diff_files(int argc, const char **argv, const char *prefix)
diff --git a/builtin/diff-index.c b/builtin/diff-index.c
index 7d158af6b6..aea139b9d8 100644
--- a/builtin/diff-index.c
+++ b/builtin/diff-index.c
@@ -9,8 +9,9 @@
#include "submodule.h"
static const char diff_cache_usage[] =
-"git diff-index [-m] [--cached] "
+"git diff-index [-m] [--cached] [--merge-base] "
"[<common-diff-options>] <tree-ish> [<path>...]"
+"\n"
COMMON_DIFF_OPTIONS_HELP;
int cmd_diff_index(int argc, const char **argv, const char *prefix)
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index 116097a404..85e8c81e59 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -83,8 +83,10 @@ static int diff_tree_stdin(char *line)
}
static const char diff_tree_usage[] =
-"git diff-tree [--stdin] [-m] [-c | --cc] [-s] [-v] [--pretty] [-t] [-r] [--root] "
-"[<common-diff-options>] <tree-ish> [<tree-ish>] [<path>...]\n"
+"git diff-tree [--stdin] [-m] [-s] [-v] [--no-commit-id] [--pretty]\n"
+" [-t] [-r] [-c | --cc] [--combined-all-paths] [--root] [--merge-base]\n"
+" [<common-diff-options>] <tree-ish> [<tree-ish>] [<path>...]\n"
+"\n"
" -r diff recursively\n"
" -c show combined diff for merge commits\n"
" --cc show combined diff for merge commits removing uninteresting hunks\n"
diff --git a/builtin/diff.c b/builtin/diff.c
index 54bb3de964..854d2c5a5c 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -30,7 +30,8 @@ static const char builtin_diff_usage[] =
" or: git diff [<options>] [--merge-base] <commit> [<commit>...] <commit> [--] [<path>...]\n"
" or: git diff [<options>] <commit>...<commit> [--] [<path>...]\n"
" or: git diff [<options>] <blob> <blob>\n"
-" or: git diff [<options>] --no-index [--] <path> <path>\n"
+" or: git diff [<options>] --no-index [--] <path> <path>"
+"\n"
COMMON_DIFF_OPTIONS_HELP;
static const char *blob_path(struct object_array_entry *entry)
@@ -209,7 +210,7 @@ static int builtin_diff_tree(struct rev_info *revs,
static int builtin_diff_combined(struct rev_info *revs,
int argc, const char **argv,
struct object_array_entry *ent,
- int ents)
+ int ents, int first_non_parent)
{
struct oid_array parents = OID_ARRAY_INIT;
int i;
@@ -217,11 +218,18 @@ static int builtin_diff_combined(struct rev_info *revs,
if (argc > 1)
usage(builtin_diff_usage);
+ if (first_non_parent < 0)
+ die(_("no merge given, only parents."));
+ if (first_non_parent >= ents)
+ BUG("first_non_parent out of range: %d", first_non_parent);
+
diff_merges_set_dense_combined_if_unset(revs);
- for (i = 1; i < ents; i++)
- oid_array_append(&parents, &ent[i].item->oid);
- diff_tree_combined(&ent[0].item->oid, &parents, revs);
+ for (i = 0; i < ents; i++) {
+ if (i != first_non_parent)
+ oid_array_append(&parents, &ent[i].item->oid);
+ }
+ diff_tree_combined(&ent[first_non_parent].item->oid, &parents, revs);
oid_array_clear(&parents);
return 0;
}
@@ -385,6 +393,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
int i;
struct rev_info rev;
struct object_array ent = OBJECT_ARRAY_INIT;
+ int first_non_parent = -1;
int blobs = 0, paths = 0;
struct object_array_entry *blob[2];
int nongit = 0, no_index = 0;
@@ -543,6 +552,10 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
continue;
obj->flags |= flags;
add_object_array(obj, name, &ent);
+ if (first_non_parent < 0 &&
+ (i >= rev.cmdline.nr || /* HEAD by hand. */
+ rev.cmdline.rev[i].whence != REV_CMD_PARENTS_ONLY))
+ first_non_parent = ent.nr - 1;
} else if (obj->type == OBJ_BLOB) {
if (2 <= blobs)
die(_("more than two blobs given: '%s'"), name);
@@ -590,7 +603,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
&ent.objects[0], &ent.objects[1]);
} else
result = builtin_diff_combined(&rev, argc, argv,
- ent.objects, ent.nr);
+ ent.objects, ent.nr,
+ first_non_parent);
result = diff_result_code(&rev.diffopt, result);
if (1 < rev.diffopt.skip_stat_unmatch)
refresh_index_quietly();
diff --git a/builtin/fetch.c b/builtin/fetch.c
index a0fca93bb6..b06e454cbd 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -122,6 +122,8 @@ static int git_fetch_config(const char *k, const char *v, void *cb)
fetch_parallel_config = git_config_int(k, v);
if (fetch_parallel_config < 0)
die(_("fetch.parallel cannot be negative"));
+ if (!fetch_parallel_config)
+ fetch_parallel_config = online_cpus();
return 0;
}
@@ -1951,17 +1953,22 @@ static int fetch_multiple(struct string_list *list, int max_children)
if (max_children != 1 && list->nr != 1) {
struct parallel_fetch_state state = { argv.v, list, 0, 0 };
+ const struct run_process_parallel_opts opts = {
+ .tr2_category = "fetch",
+ .tr2_label = "parallel/fetch",
+
+ .processes = max_children,
+
+ .get_next_task = &fetch_next_remote,
+ .start_failure = &fetch_failed_to_start,
+ .task_finished = &fetch_finished,
+ .data = &state,
+ };
strvec_push(&argv, "--end-of-options");
- result = run_processes_parallel_tr2(max_children,
- &fetch_next_remote,
- &fetch_failed_to_start,
- &fetch_finished,
- &state,
- "fetch", "parallel/fetch");
-
- if (!result)
- result = state.result;
+
+ run_processes_parallel(&opts);
+ result = state.result;
} else
for (i = 0; i < list->nr; i++) {
const char *name = list->items[i].string;
diff --git a/builtin/for-each-repo.c b/builtin/for-each-repo.c
index fd86e5a861..d45d873f57 100644
--- a/builtin/for-each-repo.c
+++ b/builtin/for-each-repo.c
@@ -6,7 +6,7 @@
#include "string-list.h"
static const char * const for_each_repo_usage[] = {
- N_("git for-each-repo --config=<config> <command-args>"),
+ N_("git for-each-repo --config=<config> [--] <arguments>"),
NULL
};
diff --git a/builtin/fsck.c b/builtin/fsck.c
index f7916f06ed..7436e1a68e 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -228,6 +228,8 @@ static void mark_unreachable_referents(const struct object_id *oid)
options.walk = mark_used;
fsck_walk(obj, NULL, &options);
+ if (obj->type == OBJ_TREE)
+ free_tree_buffer((struct tree *)obj);
}
static int mark_loose_unreachable_referents(const struct object_id *oid,
@@ -437,9 +439,6 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
out:
if (obj->type == OBJ_TREE)
free_tree_buffer((struct tree *)obj);
- if (obj->type == OBJ_COMMIT)
- free_commit_buffer(the_repository->parsed_objects,
- (struct commit *)obj);
return err;
}
@@ -821,7 +820,10 @@ static int mark_packed_for_connectivity(const struct object_id *oid,
}
static char const * const fsck_usage[] = {
- N_("git fsck [<options>] [<object>...]"),
+ N_("git fsck [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]\n"
+ " [--[no-]full] [--strict] [--verbose] [--lost-found]\n"
+ " [--[no-]dangling] [--[no-]progress] [--connectivity-only]\n"
+ " [--[no-]name-objects] [<object>...]"),
NULL
};
@@ -853,6 +855,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
errors_found = 0;
read_replace_refs = 0;
+ save_commit_buffer = 0;
argc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0);
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 2c109cf8b3..6f30a4f93a 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -3,6 +3,7 @@
#include "parse-options.h"
#include "fsmonitor.h"
#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
#include "compat/fsmonitor/fsm-health.h"
#include "compat/fsmonitor/fsm-listen.h"
#include "fsmonitor--daemon.h"
@@ -13,8 +14,8 @@
static const char * const builtin_fsmonitor__daemon_usage[] = {
N_("git fsmonitor--daemon start [<options>]"),
N_("git fsmonitor--daemon run [<options>]"),
- N_("git fsmonitor--daemon stop"),
- N_("git fsmonitor--daemon status"),
+ "git fsmonitor--daemon stop",
+ "git fsmonitor--daemon status",
NULL
};
@@ -1282,6 +1283,11 @@ static int fsmonitor_run_daemon(void)
strbuf_addstr(&state.path_worktree_watch, absolute_path(get_git_work_tree()));
state.nr_paths_watching = 1;
+ strbuf_init(&state.alias.alias, 0);
+ strbuf_init(&state.alias.points_to, 0);
+ if ((err = fsmonitor__get_alias(state.path_worktree_watch.buf, &state.alias)))
+ goto done;
+
/*
* We create and delete cookie files somewhere inside the .git
* directory to help us keep sync with the file system. If
@@ -1343,7 +1349,8 @@ static int fsmonitor_run_daemon(void)
* directory.)
*/
strbuf_init(&state.path_ipc, 0);
- strbuf_addstr(&state.path_ipc, absolute_path(fsmonitor_ipc__get_path()));
+ strbuf_addstr(&state.path_ipc,
+ absolute_path(fsmonitor_ipc__get_path(the_repository)));
/*
* Confirm that we can create platform-specific resources for the
@@ -1390,6 +1397,8 @@ done:
strbuf_release(&state.path_gitdir_watch);
strbuf_release(&state.path_cookie_prefix);
strbuf_release(&state.path_ipc);
+ strbuf_release(&state.alias.alias);
+ strbuf_release(&state.alias.points_to);
return err;
}
diff --git a/builtin/gc.c b/builtin/gc.c
index 2753bd15a5..24ea85c7af 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -167,16 +167,9 @@ static void gc_config(void)
struct maintenance_run_opts;
static int maintenance_task_pack_refs(MAYBE_UNUSED struct maintenance_run_opts *opts)
{
- struct strvec pack_refs_cmd = STRVEC_INIT;
- int ret;
+ const char *argv[] = { "pack-refs", "--all", "--prune", NULL };
- strvec_pushl(&pack_refs_cmd, "pack-refs", "--all", "--prune", NULL);
-
- ret = run_command_v_opt(pack_refs_cmd.v, RUN_GIT_CMD);
-
- strvec_clear(&pack_refs_cmd);
-
- return ret;
+ return run_command_v_opt(argv, RUN_GIT_CMD);
}
static int too_many_loose_objects(void)
@@ -329,7 +322,7 @@ static uint64_t estimate_repack_memory(struct packed_git *pack)
return os_cache + heap;
}
-static int keep_one_pack(struct string_list_item *item, void *data)
+static int keep_one_pack(struct string_list_item *item, void *data UNUSED)
{
strvec_pushf(&repack, "--keep-pack=%s", basename(item->string));
return 0;
@@ -1470,11 +1463,12 @@ static int maintenance_register(int argc, const char **argv, const char *prefix)
struct option options[] = {
OPT_END(),
};
- int rc;
+ int found = 0;
+ const char *key = "maintenance.repo";
char *config_value;
- struct child_process config_set = CHILD_PROCESS_INIT;
- struct child_process config_get = CHILD_PROCESS_INIT;
char *maintpath = get_maintpath();
+ struct string_list_item *item;
+ const struct string_list *list;
argc = parse_options(argc, argv, prefix, options,
builtin_maintenance_register_usage, 0);
@@ -1491,46 +1485,56 @@ static int maintenance_register(int argc, const char **argv, const char *prefix)
else
git_config_set("maintenance.strategy", "incremental");
- config_get.git_cmd = 1;
- strvec_pushl(&config_get.args, "config", "--global", "--get",
- "--fixed-value", "maintenance.repo", maintpath, NULL);
- config_get.out = -1;
-
- if (start_command(&config_get)) {
- rc = error(_("failed to run 'git config'"));
- goto done;
+ list = git_config_get_value_multi(key);
+ if (list) {
+ for_each_string_list_item(item, list) {
+ if (!strcmp(maintpath, item->string)) {
+ found = 1;
+ break;
+ }
+ }
}
- /* We already have this value in our config! */
- if (!finish_command(&config_get)) {
- rc = 0;
- goto done;
+ if (!found) {
+ int rc;
+ char *user_config, *xdg_config;
+ git_global_config(&user_config, &xdg_config);
+ if (!user_config)
+ die(_("$HOME not set"));
+ rc = git_config_set_multivar_in_file_gently(
+ user_config, "maintenance.repo", maintpath,
+ CONFIG_REGEX_NONE, 0);
+ free(user_config);
+ free(xdg_config);
+
+ if (rc)
+ die(_("unable to add '%s' value of '%s'"),
+ key, maintpath);
}
- config_set.git_cmd = 1;
- strvec_pushl(&config_set.args, "config", "--add", "--global", "maintenance.repo",
- maintpath, NULL);
-
- rc = run_command(&config_set);
-
-done:
free(maintpath);
- return rc;
+ return 0;
}
static char const * const builtin_maintenance_unregister_usage[] = {
- "git maintenance unregister",
+ "git maintenance unregister [--force]",
NULL
};
static int maintenance_unregister(int argc, const char **argv, const char *prefix)
{
+ int force = 0;
struct option options[] = {
+ OPT__FORCE(&force,
+ N_("return success even if repository was not registered"),
+ PARSE_OPT_NOCOMPLETE),
OPT_END(),
};
- int rc;
- struct child_process config_unset = CHILD_PROCESS_INIT;
+ const char *key = "maintenance.repo";
char *maintpath = get_maintpath();
+ int found = 0;
+ struct string_list_item *item;
+ const struct string_list *list;
argc = parse_options(argc, argv, prefix, options,
builtin_maintenance_unregister_usage, 0);
@@ -1538,13 +1542,38 @@ static int maintenance_unregister(int argc, const char **argv, const char *prefi
usage_with_options(builtin_maintenance_unregister_usage,
options);
- config_unset.git_cmd = 1;
- strvec_pushl(&config_unset.args, "config", "--global", "--unset",
- "--fixed-value", "maintenance.repo", maintpath, NULL);
+ list = git_config_get_value_multi(key);
+ if (list) {
+ for_each_string_list_item(item, list) {
+ if (!strcmp(maintpath, item->string)) {
+ found = 1;
+ break;
+ }
+ }
+ }
+
+ if (found) {
+ int rc;
+ char *user_config, *xdg_config;
+ git_global_config(&user_config, &xdg_config);
+ if (!user_config)
+ die(_("$HOME not set"));
+ rc = git_config_set_multivar_in_file_gently(
+ user_config, key, NULL, maintpath,
+ CONFIG_FLAGS_MULTI_REPLACE | CONFIG_FLAGS_FIXED_VALUE);
+ free(user_config);
+ free(xdg_config);
+
+ if (rc &&
+ (!force || rc == CONFIG_NOTHING_SET))
+ die(_("unable to unset '%s' value of '%s'"),
+ key, maintpath);
+ } else if (!force) {
+ die(_("repository '%s' is not registered"), maintpath);
+ }
- rc = run_command(&config_unset);
free(maintpath);
- return rc;
+ return 0;
}
static const char *get_frequency(enum schedule_priority schedule)
diff --git a/builtin/grep.c b/builtin/grep.c
index e6bcdf860c..5fa927d4e2 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -458,6 +458,33 @@ static int grep_submodule(struct grep_opt *opt,
* subrepo's odbs to the in-memory alternates list.
*/
obj_read_lock();
+
+ /*
+ * NEEDSWORK: when reading a submodule, the sparsity settings in the
+ * superproject are incorrectly forgotten or misused. For example:
+ *
+ * 1. "command_requires_full_index"
+ * When this setting is turned on for `grep`, only the superproject
+ * knows it. All the submodules are read with their own configs
+ * and get prepare_repo_settings()'d. Therefore, these submodules
+ * "forget" the sparse-index feature switch. As a result, the index
+ * of these submodules are expanded unexpectedly.
+ *
+ * 2. "core_apply_sparse_checkout"
+ * When running `grep` in the superproject, this setting is
+ * populated using the superproject's configs. However, once
+ * initialized, this config is globally accessible and is read by
+ * prepare_repo_settings() for the submodules. For instance, if a
+ * submodule is using a sparse-checkout, however, the superproject
+ * is not, the result is that the config from the superproject will
+ * dictate the behavior for the submodule, making it "forget" its
+ * sparse-checkout state.
+ *
+ * 3. "core_sparse_checkout_cone"
+ * ditto.
+ *
+ * Note that this list is not exhaustive.
+ */
repo_read_gitmodules(subrepo, 0);
/*
@@ -520,8 +547,6 @@ static int grep_cache(struct grep_opt *opt,
if (repo_read_index(repo) < 0)
die(_("index file corrupt"));
- /* TODO: audit for interaction with sparse-index. */
- ensure_full_index(repo->index);
for (nr = 0; nr < repo->index->cache_nr; nr++) {
const struct cache_entry *ce = repo->index->cache[nr];
@@ -530,8 +555,20 @@ static int grep_cache(struct grep_opt *opt,
strbuf_setlen(&name, name_base_len);
strbuf_addstr(&name, ce->name);
+ if (S_ISSPARSEDIR(ce->ce_mode)) {
+ enum object_type type;
+ struct tree_desc tree;
+ void *data;
+ unsigned long size;
- if (S_ISREG(ce->ce_mode) &&
+ data = read_object_file(&ce->oid, &type, &size);
+ init_tree_desc(&tree, data, size);
+
+ hit |= grep_tree(opt, pathspec, &tree, &name, 0, 0);
+ strbuf_setlen(&name, name_base_len);
+ strbuf_addstr(&name, ce->name);
+ free(data);
+ } else if (S_ISREG(ce->ce_mode) &&
match_pathspec(repo->index, pathspec, name.buf, name.len, 0, NULL,
S_ISDIR(ce->ce_mode) ||
S_ISGITLINK(ce->ce_mode))) {
@@ -984,6 +1021,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
PARSE_OPT_KEEP_DASHDASH |
PARSE_OPT_STOP_AT_NON_OPTION);
+ if (the_repository->gitdir) {
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+ }
+
if (use_index && !startup_info->have_repository) {
int fallback = 0;
git_config_get_bool("grep.fallbacktonoindex", &fallback);
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index fbae878c2b..b506381502 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -80,8 +80,9 @@ static void hash_stdin_paths(const char *type, int no_filters, unsigned flags,
int cmd_hash_object(int argc, const char **argv, const char *prefix)
{
static const char * const hash_object_usage[] = {
- N_("git hash-object [-t <type>] [-w] [--path=<file> | --no-filters] [--stdin] [--] <file>..."),
- "git hash-object --stdin-paths",
+ N_("git hash-object [-t <type>] [-w] [--path=<file> | --no-filters]\n"
+ " [--stdin [--literally]] [--] <file>..."),
+ N_("git hash-object [-t <type>] [-w] --stdin-paths [--no-filters]"),
NULL
};
const char *type = blob_type;
diff --git a/builtin/help.c b/builtin/help.c
index 6f2796f211..53f2812dfb 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -88,7 +88,7 @@ static struct option builtin_help_options[] = {
};
static const char * const builtin_help_usage[] = {
- "git help [-a|--all] [--[no-]verbose]] [--[no-]external-commands] [--[no-]aliases]",
+ "git help [-a|--all] [--[no-]verbose] [--[no-]external-commands] [--[no-]aliases]",
N_("git help [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]"),
"git help [-g|--guides]",
"git help [-c|--config]",
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 546f9c595e..dcaaf102ea 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -515,7 +515,10 @@ static int shared_callback(const struct option *opt, const char *arg, int unset)
}
static const char *const init_db_usage[] = {
- N_("git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]] [<directory>]"),
+ N_("git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
+ " [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
+ " [-b <branch-name> | --initial-branch=<branch-name>]\n"
+ " [--shared[=<permissions>]] [<directory>]"),
NULL
};
diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c
index 84748eafc0..e58627c72a 100644
--- a/builtin/interpret-trailers.c
+++ b/builtin/interpret-trailers.c
@@ -13,7 +13,9 @@
#include "config.h"
static const char * const git_interpret_trailers_usage[] = {
- N_("git interpret-trailers [--in-place] [--trim-empty] [(--trailer <token>[(=|:)<value>])...] [<file>...]"),
+ N_("git interpret-trailers [--in-place] [--trim-empty]\n"
+ " [(--trailer <token>[(=|:)<value>])...]\n"
+ " [--parse] [<file>...]"),
NULL
};
diff --git a/builtin/log.c b/builtin/log.c
index ee19dc5d45..e72869afb3 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -1763,7 +1763,7 @@ static void prepare_bases(struct base_tree_info *bases,
struct object_id *patch_id;
if (*commit_base_at(&commit_base, commit))
continue;
- if (commit_patch_id(commit, &diffopt, &oid, 0, 1))
+ if (commit_patch_id(commit, &diffopt, &oid, 0))
die(_("cannot get patch id"));
ALLOC_GROW(bases->patch_id, bases->nr_patch_id + 1, bases->alloc_patch_id);
patch_id = bases->patch_id + bases->nr_patch_id;
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index df44e5cc0d..5d5ac03871 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -7,7 +7,7 @@
static const char * const ls_remote_usage[] = {
N_("git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
- " [-q | --quiet] [--exit-code] [--get-url]\n"
+ " [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
" [--symref] [<repository> [<refs>...]]"),
NULL
};
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index a11f8c6e4b..6f3941f2a4 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -31,8 +31,8 @@ static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
static const char * const merge_base_usage[] = {
N_("git merge-base [-a | --all] <commit> <commit>..."),
N_("git merge-base [-a | --all] --octopus <commit>..."),
- N_("git merge-base --independent <commit>..."),
N_("git merge-base --is-ancestor <commit> <commit>"),
+ N_("git merge-base --independent <commit>..."),
N_("git merge-base --fork-point <ref> [<commit>]"),
NULL
};
diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c
index 9b126d6ce0..9a18a82b05 100644
--- a/builtin/multi-pack-index.c
+++ b/builtin/multi-pack-index.c
@@ -56,11 +56,12 @@ static struct opts_multi_pack_index {
static int parse_object_dir(const struct option *opt, const char *arg,
int unset)
{
- free(opts.object_dir);
+ char **value = opt->value;
+ free(*value);
if (unset)
- opts.object_dir = xstrdup(get_object_directory());
+ *value = xstrdup(get_object_directory());
else
- opts.object_dir = real_pathdup(arg, 1);
+ *value = real_pathdup(arg, 1);
return 0;
}
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 3658c05caf..573d0b20b7 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -180,8 +180,8 @@ static inline void oe_set_delta_size(struct packing_data *pack,
#define SET_DELTA_SIBLING(obj, val) oe_set_delta_sibling(&to_pack, obj, val)
static const char *pack_usage[] = {
- N_("git pack-objects --stdout [<options>...] [< <ref-list> | < <object-list>]"),
- N_("git pack-objects [<options>...] <base-name> [< <ref-list> | < <object-list>]"),
+ N_("git pack-objects --stdout [<options>] [< <ref-list> | < <object-list>]"),
+ N_("git pack-objects [<options>] <base-name> [< <ref-list> | < <object-list>]"),
NULL
};
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index ed9b9013a5..ecd49ca268 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -14,7 +14,7 @@
#define BLKSIZE 512
static const char pack_redundant_usage[] =
-"git pack-redundant [--verbose] [--alt-odb] (--all | <filename.pack>...)";
+"git pack-redundant [--verbose] [--alt-odb] (--all | <pack-filename>...)";
static int load_all_packs, verbose, alt_odb;
diff --git a/builtin/pack-refs.c b/builtin/pack-refs.c
index cfbd5c36c7..27c2ca06ac 100644
--- a/builtin/pack-refs.c
+++ b/builtin/pack-refs.c
@@ -5,7 +5,7 @@
#include "repository.h"
static char const * const pack_refs_usage[] = {
- N_("git pack-refs [<options>]"),
+ N_("git pack-refs [--all] [--no-prune]"),
NULL
};
diff --git a/builtin/patch-id.c b/builtin/patch-id.c
index 881fcf3273..f840fbf1c7 100644
--- a/builtin/patch-id.c
+++ b/builtin/patch-id.c
@@ -2,6 +2,7 @@
#include "builtin.h"
#include "config.h"
#include "diff.h"
+#include "parse-options.h"
static void flush_current_id(int patchlen, struct object_id *id, struct object_id *result)
{
@@ -57,10 +58,12 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after)
}
static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
- struct strbuf *line_buf, int stable)
+ struct strbuf *line_buf, int stable, int verbatim)
{
int patchlen = 0, found_next = 0;
int before = -1, after = -1;
+ int diff_is_binary = 0;
+ char pre_oid_str[GIT_MAX_HEXSZ + 1], post_oid_str[GIT_MAX_HEXSZ + 1];
git_hash_ctx ctx;
the_hash_algo->init_fn(&ctx);
@@ -71,11 +74,14 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
const char *p = line;
int len;
- if (!skip_prefix(line, "diff-tree ", &p) &&
- !skip_prefix(line, "commit ", &p) &&
+ /* Possibly skip over the prefix added by "log" or "format-patch" */
+ if (!skip_prefix(line, "commit ", &p) &&
!skip_prefix(line, "From ", &p) &&
- starts_with(line, "\\ ") && 12 < strlen(line))
+ starts_with(line, "\\ ") && 12 < strlen(line)) {
+ if (verbatim)
+ the_hash_algo->update_fn(&ctx, line, strlen(line));
continue;
+ }
if (!get_oid_hex(p, next_oid)) {
found_next = 1;
@@ -88,14 +94,44 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
/* Parsing diff header? */
if (before == -1) {
- if (starts_with(line, "index "))
+ if (starts_with(line, "GIT binary patch") ||
+ starts_with(line, "Binary files")) {
+ diff_is_binary = 1;
+ before = 0;
+ the_hash_algo->update_fn(&ctx, pre_oid_str,
+ strlen(pre_oid_str));
+ the_hash_algo->update_fn(&ctx, post_oid_str,
+ strlen(post_oid_str));
+ if (stable)
+ flush_one_hunk(result, &ctx);
+ continue;
+ } else if (skip_prefix(line, "index ", &p)) {
+ char *oid1_end = strstr(line, "..");
+ char *oid2_end = NULL;
+ if (oid1_end)
+ oid2_end = strstr(oid1_end, " ");
+ if (!oid2_end)
+ oid2_end = line + strlen(line) - 1;
+ if (oid1_end != NULL && oid2_end != NULL) {
+ *oid1_end = *oid2_end = '\0';
+ strlcpy(pre_oid_str, p, GIT_MAX_HEXSZ + 1);
+ strlcpy(post_oid_str, oid1_end + 2, GIT_MAX_HEXSZ + 1);
+ }
continue;
- else if (starts_with(line, "--- "))
+ } else if (starts_with(line, "--- "))
before = after = 1;
else if (!isalpha(line[0]))
break;
}
+ if (diff_is_binary) {
+ if (starts_with(line, "diff ")) {
+ diff_is_binary = 0;
+ before = -1;
+ }
+ continue;
+ }
+
/* Looking for a valid hunk header? */
if (before == 0 && after == 0) {
if (starts_with(line, "@@ -")) {
@@ -120,8 +156,8 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
if (line[0] == '+' || line[0] == ' ')
after--;
- /* Compute the sha without whitespace */
- len = remove_space(line);
+ /* Add line to hash algo (possibly removing whitespace) */
+ len = verbatim ? strlen(line) : remove_space(line);
patchlen += len;
the_hash_algo->update_fn(&ctx, line, len);
}
@@ -134,7 +170,7 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
return patchlen;
}
-static void generate_id_list(int stable)
+static void generate_id_list(int stable, int verbatim)
{
struct object_id oid, n, result;
int patchlen;
@@ -142,21 +178,32 @@ static void generate_id_list(int stable)
oidclr(&oid);
while (!feof(stdin)) {
- patchlen = get_one_patchid(&n, &result, &line_buf, stable);
+ patchlen = get_one_patchid(&n, &result, &line_buf, stable, verbatim);
flush_current_id(patchlen, &oid, &result);
oidcpy(&oid, &n);
}
strbuf_release(&line_buf);
}
-static const char patch_id_usage[] = "git patch-id [--stable | --unstable]";
+static const char *const patch_id_usage[] = {
+ N_("git patch-id [--stable | --unstable | --verbatim]"), NULL
+};
+
+struct patch_id_opts {
+ int stable;
+ int verbatim;
+};
static int git_patch_id_config(const char *var, const char *value, void *cb)
{
- int *stable = cb;
+ struct patch_id_opts *opts = cb;
if (!strcmp(var, "patchid.stable")) {
- *stable = git_config_bool(var, value);
+ opts->stable = git_config_bool(var, value);
+ return 0;
+ }
+ if (!strcmp(var, "patchid.verbatim")) {
+ opts->verbatim = git_config_bool(var, value);
return 0;
}
@@ -165,21 +212,29 @@ static int git_patch_id_config(const char *var, const char *value, void *cb)
int cmd_patch_id(int argc, const char **argv, const char *prefix)
{
- int stable = -1;
-
- git_config(git_patch_id_config, &stable);
-
- /* If nothing is set, default to unstable. */
- if (stable < 0)
- stable = 0;
-
- if (argc == 2 && !strcmp(argv[1], "--stable"))
- stable = 1;
- else if (argc == 2 && !strcmp(argv[1], "--unstable"))
- stable = 0;
- else if (argc != 1)
- usage(patch_id_usage);
-
- generate_id_list(stable);
+ /* if nothing is set, default to unstable */
+ struct patch_id_opts config = {0, 0};
+ int opts = 0;
+ struct option builtin_patch_id_options[] = {
+ OPT_CMDMODE(0, "unstable", &opts,
+ N_("use the unstable patch-id algorithm"), 1),
+ OPT_CMDMODE(0, "stable", &opts,
+ N_("use the stable patch-id algorithm"), 2),
+ OPT_CMDMODE(0, "verbatim", &opts,
+ N_("don't strip whitespace from the patch"), 3),
+ OPT_END()
+ };
+
+ git_config(git_patch_id_config, &config);
+
+ /* verbatim implies stable */
+ if (config.verbatim)
+ config.stable = 1;
+
+ argc = parse_options(argc, argv, prefix, builtin_patch_id_options,
+ patch_id_usage, 0);
+
+ generate_id_list(opts ? opts > 1 : config.stable,
+ opts ? opts == 3 : config.verbatim);
return 0;
}
diff --git a/builtin/push.c b/builtin/push.c
index df0d68e599..f0329c62a2 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -169,8 +169,8 @@ static NORETURN void die_push_simple(struct branch *branch,
if (git_branch_track != BRANCH_TRACK_SIMPLE)
advice_automergesimple_maybe = _("\n"
"To avoid automatically configuring "
- "upstream branches when their name\n"
- "doesn't match the local branch, see option "
+ "an upstream branch when its name\n"
+ "won't match the local branch, see option "
"'simple' of branch.autoSetupMerge\n"
"in 'git help config'.\n");
die(_("The upstream branch of your current branch does not match\n"
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index 9f1f33e954..f4cbe460b9 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -38,7 +38,9 @@ static int list_tree(struct object_id *oid)
}
static const char * const read_tree_usage[] = {
- N_("git read-tree [(-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>) [-u | -i]] [--no-sparse-checkout] [--index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"),
+ N_("git read-tree [(-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>)\n"
+ " [-u | -i]] [--index-output=<file>] [--no-sparse-checkout]\n"
+ " (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"),
NULL
};
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 57c5c0d061..270681dcdf 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -67,7 +67,8 @@ static int collect_reflog(const char *ref, const struct object_id *oid UNUSED,
* Avoid collecting the same shared ref multiple times because
* they are available via all worktrees.
*/
- if (!worktree->is_current && ref_type(ref) == REF_TYPE_NORMAL)
+ if (!worktree->is_current &&
+ parse_worktree_ref(ref, NULL, NULL, NULL) == REF_WORKTREE_SHARED)
return 0;
strbuf_worktree_ref(worktree, &newref, ref);
diff --git a/builtin/remote.c b/builtin/remote.c
index 985b845a18..93285fc06e 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -733,29 +733,31 @@ static int mv(int argc, const char **argv, const char *prefix)
return error(_("Could not rename config section '%s' to '%s'"),
buf.buf, buf2.buf);
- strbuf_reset(&buf);
- strbuf_addf(&buf, "remote.%s.fetch", rename.new_name);
- git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
- strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name);
- for (i = 0; i < oldremote->fetch.raw_nr; i++) {
- char *ptr;
-
- strbuf_reset(&buf2);
- strbuf_addstr(&buf2, oldremote->fetch.raw[i]);
- ptr = strstr(buf2.buf, old_remote_context.buf);
- if (ptr) {
- refspec_updated = 1;
- strbuf_splice(&buf2,
- ptr-buf2.buf + strlen(":refs/remotes/"),
- strlen(rename.old_name), rename.new_name,
- strlen(rename.new_name));
- } else
- warning(_("Not updating non-default fetch refspec\n"
- "\t%s\n"
- "\tPlease update the configuration manually if necessary."),
- buf2.buf);
-
- git_config_set_multivar(buf.buf, buf2.buf, "^$", 0);
+ if (oldremote->fetch.raw_nr) {
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "remote.%s.fetch", rename.new_name);
+ git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
+ strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name);
+ for (i = 0; i < oldremote->fetch.raw_nr; i++) {
+ char *ptr;
+
+ strbuf_reset(&buf2);
+ strbuf_addstr(&buf2, oldremote->fetch.raw[i]);
+ ptr = strstr(buf2.buf, old_remote_context.buf);
+ if (ptr) {
+ refspec_updated = 1;
+ strbuf_splice(&buf2,
+ ptr-buf2.buf + strlen(":refs/remotes/"),
+ strlen(rename.old_name), rename.new_name,
+ strlen(rename.new_name));
+ } else
+ warning(_("Not updating non-default fetch refspec\n"
+ "\t%s\n"
+ "\tPlease update the configuration manually if necessary."),
+ buf2.buf);
+
+ git_config_set_multivar(buf.buf, buf2.buf, "^$", 0);
+ }
}
read_branches();
@@ -940,7 +942,7 @@ static int rm(int argc, const char **argv, const char *prefix)
return result;
}
-static void clear_push_info(void *util, const char *string)
+static void clear_push_info(void *util, const char *string UNUSED)
{
struct push_info *info = util;
free(info->dest);
diff --git a/builtin/repack.c b/builtin/repack.c
index a5bacc7797..10e23f9ee1 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -92,44 +92,6 @@ static int repack_config(const char *var, const char *value, void *cb)
}
/*
- * Remove temporary $GIT_OBJECT_DIRECTORY/pack/.tmp-$$-pack-* files.
- */
-static void remove_temporary_files(void)
-{
- struct strbuf buf = STRBUF_INIT;
- size_t dirlen, prefixlen;
- DIR *dir;
- struct dirent *e;
-
- dir = opendir(packdir);
- if (!dir)
- return;
-
- /* Point at the slash at the end of ".../objects/pack/" */
- dirlen = strlen(packdir) + 1;
- strbuf_addstr(&buf, packtmp);
- /* Hold the length of ".tmp-%d-pack-" */
- prefixlen = buf.len - dirlen;
-
- while ((e = readdir(dir))) {
- if (strncmp(e->d_name, buf.buf + dirlen, prefixlen))
- continue;
- strbuf_setlen(&buf, dirlen);
- strbuf_addstr(&buf, e->d_name);
- unlink(buf.buf);
- }
- closedir(dir);
- strbuf_release(&buf);
-}
-
-static void remove_pack_on_signal(int signo)
-{
- remove_temporary_files();
- sigchain_pop(signo);
- raise(signo);
-}
-
-/*
* Adds all packs hex strings to either fname_nonkept_list or
* fname_kept_list based on whether each pack has a corresponding
* .keep file or not. Packs without a .keep file are not to be kept
@@ -247,11 +209,15 @@ static struct {
{".idx"},
};
-static unsigned populate_pack_exts(char *name)
+struct generated_pack_data {
+ struct tempfile *tempfiles[ARRAY_SIZE(exts)];
+};
+
+static struct generated_pack_data *populate_pack_exts(const char *name)
{
struct stat statbuf;
struct strbuf path = STRBUF_INIT;
- unsigned ret = 0;
+ struct generated_pack_data *data = xcalloc(1, sizeof(*data));
int i;
for (i = 0; i < ARRAY_SIZE(exts); i++) {
@@ -261,11 +227,11 @@ static unsigned populate_pack_exts(char *name)
if (stat(path.buf, &statbuf))
continue;
- ret |= (1 << i);
+ data->tempfiles[i] = register_tempfile(path.buf);
}
strbuf_release(&path);
- return ret;
+ return data;
}
static void repack_promisor_objects(const struct pack_objects_args *args,
@@ -320,7 +286,7 @@ static void repack_promisor_objects(const struct pack_objects_args *args,
line.buf);
write_promisor_file(promisor_name, NULL, 0);
- item->util = (void *)(uintptr_t)populate_pack_exts(item->string);
+ item->util = populate_pack_exts(item->string);
free(promisor_name);
}
@@ -661,6 +627,35 @@ static int write_midx_included_packs(struct string_list *include,
return finish_command(&cmd);
}
+static void remove_redundant_bitmaps(struct string_list *include,
+ const char *packdir)
+{
+ struct strbuf path = STRBUF_INIT;
+ struct string_list_item *item;
+ size_t packdir_len;
+
+ strbuf_addstr(&path, packdir);
+ strbuf_addch(&path, '/');
+ packdir_len = path.len;
+
+ /*
+ * Remove any pack bitmaps corresponding to packs which are now
+ * included in the MIDX.
+ */
+ for_each_string_list_item(item, include) {
+ strbuf_addstr(&path, item->string);
+ strbuf_strip_suffix(&path, ".idx");
+ strbuf_addstr(&path, ".bitmap");
+
+ if (unlink(path.buf) && errno != ENOENT)
+ warning_errno(_("could not remove stale bitmap: %s"),
+ path.buf);
+
+ strbuf_setlen(&path, packdir_len);
+ }
+ strbuf_release(&path);
+}
+
static int write_cruft_pack(const struct pack_objects_args *args,
const char *pack_prefix,
struct string_list *names,
@@ -710,10 +705,14 @@ static int write_cruft_pack(const struct pack_objects_args *args,
out = xfdopen(cmd.out, "r");
while (strbuf_getline_lf(&line, out) != EOF) {
+ struct string_list_item *item;
+
if (line.len != the_hash_algo->hexsz)
die(_("repack: Expecting full hex object ID lines only "
"from pack-objects."));
- string_list_append(names, line.buf);
+
+ item = string_list_append(names, line.buf);
+ item->util = populate_pack_exts(line.buf);
}
fclose(out);
@@ -859,8 +858,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
split_pack_geometry(geometry, geometric_factor);
}
- sigchain_push_common(remove_pack_on_signal);
-
prepare_pack_objects(&cmd, &po_args);
show_progress = !po_args.quiet && isatty(2);
@@ -952,9 +949,12 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
out = xfdopen(cmd.out, "r");
while (strbuf_getline_lf(&line, out) != EOF) {
+ struct string_list_item *item;
+
if (line.len != the_hash_algo->hexsz)
die(_("repack: Expecting full hex object ID lines only from pack-objects."));
- string_list_append(&names, line.buf);
+ item = string_list_append(&names, line.buf);
+ item->util = populate_pack_exts(item->string);
}
fclose(out);
ret = finish_command(&cmd);
@@ -993,40 +993,38 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
string_list_sort(&names);
- for_each_string_list_item(item, &names) {
- item->util = (void *)(uintptr_t)populate_pack_exts(item->string);
- }
-
close_object_store(the_repository->objects);
/*
* Ok we have prepared all new packfiles.
*/
for_each_string_list_item(item, &names) {
+ struct generated_pack_data *data = item->util;
+
for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
- char *fname, *fname_old;
+ char *fname;
fname = mkpathdup("%s/pack-%s%s",
packdir, item->string, exts[ext].name);
- fname_old = mkpathdup("%s-%s%s",
- packtmp, item->string, exts[ext].name);
- if (((uintptr_t)item->util) & ((uintptr_t)1 << ext)) {
+ if (data->tempfiles[ext]) {
+ const char *fname_old = get_tempfile_path(data->tempfiles[ext]);
struct stat statbuffer;
+
if (!stat(fname_old, &statbuffer)) {
statbuffer.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
chmod(fname_old, statbuffer.st_mode);
}
- if (rename(fname_old, fname))
- die_errno(_("renaming '%s' failed"), fname_old);
+ if (rename_tempfile(&data->tempfiles[ext], fname))
+ die_errno(_("renaming pack to '%s' failed"), fname);
} else if (!exts[ext].optional)
- die(_("missing required file: %s"), fname_old);
+ die(_("pack-objects did not write a '%s' file for pack %s-%s"),
+ exts[ext].name, packtmp, item->string);
else if (unlink(fname) < 0 && errno != ENOENT)
die_errno(_("could not unlink: %s"), fname);
free(fname);
- free(fname_old);
}
}
/* End of pack replacement. */
@@ -1059,6 +1057,9 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
refs_snapshot ? get_tempfile_path(refs_snapshot) : NULL,
show_progress, write_bitmaps > 0);
+ if (!ret && write_bitmaps)
+ remove_redundant_bitmaps(&include, packdir);
+
string_list_clear(&include, 0);
if (ret)
@@ -1089,6 +1090,11 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
strbuf_addstr(&buf, pack_basename(p));
strbuf_strip_suffix(&buf, ".pack");
+ if ((p->pack_keep) ||
+ (string_list_has_string(&existing_kept_packs,
+ buf.buf)))
+ continue;
+
remove_redundant_pack(packdir, buf.buf);
}
strbuf_release(&buf);
@@ -1106,7 +1112,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (run_update_server_info)
update_server_info(0);
- remove_temporary_files();
if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX, 0)) {
unsigned flags = 0;
@@ -1115,7 +1120,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
write_midx_file(get_object_directory(), NULL, NULL, flags);
}
- string_list_clear(&names, 0);
+ string_list_clear(&names, 1);
string_list_clear(&existing_nonkept_packs, 0);
string_list_clear(&existing_kept_packs, 0);
clear_pack_geometry(geometry);
diff --git a/builtin/rerere.c b/builtin/rerere.c
index 83d7a778e3..8b7392d5b4 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -10,7 +10,7 @@
#include "pathspec.h"
static const char * const rerere_usage[] = {
- N_("git rerere [clear | forget <path>... | status | remaining | diff | gc]"),
+ N_("git rerere [clear | forget <pathspec>... | diff | status | remaining | gc]"),
NULL,
};
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index fba6f5d51f..3acd93f71e 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -20,7 +20,8 @@
#include "packfile.h"
static const char rev_list_usage[] =
-"git rev-list [<options>] <commit-id>... [-- <path>...]\n"
+"git rev-list [<options>] <commit>... [--] [<path>...]\n"
+"\n"
" limiting output:\n"
" --max-count=<n>\n"
" --max-age=<epoch>\n"
diff --git a/builtin/revert.c b/builtin/revert.c
index ee2a0807f0..ee32c714a7 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -21,14 +21,15 @@
*/
static const char * const revert_usage[] = {
- N_("git revert [<options>] <commit-ish>..."),
- N_("git revert <subcommand>"),
+ N_("git revert [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>..."),
+ N_("git revert (--continue | --skip | --abort | --quit)"),
NULL
};
static const char * const cherry_pick_usage[] = {
- N_("git cherry-pick [<options>] <commit-ish>..."),
- N_("git cherry-pick <subcommand>"),
+ N_("git cherry-pick [--edit] [-n] [-m <parent-number>] [-s] [-x] [--ff]\n"
+ " [-S[<keyid>]] <commit>..."),
+ N_("git cherry-pick (--continue | --skip | --abort | --quit)"),
NULL
};
diff --git a/builtin/rm.c b/builtin/rm.c
index b6ba859fe4..f0d025a4e2 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -17,7 +17,9 @@
#include "pathspec.h"
static const char * const builtin_rm_usage[] = {
- N_("git rm [<options>] [--] <file>..."),
+ N_("git rm [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch]\n"
+ " [--quiet] [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
+ " [--] [<pathspec>...]"),
NULL
};
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 64962be016..4c5d125fa0 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -20,6 +20,7 @@ static const char * const send_pack_usage[] = {
N_("git send-pack [--mirror] [--dry-run] [--force]\n"
" [--receive-pack=<git-receive-pack>]\n"
" [--verbose] [--thin] [--atomic]\n"
+ " [--[no-]signed | --signed=(true|false|if-asked)]\n"
" [<host>:]<directory> (--all | <ref>...)"),
NULL,
};
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index d3f5715e3e..c013abaf94 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -14,7 +14,8 @@ static const char* show_branch_usage[] = {
N_("git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
" [--current] [--color[=<when>] | --no-color] [--sparse]\n"
" [--more=<n> | --list | --independent | --merge-base]\n"
- " [--no-name | --sha1-name] [--topics] [(<rev> | <glob>)...]"),
+ " [--no-name | --sha1-name] [--topics]\n"
+ " [(<rev> | <glob>)...]"),
N_("git show-branch (-g | --reflog)[=<n>[,<base>]] [--list] [<ref>]"),
NULL
};
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index 4856906108..3af6a53ee9 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -9,7 +9,9 @@
#include "parse-options.h"
static const char * const show_ref_usage[] = {
- N_("git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference] [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [<pattern>...]"),
+ N_("git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference]\n"
+ " [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
+ " [--heads] [--] [<pattern>...]"),
N_("git show-ref --exclude-existing[=<pattern>]"),
NULL
};
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index 287716db68..58a22503f0 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -20,7 +20,7 @@
static const char *empty_base = "";
static char const * const builtin_sparse_checkout_usage[] = {
- N_("git sparse-checkout (init|list|set|add|reapply|disable) <options>"),
+ N_("git sparse-checkout (init | list | set | add | reapply | disable) [<options>]"),
NULL
};
diff --git a/builtin/stash.c b/builtin/stash.c
index 2274aae255..bb5485b409 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -21,72 +21,95 @@
#define INCLUDE_ALL_FILES 2
+#define BUILTIN_STASH_LIST_USAGE \
+ N_("git stash list [<log-options>]")
+#define BUILTIN_STASH_SHOW_USAGE \
+ N_("git stash show [-u | --include-untracked | --only-untracked] [<diff-options>] [<stash>]")
+#define BUILTIN_STASH_DROP_USAGE \
+ N_("git stash drop [-q | --quiet] [<stash>]")
+#define BUILTIN_STASH_POP_USAGE \
+ N_("git stash pop [--index] [-q | --quiet] [<stash>]")
+#define BUILTIN_STASH_APPLY_USAGE \
+ N_("git stash apply [--index] [-q | --quiet] [<stash>]")
+#define BUILTIN_STASH_BRANCH_USAGE \
+ N_("git stash branch <branchname> [<stash>]")
+#define BUILTIN_STASH_STORE_USAGE \
+ N_("git stash store [(-m | --message) <message>] [-q | --quiet] <commit>")
+#define BUILTIN_STASH_PUSH_USAGE \
+ N_("git stash [push [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]\n" \
+ " [-u | --include-untracked] [-a | --all] [(-m | --message) <message>]\n" \
+ " [--pathspec-from-file=<file> [--pathspec-file-nul]]\n" \
+ " [--] [<pathspec>...]]")
+#define BUILTIN_STASH_SAVE_USAGE \
+ N_("git stash save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]\n" \
+ " [-u | --include-untracked] [-a | --all] [<message>]")
+#define BUILTIN_STASH_CREATE_USAGE \
+ N_("git stash create [<message>]")
+#define BUILTIN_STASH_CLEAR_USAGE \
+ "git stash clear"
+
static const char * const git_stash_usage[] = {
- N_("git stash list [<options>]"),
- N_("git stash show [<options>] [<stash>]"),
- N_("git stash drop [-q|--quiet] [<stash>]"),
- N_("git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>]"),
- N_("git stash branch <branchname> [<stash>]"),
- "git stash clear",
- N_("git stash [push [-p|--patch] [-S|--staged] [-k|--[no-]keep-index] [-q|--quiet]\n"
- " [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
- " [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
- " [--] [<pathspec>...]]"),
- N_("git stash save [-p|--patch] [-S|--staged] [-k|--[no-]keep-index] [-q|--quiet]\n"
- " [-u|--include-untracked] [-a|--all] [<message>]"),
+ BUILTIN_STASH_LIST_USAGE,
+ BUILTIN_STASH_SHOW_USAGE,
+ BUILTIN_STASH_DROP_USAGE,
+ BUILTIN_STASH_POP_USAGE,
+ BUILTIN_STASH_APPLY_USAGE,
+ BUILTIN_STASH_BRANCH_USAGE,
+ BUILTIN_STASH_PUSH_USAGE,
+ BUILTIN_STASH_SAVE_USAGE,
+ BUILTIN_STASH_CLEAR_USAGE,
+ BUILTIN_STASH_CREATE_USAGE,
+ BUILTIN_STASH_STORE_USAGE,
NULL
};
static const char * const git_stash_list_usage[] = {
- N_("git stash list [<options>]"),
+ BUILTIN_STASH_LIST_USAGE,
NULL
};
static const char * const git_stash_show_usage[] = {
- N_("git stash show [<options>] [<stash>]"),
+ BUILTIN_STASH_SHOW_USAGE,
NULL
};
static const char * const git_stash_drop_usage[] = {
- N_("git stash drop [-q|--quiet] [<stash>]"),
+ BUILTIN_STASH_DROP_USAGE,
NULL
};
static const char * const git_stash_pop_usage[] = {
- N_("git stash pop [--index] [-q|--quiet] [<stash>]"),
+ BUILTIN_STASH_POP_USAGE,
NULL
};
static const char * const git_stash_apply_usage[] = {
- N_("git stash apply [--index] [-q|--quiet] [<stash>]"),
+ BUILTIN_STASH_APPLY_USAGE,
NULL
};
static const char * const git_stash_branch_usage[] = {
- N_("git stash branch <branchname> [<stash>]"),
+ BUILTIN_STASH_BRANCH_USAGE,
NULL
};
static const char * const git_stash_clear_usage[] = {
- "git stash clear",
+ BUILTIN_STASH_CLEAR_USAGE,
NULL
};
static const char * const git_stash_store_usage[] = {
- N_("git stash store [-m|--message <message>] [-q|--quiet] <commit>"),
+ BUILTIN_STASH_STORE_USAGE,
NULL
};
static const char * const git_stash_push_usage[] = {
- N_("git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
- " [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
- " [--] [<pathspec>...]]"),
+ BUILTIN_STASH_PUSH_USAGE,
NULL
};
static const char * const git_stash_save_usage[] = {
- N_("git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
- " [-u|--include-untracked] [-a|--all] [<message>]"),
+ BUILTIN_STASH_SAVE_USAGE,
NULL
};
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 0b4acb442b..a7683d3529 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -181,7 +181,7 @@ static void module_list_release(struct module_list *ml)
free(ml->entries);
}
-static int module_list_compute(int argc, const char **argv,
+static int module_list_compute(const char **argv,
const char *prefix,
struct pathspec *pathspec,
struct module_list *list)
@@ -405,7 +405,7 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, module_foreach_options,
git_submodule_helper_usage, 0);
- if (module_list_compute(0, NULL, prefix, &pathspec, &list) < 0)
+ if (module_list_compute(NULL, prefix, &pathspec, &list) < 0)
goto cleanup;
info.argc = argc;
@@ -545,7 +545,7 @@ static int module_init(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, module_init_options,
git_submodule_helper_usage, 0);
- if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
+ if (module_list_compute(argv, prefix, &pathspec, &list) < 0)
goto cleanup;
/*
@@ -732,7 +732,7 @@ static int module_status(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, module_status_options,
git_submodule_helper_usage, 0);
- if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
+ if (module_list_compute(argv, prefix, &pathspec, &list) < 0)
goto cleanup;
info.prefix = prefix;
@@ -1326,7 +1326,7 @@ static int module_sync(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, module_sync_options,
git_submodule_helper_usage, 0);
- if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
+ if (module_list_compute(argv, prefix, &pathspec, &list) < 0)
goto cleanup;
info.prefix = prefix;
@@ -1479,7 +1479,7 @@ static int module_deinit(int argc, const char **argv, const char *prefix)
if (!argc && !all)
die(_("Use '--all' if you really want to deinitialize all submodules"));
- if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
+ if (module_list_compute(argv, prefix, &pathspec, &list) < 0)
goto cleanup;
info.prefix = prefix;
@@ -2567,12 +2567,20 @@ static int update_submodules(struct update_data *update_data)
{
int i, ret = 0;
struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
+ const struct run_process_parallel_opts opts = {
+ .tr2_category = "submodule",
+ .tr2_label = "parallel/update",
+
+ .processes = update_data->max_jobs,
+
+ .get_next_task = update_clone_get_next_task,
+ .start_failure = update_clone_start_failure,
+ .task_finished = update_clone_task_finished,
+ .data = &suc,
+ };
suc.update_data = update_data;
- run_processes_parallel_tr2(suc.update_data->max_jobs, update_clone_get_next_task,
- update_clone_start_failure,
- update_clone_task_finished, &suc, "submodule",
- "parallel/update");
+ run_processes_parallel(&opts);
/*
* We saved the output and put it out all at once now.
@@ -2697,7 +2705,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
if (opt.update_default)
opt.update_strategy.type = opt.update_default;
- if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0) {
+ if (module_list_compute(argv, prefix, &pathspec, &opt.list) < 0) {
ret = 1;
goto cleanup;
}
@@ -2709,7 +2717,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
struct module_list list = MODULE_LIST_INIT;
struct init_cb info = INIT_CB_INIT;
- if (module_list_compute(argc, argv, opt.prefix,
+ if (module_list_compute(argv, opt.prefix,
&pathspec2, &list) < 0) {
module_list_release(&list);
ret = 1;
@@ -2840,7 +2848,7 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, embed_gitdir_options,
git_submodule_helper_usage, 0);
- if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
+ if (module_list_compute(argv, prefix, &pathspec, &list) < 0)
goto cleanup;
for (i = 0; i < list.nr; i++)
diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c
index 1b0f10225f..e00768a8b7 100644
--- a/builtin/symbolic-ref.c
+++ b/builtin/symbolic-ref.c
@@ -5,15 +5,19 @@
#include "parse-options.h"
static const char * const git_symbolic_ref_usage[] = {
- N_("git symbolic-ref [<options>] <name> [<ref>]"),
- N_("git symbolic-ref -d [-q] <name>"),
+ N_("git symbolic-ref [-m <reason>] <name> <ref>"),
+ N_("git symbolic-ref [-q] [--short] [--no-recurse] <name>"),
+ N_("git symbolic-ref --delete [-q] <name>"),
NULL
};
-static int check_symref(const char *HEAD, int quiet, int shorten, int print)
+static int check_symref(const char *HEAD, int quiet, int shorten, int recurse, int print)
{
- int flag;
- const char *refname = resolve_ref_unsafe(HEAD, 0, NULL, &flag);
+ int resolve_flags, flag;
+ const char *refname;
+
+ resolve_flags = (recurse ? 0 : RESOLVE_REF_NO_RECURSE);
+ refname = resolve_ref_unsafe(HEAD, resolve_flags, NULL, &flag);
if (!refname)
die("No such ref: %s", HEAD);
@@ -35,13 +39,14 @@ static int check_symref(const char *HEAD, int quiet, int shorten, int print)
int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
{
- int quiet = 0, delete = 0, shorten = 0, ret = 0;
+ int quiet = 0, delete = 0, shorten = 0, recurse = 1, ret = 0;
const char *msg = NULL;
struct option options[] = {
OPT__QUIET(&quiet,
N_("suppress error message for non-symbolic (detached) refs")),
OPT_BOOL('d', "delete", &delete, N_("delete symbolic ref")),
OPT_BOOL(0, "short", &shorten, N_("shorten ref output")),
+ OPT_BOOL(0, "recurse", &recurse, N_("recursively dereference (default)")),
OPT_STRING('m', NULL, &msg, N_("reason"), N_("reason of the update")),
OPT_END(),
};
@@ -55,7 +60,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
if (delete) {
if (argc != 1)
usage_with_options(git_symbolic_ref_usage, options);
- ret = check_symref(argv[0], 1, 0, 0);
+ ret = check_symref(argv[0], 1, 0, 0, 0);
if (ret)
die("Cannot delete %s, not a symbolic ref", argv[0]);
if (!strcmp(argv[0], "HEAD"))
@@ -65,7 +70,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
switch (argc) {
case 1:
- ret = check_symref(argv[0], quiet, shorten, 1);
+ ret = check_symref(argv[0], quiet, shorten, recurse, 1);
break;
case 2:
if (!strcmp(argv[0], "HEAD") &&
diff --git a/builtin/tag.c b/builtin/tag.c
index 75dece0e4f..d428c45dc8 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -23,11 +23,13 @@
#include "date.h"
static const char * const git_tag_usage[] = {
- N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>]\n"
- " <tagname> [<head>]"),
+ N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
+ " <tagname> [<commit> | <object>]"),
N_("git tag -d <tagname>..."),
- N_("git tag -l [-n[<num>]] [--contains <commit>] [--no-contains <commit>] [--points-at <object>]\n"
- " [--format=<format>] [--merged <commit>] [--no-merged <commit>] [<pattern>...]"),
+ N_("git tag [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]\n"
+ " [--points-at <object>] [--column[=<options>] | --no-column]\n"
+ " [--create-reflog] [--sort=<key>] [--format=<format>]\n"
+ " [--merged <commit>] [--no-merged <commit>] [<pattern>...]"),
N_("git tag -v [--format=<format>] <tagname>..."),
NULL
};
diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c
index 58652229f2..9e8119dd35 100644
--- a/builtin/unpack-file.c
+++ b/builtin/unpack-file.c
@@ -27,7 +27,7 @@ int cmd_unpack_file(int argc, const char **argv, const char *prefix)
struct object_id oid;
if (argc != 2 || !strcmp(argv[1], "-h"))
- usage("git unpack-file <sha1>");
+ usage("git unpack-file <blob>");
if (get_oid(argv[1], &oid))
die("Not a valid object name %s", argv[1]);
diff --git a/builtin/update-index.c b/builtin/update-index.c
index b62249905f..7b0c924d7d 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -732,7 +732,7 @@ static int do_unresolve(int ac, const char **av,
return err;
}
-static int do_reupdate(int ac, const char **av,
+static int do_reupdate(const char **paths,
const char *prefix)
{
/* Read HEAD and run update-index on paths that are
@@ -744,7 +744,7 @@ static int do_reupdate(int ac, const char **av,
parse_pathspec(&pathspec, 0,
PATHSPEC_PREFER_CWD,
- prefix, av + 1);
+ prefix, paths);
if (read_ref("HEAD", &head_oid))
/* If there is no HEAD, that means it is an initial
@@ -970,7 +970,7 @@ static enum parse_opt_result reupdate_callback(
/* consume remaining arguments. */
setup_work_tree();
- *has_errors = do_reupdate(ctx->argc, ctx->argv, prefix);
+ *has_errors = do_reupdate(ctx->argv + 1, prefix);
if (*has_errors)
active_cache_changed = 0;
diff --git a/builtin/update-server-info.c b/builtin/update-server-info.c
index 880fffec58..d2239c9ef4 100644
--- a/builtin/update-server-info.c
+++ b/builtin/update-server-info.c
@@ -4,7 +4,7 @@
#include "parse-options.h"
static const char * const update_server_info_usage[] = {
- "git update-server-info [--force]",
+ "git update-server-info [-f | --force]",
NULL
};
diff --git a/builtin/upload-archive.c b/builtin/upload-archive.c
index 98d028dae6..945ee2b412 100644
--- a/builtin/upload-archive.c
+++ b/builtin/upload-archive.c
@@ -10,7 +10,7 @@
#include "strvec.h"
static const char upload_archive_usage[] =
- "git upload-archive <repo>";
+ "git upload-archive <repository>";
static const char deadchild[] =
"git upload-archive: archiver died with error";
diff --git a/builtin/upload-pack.c b/builtin/upload-pack.c
index 125af53885..25b69da2bf 100644
--- a/builtin/upload-pack.c
+++ b/builtin/upload-pack.c
@@ -8,7 +8,8 @@
#include "serve.h"
static const char * const upload_pack_usage[] = {
- N_("git upload-pack [<options>] <dir>"),
+ N_("git-upload-pack [--[no-]strict] [--timeout=<n>] [--stateless-rpc]\n"
+ " [--advertise-refs] <directory>"),
NULL
};
diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c
index 40c69a0bed..3ebad32b0f 100644
--- a/builtin/verify-commit.c
+++ b/builtin/verify-commit.c
@@ -16,7 +16,7 @@
#include "gpg-interface.h"
static const char * const verify_commit_usage[] = {
- N_("git verify-commit [-v | --verbose] <commit>..."),
+ N_("git verify-commit [-v | --verbose] [--raw] <commit>..."),
NULL
};
diff --git a/builtin/verify-pack.c b/builtin/verify-pack.c
index 05c5213594..27d6f75fd8 100644
--- a/builtin/verify-pack.c
+++ b/builtin/verify-pack.c
@@ -56,7 +56,7 @@ static int verify_one_pack(const char *path, unsigned int flags, const char *has
}
static const char * const verify_pack_usage[] = {
- N_("git verify-pack [-v | --verbose] [-s | --stat-only] <pack>..."),
+ N_("git verify-pack [-v | --verbose] [-s | --stat-only] [--] <pack>.idx..."),
NULL
};
diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c
index f45136a06b..217566952d 100644
--- a/builtin/verify-tag.c
+++ b/builtin/verify-tag.c
@@ -15,7 +15,7 @@
#include "ref-filter.h"
static const char * const verify_tag_usage[] = {
- N_("git verify-tag [-v | --verbose] [--format=<format>] <tag>..."),
+ N_("git verify-tag [-v | --verbose] [--format=<format>] [--raw] <tag>..."),
NULL
};
diff --git a/builtin/worktree.c b/builtin/worktree.c
index c6710b2552..4a24d53be1 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -15,15 +15,73 @@
#include "worktree.h"
#include "quote.h"
-static const char * const worktree_usage[] = {
- N_("git worktree add [<options>] <path> [<commit-ish>]"),
- N_("git worktree list [<options>]"),
- N_("git worktree lock [<options>] <path>"),
- N_("git worktree move <worktree> <new-path>"),
- N_("git worktree prune [<options>]"),
- N_("git worktree remove [<options>] <worktree>"),
- N_("git worktree repair [<path>...]"),
- N_("git worktree unlock <path>"),
+#define BUILTIN_WORKTREE_ADD_USAGE \
+ N_("git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]\n" \
+ " [-b <new-branch>] <path> [<commit-ish>]")
+#define BUILTIN_WORKTREE_LIST_USAGE \
+ N_("git worktree list [-v | --porcelain [-z]]")
+#define BUILTIN_WORKTREE_LOCK_USAGE \
+ N_("git worktree lock [--reason <string>] <worktree>")
+#define BUILTIN_WORKTREE_MOVE_USAGE \
+ N_("git worktree move <worktree> <new-path>")
+#define BUILTIN_WORKTREE_PRUNE_USAGE \
+ N_("git worktree prune [-n] [-v] [--expire <expire>]")
+#define BUILTIN_WORKTREE_REMOVE_USAGE \
+ N_("git worktree remove [-f] <worktree>")
+#define BUILTIN_WORKTREE_REPAIR_USAGE \
+ N_("git worktree repair [<path>...]")
+#define BUILTIN_WORKTREE_UNLOCK_USAGE \
+ N_("git worktree unlock <worktree>")
+
+static const char * const git_worktree_usage[] = {
+ BUILTIN_WORKTREE_ADD_USAGE,
+ BUILTIN_WORKTREE_LIST_USAGE,
+ BUILTIN_WORKTREE_LOCK_USAGE,
+ BUILTIN_WORKTREE_MOVE_USAGE,
+ BUILTIN_WORKTREE_PRUNE_USAGE,
+ BUILTIN_WORKTREE_REMOVE_USAGE,
+ BUILTIN_WORKTREE_REPAIR_USAGE,
+ BUILTIN_WORKTREE_UNLOCK_USAGE,
+ NULL
+};
+
+static const char * const git_worktree_add_usage[] = {
+ BUILTIN_WORKTREE_ADD_USAGE,
+ NULL,
+};
+
+static const char * const git_worktree_list_usage[] = {
+ BUILTIN_WORKTREE_LIST_USAGE,
+ NULL
+};
+
+static const char * const git_worktree_lock_usage[] = {
+ BUILTIN_WORKTREE_LOCK_USAGE,
+ NULL
+};
+
+static const char * const git_worktree_move_usage[] = {
+ BUILTIN_WORKTREE_MOVE_USAGE,
+ NULL
+};
+
+static const char * const git_worktree_prune_usage[] = {
+ BUILTIN_WORKTREE_PRUNE_USAGE,
+ NULL
+};
+
+static const char * const git_worktree_remove_usage[] = {
+ BUILTIN_WORKTREE_REMOVE_USAGE,
+ NULL
+};
+
+static const char * const git_worktree_repair_usage[] = {
+ BUILTIN_WORKTREE_REPAIR_USAGE,
+ NULL
+};
+
+static const char * const git_worktree_unlock_usage[] = {
+ BUILTIN_WORKTREE_UNLOCK_USAGE,
NULL
};
@@ -153,9 +211,10 @@ static int prune(int ac, const char **av, const char *prefix)
};
expire = TIME_MAX;
- ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ ac = parse_options(ac, av, prefix, options, git_worktree_prune_usage,
+ 0);
if (ac)
- usage_with_options(worktree_usage, options);
+ usage_with_options(git_worktree_prune_usage, options);
prune_worktrees();
return 0;
}
@@ -573,7 +632,7 @@ static int add(int ac, const char **av, const char *prefix)
memset(&opts, 0, sizeof(opts));
opts.checkout = 1;
- ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ ac = parse_options(ac, av, prefix, options, git_worktree_add_usage, 0);
if (!!opts.detach + !!new_branch + !!new_branch_force > 1)
die(_("options '%s', '%s', and '%s' cannot be used together"), "-b", "-B", "--detach");
if (lock_reason && !keep_locked)
@@ -584,7 +643,7 @@ static int add(int ac, const char **av, const char *prefix)
opts.keep_locked = _("added with --lock");
if (ac < 1 || ac > 2)
- usage_with_options(worktree_usage, options);
+ usage_with_options(git_worktree_add_usage, options);
path = prefix_filename(prefix, av[0]);
branch = ac < 2 ? "HEAD" : av[1];
@@ -772,9 +831,9 @@ static int list(int ac, const char **av, const char *prefix)
};
expire = TIME_MAX;
- ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ ac = parse_options(ac, av, prefix, options, git_worktree_list_usage, 0);
if (ac)
- usage_with_options(worktree_usage, options);
+ usage_with_options(git_worktree_list_usage, options);
else if (verbose && porcelain)
die(_("options '%s' and '%s' cannot be used together"), "--verbose", "--porcelain");
else if (!line_terminator && !porcelain)
@@ -811,9 +870,9 @@ static int lock_worktree(int ac, const char **av, const char *prefix)
};
struct worktree **worktrees, *wt;
- ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ ac = parse_options(ac, av, prefix, options, git_worktree_lock_usage, 0);
if (ac != 1)
- usage_with_options(worktree_usage, options);
+ usage_with_options(git_worktree_lock_usage, options);
worktrees = get_worktrees();
wt = find_worktree(worktrees, prefix, av[0]);
@@ -844,9 +903,9 @@ static int unlock_worktree(int ac, const char **av, const char *prefix)
struct worktree **worktrees, *wt;
int ret;
- ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ ac = parse_options(ac, av, prefix, options, git_worktree_unlock_usage, 0);
if (ac != 1)
- usage_with_options(worktree_usage, options);
+ usage_with_options(git_worktree_unlock_usage, options);
worktrees = get_worktrees();
wt = find_worktree(worktrees, prefix, av[0]);
@@ -914,9 +973,10 @@ static int move_worktree(int ac, const char **av, const char *prefix)
const char *reason = NULL;
char *path;
- ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ ac = parse_options(ac, av, prefix, options, git_worktree_move_usage,
+ 0);
if (ac != 2)
- usage_with_options(worktree_usage, options);
+ usage_with_options(git_worktree_move_usage, options);
path = prefix_filename(prefix, av[1]);
strbuf_addstr(&dst, path);
@@ -1042,9 +1102,9 @@ static int remove_worktree(int ac, const char **av, const char *prefix)
const char *reason = NULL;
int ret = 0;
- ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ ac = parse_options(ac, av, prefix, options, git_worktree_remove_usage, 0);
if (ac != 1)
- usage_with_options(worktree_usage, options);
+ usage_with_options(git_worktree_remove_usage, options);
worktrees = get_worktrees();
wt = find_worktree(worktrees, prefix, av[0]);
@@ -1102,7 +1162,7 @@ static int repair(int ac, const char **av, const char *prefix)
};
int rc = 0;
- ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ ac = parse_options(ac, av, prefix, options, git_worktree_repair_usage, 0);
p = ac > 0 ? av : self;
for (; *p; p++)
repair_worktree_at_path(*p, report_repair, &rc);
@@ -1130,6 +1190,6 @@ int cmd_worktree(int ac, const char **av, const char *prefix)
if (!prefix)
prefix = "";
- ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ ac = parse_options(ac, av, prefix, options, git_worktree_usage, 0);
return fn(ac, av, prefix);
}
diff --git a/ci/lib.sh b/ci/lib.sh
index 1b0cc2b57d..1808e3b1ce 100755
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -259,6 +259,8 @@ macos-latest)
MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=$(which python3)"
else
MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=$(which python2)"
+ MAKEFLAGS="$MAKEFLAGS NO_APPLE_COMMON_CRYPTO=NoThanks"
+ MAKEFLAGS="$MAKEFLAGS DC_SHA1=YesPlease NO_OPENSSL=NoThanks"
fi
;;
esac
@@ -278,6 +280,12 @@ linux-leaks)
export GIT_TEST_PASSING_SANITIZE_LEAK=true
export GIT_TEST_SANITIZE_LEAK_LOG=true
;;
+linux-asan)
+ export SANITIZE=address
+ ;;
+linux-ubsan)
+ export SANITIZE=undefined
+ ;;
esac
MAKEFLAGS="$MAKEFLAGS CC=${CC:-cc}"
diff --git a/common-main.c b/common-main.c
index c531372f3f..0a22861f1c 100644
--- a/common-main.c
+++ b/common-main.c
@@ -40,6 +40,7 @@ int main(int argc, const char **argv)
git_resolve_executable_dir(argv[0]);
+ setlocale(LC_CTYPE, "");
git_setup_gettext();
initialize_the_repository();
diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c
new file mode 100644
index 0000000000..d67b0ee50d
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-darwin.c
@@ -0,0 +1,52 @@
+#include "cache.h"
+#include "config.h"
+#include "strbuf.h"
+#include "fsmonitor.h"
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
+
+static GIT_PATH_FUNC(fsmonitor_ipc__get_default_path, "fsmonitor--daemon.ipc")
+
+const char *fsmonitor_ipc__get_path(struct repository *r)
+{
+ static const char *ipc_path = NULL;
+ git_SHA_CTX sha1ctx;
+ char *sock_dir = NULL;
+ struct strbuf ipc_file = STRBUF_INIT;
+ unsigned char hash[GIT_MAX_RAWSZ];
+
+ if (!r)
+ BUG("No repository passed into fsmonitor_ipc__get_path");
+
+ if (ipc_path)
+ return ipc_path;
+
+
+ /* By default the socket file is created in the .git directory */
+ if (fsmonitor__is_fs_remote(r->gitdir) < 1) {
+ ipc_path = fsmonitor_ipc__get_default_path();
+ return ipc_path;
+ }
+
+ git_SHA1_Init(&sha1ctx);
+ git_SHA1_Update(&sha1ctx, r->worktree, strlen(r->worktree));
+ git_SHA1_Final(hash, &sha1ctx);
+
+ repo_config_get_string(r, "fsmonitor.socketdir", &sock_dir);
+
+ /* Create the socket file in either socketDir or $HOME */
+ if (sock_dir && *sock_dir) {
+ strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s",
+ sock_dir, hash_to_hex(hash));
+ } else {
+ strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s", hash_to_hex(hash));
+ }
+ free(sock_dir);
+
+ ipc_path = interpolate_path(ipc_file.buf, 1);
+ if (!ipc_path)
+ die(_("Invalid path: %s"), ipc_file.buf);
+
+ strbuf_release(&ipc_file);
+ return ipc_path;
+}
diff --git a/compat/fsmonitor/fsm-ipc-win32.c b/compat/fsmonitor/fsm-ipc-win32.c
new file mode 100644
index 0000000000..e08c505c14
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-win32.c
@@ -0,0 +1,9 @@
+#include "config.h"
+#include "fsmonitor-ipc.h"
+
+const char *fsmonitor_ipc__get_path(struct repository *r) {
+ static char *ret;
+ if (!ret)
+ ret = git_pathdup("fsmonitor--daemon.ipc");
+ return ret;
+}
diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c
index 8e208e8289..daeee4e465 100644
--- a/compat/fsmonitor/fsm-listen-darwin.c
+++ b/compat/fsmonitor/fsm-listen-darwin.c
@@ -26,6 +26,7 @@
#include "fsmonitor.h"
#include "fsm-listen.h"
#include "fsmonitor--daemon.h"
+#include "fsmonitor-path-utils.h"
struct fsm_listen_data
{
@@ -198,8 +199,9 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
struct string_list cookie_list = STRING_LIST_INIT_DUP;
const char *path_k;
const char *slash;
- int k;
+ char *resolved = NULL;
struct strbuf tmp = STRBUF_INIT;
+ int k;
/*
* Build a list of all filesystem changes into a private/local
@@ -209,7 +211,12 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
/*
* On Mac, we receive an array of absolute paths.
*/
- path_k = paths[k];
+ free(resolved);
+ resolved = fsmonitor__resolve_alias(paths[k], &state->alias);
+ if (resolved)
+ path_k = resolved;
+ else
+ path_k = paths[k];
/*
* If you want to debug FSEvents, log them to GIT_TRACE_FSMONITOR.
@@ -238,6 +245,7 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
fsmonitor_force_resync(state);
fsmonitor_batch__free_list(batch);
string_list_clear(&cookie_list, 0);
+ batch = NULL;
/*
* We assume that any events that we received
@@ -360,12 +368,14 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
}
}
+ free(resolved);
fsmonitor_publish(state, batch, &cookie_list);
string_list_clear(&cookie_list, 0);
strbuf_release(&tmp);
return;
force_shutdown:
+ free(resolved);
fsmonitor_batch__free_list(batch);
string_list_clear(&cookie_list, 0);
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
new file mode 100644
index 0000000000..ce5a8febe0
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -0,0 +1,135 @@
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ struct statfs fs;
+ if (statfs(path, &fs) == -1) {
+ int saved_errno = errno;
+ trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
+ path, strerror(saved_errno));
+ errno = saved_errno;
+ return -1;
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
+ path, fs.f_type, fs.f_flags, fs.f_fstypename);
+
+ if (!(fs.f_flags & MNT_LOCAL))
+ fs_info->is_remote = 1;
+ else
+ fs_info->is_remote = 0;
+
+ fs_info->typename = xstrdup(fs.f_fstypename);
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+
+ free(fs.typename);
+
+ return fs.is_remote;
+}
+
+/*
+ * Scan the root directory for synthetic firmlinks that when resolved
+ * are a prefix of the path, stopping at the first one found.
+ *
+ * Some information about firmlinks and synthetic firmlinks:
+ * https://eclecticlight.co/2020/01/23/catalina-boot-volumes/
+ *
+ * macOS no longer allows symlinks in the root directory; any link found
+ * there is therefore a synthetic firmlink.
+ *
+ * If this function gets called often, will want to cache all the firmlink
+ * information, but for now there is only one caller of this function.
+ *
+ * If there is more than one alias for the path, that is another
+ * matter altogether.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ DIR *dir;
+ int retval = -1;
+ const char *const root = "/";
+ struct stat st;
+ struct dirent *de;
+ struct strbuf alias;
+ struct strbuf points_to = STRBUF_INIT;
+
+ dir = opendir(root);
+ if (!dir)
+ return error_errno(_("opendir('%s') failed"), root);
+
+ strbuf_init(&alias, 256);
+
+ while ((de = readdir(dir)) != NULL) {
+ strbuf_reset(&alias);
+ strbuf_addf(&alias, "%s%s", root, de->d_name);
+
+ if (lstat(alias.buf, &st) < 0) {
+ error_errno(_("lstat('%s') failed"), alias.buf);
+ goto done;
+ }
+
+ if (!S_ISLNK(st.st_mode))
+ continue;
+
+ if (strbuf_readlink(&points_to, alias.buf, st.st_size) < 0) {
+ error_errno(_("strbuf_readlink('%s') failed"), alias.buf);
+ goto done;
+ }
+
+ if (!strncmp(points_to.buf, path, points_to.len) &&
+ (path[points_to.len] == '/')) {
+ strbuf_addbuf(&info->alias, &alias);
+ strbuf_addbuf(&info->points_to, &points_to);
+ trace_printf_key(&trace_fsmonitor,
+ "Found alias for '%s' : '%s' -> '%s'",
+ path, info->alias.buf, info->points_to.buf);
+ retval = 0;
+ goto done;
+ }
+ }
+ retval = 0; /* no alias */
+
+done:
+ strbuf_release(&alias);
+ strbuf_release(&points_to);
+ if (closedir(dir) < 0)
+ return error_errno(_("closedir('%s') failed"), root);
+ return retval;
+}
+
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ if (!info->alias.len)
+ return NULL;
+
+ if ((!strncmp(info->alias.buf, path, info->alias.len))
+ && path[info->alias.len] == '/') {
+ struct strbuf tmp = STRBUF_INIT;
+ const char *remainder = path + info->alias.len;
+
+ strbuf_addbuf(&tmp, &info->points_to);
+ strbuf_add(&tmp, remainder, strlen(remainder));
+ return strbuf_detach(&tmp, NULL);
+ }
+
+ return NULL;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
new file mode 100644
index 0000000000..0d95bbb416
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -0,0 +1,145 @@
+#include "cache.h"
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+
+/*
+ * Check remote working directory protocol.
+ *
+ * Return -1 if client machine cannot get remote protocol information.
+ */
+static int check_remote_protocol(wchar_t *wpath)
+{
+ HANDLE h;
+ FILE_REMOTE_PROTOCOL_INFO proto_info;
+
+ h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ error(_("[GLE %ld] unable to open for read '%ls'"),
+ GetLastError(), wpath);
+ return -1;
+ }
+
+ if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
+ &proto_info, sizeof(proto_info))) {
+ error(_("[GLE %ld] unable to get protocol information for '%ls'"),
+ GetLastError(), wpath);
+ CloseHandle(h);
+ return -1;
+ }
+
+ CloseHandle(h);
+
+ trace_printf_key(&trace_fsmonitor,
+ "check_remote_protocol('%ls') remote protocol %#8.8lx",
+ wpath, proto_info.Protocol);
+
+ return 0;
+}
+
+/*
+ * Notes for testing:
+ *
+ * (a) Windows allows a network share to be mapped to a drive letter.
+ * (This is the normal method to access it.)
+ *
+ * $ NET USE Z: \\server\share
+ * $ git -C Z:/repo status
+ *
+ * (b) Windows allows a network share to be referenced WITHOUT mapping
+ * it to drive letter.
+ *
+ * $ NET USE \\server\share\dir
+ * $ git -C //server/share/repo status
+ *
+ * (c) Windows allows "SUBST" to create a fake drive mapping to an
+ * arbitrary path (which may be remote)
+ *
+ * $ SUBST Q: Z:\repo
+ * $ git -C Q:/ status
+ *
+ * (d) Windows allows a directory symlink to be created on a local
+ * file system that points to a remote repo.
+ *
+ * $ mklink /d ./link //server/share/repo
+ * $ git -C ./link status
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+ wchar_t wpath[MAX_PATH];
+ wchar_t wfullpath[MAX_PATH];
+ size_t wlen;
+ UINT driveType;
+
+ /*
+ * Do everything in wide chars because the drive letter might be
+ * a multi-byte sequence. See win32_has_dos_drive_prefix().
+ */
+ if (xutftowcs_path(wpath, path) < 0) {
+ return -1;
+ }
+
+ /*
+ * GetDriveTypeW() requires a final slash. We assume that the
+ * worktree pathname points to an actual directory.
+ */
+ wlen = wcslen(wpath);
+ if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
+ wpath[wlen++] = L'\\';
+ wpath[wlen] = 0;
+ }
+
+ /*
+ * Normalize the path. If nothing else, this converts forward
+ * slashes to backslashes. This is essential to get GetDriveTypeW()
+ * correctly handle some UNC "\\server\share\..." paths.
+ */
+ if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL)) {
+ return -1;
+ }
+
+ driveType = GetDriveTypeW(wfullpath);
+ trace_printf_key(&trace_fsmonitor,
+ "DriveType '%s' L'%ls' (%u)",
+ path, wfullpath, driveType);
+
+ if (driveType == DRIVE_REMOTE) {
+ fs_info->is_remote = 1;
+ if (check_remote_protocol(wfullpath) < 0)
+ return -1;
+ } else {
+ fs_info->is_remote = 0;
+ }
+
+ trace_printf_key(&trace_fsmonitor,
+ "'%s' is_remote: %d",
+ path, fs_info->is_remote);
+
+ return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+ struct fs_info fs;
+ if (fsmonitor__get_fs_info(path, &fs))
+ return -1;
+ return fs.is_remote;
+}
+
+/*
+ * No-op for now.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+ return 0;
+}
+
+/*
+ * No-op for now.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info)
+{
+ return NULL;
+}
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
index efc732c0f3..6abbc7af3a 100644
--- a/compat/fsmonitor/fsm-settings-darwin.c
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -1,32 +1,10 @@
-#include "cache.h"
#include "config.h"
-#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
-#include <sys/param.h>
-#include <sys/mount.h>
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
-/*
- * [1] Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type (NFS, SAMBA, etc.) dictates whether notification events
- * are available at all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
+ /*
* For the builtin FSMonitor, we create the Unix domain socket for the
* IPC in the .git directory. If the working directory is remote,
* then the socket will be created on the remote file system. This
@@ -38,52 +16,47 @@
* be taken to ensure that $HOME is actually local and not a managed
* file share.)
*
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- *
- * [2] FAT32 and NTFS working directories are problematic too.
+ * FAT32 and NTFS working directories are problematic too.
*
* The builtin FSMonitor uses a Unix domain socket in the .git
* directory for IPC. These Windows drive formats do not support
* Unix domain sockets, so mark them as incompatible for the daemon.
*
*/
-static enum fsmonitor_reason check_volume(struct repository *r)
+static enum fsmonitor_reason check_uds_volume(struct repository *r)
{
- struct statfs fs;
+ struct fs_info fs;
+ const char *ipc_path = fsmonitor_ipc__get_path(r);
+ struct strbuf path = STRBUF_INIT;
+ strbuf_add(&path, ipc_path, strlen(ipc_path));
- if (statfs(r->worktree, &fs) == -1) {
- int saved_errno = errno;
- trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
- r->worktree, strerror(saved_errno));
- errno = saved_errno;
+ if (fsmonitor__get_fs_info(dirname(path.buf), &fs) == -1) {
+ strbuf_release(&path);
return FSMONITOR_REASON_ERROR;
}
- trace_printf_key(&trace_fsmonitor,
- "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
- r->worktree, fs.f_type, fs.f_flags, fs.f_fstypename);
+ strbuf_release(&path);
- if (!(fs.f_flags & MNT_LOCAL))
- return FSMONITOR_REASON_REMOTE;
-
- if (!strcmp(fs.f_fstypename, "msdos")) /* aka FAT32 */
- return FSMONITOR_REASON_NOSOCKETS;
-
- if (!strcmp(fs.f_fstypename, "ntfs"))
+ if (fs.is_remote ||
+ !strcmp(fs.typename, "msdos") ||
+ !strcmp(fs.typename, "ntfs")) {
+ free(fs.typename);
return FSMONITOR_REASON_NOSOCKETS;
+ }
+ free(fs.typename);
return FSMONITOR_REASON_OK;
}
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
- reason = check_volume(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
+ if (ipc) {
+ reason = check_uds_volume(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
+ }
return FSMONITOR_REASON_OK;
}
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
index e5ec5b0a9f..a8af31b71d 100644
--- a/compat/fsmonitor/fsm-settings-win32.c
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -1,8 +1,9 @@
#include "cache.h"
#include "config.h"
#include "repository.h"
-#include "fsmonitor-settings.h"
#include "fsmonitor.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* VFS for Git is incompatible with FSMonitor.
@@ -24,172 +25,7 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r)
return FSMONITOR_REASON_OK;
}
-/*
- * Check if monitoring remote working directories is allowed.
- *
- * By default, monitoring remote working directories is
- * disabled. Users may override this behavior in enviroments where
- * they have proper support.
- */
-static int check_config_allowremote(struct repository *r)
-{
- int allow;
-
- if (!repo_config_get_bool(r, "fsmonitor.allowremote", &allow))
- return allow;
-
- return -1; /* fsmonitor.allowremote not set */
-}
-
-/*
- * Check remote working directory protocol.
- *
- * Error if client machine cannot get remote protocol information.
- */
-static int check_remote_protocol(wchar_t *wpath)
-{
- HANDLE h;
- FILE_REMOTE_PROTOCOL_INFO proto_info;
-
- h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS, NULL);
-
- if (h == INVALID_HANDLE_VALUE) {
- error(_("[GLE %ld] unable to open for read '%ls'"),
- GetLastError(), wpath);
- return -1;
- }
-
- if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
- &proto_info, sizeof(proto_info))) {
- error(_("[GLE %ld] unable to get protocol information for '%ls'"),
- GetLastError(), wpath);
- CloseHandle(h);
- return -1;
- }
-
- CloseHandle(h);
-
- trace_printf_key(&trace_fsmonitor,
- "check_remote_protocol('%ls') remote protocol %#8.8lx",
- wpath, proto_info.Protocol);
-
- return 0;
-}
-
-/*
- * Remote working directories are problematic for FSMonitor.
- *
- * The underlying file system on the server machine and/or the remote
- * mount type dictates whether notification events are available at
- * all to remote client machines.
- *
- * Kernel differences between the server and client machines also
- * dictate the how (buffering, frequency, de-dup) the events are
- * delivered to client machine processes.
- *
- * A client machine (such as a laptop) may choose to suspend/resume
- * and it is unclear (without lots of testing) whether the watcher can
- * resync after a resume. We might be able to treat this as a normal
- * "events were dropped by the kernel" event and do our normal "flush
- * and resync" --or-- we might need to close the existing (zombie?)
- * notification fd and create a new one.
- *
- * In theory, the above issues need to be addressed whether we are
- * using the Hook or IPC API.
- *
- * So (for now at least), mark remote working directories as
- * incompatible.
- *
- * Notes for testing:
- *
- * (a) Windows allows a network share to be mapped to a drive letter.
- * (This is the normal method to access it.)
- *
- * $ NET USE Z: \\server\share
- * $ git -C Z:/repo status
- *
- * (b) Windows allows a network share to be referenced WITHOUT mapping
- * it to drive letter.
- *
- * $ NET USE \\server\share\dir
- * $ git -C //server/share/repo status
- *
- * (c) Windows allows "SUBST" to create a fake drive mapping to an
- * arbitrary path (which may be remote)
- *
- * $ SUBST Q: Z:\repo
- * $ git -C Q:/ status
- *
- * (d) Windows allows a directory symlink to be created on a local
- * file system that points to a remote repo.
- *
- * $ mklink /d ./link //server/share/repo
- * $ git -C ./link status
- */
-static enum fsmonitor_reason check_remote(struct repository *r)
-{
- int ret;
- wchar_t wpath[MAX_PATH];
- wchar_t wfullpath[MAX_PATH];
- size_t wlen;
- UINT driveType;
-
- /*
- * Do everything in wide chars because the drive letter might be
- * a multi-byte sequence. See win32_has_dos_drive_prefix().
- */
- if (xutftowcs_path(wpath, r->worktree) < 0)
- return FSMONITOR_REASON_ERROR;
-
- /*
- * GetDriveTypeW() requires a final slash. We assume that the
- * worktree pathname points to an actual directory.
- */
- wlen = wcslen(wpath);
- if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
- wpath[wlen++] = L'\\';
- wpath[wlen] = 0;
- }
-
- /*
- * Normalize the path. If nothing else, this converts forward
- * slashes to backslashes. This is essential to get GetDriveTypeW()
- * correctly handle some UNC "\\server\share\..." paths.
- */
- if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL))
- return FSMONITOR_REASON_ERROR;
-
- driveType = GetDriveTypeW(wfullpath);
- trace_printf_key(&trace_fsmonitor,
- "DriveType '%s' L'%ls' (%u)",
- r->worktree, wfullpath, driveType);
-
- if (driveType == DRIVE_REMOTE) {
- trace_printf_key(&trace_fsmonitor,
- "check_remote('%s') true",
- r->worktree);
-
- ret = check_remote_protocol(wfullpath);
- if (ret < 0)
- return FSMONITOR_REASON_ERROR;
-
- switch (check_config_allowremote(r)) {
- case 0: /* config overrides and disables */
- return FSMONITOR_REASON_REMOTE;
- case 1: /* config overrides and enables */
- return FSMONITOR_REASON_OK;
- default:
- break; /* config has no opinion */
- }
-
- return FSMONITOR_REASON_REMOTE;
- }
-
- return FSMONITOR_REASON_OK;
-}
-
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
{
enum fsmonitor_reason reason;
@@ -197,9 +33,5 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
if (reason != FSMONITOR_REASON_OK)
return reason;
- reason = check_remote(r);
- if (reason != FSMONITOR_REASON_OK)
- return reason;
-
return FSMONITOR_REASON_OK;
}
diff --git a/compat/nonblock.c b/compat/nonblock.c
index 9694ebdb1d..5b51195c32 100644
--- a/compat/nonblock.c
+++ b/compat/nonblock.c
@@ -41,7 +41,7 @@ int enable_pipe_nonblock(int fd)
#else
-int enable_pipe_nonblock(int fd)
+int enable_pipe_nonblock(int fd UNUSED)
{
errno = ENOSYS;
return -1;
diff --git a/config.c b/config.c
index cbb5a3bab7..c157fb5ae3 100644
--- a/config.c
+++ b/config.c
@@ -2392,11 +2392,6 @@ int git_configset_add_file(struct config_set *cs, const char *filename)
return git_config_from_file(config_set_callback, filename, cs);
}
-int git_configset_add_parameters(struct config_set *cs)
-{
- return git_config_from_parameters(config_set_callback, cs);
-}
-
int git_configset_get_value(struct config_set *cs, const char *key, const char **value)
{
const struct string_list *values = NULL;
@@ -2641,24 +2636,15 @@ int repo_config_get_pathname(struct repository *repo,
/* Read values into protected_config. */
static void read_protected_config(void)
{
- char *xdg_config = NULL, *user_config = NULL, *system_config = NULL;
-
+ struct config_options opts = {
+ .respect_includes = 1,
+ .ignore_repo = 1,
+ .ignore_worktree = 1,
+ .system_gently = 1,
+ };
git_configset_init(&protected_config);
-
- system_config = git_system_config();
- git_global_config(&user_config, &xdg_config);
-
- if (system_config)
- git_configset_add_file(&protected_config, system_config);
- if (xdg_config)
- git_configset_add_file(&protected_config, xdg_config);
- if (user_config)
- git_configset_add_file(&protected_config, user_config);
- git_configset_add_parameters(&protected_config);
-
- free(system_config);
- free(xdg_config);
- free(user_config);
+ config_with_options(config_set_callback, &protected_config,
+ NULL, &opts);
}
void git_protected_config(config_fn_t fn, void *data)
diff --git a/config.mak.dev b/config.mak.dev
index 4fa19d361b..981304727c 100644
--- a/config.mak.dev
+++ b/config.mak.dev
@@ -69,6 +69,31 @@ DEVELOPER_CFLAGS += -Wno-missing-braces
endif
endif
+# Old versions of clang complain about initializaing a
+# struct-within-a-struct using just "{0}" rather than "{{0}}". This
+# error is considered a false-positive and not worth fixing, because
+# new clang versions do not, so just disable it.
+#
+# The "bug" was fixed in upstream clang 9.
+#
+# Complicating this is that versions of clang released by Apple have
+# their own version numbers (associated with the corresponding version
+# of XCode) unrelated to the official clang version numbers.
+#
+# The bug was fixed in Apple clang 12.
+#
+ifneq ($(filter clang1,$(COMPILER_FEATURES)),) # if we are using clang
+ifeq ($(uname_S),Darwin) # if we are on darwin
+ifeq ($(filter clang12,$(COMPILER_FEATURES)),) # if version < 12
+DEVELOPER_CFLAGS += -Wno-missing-braces
+endif
+else # not darwin
+ifeq ($(filter clang9,$(COMPILER_FEATURES)),) # if version < 9
+DEVELOPER_CFLAGS += -Wno-missing-braces
+endif
+endif
+endif
+
# https://bugzilla.redhat.com/show_bug.cgi?id=2075786
ifneq ($(filter gcc12,$(COMPILER_FEATURES)),)
DEVELOPER_CFLAGS += -Wno-error=stringop-overread
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index ea2a531be8..3957e4cf8c 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -308,6 +308,8 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-win32.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-win32.c)
@@ -315,6 +317,8 @@ if(SUPPORTS_SIMPLE_IPC)
add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-darwin.c)
+ list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c)
add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS)
list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-darwin.c)
@@ -1070,18 +1074,14 @@ endif()
#Make the tests work when building out of the source tree
get_filename_component(CACHE_PATH ${CMAKE_CURRENT_LIST_DIR}/../../CMakeCache.txt ABSOLUTE)
if(NOT ${CMAKE_BINARY_DIR}/CMakeCache.txt STREQUAL ${CACHE_PATH})
- file(RELATIVE_PATH BUILD_DIR_RELATIVE ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR}/CMakeCache.txt)
- string(REPLACE "/CMakeCache.txt" "" BUILD_DIR_RELATIVE ${BUILD_DIR_RELATIVE})
#Setting the build directory in test-lib.sh before running tests
file(WRITE ${CMAKE_BINARY_DIR}/CTestCustom.cmake
- "file(STRINGS ${CMAKE_SOURCE_DIR}/t/test-lib.sh GIT_BUILD_DIR_REPL REGEX \"GIT_BUILD_DIR=(.*)\")\n"
- "file(STRINGS ${CMAKE_SOURCE_DIR}/t/test-lib.sh content NEWLINE_CONSUME)\n"
- "string(REPLACE \"\${GIT_BUILD_DIR_REPL}\" \"GIT_BUILD_DIR=\\\"$TEST_DIRECTORY/../${BUILD_DIR_RELATIVE}\\\"\" content \"\${content}\")\n"
- "file(WRITE ${CMAKE_SOURCE_DIR}/t/test-lib.sh \${content})")
+ "file(WRITE ${CMAKE_SOURCE_DIR}/GIT-BUILD-DIR \"${CMAKE_BINARY_DIR}\")")
#misc copies
file(COPY ${CMAKE_SOURCE_DIR}/t/chainlint.pl DESTINATION ${CMAKE_BINARY_DIR}/t/)
file(COPY ${CMAKE_SOURCE_DIR}/po/is.po DESTINATION ${CMAKE_BINARY_DIR}/po/)
- file(COPY ${CMAKE_SOURCE_DIR}/mergetools/tkdiff DESTINATION ${CMAKE_BINARY_DIR}/mergetools/)
+ file(GLOB mergetools "${CMAKE_SOURCE_DIR}/mergetools/*")
+ file(COPY ${mergetools} DESTINATION ${CMAKE_BINARY_DIR}/mergetools/)
file(COPY ${CMAKE_SOURCE_DIR}/contrib/completion/git-prompt.sh DESTINATION ${CMAKE_BINARY_DIR}/contrib/completion/)
file(COPY ${CMAKE_SOURCE_DIR}/contrib/completion/git-completion.bash DESTINATION ${CMAKE_BINARY_DIR}/contrib/completion/)
endif()
@@ -1091,8 +1091,12 @@ file(GLOB test_scipts "${CMAKE_SOURCE_DIR}/t/t[0-9]*.sh")
#test
foreach(tsh ${test_scipts})
add_test(NAME ${tsh}
- COMMAND ${SH_EXE} ${tsh}
+ COMMAND ${SH_EXE} ${tsh} --no-bin-wrappers --no-chain-lint -vx
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/t)
endforeach()
+# This test script takes an extremely long time and is known to time out even
+# on fast machines because it requires in excess of one hour to run
+set_tests_properties("${CMAKE_SOURCE_DIR}/t/t7112-reset-submodule.sh" PROPERTIES TIMEOUT 4000)
+
endif()#BUILD_TESTING
diff --git a/contrib/credential/netrc/git-credential-netrc.perl b/contrib/credential/netrc/git-credential-netrc.perl
index bc57cc6588..9fb998ae09 100755
--- a/contrib/credential/netrc/git-credential-netrc.perl
+++ b/contrib/credential/netrc/git-credential-netrc.perl
@@ -356,7 +356,10 @@ sub read_credential_data_from_stdin {
next unless m/^([^=]+)=(.+)/;
my ($token, $value) = ($1, $2);
- die "Unknown search token $token" unless exists $q{$token};
+
+ # skip any unknown tokens
+ next unless exists $q{$token};
+
$q{$token} = $value;
log_debug("We were given search token $token and value $value");
}
diff --git a/contrib/credential/osxkeychain/git-credential-osxkeychain.c b/contrib/credential/osxkeychain/git-credential-osxkeychain.c
index bf77748d60..e29cc28779 100644
--- a/contrib/credential/osxkeychain/git-credential-osxkeychain.c
+++ b/contrib/credential/osxkeychain/git-credential-osxkeychain.c
@@ -159,6 +159,11 @@ static void read_credential(void)
username = xstrdup(v);
else if (!strcmp(buf, "password"))
password = xstrdup(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.
+ */
}
}
diff --git a/contrib/credential/wincred/git-credential-wincred.c b/contrib/credential/wincred/git-credential-wincred.c
index 5091048f9c..ead6e267c7 100644
--- a/contrib/credential/wincred/git-credential-wincred.c
+++ b/contrib/credential/wincred/git-credential-wincred.c
@@ -278,8 +278,11 @@ static void read_credential(void)
wusername = utf8_to_utf16_dup(v);
} else if (!strcmp(buf, "password"))
password = utf8_to_utf16_dup(v);
- else
- die("unrecognized input");
+ /*
+ * 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.
+ */
}
}
diff --git a/convert.c b/convert.c
index 95e6a5244f..9b67649032 100644
--- a/convert.c
+++ b/convert.c
@@ -1549,7 +1549,7 @@ struct stream_filter {
struct stream_filter_vtbl *vtbl;
};
-static int null_filter_fn(struct stream_filter *filter,
+static int null_filter_fn(struct stream_filter *filter UNUSED,
const char *input, size_t *isize_p,
char *output, size_t *osize_p)
{
@@ -1568,7 +1568,7 @@ static int null_filter_fn(struct stream_filter *filter,
return 0;
}
-static void null_free_fn(struct stream_filter *filter)
+static void null_free_fn(struct stream_filter *filter UNUSED)
{
; /* nothing -- null instances are shared */
}
diff --git a/date.c b/date.c
index 68a260c214..53bd6a7932 100644
--- a/date.c
+++ b/date.c
@@ -1101,7 +1101,7 @@ static void date_tea(struct tm *tm, struct tm *now, int *num)
date_time(tm, now, 17);
}
-static void date_pm(struct tm *tm, struct tm *now, int *num)
+static void date_pm(struct tm *tm, struct tm *now UNUSED, int *num)
{
int hour, n = *num;
*num = 0;
@@ -1115,7 +1115,7 @@ static void date_pm(struct tm *tm, struct tm *now, int *num)
tm->tm_hour = (hour % 12) + 12;
}
-static void date_am(struct tm *tm, struct tm *now, int *num)
+static void date_am(struct tm *tm, struct tm *now UNUSED, int *num)
{
int hour, n = *num;
*num = 0;
@@ -1129,7 +1129,7 @@ static void date_am(struct tm *tm, struct tm *now, int *num)
tm->tm_hour = (hour % 12);
}
-static void date_never(struct tm *tm, struct tm *now, int *num)
+static void date_never(struct tm *tm, struct tm *now UNUSED, int *num)
{
time_t n = 0;
localtime_r(&n, tm);
diff --git a/diff-merges.c b/diff-merges.c
index 7f64156b8b..85cbefa5af 100644
--- a/diff-merges.c
+++ b/diff-merges.c
@@ -20,9 +20,20 @@ static void suppress(struct rev_info *revs)
revs->remerge_diff = 0;
}
-static void set_separate(struct rev_info *revs)
+static void common_setup(struct rev_info *revs)
{
suppress(revs);
+ revs->merges_need_diff = 1;
+}
+
+static void set_none(struct rev_info *revs)
+{
+ suppress(revs);
+}
+
+static void set_separate(struct rev_info *revs)
+{
+ common_setup(revs);
revs->separate_merges = 1;
revs->simplify_history = 0;
}
@@ -35,21 +46,21 @@ static void set_first_parent(struct rev_info *revs)
static void set_combined(struct rev_info *revs)
{
- suppress(revs);
+ common_setup(revs);
revs->combine_merges = 1;
revs->dense_combined_merges = 0;
}
static void set_dense_combined(struct rev_info *revs)
{
- suppress(revs);
+ common_setup(revs);
revs->combine_merges = 1;
revs->dense_combined_merges = 1;
}
static void set_remerge_diff(struct rev_info *revs)
{
- suppress(revs);
+ common_setup(revs);
revs->remerge_diff = 1;
revs->simplify_history = 0;
}
@@ -57,18 +68,18 @@ static void set_remerge_diff(struct rev_info *revs)
static diff_merges_setup_func_t func_by_opt(const char *optarg)
{
if (!strcmp(optarg, "off") || !strcmp(optarg, "none"))
- return suppress;
+ return set_none;
if (!strcmp(optarg, "1") || !strcmp(optarg, "first-parent"))
return set_first_parent;
- else if (!strcmp(optarg, "separate"))
+ if (!strcmp(optarg, "separate"))
return set_separate;
- else if (!strcmp(optarg, "c") || !strcmp(optarg, "combined"))
+ if (!strcmp(optarg, "c") || !strcmp(optarg, "combined"))
return set_combined;
- else if (!strcmp(optarg, "cc") || !strcmp(optarg, "dense-combined"))
+ if (!strcmp(optarg, "cc") || !strcmp(optarg, "dense-combined"))
return set_dense_combined;
- else if (!strcmp(optarg, "r") || !strcmp(optarg, "remerge"))
+ if (!strcmp(optarg, "r") || !strcmp(optarg, "remerge"))
return set_remerge_diff;
- else if (!strcmp(optarg, "m") || !strcmp(optarg, "on"))
+ if (!strcmp(optarg, "m") || !strcmp(optarg, "on"))
return set_to_default;
return NULL;
}
@@ -81,10 +92,6 @@ static void set_diff_merges(struct rev_info *revs, const char *optarg)
die(_("invalid value for '%s': '%s'"), "--diff-merges", optarg);
func(revs);
-
- /* NOTE: the merges_need_diff flag is cleared by func() call */
- if (func != suppress)
- revs->merges_need_diff = 1;
}
/*
@@ -115,6 +122,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)
if (!suppress_m_parsing && !strcmp(arg, "-m")) {
set_to_default(revs);
+ revs->merges_need_diff = 0;
} else if (!strcmp(arg, "-c")) {
set_combined(revs);
revs->merges_imply_patch = 1;
@@ -125,7 +133,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)
set_remerge_diff(revs);
revs->merges_imply_patch = 1;
} else if (!strcmp(arg, "--no-diff-merges")) {
- suppress(revs);
+ set_none(revs);
} else if (!strcmp(arg, "--combined-all-paths")) {
revs->combined_all_paths = 1;
} else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
@@ -139,7 +147,7 @@ int diff_merges_parse_opts(struct rev_info *revs, const char **argv)
void diff_merges_suppress(struct rev_info *revs)
{
- suppress(revs);
+ set_none(revs);
}
void diff_merges_default_to_first_parent(struct rev_info *revs)
diff --git a/diff.c b/diff.c
index 648f6717a5..35e46dd968 100644
--- a/diff.c
+++ b/diff.c
@@ -2488,6 +2488,9 @@ static int diffstat_consume(void *priv, char *line, unsigned long len)
struct diffstat_t *diffstat = priv;
struct diffstat_file *x = diffstat->files[diffstat->nr - 1];
+ if (!len)
+ BUG("xdiff fed us an empty line");
+
if (line[0] == '+')
x->added++;
else if (line[0] == '-')
@@ -2621,7 +2624,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
continue;
}
fill_print_name(file);
- len = strlen(file->print_name);
+ len = utf8_strwidth(file->print_name);
if (max_len < len)
max_len = len;
@@ -2674,6 +2677,11 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
* making the line longer than the maximum width.
*/
+ /*
+ * NEEDSWORK: line_prefix is often used for "log --graph" output
+ * and contains ANSI-colored string. utf8_strnwidth() should be
+ * used to correctly count the display width instead of strlen().
+ */
if (options->stat_width == -1)
width = term_columns() - strlen(line_prefix);
else
@@ -2735,7 +2743,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
char *name = file->print_name;
uintmax_t added = file->added;
uintmax_t deleted = file->deleted;
- int name_len;
+ int name_len, padding;
if (!file->is_interesting && (added + deleted == 0))
continue;
@@ -2744,20 +2752,34 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
* "scale" the filename
*/
len = name_width;
- name_len = strlen(name);
+ name_len = utf8_strwidth(name);
if (name_width < name_len) {
char *slash;
prefix = "...";
len -= 3;
+ /*
+ * NEEDSWORK: (name_len - len) counts the display
+ * width, which would be shorter than the byte
+ * length of the corresponding substring.
+ * Advancing "name" by that number of bytes does
+ * *NOT* skip over that many columns, so it is
+ * very likely that chomping the pathname at the
+ * slash we will find starting from "name" will
+ * leave the resulting string still too long.
+ */
name += name_len - len;
slash = strchr(name, '/');
if (slash)
name = slash;
}
+ padding = len - utf8_strwidth(name);
+ if (padding < 0)
+ padding = 0;
if (file->is_binary) {
- strbuf_addf(&out, " %s%-*s |", prefix, len, name);
- strbuf_addf(&out, " %*s", number_width, "Bin");
+ strbuf_addf(&out, " %s%s%*s | %*s",
+ prefix, name, padding, "",
+ number_width, "Bin");
if (!added && !deleted) {
strbuf_addch(&out, '\n');
emit_diff_symbol(options, DIFF_SYMBOL_STATS_LINE,
@@ -2777,8 +2799,9 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
continue;
}
else if (file->is_unmerged) {
- strbuf_addf(&out, " %s%-*s |", prefix, len, name);
- strbuf_addstr(&out, " Unmerged\n");
+ strbuf_addf(&out, " %s%s%*s | %*s",
+ prefix, name, padding, "",
+ number_width, "Unmerged");
emit_diff_symbol(options, DIFF_SYMBOL_STATS_LINE,
out.buf, out.len, 0);
strbuf_reset(&out);
@@ -2804,10 +2827,10 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
add = total - del;
}
}
- strbuf_addf(&out, " %s%-*s |", prefix, len, name);
- strbuf_addf(&out, " %*"PRIuMAX"%s",
- number_width, added + deleted,
- added + deleted ? " " : "");
+ strbuf_addf(&out, " %s%s%*s | %*"PRIuMAX"%s",
+ prefix, name, padding, "",
+ number_width, added + deleted,
+ added + deleted ? " " : "");
show_graph(&out, '+', add, add_c, reset);
show_graph(&out, '-', del, del_c, reset);
strbuf_addch(&out, '\n');
@@ -6206,7 +6229,7 @@ static void patch_id_add_mode(git_hash_ctx *ctx, unsigned mode)
}
/* returns 0 upon success, and writes result into oid */
-static int diff_get_patch_id(struct diff_options *options, struct object_id *oid, int diff_header_only, int stable)
+static int diff_get_patch_id(struct diff_options *options, struct object_id *oid, int diff_header_only)
{
struct diff_queue_struct *q = &diff_queued_diff;
int i;
@@ -6253,61 +6276,62 @@ static int diff_get_patch_id(struct diff_options *options, struct object_id *oid
if (p->one->mode == 0) {
patch_id_add_string(&ctx, "newfilemode");
patch_id_add_mode(&ctx, p->two->mode);
- patch_id_add_string(&ctx, "---/dev/null");
- patch_id_add_string(&ctx, "+++b/");
- the_hash_algo->update_fn(&ctx, p->two->path, len2);
} else if (p->two->mode == 0) {
patch_id_add_string(&ctx, "deletedfilemode");
patch_id_add_mode(&ctx, p->one->mode);
- patch_id_add_string(&ctx, "---a/");
- the_hash_algo->update_fn(&ctx, p->one->path, len1);
- patch_id_add_string(&ctx, "+++/dev/null");
- } else {
- patch_id_add_string(&ctx, "---a/");
- the_hash_algo->update_fn(&ctx, p->one->path, len1);
- patch_id_add_string(&ctx, "+++b/");
- the_hash_algo->update_fn(&ctx, p->two->path, len2);
+ } else if (p->one->mode != p->two->mode) {
+ patch_id_add_string(&ctx, "oldmode");
+ patch_id_add_mode(&ctx, p->one->mode);
+ patch_id_add_string(&ctx, "newmode");
+ patch_id_add_mode(&ctx, p->two->mode);
}
- if (diff_header_only)
- continue;
-
- if (fill_mmfile(options->repo, &mf1, p->one) < 0 ||
- fill_mmfile(options->repo, &mf2, p->two) < 0)
- return error("unable to read files to diff");
-
- if (diff_filespec_is_binary(options->repo, p->one) ||
+ if (diff_header_only) {
+ /* don't do anything since we're only populating header info */
+ } else if (diff_filespec_is_binary(options->repo, p->one) ||
diff_filespec_is_binary(options->repo, p->two)) {
the_hash_algo->update_fn(&ctx, oid_to_hex(&p->one->oid),
the_hash_algo->hexsz);
the_hash_algo->update_fn(&ctx, oid_to_hex(&p->two->oid),
the_hash_algo->hexsz);
- continue;
- }
-
- xpp.flags = 0;
- xecfg.ctxlen = 3;
- xecfg.flags = XDL_EMIT_NO_HUNK_HDR;
- if (xdi_diff_outf(&mf1, &mf2, NULL,
- patch_id_consume, &data, &xpp, &xecfg))
- return error("unable to generate patch-id diff for %s",
- p->one->path);
+ } else {
+ if (p->one->mode == 0) {
+ patch_id_add_string(&ctx, "---/dev/null");
+ patch_id_add_string(&ctx, "+++b/");
+ the_hash_algo->update_fn(&ctx, p->two->path, len2);
+ } else if (p->two->mode == 0) {
+ patch_id_add_string(&ctx, "---a/");
+ the_hash_algo->update_fn(&ctx, p->one->path, len1);
+ patch_id_add_string(&ctx, "+++/dev/null");
+ } else {
+ patch_id_add_string(&ctx, "---a/");
+ the_hash_algo->update_fn(&ctx, p->one->path, len1);
+ patch_id_add_string(&ctx, "+++b/");
+ the_hash_algo->update_fn(&ctx, p->two->path, len2);
+ }
- if (stable)
- flush_one_hunk(oid, &ctx);
+ if (fill_mmfile(options->repo, &mf1, p->one) < 0 ||
+ fill_mmfile(options->repo, &mf2, p->two) < 0)
+ return error("unable to read files to diff");
+ xpp.flags = 0;
+ xecfg.ctxlen = 3;
+ xecfg.flags = XDL_EMIT_NO_HUNK_HDR;
+ if (xdi_diff_outf(&mf1, &mf2, NULL,
+ patch_id_consume, &data, &xpp, &xecfg))
+ return error("unable to generate patch-id diff for %s",
+ p->one->path);
+ }
+ flush_one_hunk(oid, &ctx);
}
- if (!stable)
- the_hash_algo->final_oid_fn(oid, &ctx);
-
return 0;
}
-int diff_flush_patch_id(struct diff_options *options, struct object_id *oid, int diff_header_only, int stable)
+int diff_flush_patch_id(struct diff_options *options, struct object_id *oid, int diff_header_only)
{
struct diff_queue_struct *q = &diff_queued_diff;
int i;
- int result = diff_get_patch_id(options, oid, diff_header_only, stable);
+ int result = diff_get_patch_id(options, oid, diff_header_only);
for (i = 0; i < q->nr; i++)
diff_free_filepair(q->queue[i]);
diff --git a/diff.h b/diff.h
index 8ae18e5ab1..fd33caeb25 100644
--- a/diff.h
+++ b/diff.h
@@ -634,7 +634,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option);
int run_diff_index(struct rev_info *revs, unsigned int option);
int do_diff_cache(const struct object_id *, struct diff_options *);
-int diff_flush_patch_id(struct diff_options *, struct object_id *, int, int);
+int diff_flush_patch_id(struct diff_options *, struct object_id *, int);
void flush_one_hunk(struct object_id *result, git_hash_ctx *ctx);
int diff_result_code(struct diff_options *, int);
diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c
index c88e50c632..03fcbcb40b 100644
--- a/diffcore-pickaxe.c
+++ b/diffcore-pickaxe.c
@@ -38,7 +38,7 @@ static int diffgrep_consume(void *priv, char *line, unsigned long len)
static int diff_grep(mmfile_t *one, mmfile_t *two,
struct diff_options *o,
- regex_t *regexp, kwset_t kws)
+ regex_t *regexp, kwset_t kws UNUSED)
{
struct diffgrep_cb ecbdata;
xpparam_t xpp;
@@ -114,7 +114,7 @@ static unsigned int contains(mmfile_t *mf, regex_t *regexp, kwset_t kws,
}
static int has_changes(mmfile_t *one, mmfile_t *two,
- struct diff_options *o,
+ struct diff_options *o UNUSED,
regex_t *regexp, kwset_t kws)
{
unsigned int c1 = one ? contains(one, regexp, kws, 0) : 0;
diff --git a/dir.c b/dir.c
index 7542950820..d604d1bab9 100644
--- a/dir.c
+++ b/dir.c
@@ -669,9 +669,7 @@ int pl_hashmap_cmp(const void *cmp_data UNUSED,
? ee1->patternlen
: ee2->patternlen;
- if (ignore_case)
- return strncasecmp(ee1->pattern, ee2->pattern, min_len);
- return strncmp(ee1->pattern, ee2->pattern, min_len);
+ return fspathncmp(ee1->pattern, ee2->pattern, min_len);
}
static char *dup_and_filter_pattern(const char *pattern)
diff --git a/exec-cmd.c b/exec-cmd.c
index eeb2ee52b8..0232bbc990 100644
--- a/exec-cmd.c
+++ b/exec-cmd.c
@@ -252,7 +252,7 @@ static const char *system_prefix(void)
* This is called during initialization, but No work needs to be done here when
* runtime prefix is not being used.
*/
-void git_resolve_executable_dir(const char *argv0)
+void git_resolve_executable_dir(const char *argv0 UNUSED)
{
}
diff --git a/fsmonitor--daemon.h b/fsmonitor--daemon.h
index 2102a5c9ff..e24838f9a8 100644
--- a/fsmonitor--daemon.h
+++ b/fsmonitor--daemon.h
@@ -8,6 +8,7 @@
#include "run-command.h"
#include "simple-ipc.h"
#include "thread-utils.h"
+#include "fsmonitor-path-utils.h"
struct fsmonitor_batch;
struct fsmonitor_token_data;
@@ -43,6 +44,7 @@ struct fsmonitor_daemon_state {
struct strbuf path_worktree_watch;
struct strbuf path_gitdir_watch;
+ struct alias_info alias;
int nr_paths_watching;
struct fsmonitor_token_data *current_token_data;
@@ -59,6 +61,7 @@ struct fsmonitor_daemon_state {
struct ipc_server_data *ipc_server_data;
struct strbuf path_ipc;
+
};
/*
diff --git a/fsmonitor-ipc.c b/fsmonitor-ipc.c
index 789e7397ba..c0f42301c8 100644
--- a/fsmonitor-ipc.c
+++ b/fsmonitor-ipc.c
@@ -18,7 +18,7 @@ int fsmonitor_ipc__is_supported(void)
return 0;
}
-const char *fsmonitor_ipc__get_path(void)
+const char *fsmonitor_ipc__get_path(struct repository *r)
{
return NULL;
}
@@ -47,11 +47,9 @@ int fsmonitor_ipc__is_supported(void)
return 1;
}
-GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc")
-
enum ipc_active_state fsmonitor_ipc__get_state(void)
{
- return ipc_get_active_state(fsmonitor_ipc__get_path());
+ return ipc_get_active_state(fsmonitor_ipc__get_path(the_repository));
}
static int spawn_daemon(void)
@@ -81,8 +79,8 @@ int fsmonitor_ipc__send_query(const char *since_token,
trace2_data_string("fsm_client", NULL, "query/command", tok);
try_again:
- state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
- &connection);
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
+ &options, &connection);
switch (state) {
case IPC_STATE__LISTENING:
@@ -117,13 +115,13 @@ try_again:
case IPC_STATE__INVALID_PATH:
ret = error(_("fsmonitor_ipc__send_query: invalid path '%s'"),
- fsmonitor_ipc__get_path());
+ fsmonitor_ipc__get_path(the_repository));
goto done;
case IPC_STATE__OTHER_ERROR:
default:
ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"),
- fsmonitor_ipc__get_path());
+ fsmonitor_ipc__get_path(the_repository));
goto done;
}
@@ -149,8 +147,8 @@ int fsmonitor_ipc__send_command(const char *command,
options.wait_if_busy = 1;
options.wait_if_not_found = 0;
- state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options,
- &connection);
+ state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository),
+ &options, &connection);
if (state != IPC_STATE__LISTENING) {
die(_("fsmonitor--daemon is not running"));
return -1;
diff --git a/fsmonitor-ipc.h b/fsmonitor-ipc.h
index b6a7067c3a..8b489da762 100644
--- a/fsmonitor-ipc.h
+++ b/fsmonitor-ipc.h
@@ -3,6 +3,8 @@
#include "simple-ipc.h"
+struct repository;
+
/*
* Returns true if built-in file system monitor daemon is defined
* for this platform.
@@ -16,7 +18,7 @@ int fsmonitor_ipc__is_supported(void);
*
* Returns NULL if the daemon is not supported on this platform.
*/
-const char *fsmonitor_ipc__get_path(void);
+const char *fsmonitor_ipc__get_path(struct repository *r);
/*
* Try to determine whether there is a `git-fsmonitor--daemon` process
diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h
new file mode 100644
index 0000000000..5bfdfb81c1
--- /dev/null
+++ b/fsmonitor-path-utils.h
@@ -0,0 +1,60 @@
+#ifndef FSM_PATH_UTILS_H
+#define FSM_PATH_UTILS_H
+
+#include "strbuf.h"
+
+struct alias_info
+{
+ struct strbuf alias;
+ struct strbuf points_to;
+};
+
+struct fs_info {
+ int is_remote;
+ char *typename;
+};
+
+/*
+ * Get some basic filesystem information for the given path
+ *
+ * The caller owns the storage that is occupied by fs_info and
+ * is responsible for releasing it.
+ *
+ * Returns -1 on error, zero otherwise.
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info);
+
+/*
+ * Determines if the filesystem that path resides on is remote.
+ *
+ * Returns -1 on error, 0 if not remote, 1 if remote.
+ */
+int fsmonitor__is_fs_remote(const char *path);
+
+/*
+ * Get the alias in given path, if any.
+ *
+ * Sets alias to the first alias that matches any part of the path.
+ *
+ * If an alias is found, info.alias and info.points_to are set to the
+ * found mapping.
+ *
+ * Returns -1 on error, 0 otherwise.
+ *
+ * The caller owns the storage that is occupied by info.alias and
+ * info.points_to and is responsible for releasing it.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info);
+
+/*
+ * Resolve the path against the given alias.
+ *
+ * Returns the resolved path if there is one, NULL otherwise.
+ *
+ * The caller owns the storage that the returned string occupies and
+ * is responsible for releasing it.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+ const struct alias_info *info);
+
+#endif
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index 464424a1e9..ee63a97dc5 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -1,7 +1,9 @@
#include "cache.h"
#include "config.h"
#include "repository.h"
+#include "fsmonitor-ipc.h"
#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
/*
* We keep this structure defintion private and have getters
@@ -13,7 +15,53 @@ struct fsmonitor_settings {
char *hook_path;
};
-static enum fsmonitor_reason check_for_incompatible(struct repository *r)
+/*
+ * Remote working directories are problematic for FSMonitor.
+ *
+ * The underlying file system on the server machine and/or the remote
+ * mount type dictates whether notification events are available at
+ * all to remote client machines.
+ *
+ * Kernel differences between the server and client machines also
+ * dictate the how (buffering, frequency, de-dup) the events are
+ * delivered to client machine processes.
+ *
+ * A client machine (such as a laptop) may choose to suspend/resume
+ * and it is unclear (without lots of testing) whether the watcher can
+ * resync after a resume. We might be able to treat this as a normal
+ * "events were dropped by the kernel" event and do our normal "flush
+ * and resync" --or-- we might need to close the existing (zombie?)
+ * notification fd and create a new one.
+ *
+ * In theory, the above issues need to be addressed whether we are
+ * using the Hook or IPC API.
+ *
+ * So (for now at least), mark remote working directories as
+ * incompatible unless 'fsmonitor.allowRemote' is true.
+ *
+ */
+#ifdef HAVE_FSMONITOR_OS_SETTINGS
+static enum fsmonitor_reason check_remote(struct repository *r)
+{
+ int allow_remote = -1; /* -1 unset, 0 not allowed, 1 allowed */
+ int is_remote = fsmonitor__is_fs_remote(r->worktree);
+
+ switch (is_remote) {
+ case 0:
+ return FSMONITOR_REASON_OK;
+ case 1:
+ repo_config_get_bool(r, "fsmonitor.allowremote", &allow_remote);
+ if (allow_remote < 1)
+ return FSMONITOR_REASON_REMOTE;
+ else
+ return FSMONITOR_REASON_OK;
+ default:
+ return FSMONITOR_REASON_ERROR;
+ }
+}
+#endif
+
+static enum fsmonitor_reason check_for_incompatible(struct repository *r, int ipc)
{
if (!r->worktree) {
/*
@@ -27,7 +75,10 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r)
{
enum fsmonitor_reason reason;
- reason = fsm_os__incompatible(r);
+ reason = check_remote(r);
+ if (reason != FSMONITOR_REASON_OK)
+ return reason;
+ reason = fsm_os__incompatible(r, ipc);
if (reason != FSMONITOR_REASON_OK)
return reason;
}
@@ -112,7 +163,7 @@ const char *fsm_settings__get_hook_path(struct repository *r)
void fsm_settings__set_ipc(struct repository *r)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 1);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
@@ -135,7 +186,7 @@ void fsm_settings__set_ipc(struct repository *r)
void fsm_settings__set_hook(struct repository *r, const char *path)
{
- enum fsmonitor_reason reason = check_for_incompatible(r);
+ enum fsmonitor_reason reason = check_for_incompatible(r, 0);
if (reason != FSMONITOR_REASON_OK) {
fsm_settings__set_incompatible(r, reason);
@@ -192,10 +243,11 @@ enum fsmonitor_reason fsm_settings__get_reason(struct repository *r)
return r->settings.fsmonitor->reason;
}
-char *fsm_settings__get_incompatible_msg(const struct repository *r,
+char *fsm_settings__get_incompatible_msg(struct repository *r,
enum fsmonitor_reason reason)
{
struct strbuf msg = STRBUF_INIT;
+ const char *socket_dir;
switch (reason) {
case FSMONITOR_REASON_UNTESTED:
@@ -231,9 +283,11 @@ char *fsm_settings__get_incompatible_msg(const struct repository *r,
goto done;
case FSMONITOR_REASON_NOSOCKETS:
+ socket_dir = dirname((char *)fsmonitor_ipc__get_path(r));
strbuf_addf(&msg,
- _("repository '%s' is incompatible with fsmonitor due to lack of Unix sockets"),
- r->worktree);
+ _("socket directory '%s' is incompatible with fsmonitor due"
+ " to lack of Unix sockets support"),
+ socket_dir);
goto done;
}
diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h
index d9c2605197..ab02e3995e 100644
--- a/fsmonitor-settings.h
+++ b/fsmonitor-settings.h
@@ -33,7 +33,7 @@ enum fsmonitor_mode fsm_settings__get_mode(struct repository *r);
const char *fsm_settings__get_hook_path(struct repository *r);
enum fsmonitor_reason fsm_settings__get_reason(struct repository *r);
-char *fsm_settings__get_incompatible_msg(const struct repository *r,
+char *fsm_settings__get_incompatible_msg(struct repository *r,
enum fsmonitor_reason reason);
struct fsmonitor_settings;
@@ -48,7 +48,7 @@ struct fsmonitor_settings;
* fsm_os__* routines should considered private to fsm_settings__
* routines.
*/
-enum fsmonitor_reason fsm_os__incompatible(struct repository *r);
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc);
#endif /* HAVE_FSMONITOR_OS_SETTINGS */
#endif /* FSMONITOR_SETTINGS_H */
diff --git a/fsmonitor.c b/fsmonitor.c
index 57d6a483be..08af00c738 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -295,6 +295,7 @@ static int fsmonitor_force_update_threshold = 100;
void refresh_fsmonitor(struct index_state *istate)
{
+ static int warn_once = 0;
struct strbuf query_result = STRBUF_INIT;
int query_success = 0, hook_version = -1;
size_t bol = 0; /* beginning of line */
@@ -305,6 +306,14 @@ void refresh_fsmonitor(struct index_state *istate)
int is_trivial = 0;
struct repository *r = istate->repo ? istate->repo : the_repository;
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
+ enum fsmonitor_reason reason = fsm_settings__get_reason(r);
+
+ if (!warn_once && reason > FSMONITOR_REASON_OK) {
+ char *msg = fsm_settings__get_incompatible_msg(r, reason);
+ warn_once = 1;
+ warning("%s", msg);
+ free(msg);
+ }
if (fsm_mode <= FSMONITOR_MODE_DISABLED ||
istate->fsmonitor_has_run_once)
diff --git a/gettext.c b/gettext.c
index bb5ba1fe7c..f139008d0a 100644
--- a/gettext.c
+++ b/gettext.c
@@ -10,7 +10,6 @@
#include "config.h"
#ifndef NO_GETTEXT
-# include <locale.h>
# include <libintl.h>
# ifdef GIT_WINDOWS_NATIVE
@@ -80,7 +79,6 @@ static int test_vsnprintf(const char *fmt, ...)
static void init_gettext_charset(const char *domain)
{
- setlocale(LC_CTYPE, "");
charset = locale_charset();
bind_textdomain_codeset(domain, charset);
diff --git a/git-compat-util.h b/git-compat-util.h
index b90b64718e..a76d0526f7 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -189,9 +189,12 @@ struct strbuf;
#define _NETBSD_SOURCE 1
#define _SGI_SOURCE 1
-#if defined(__GNUC__)
+#if GIT_GNUC_PREREQ(4, 5)
#define UNUSED __attribute__((unused)) \
__attribute__((deprecated ("parameter declared as UNUSED")))
+#elif defined(__GNUC__)
+#define UNUSED __attribute__((unused)) \
+ __attribute__((deprecated))
#else
#define UNUSED
#endif
@@ -222,6 +225,7 @@ struct strbuf;
#endif
#include <errno.h>
#include <limits.h>
+#include <locale.h>
#ifdef NEEDS_SYS_PARAM_H
#include <sys/param.h>
#endif
@@ -310,7 +314,9 @@ typedef unsigned long uintptr_t;
#ifdef PRECOMPOSE_UNICODE
#include "compat/precompose_utf8.h"
#else
-static inline const char *precompose_argv_prefix(int argc, const char **argv, const char *prefix)
+static inline const char *precompose_argv_prefix(int argc UNUSED,
+ const char **argv UNUSED,
+ const char *prefix)
{
return prefix;
}
@@ -335,7 +341,9 @@ struct itimerval {
#endif
#ifdef NO_SETITIMER
-static inline int setitimer(int which, const struct itimerval *value, struct itimerval *newvalue) {
+static inline int setitimer(int which UNUSED,
+ const struct itimerval *value UNUSED,
+ struct itimerval *newvalue UNUSED) {
return 0; /* pretend success */
}
#endif
@@ -420,7 +428,7 @@ int lstat_cache_aware_rmdir(const char *path);
#endif
#ifndef has_dos_drive_prefix
-static inline int git_has_dos_drive_prefix(const char *path)
+static inline int git_has_dos_drive_prefix(const char *path UNUSED)
{
return 0;
}
@@ -428,7 +436,7 @@ static inline int git_has_dos_drive_prefix(const char *path)
#endif
#ifndef skip_dos_drive_prefix
-static inline int git_skip_dos_drive_prefix(char **path)
+static inline int git_skip_dos_drive_prefix(char **path UNUSED)
{
return 0;
}
@@ -1463,11 +1471,11 @@ int open_nofollow(const char *path, int flags);
#endif
#ifndef _POSIX_THREAD_SAFE_FUNCTIONS
-static inline void flockfile(FILE *fh)
+static inline void flockfile(FILE *fh UNUSED)
{
; /* nothing */
}
-static inline void funlockfile(FILE *fh)
+static inline void funlockfile(FILE *fh UNUSED)
{
; /* nothing */
}
diff --git a/git.c b/git.c
index da411c5382..ee7758dcb0 100644
--- a/git.c
+++ b/git.c
@@ -894,12 +894,8 @@ int cmd_main(int argc, const char **argv)
argv++;
argc--;
handle_options(&argv, &argc, NULL);
- if (argc > 0) {
- if (!strcmp("--version", argv[0]) || !strcmp("-v", argv[0]))
- argv[0] = "version";
- else if (!strcmp("--help", argv[0]) || !strcmp("-h", argv[0]))
- argv[0] = "help";
- } else {
+
+ if (!argc) {
/* The user didn't specify a command; give them help */
commit_pager_choice();
printf(_("usage: %s\n\n"), git_usage_string);
@@ -907,6 +903,12 @@ int cmd_main(int argc, const char **argv)
printf("\n%s\n", _(git_more_info_string));
exit(1);
}
+
+ if (!strcmp("--version", argv[0]) || !strcmp("-v", argv[0]))
+ argv[0] = "version";
+ else if (!strcmp("--help", argv[0]) || !strcmp("-h", argv[0]))
+ argv[0] = "help";
+
cmd = argv[0];
/*
diff --git a/gpg-interface.c b/gpg-interface.c
index 9aa714bdee..f877a1ea56 100644
--- a/gpg-interface.c
+++ b/gpg-interface.c
@@ -1059,12 +1059,11 @@ static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
strbuf_addbuf(&ssh_signature_filename, &buffer_file->filename);
strbuf_addstr(&ssh_signature_filename, ".sig");
if (strbuf_read_file(signature, ssh_signature_filename.buf, 0) < 0) {
- error_errno(
+ ret = error_errno(
_("failed reading ssh signing data buffer from '%s'"),
ssh_signature_filename.buf);
+ goto out;
}
- unlink_or_warn(ssh_signature_filename.buf);
-
/* Strip CR from the line endings, in case we are on Windows. */
remove_cr_after(signature, bottom);
@@ -1073,6 +1072,8 @@ out:
delete_tempfile(&key_file);
if (buffer_file)
delete_tempfile(&buffer_file);
+ if (ssh_signature_filename.len)
+ unlink_or_warn(ssh_signature_filename.buf);
strbuf_release(&signer_stderr);
strbuf_release(&ssh_signature_filename);
FREE_AND_NULL(ssh_signing_key_file);
diff --git a/grep.c b/grep.c
index 52a894c989..06eed69493 100644
--- a/grep.c
+++ b/grep.c
@@ -708,6 +708,7 @@ void compile_grep_patterns(struct grep_opt *opt)
{
struct grep_pat *p;
struct grep_expr *header_expr = prep_header_patterns(opt);
+ int extended = 0;
for (p = opt->pattern_list; p; p = p->next) {
switch (p->token) {
@@ -717,14 +718,14 @@ void compile_grep_patterns(struct grep_opt *opt)
compile_regexp(p, opt);
break;
default:
- opt->extended = 1;
+ extended = 1;
break;
}
}
if (opt->all_match || opt->no_body_match || header_expr)
- opt->extended = 1;
- else if (!opt->extended)
+ extended = 1;
+ else if (!extended)
return;
p = opt->pattern_list;
@@ -790,7 +791,7 @@ void free_grep_patterns(struct grep_opt *opt)
free(p);
}
- if (!opt->extended)
+ if (!opt->pattern_expression)
return;
free_pattern_expr(opt->pattern_expression);
}
@@ -971,8 +972,6 @@ static int match_expr_eval(struct grep_opt *opt, struct grep_expr *x,
{
int h = 0;
- if (!x)
- die("Not a valid grep expression");
switch (x->node) {
case GREP_NODE_TRUE:
h = 1;
@@ -1052,7 +1051,7 @@ static int match_line(struct grep_opt *opt,
struct grep_pat *p;
int hit = 0;
- if (opt->extended)
+ if (opt->pattern_expression)
return match_expr(opt, bol, eol, ctx, col, icol,
collect_hits);
@@ -1370,7 +1369,7 @@ static int should_lookahead(struct grep_opt *opt)
{
struct grep_pat *p;
- if (opt->extended)
+ if (opt->pattern_expression)
return 0; /* punt for too complex stuff */
if (opt->invert)
return 0;
diff --git a/grep.h b/grep.h
index bdcadce61b..6075f997e6 100644
--- a/grep.h
+++ b/grep.h
@@ -151,7 +151,6 @@ struct grep_opt {
#define GREP_BINARY_TEXT 2
int binary;
int allow_textconv;
- int extended;
int use_reflog_filter;
int relative;
int pathname;
diff --git a/help.c b/help.c
index d04542d826..f1e090a442 100644
--- a/help.c
+++ b/help.c
@@ -757,7 +757,7 @@ int cmd_version(int argc, const char **argv, const char *prefix)
struct strbuf buf = STRBUF_INIT;
int build_options = 0;
const char * const usage[] = {
- N_("git version [<options>]"),
+ N_("git version [--build-options]"),
NULL
};
struct option options[] = {
diff --git a/hook.c b/hook.c
index a493939a4f..a4fa1031f2 100644
--- a/hook.c
+++ b/hook.c
@@ -114,8 +114,20 @@ int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
.options = options,
};
const char *const hook_path = find_hook(hook_name);
- int jobs = 1;
int ret = 0;
+ const struct run_process_parallel_opts opts = {
+ .tr2_category = "hook",
+ .tr2_label = hook_name,
+
+ .processes = 1,
+ .ungroup = 1,
+
+ .get_next_task = pick_next_hook,
+ .start_failure = notify_start_failure,
+ .task_finished = notify_hook_finished,
+
+ .data = &cb_data,
+ };
if (!options)
BUG("a struct run_hooks_opt must be provided to run_hooks");
@@ -137,14 +149,7 @@ int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
cb_data.hook_path = abs_path.buf;
}
- run_processes_parallel_ungroup = 1;
- run_processes_parallel_tr2(jobs,
- pick_next_hook,
- notify_start_failure,
- notify_hook_finished,
- &cb_data,
- "hook",
- hook_name);
+ run_processes_parallel(&opts);
ret = cb_data.rc;
cleanup:
strbuf_release(&abs_path);
diff --git a/ll-merge.c b/ll-merge.c
index 8955d7e1f6..a8e2db9336 100644
--- a/ll-merge.c
+++ b/ll-merge.c
@@ -49,14 +49,14 @@ void reset_merge_attributes(void)
/*
* Built-in low-levels
*/
-static enum ll_merge_result ll_binary_merge(const struct ll_merge_driver *drv_unused,
+static enum ll_merge_result ll_binary_merge(const struct ll_merge_driver *drv UNUSED,
mmbuffer_t *result,
- const char *path,
- mmfile_t *orig, const char *orig_name,
- mmfile_t *src1, const char *name1,
- mmfile_t *src2, const char *name2,
+ const char *path UNUSED,
+ mmfile_t *orig, const char *orig_name UNUSED,
+ mmfile_t *src1, const char *name1 UNUSED,
+ mmfile_t *src2, const char *name2 UNUSED,
const struct ll_merge_options *opts,
- int marker_size)
+ int marker_size UNUSED)
{
enum ll_merge_result ret;
mmfile_t *stolen;
@@ -183,9 +183,9 @@ static void create_temp(mmfile_t *src, char *path, size_t len)
static enum ll_merge_result ll_ext_merge(const struct ll_merge_driver *fn,
mmbuffer_t *result,
const char *path,
- mmfile_t *orig, const char *orig_name,
- mmfile_t *src1, const char *name1,
- mmfile_t *src2, const char *name2,
+ mmfile_t *orig, const char *orig_name UNUSED,
+ mmfile_t *src1, const char *name1 UNUSED,
+ mmfile_t *src2, const char *name2 UNUSED,
const struct ll_merge_options *opts,
int marker_size)
{
diff --git a/mailinfo.c b/mailinfo.c
index 9621ba62a3..833d28612f 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -317,7 +317,7 @@ static void cleanup_subject(struct mailinfo *mi, struct strbuf *subject)
pos = strchr(subject->buf + at, ']');
if (!pos)
break;
- remove = pos - subject->buf + at + 1;
+ remove = pos - (subject->buf + at) + 1;
if (!mi->keep_non_patch_brackets_in_subject ||
(7 <= remove &&
memmem(subject->buf + at, remove, "PATCH", 5)))
diff --git a/merge-ort.c b/merge-ort.c
index 99dcee2db8..7e83ebfaa9 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -397,7 +397,7 @@ struct conflicted_submodule_item {
int flag;
};
-static void conflicted_submodule_item_free(void *util, const char *str)
+static void conflicted_submodule_item_free(void *util, const char *str UNUSED)
{
struct conflicted_submodule_item *item = util;
@@ -2807,6 +2807,8 @@ static int process_renames(struct merge_options *opt,
pathnames,
1 + 2 * opt->priv->call_depth,
&merged);
+ if (clean_merge < 0)
+ return -1;
if (!clean_merge &&
merged.mode == side1->stages[1].mode &&
oideq(&merged.oid, &side1->stages[1].oid))
@@ -2916,7 +2918,7 @@ static int process_renames(struct merge_options *opt,
struct version_info merged;
struct conflict_info *base, *side1, *side2;
- unsigned clean;
+ int clean;
pathnames[0] = oldpath;
pathnames[other_source_index] = oldpath;
@@ -2937,6 +2939,8 @@ static int process_renames(struct merge_options *opt,
pathnames,
1 + 2 * opt->priv->call_depth,
&merged);
+ if (clean < 0)
+ return -1;
memcpy(&newinfo->stages[target_index], &merged,
sizeof(merged));
@@ -3571,15 +3575,15 @@ static int tree_entry_order(const void *a_, const void *b_)
b->string, strlen(b->string), bmi->result.mode);
}
-static void write_tree(struct object_id *result_oid,
- struct string_list *versions,
- unsigned int offset,
- size_t hash_size)
+static int write_tree(struct object_id *result_oid,
+ struct string_list *versions,
+ unsigned int offset,
+ size_t hash_size)
{
size_t maxlen = 0, extra;
unsigned int nr;
struct strbuf buf = STRBUF_INIT;
- int i;
+ int i, ret = 0;
assert(offset <= versions->nr);
nr = versions->nr - offset;
@@ -3605,8 +3609,10 @@ static void write_tree(struct object_id *result_oid,
}
/* Write this object file out, and record in result_oid */
- write_object_file(buf.buf, buf.len, OBJ_TREE, result_oid);
+ if (write_object_file(buf.buf, buf.len, OBJ_TREE, result_oid))
+ ret = -1;
strbuf_release(&buf);
+ return ret;
}
static void record_entry_for_tree(struct directory_versions *dir_metadata,
@@ -3625,13 +3631,13 @@ static void record_entry_for_tree(struct directory_versions *dir_metadata,
basename)->util = &mi->result;
}
-static void write_completed_directory(struct merge_options *opt,
- const char *new_directory_name,
- struct directory_versions *info)
+static int write_completed_directory(struct merge_options *opt,
+ const char *new_directory_name,
+ struct directory_versions *info)
{
const char *prev_dir;
struct merged_info *dir_info = NULL;
- unsigned int offset;
+ unsigned int offset, ret = 0;
/*
* Some explanation of info->versions and info->offsets...
@@ -3717,7 +3723,7 @@ static void write_completed_directory(struct merge_options *opt,
* strcmp here.)
*/
if (new_directory_name == info->last_directory)
- return;
+ return 0;
/*
* If we are just starting (last_directory is NULL), or last_directory
@@ -3739,7 +3745,7 @@ static void write_completed_directory(struct merge_options *opt,
*/
string_list_append(&info->offsets,
info->last_directory)->util = (void*)offset;
- return;
+ return 0;
}
/*
@@ -3769,8 +3775,9 @@ static void write_completed_directory(struct merge_options *opt,
*/
dir_info->is_null = 0;
dir_info->result.mode = S_IFDIR;
- write_tree(&dir_info->result.oid, &info->versions, offset,
- opt->repo->hash_algo->rawsz);
+ if (write_tree(&dir_info->result.oid, &info->versions, offset,
+ opt->repo->hash_algo->rawsz) < 0)
+ ret = -1;
}
/*
@@ -3798,13 +3805,15 @@ static void write_completed_directory(struct merge_options *opt,
/* And, of course, we need to update last_directory to match. */
info->last_directory = new_directory_name;
info->last_directory_len = strlen(info->last_directory);
+
+ return ret;
}
/* Per entry merge function */
-static void process_entry(struct merge_options *opt,
- const char *path,
- struct conflict_info *ci,
- struct directory_versions *dir_metadata)
+static int process_entry(struct merge_options *opt,
+ const char *path,
+ struct conflict_info *ci,
+ struct directory_versions *dir_metadata)
{
int df_file_index = 0;
@@ -3818,7 +3827,7 @@ static void process_entry(struct merge_options *opt,
record_entry_for_tree(dir_metadata, path, &ci->merged);
if (ci->filemask == 0)
/* nothing else to handle */
- return;
+ return 0;
assert(ci->df_conflict);
}
@@ -3865,7 +3874,7 @@ static void process_entry(struct merge_options *opt,
*/
if (ci->filemask == 1) {
ci->filemask = 0;
- return;
+ return 0;
}
/*
@@ -4060,7 +4069,7 @@ static void process_entry(struct merge_options *opt,
} else if (ci->filemask >= 6) {
/* Need a two-way or three-way content merge */
struct version_info merged_file;
- unsigned clean_merge;
+ int clean_merge;
struct version_info *o = &ci->stages[0];
struct version_info *a = &ci->stages[1];
struct version_info *b = &ci->stages[2];
@@ -4069,6 +4078,8 @@ static void process_entry(struct merge_options *opt,
ci->pathnames,
opt->priv->call_depth * 2,
&merged_file);
+ if (clean_merge < 0)
+ return -1;
ci->merged.clean = clean_merge &&
!ci->df_conflict && !ci->path_conflict;
ci->merged.result.mode = merged_file.mode;
@@ -4164,6 +4175,7 @@ static void process_entry(struct merge_options *opt,
/* Record metadata for ci->merged in dir_metadata */
record_entry_for_tree(dir_metadata, path, &ci->merged);
+ return 0;
}
static void prefetch_for_content_merges(struct merge_options *opt,
@@ -4214,8 +4226,8 @@ static void prefetch_for_content_merges(struct merge_options *opt,
oid_array_clear(&to_fetch);
}
-static void process_entries(struct merge_options *opt,
- struct object_id *result_oid)
+static int process_entries(struct merge_options *opt,
+ struct object_id *result_oid)
{
struct hashmap_iter iter;
struct strmap_entry *e;
@@ -4224,11 +4236,12 @@ static void process_entries(struct merge_options *opt,
struct directory_versions dir_metadata = { STRING_LIST_INIT_NODUP,
STRING_LIST_INIT_NODUP,
NULL, 0 };
+ int ret = 0;
trace2_region_enter("merge", "process_entries setup", opt->repo);
if (strmap_empty(&opt->priv->paths)) {
oidcpy(result_oid, opt->repo->hash_algo->empty_tree);
- return;
+ return 0;
}
/* Hack to pre-allocate plist to the desired size */
@@ -4270,13 +4283,19 @@ static void process_entries(struct merge_options *opt,
*/
struct merged_info *mi = entry->util;
- write_completed_directory(opt, mi->directory_name,
- &dir_metadata);
+ if (write_completed_directory(opt, mi->directory_name,
+ &dir_metadata) < 0) {
+ ret = -1;
+ goto cleanup;
+ }
if (mi->clean)
record_entry_for_tree(&dir_metadata, path, mi);
else {
struct conflict_info *ci = (struct conflict_info *)mi;
- process_entry(opt, path, ci, &dir_metadata);
+ if (process_entry(opt, path, ci, &dir_metadata) < 0) {
+ ret = -1;
+ goto cleanup;
+ };
}
}
trace2_region_leave("merge", "processing", opt->repo);
@@ -4291,12 +4310,16 @@ static void process_entries(struct merge_options *opt,
fflush(stdout);
BUG("dir_metadata accounting completely off; shouldn't happen");
}
- write_tree(result_oid, &dir_metadata.versions, 0,
- opt->repo->hash_algo->rawsz);
+ if (write_tree(result_oid, &dir_metadata.versions, 0,
+ opt->repo->hash_algo->rawsz) < 0)
+ ret = -1;
+cleanup:
string_list_clear(&plist, 0);
string_list_clear(&dir_metadata.versions, 0);
string_list_clear(&dir_metadata.offsets, 0);
trace2_region_leave("merge", "process_entries cleanup", opt->repo);
+
+ return ret;
}
/*** Function Grouping: functions related to merge_switch_to_result() ***/
@@ -4928,15 +4951,18 @@ redo:
}
trace2_region_enter("merge", "process_entries", opt->repo);
- process_entries(opt, &working_tree_oid);
+ if (process_entries(opt, &working_tree_oid) < 0)
+ result->clean = -1;
trace2_region_leave("merge", "process_entries", opt->repo);
/* Set return values */
result->path_messages = &opt->priv->conflicts;
- result->tree = parse_tree_indirect(&working_tree_oid);
- /* existence of conflicted entries implies unclean */
- result->clean &= strmap_empty(&opt->priv->conflicted);
+ if (result->clean >= 0) {
+ result->tree = parse_tree_indirect(&working_tree_oid);
+ /* existence of conflicted entries implies unclean */
+ result->clean &= strmap_empty(&opt->priv->conflicted);
+ }
if (!opt->priv->call_depth) {
result->priv = opt->priv;
result->_properly_initialized = RESULT_INITIALIZED;
diff --git a/midx.c b/midx.c
index c27d0e5f15..7cfad04a24 100644
--- a/midx.c
+++ b/midx.c
@@ -278,7 +278,7 @@ uint32_t nth_midxed_pack_int_id(struct multi_pack_index *m, uint32_t pos)
(off_t)pos * MIDX_CHUNK_OFFSET_WIDTH);
}
-int fill_midx_entry(struct repository * r,
+int fill_midx_entry(struct repository *r,
const struct object_id *oid,
struct pack_entry *e,
struct multi_pack_index *m)
@@ -913,6 +913,8 @@ static uint32_t *midx_pack_order(struct write_midx_context *ctx)
uint32_t *pack_order;
uint32_t i;
+ trace2_region_enter("midx", "midx_pack_order", the_repository);
+
ALLOC_ARRAY(data, ctx->entries_nr);
for (i = 0; i < ctx->entries_nr; i++) {
struct pack_midx_entry *e = &ctx->entries[i];
@@ -930,6 +932,8 @@ static uint32_t *midx_pack_order(struct write_midx_context *ctx)
pack_order[i] = data[i].nr;
free(data);
+ trace2_region_leave("midx", "midx_pack_order", the_repository);
+
return pack_order;
}
@@ -939,6 +943,8 @@ static void write_midx_reverse_index(char *midx_name, unsigned char *midx_hash,
struct strbuf buf = STRBUF_INIT;
const char *tmp_file;
+ trace2_region_enter("midx", "write_midx_reverse_index", the_repository);
+
strbuf_addf(&buf, "%s-%s.rev", midx_name, hash_to_hex(midx_hash));
tmp_file = write_rev_file_order(NULL, ctx->pack_order, ctx->entries_nr,
@@ -948,6 +954,8 @@ static void write_midx_reverse_index(char *midx_name, unsigned char *midx_hash,
die(_("cannot store reverse index file"));
strbuf_release(&buf);
+
+ trace2_region_leave("midx", "write_midx_reverse_index", the_repository);
}
static void clear_midx_files_ext(const char *object_dir, const char *ext,
@@ -963,6 +971,8 @@ static void prepare_midx_packing_data(struct packing_data *pdata,
{
uint32_t i;
+ trace2_region_enter("midx", "prepare_midx_packing_data", the_repository);
+
memset(pdata, 0, sizeof(struct packing_data));
prepare_packing_data(the_repository, pdata);
@@ -973,6 +983,8 @@ static void prepare_midx_packing_data(struct packing_data *pdata,
oe_set_in_pack(pdata, to,
ctx->info[ctx->pack_perm[from->pack_int_id]].p);
}
+
+ trace2_region_leave("midx", "prepare_midx_packing_data", the_repository);
}
static int add_ref_to_pending(const char *refname,
@@ -980,6 +992,7 @@ static int add_ref_to_pending(const char *refname,
int flag, void *cb_data)
{
struct rev_info *revs = (struct rev_info*)cb_data;
+ struct object_id peeled;
struct object *object;
if ((flag & REF_ISSYMREF) && (flag & REF_ISBROKEN)) {
@@ -987,6 +1000,9 @@ static int add_ref_to_pending(const char *refname,
return 0;
}
+ if (!peel_iterated_oid(oid, &peeled))
+ oid = &peeled;
+
object = parse_object_or_die(oid, refname);
if (object->type != OBJ_COMMIT)
return 0;
@@ -1066,6 +1082,9 @@ static struct commit **find_commits_for_midx_bitmap(uint32_t *indexed_commits_nr
struct rev_info revs;
struct bitmap_commit_cb cb = {0};
+ trace2_region_enter("midx", "find_commits_for_midx_bitmap",
+ the_repository);
+
cb.ctx = ctx;
repo_init_revisions(the_repository, &revs, NULL);
@@ -1099,6 +1118,10 @@ static struct commit **find_commits_for_midx_bitmap(uint32_t *indexed_commits_nr
*indexed_commits_nr_p = cb.commits_nr;
release_revisions(&revs);
+
+ trace2_region_leave("midx", "find_commits_for_midx_bitmap",
+ the_repository);
+
return cb.commits;
}
@@ -1116,6 +1139,8 @@ static int write_midx_bitmap(const char *midx_name,
char *bitmap_name = xstrfmt("%s-%s.bitmap", midx_name,
hash_to_hex(midx_hash));
+ trace2_region_enter("midx", "write_midx_bitmap", the_repository);
+
if (flags & MIDX_WRITE_BITMAP_HASH_CACHE)
options |= BITMAP_OPT_HASH_CACHE;
@@ -1161,6 +1186,9 @@ static int write_midx_bitmap(const char *midx_name,
cleanup:
free(index);
free(bitmap_name);
+
+ trace2_region_leave("midx", "write_midx_bitmap", the_repository);
+
return ret;
}
@@ -1207,6 +1235,8 @@ static int write_midx_internal(const char *object_dir,
int result = 0;
struct chunkfile *cf;
+ trace2_region_enter("midx", "write_midx_internal", the_repository);
+
get_midx_filename(&midx_name, object_dir);
if (safe_create_leading_directories(midx_name.buf))
die_errno(_("unable to create leading directories of %s"),
@@ -1548,6 +1578,8 @@ cleanup:
free(ctx.pack_order);
strbuf_release(&midx_name);
+ trace2_region_leave("midx", "write_midx_internal", the_repository);
+
return result;
}
@@ -1839,7 +1871,7 @@ int expire_midx_packs(struct repository *r, const char *object_dir, unsigned fla
if (prepare_midx_pack(r, m, i))
continue;
- if (m->packs[i]->pack_keep)
+ if (m->packs[i]->pack_keep || m->packs[i]->is_cruft)
continue;
pack_name = xstrdup(m->packs[i]->pack_name);
@@ -1895,6 +1927,8 @@ static int fill_included_packs_all(struct repository *r,
continue;
if (!pack_kept_objects && m->packs[i]->pack_keep)
continue;
+ if (m->packs[i]->is_cruft)
+ continue;
include_pack[i] = 1;
count++;
@@ -1910,9 +1944,11 @@ static int fill_included_packs_batch(struct repository *r,
{
uint32_t i, packs_to_repack;
size_t total_size;
- struct repack_info *pack_info = xcalloc(m->num_packs, sizeof(struct repack_info));
+ struct repack_info *pack_info;
int pack_kept_objects = 0;
+ CALLOC_ARRAY(pack_info, m->num_packs);
+
repo_config_get_bool(r, "repack.packkeptobjects", &pack_kept_objects);
for (i = 0; i < m->num_packs; i++) {
@@ -1924,7 +1960,7 @@ static int fill_included_packs_batch(struct repository *r,
pack_info[i].mtime = m->packs[i]->mtime;
}
- for (i = 0; batch_size && i < m->num_objects; i++) {
+ for (i = 0; i < m->num_objects; i++) {
uint32_t pack_int_id = nth_midxed_pack_int_id(m, i);
pack_info[pack_int_id].referenced_objects++;
}
@@ -1942,6 +1978,8 @@ static int fill_included_packs_batch(struct repository *r,
continue;
if (!pack_kept_objects && p->pack_keep)
continue;
+ if (p->is_cruft)
+ continue;
if (open_pack_index(p) || !p->num_objects)
continue;
diff --git a/object-file.c b/object-file.c
index 5b270f046d..957790098f 100644
--- a/object-file.c
+++ b/object-file.c
@@ -140,27 +140,32 @@ static void git_hash_sha256_final_oid(struct object_id *oid, git_hash_ctx *ctx)
oid->algo = GIT_HASH_SHA256;
}
-static void git_hash_unknown_init(git_hash_ctx *ctx)
+static void git_hash_unknown_init(git_hash_ctx *ctx UNUSED)
{
BUG("trying to init unknown hash");
}
-static void git_hash_unknown_clone(git_hash_ctx *dst, const git_hash_ctx *src)
+static void git_hash_unknown_clone(git_hash_ctx *dst UNUSED,
+ const git_hash_ctx *src UNUSED)
{
BUG("trying to clone unknown hash");
}
-static void git_hash_unknown_update(git_hash_ctx *ctx, const void *data, size_t len)
+static void git_hash_unknown_update(git_hash_ctx *ctx UNUSED,
+ const void *data UNUSED,
+ size_t len UNUSED)
{
BUG("trying to update unknown hash");
}
-static void git_hash_unknown_final(unsigned char *hash, git_hash_ctx *ctx)
+static void git_hash_unknown_final(unsigned char *hash UNUSED,
+ git_hash_ctx *ctx UNUSED)
{
BUG("trying to finalize unknown hash");
}
-static void git_hash_unknown_final_oid(struct object_id *oid, git_hash_ctx *ctx)
+static void git_hash_unknown_final_oid(struct object_id *oid UNUSED,
+ git_hash_ctx *ctx UNUSED)
{
BUG("trying to finalize unknown hash");
}
@@ -1599,10 +1604,6 @@ static int do_oid_object_info_extended(struct repository *r,
if (fetch_if_missing && repo_has_promisor_remote(r) &&
!already_retried &&
!(flags & OBJECT_INFO_SKIP_FETCH_OBJECT)) {
- /*
- * TODO Investigate checking promisor_remote_get_direct()
- * TODO return value and stopping on error here.
- */
promisor_remote_get_direct(r, real, 1);
already_retried = 1;
continue;
diff --git a/object.c b/object.c
index 2e4589bae5..8a74eb85e9 100644
--- a/object.c
+++ b/object.c
@@ -233,7 +233,8 @@ struct object *parse_object_buffer(struct repository *r, const struct object_id
if (commit) {
if (parse_commit_buffer(r, commit, buffer, size, 1))
return NULL;
- if (!get_cached_commit_buffer(r, commit, NULL)) {
+ if (save_commit_buffer &&
+ !get_cached_commit_buffer(r, commit, NULL)) {
set_commit_buffer(r, commit, buffer, size);
*eaten_p = 1;
}
diff --git a/oss-fuzz/.gitignore b/oss-fuzz/.gitignore
new file mode 100644
index 0000000000..9acb74412e
--- /dev/null
+++ b/oss-fuzz/.gitignore
@@ -0,0 +1,3 @@
+fuzz-commit-graph
+fuzz-pack-headers
+fuzz-pack-idx
diff --git a/fuzz-commit-graph.c b/oss-fuzz/fuzz-commit-graph.c
index 914026f5d8..914026f5d8 100644
--- a/fuzz-commit-graph.c
+++ b/oss-fuzz/fuzz-commit-graph.c
diff --git a/fuzz-pack-headers.c b/oss-fuzz/fuzz-pack-headers.c
index 99da1d0fd3..99da1d0fd3 100644
--- a/fuzz-pack-headers.c
+++ b/oss-fuzz/fuzz-pack-headers.c
diff --git a/fuzz-pack-idx.c b/oss-fuzz/fuzz-pack-idx.c
index 0c3d777aac..0c3d777aac 100644
--- a/fuzz-pack-idx.c
+++ b/oss-fuzz/fuzz-pack-idx.c
diff --git a/pack-bitmap-write.c b/pack-bitmap-write.c
index a213f5eddc..cfa67a510f 100644
--- a/pack-bitmap-write.c
+++ b/pack-bitmap-write.c
@@ -384,6 +384,8 @@ static int fill_bitmap_tree(struct bitmap *bitmap,
return 0;
}
+static int reused_bitmaps_nr;
+
static int fill_bitmap_commit(struct bb_commit *ent,
struct commit *commit,
struct prio_queue *queue,
@@ -409,8 +411,10 @@ static int fill_bitmap_commit(struct bb_commit *ent,
* bitmap and add its bits to this one. No need to walk
* parents or the tree for this commit.
*/
- if (old && !rebuild_bitmap(mapping, old, ent->bitmap))
+ if (old && !rebuild_bitmap(mapping, old, ent->bitmap)) {
+ reused_bitmaps_nr++;
continue;
+ }
}
/*
@@ -526,6 +530,8 @@ int bitmap_writer_build(struct packing_data *to_pack)
trace2_region_leave("pack-bitmap-write", "building_bitmaps_total",
the_repository);
+ trace2_data_intmax("pack-bitmap-write", the_repository,
+ "building_bitmaps_reused", reused_bitmaps_nr);
stop_progress(&writer.progress);
diff --git a/patch-ids.c b/patch-ids.c
index 46c6a8f3ea..3153446626 100644
--- a/patch-ids.c
+++ b/patch-ids.c
@@ -11,7 +11,7 @@ static int patch_id_defined(struct commit *commit)
}
int commit_patch_id(struct commit *commit, struct diff_options *options,
- struct object_id *oid, int diff_header_only, int stable)
+ struct object_id *oid, int diff_header_only)
{
if (!patch_id_defined(commit))
return -1;
@@ -22,7 +22,7 @@ int commit_patch_id(struct commit *commit, struct diff_options *options,
else
diff_root_tree_oid(&commit->object.oid, "", options);
diffcore_std(options);
- return diff_flush_patch_id(options, oid, diff_header_only, stable);
+ return diff_flush_patch_id(options, oid, diff_header_only);
}
/*
@@ -48,11 +48,11 @@ static int patch_id_neq(const void *cmpfn_data,
b = container_of(entry_or_key, struct patch_id, ent);
if (is_null_oid(&a->patch_id) &&
- commit_patch_id(a->commit, opt, &a->patch_id, 0, 0))
+ commit_patch_id(a->commit, opt, &a->patch_id, 0))
return error("Could not get patch ID for %s",
oid_to_hex(&a->commit->object.oid));
if (is_null_oid(&b->patch_id) &&
- commit_patch_id(b->commit, opt, &b->patch_id, 0, 0))
+ commit_patch_id(b->commit, opt, &b->patch_id, 0))
return error("Could not get patch ID for %s",
oid_to_hex(&b->commit->object.oid));
return !oideq(&a->patch_id, &b->patch_id);
@@ -82,7 +82,7 @@ static int init_patch_id_entry(struct patch_id *patch,
struct object_id header_only_patch_id;
patch->commit = commit;
- if (commit_patch_id(commit, &ids->diffopts, &header_only_patch_id, 1, 0))
+ if (commit_patch_id(commit, &ids->diffopts, &header_only_patch_id, 1))
return -1;
hashmap_entry_init(&patch->ent, oidhash(&header_only_patch_id));
diff --git a/patch-ids.h b/patch-ids.h
index ab6c6a6804..490d739371 100644
--- a/patch-ids.h
+++ b/patch-ids.h
@@ -20,7 +20,7 @@ struct patch_ids {
};
int commit_patch_id(struct commit *commit, struct diff_options *options,
- struct object_id *oid, int, int);
+ struct object_id *oid, int);
int init_patch_ids(struct repository *, struct patch_ids *);
int free_patch_ids(struct patch_ids *);
diff --git a/perl/Git.pm b/perl/Git.pm
index 080cdc2a21..117765dc73 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -177,16 +177,27 @@ sub repository {
-d $opts{Directory} or throw Error::Simple("Directory not found: $opts{Directory} $!");
my $search = Git->repository(WorkingCopy => $opts{Directory});
- my $dir;
+
+ # This rev-parse will throw an exception if we're not in a
+ # repository, which is what we want, but it's kind of noisy.
+ # Ideally we'd capture stderr and relay it, but doing so is
+ # awkward without depending on it fitting in a pipe buffer. So
+ # we just reproduce a plausible error message ourselves.
+ my $out;
try {
- $dir = $search->command_oneline(['rev-parse', '--git-dir'],
- STDERR => 0);
+ # Note that "--is-bare-repository" must come first, as
+ # --git-dir output could contain newlines.
+ $out = $search->command([qw(rev-parse --is-bare-repository --git-dir)],
+ STDERR => 0);
} catch Git::Error::Command with {
- $dir = undef;
+ throw Error::Simple("fatal: not a git repository: $opts{Directory}");
};
+ chomp $out;
+ my ($bare, $dir) = split /\n/, $out, 2;
+
require Cwd;
- if ($dir) {
+ if ($bare ne 'true') {
require File::Spec;
File::Spec->file_name_is_absolute($dir) or $dir = $opts{Directory} . '/' . $dir;
$opts{Repository} = Cwd::abs_path($dir);
@@ -204,21 +215,6 @@ sub repository {
$opts{WorkingSubdir} = $prefix;
} else {
- # A bare repository? Let's see...
- $dir = $opts{Directory};
-
- unless (-d "$dir/refs" and -d "$dir/objects" and -e "$dir/HEAD") {
- # Mimic git-rev-parse --git-dir error message:
- throw Error::Simple("fatal: Not a git repository: $dir");
- }
- my $search = Git->repository(Repository => $dir);
- try {
- $search->command('symbolic-ref', 'HEAD');
- } catch Git::Error::Command with {
- # Mimic git-rev-parse --git-dir error message:
- throw Error::Simple("fatal: Not a git repository: $dir");
- }
-
$opts{Repository} = Cwd::abs_path($dir);
}
diff --git a/promisor-remote.c b/promisor-remote.c
index 68f46f5ec7..faa7612941 100644
--- a/promisor-remote.c
+++ b/promisor-remote.c
@@ -4,6 +4,7 @@
#include "config.h"
#include "transport.h"
#include "strvec.h"
+#include "packfile.h"
struct promisor_remote_config {
struct promisor_remote *promisors;
@@ -230,18 +231,18 @@ static int remove_fetched_oids(struct repository *repo,
return remaining_nr;
}
-int promisor_remote_get_direct(struct repository *repo,
- const struct object_id *oids,
- int oid_nr)
+void promisor_remote_get_direct(struct repository *repo,
+ const struct object_id *oids,
+ int oid_nr)
{
struct promisor_remote *r;
struct object_id *remaining_oids = (struct object_id *)oids;
int remaining_nr = oid_nr;
int to_free = 0;
- int res = -1;
+ int i;
if (oid_nr == 0)
- return 0;
+ return;
promisor_remote_init(repo);
@@ -256,12 +257,16 @@ int promisor_remote_get_direct(struct repository *repo,
continue;
}
}
- res = 0;
- break;
+ goto all_fetched;
}
+ for (i = 0; i < remaining_nr; i++) {
+ if (is_promisor_object(&remaining_oids[i]))
+ die(_("could not fetch %s from promisor remote"),
+ oid_to_hex(&remaining_oids[i]));
+ }
+
+all_fetched:
if (to_free)
free(remaining_oids);
-
- return res;
}
diff --git a/promisor-remote.h b/promisor-remote.h
index edc45ab0f5..df36eb08ef 100644
--- a/promisor-remote.h
+++ b/promisor-remote.h
@@ -39,13 +39,12 @@ static inline int has_promisor_remote(void)
/*
* Fetches all requested objects from all promisor remotes, trying them one at
- * a time until all objects are fetched. Returns 0 upon success, and non-zero
- * otherwise.
+ * a time until all objects are fetched.
*
- * If oid_nr is 0, this function returns 0 (success) immediately.
+ * If oid_nr is 0, this function returns immediately.
*/
-int promisor_remote_get_direct(struct repository *repo,
- const struct object_id *oids,
- int oid_nr);
+void promisor_remote_get_direct(struct repository *repo,
+ const struct object_id *oids,
+ int oid_nr);
#endif /* PROMISOR_REMOTE_H */
diff --git a/read-cache.c b/read-cache.c
index b09128b188..3202402927 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -1873,9 +1873,20 @@ static int read_index_extension(struct index_state *istate,
return 0;
}
+/*
+ * Parses the contents of the cache entry contained within the 'ondisk' buffer
+ * into a new incore 'cache_entry'.
+ *
+ * Note that 'char *ondisk' may not be aligned to a 4-byte address interval in
+ * index v4, so we cannot cast it to 'struct ondisk_cache_entry *' and access
+ * its members. Instead, we use the byte offsets of members within the struct to
+ * identify where 'get_be16()', 'get_be32()', and 'oidread()' (which can all
+ * read from an unaligned memory buffer) should read from the 'ondisk' buffer
+ * into the corresponding incore 'cache_entry' members.
+ */
static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool,
unsigned int version,
- struct ondisk_cache_entry *ondisk,
+ const char *ondisk,
unsigned long *ent_size,
const struct cache_entry *previous_ce)
{
@@ -1883,7 +1894,7 @@ static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool,
size_t len;
const char *name;
const unsigned hashsz = the_hash_algo->rawsz;
- const uint16_t *flagsp = (const uint16_t *)(ondisk->data + hashsz);
+ const char *flagsp = ondisk + offsetof(struct ondisk_cache_entry, data) + hashsz;
unsigned int flags;
size_t copy_len = 0;
/*
@@ -1901,15 +1912,15 @@ static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool,
if (flags & CE_EXTENDED) {
int extended_flags;
- extended_flags = get_be16(flagsp + 1) << 16;
+ extended_flags = get_be16(flagsp + sizeof(uint16_t)) << 16;
/* We do not yet understand any bit out of CE_EXTENDED_FLAGS */
if (extended_flags & ~CE_EXTENDED_FLAGS)
die(_("unknown index entry format 0x%08x"), extended_flags);
flags |= extended_flags;
- name = (const char *)(flagsp + 2);
+ name = (const char *)(flagsp + 2 * sizeof(uint16_t));
}
else
- name = (const char *)(flagsp + 1);
+ name = (const char *)(flagsp + sizeof(uint16_t));
if (expand_name_field) {
const unsigned char *cp = (const unsigned char *)name;
@@ -1935,20 +1946,32 @@ static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool,
ce = mem_pool__ce_alloc(ce_mem_pool, len);
- ce->ce_stat_data.sd_ctime.sec = get_be32(&ondisk->ctime.sec);
- ce->ce_stat_data.sd_mtime.sec = get_be32(&ondisk->mtime.sec);
- ce->ce_stat_data.sd_ctime.nsec = get_be32(&ondisk->ctime.nsec);
- ce->ce_stat_data.sd_mtime.nsec = get_be32(&ondisk->mtime.nsec);
- ce->ce_stat_data.sd_dev = get_be32(&ondisk->dev);
- ce->ce_stat_data.sd_ino = get_be32(&ondisk->ino);
- ce->ce_mode = get_be32(&ondisk->mode);
- ce->ce_stat_data.sd_uid = get_be32(&ondisk->uid);
- ce->ce_stat_data.sd_gid = get_be32(&ondisk->gid);
- ce->ce_stat_data.sd_size = get_be32(&ondisk->size);
+ /*
+ * NEEDSWORK: using 'offsetof()' is cumbersome and should be replaced
+ * with something more akin to 'load_bitmap_entries_v1()'s use of
+ * 'read_be16'/'read_be32'. For consistency with the corresponding
+ * ondisk entry write function ('copy_cache_entry_to_ondisk()'), this
+ * should be done at the same time as removing references to
+ * 'ondisk_cache_entry' there.
+ */
+ ce->ce_stat_data.sd_ctime.sec = get_be32(ondisk + offsetof(struct ondisk_cache_entry, ctime)
+ + offsetof(struct cache_time, sec));
+ ce->ce_stat_data.sd_mtime.sec = get_be32(ondisk + offsetof(struct ondisk_cache_entry, mtime)
+ + offsetof(struct cache_time, sec));
+ ce->ce_stat_data.sd_ctime.nsec = get_be32(ondisk + offsetof(struct ondisk_cache_entry, ctime)
+ + offsetof(struct cache_time, nsec));
+ ce->ce_stat_data.sd_mtime.nsec = get_be32(ondisk + offsetof(struct ondisk_cache_entry, mtime)
+ + offsetof(struct cache_time, nsec));
+ ce->ce_stat_data.sd_dev = get_be32(ondisk + offsetof(struct ondisk_cache_entry, dev));
+ ce->ce_stat_data.sd_ino = get_be32(ondisk + offsetof(struct ondisk_cache_entry, ino));
+ ce->ce_mode = get_be32(ondisk + offsetof(struct ondisk_cache_entry, mode));
+ ce->ce_stat_data.sd_uid = get_be32(ondisk + offsetof(struct ondisk_cache_entry, uid));
+ ce->ce_stat_data.sd_gid = get_be32(ondisk + offsetof(struct ondisk_cache_entry, gid));
+ ce->ce_stat_data.sd_size = get_be32(ondisk + offsetof(struct ondisk_cache_entry, size));
ce->ce_flags = flags & ~CE_NAMEMASK;
ce->ce_namelen = len;
ce->index = 0;
- oidread(&ce->oid, ondisk->data);
+ oidread(&ce->oid, (const unsigned char *)ondisk + offsetof(struct ondisk_cache_entry, data));
if (expand_name_field) {
if (copy_len)
@@ -2117,12 +2140,12 @@ static unsigned long load_cache_entry_block(struct index_state *istate,
unsigned long src_offset = start_offset;
for (i = offset; i < offset + nr; i++) {
- struct ondisk_cache_entry *disk_ce;
struct cache_entry *ce;
unsigned long consumed;
- disk_ce = (struct ondisk_cache_entry *)(mmap + src_offset);
- ce = create_from_disk(ce_mem_pool, istate->version, disk_ce, &consumed, previous_ce);
+ ce = create_from_disk(ce_mem_pool, istate->version,
+ mmap + src_offset,
+ &consumed, previous_ce);
set_index_entry(istate, i, ce);
src_offset += consumed;
diff --git a/ref-filter.c b/ref-filter.c
index fd1cb14b0f..914908fac5 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1722,6 +1722,8 @@ char *get_head_description(void)
} else
strbuf_addstr(&desc, _("(no branch)"));
+ wt_status_state_free_buffers(&state);
+
return strbuf_detach(&desc, NULL);
}
diff --git a/reflog-walk.c b/reflog-walk.c
index 7aa6595a51..8a4d8fa3bd 100644
--- a/reflog-walk.c
+++ b/reflog-walk.c
@@ -55,7 +55,7 @@ static void free_complete_reflog(struct complete_reflogs *array)
free(array);
}
-static void complete_reflogs_clear(void *util, const char *str)
+static void complete_reflogs_clear(void *util, const char *str UNUSED)
{
struct complete_reflogs *array = util;
free_complete_reflog(array);
diff --git a/reflog.c b/reflog.c
index d258fd3199..78e9350e20 100644
--- a/reflog.c
+++ b/reflog.c
@@ -312,16 +312,9 @@ static int push_tip_to_list(const char *refname UNUSED,
static int is_head(const char *refname)
{
- switch (ref_type(refname)) {
- case REF_TYPE_OTHER_PSEUDOREF:
- case REF_TYPE_MAIN_PSEUDOREF:
- if (parse_worktree_ref(refname, NULL, NULL, &refname))
- BUG("not a worktree ref: %s", refname);
- break;
- default:
- break;
- }
- return !strcmp(refname, "HEAD");
+ const char *stripped_refname;
+ parse_worktree_ref(refname, NULL, NULL, &stripped_refname);
+ return !strcmp(stripped_refname, "HEAD");
}
void reflog_expiry_prepare(const char *refname,
diff --git a/refs.c b/refs.c
index c89d558892..1491ae937e 100644
--- a/refs.c
+++ b/refs.c
@@ -811,7 +811,7 @@ int dwim_log(const char *str, int len, struct object_id *oid, char **log)
return repo_dwim_log(the_repository, str, len, oid, log);
}
-static int is_per_worktree_ref(const char *refname)
+int is_per_worktree_ref(const char *refname)
{
return starts_with(refname, "refs/worktree/") ||
starts_with(refname, "refs/bisect/") ||
@@ -827,37 +827,63 @@ static int is_pseudoref_syntax(const char *refname)
return 0;
}
+ /*
+ * HEAD is not a pseudoref, but it certainly uses the
+ * pseudoref syntax.
+ */
return 1;
}
-static int is_main_pseudoref_syntax(const char *refname)
-{
- return skip_prefix(refname, "main-worktree/", &refname) &&
- *refname &&
- is_pseudoref_syntax(refname);
+static int is_current_worktree_ref(const char *ref) {
+ return is_pseudoref_syntax(ref) || is_per_worktree_ref(ref);
}
-static int is_other_pseudoref_syntax(const char *refname)
+enum ref_worktree_type parse_worktree_ref(const char *maybe_worktree_ref,
+ const char **worktree_name, int *worktree_name_length,
+ const char **bare_refname)
{
- if (!skip_prefix(refname, "worktrees/", &refname))
- return 0;
- refname = strchr(refname, '/');
- if (!refname || !refname[1])
- return 0;
- return is_pseudoref_syntax(refname + 1);
-}
+ const char *name_dummy;
+ int name_length_dummy;
+ const char *ref_dummy;
-enum ref_type ref_type(const char *refname)
-{
- if (is_per_worktree_ref(refname))
- return REF_TYPE_PER_WORKTREE;
- if (is_pseudoref_syntax(refname))
- return REF_TYPE_PSEUDOREF;
- if (is_main_pseudoref_syntax(refname))
- return REF_TYPE_MAIN_PSEUDOREF;
- if (is_other_pseudoref_syntax(refname))
- return REF_TYPE_OTHER_PSEUDOREF;
- return REF_TYPE_NORMAL;
+ if (!worktree_name)
+ worktree_name = &name_dummy;
+ if (!worktree_name_length)
+ worktree_name_length = &name_length_dummy;
+ if (!bare_refname)
+ bare_refname = &ref_dummy;
+
+ if (skip_prefix(maybe_worktree_ref, "worktrees/", bare_refname)) {
+ const char *slash = strchr(*bare_refname, '/');
+
+ *worktree_name = *bare_refname;
+ if (!slash) {
+ *worktree_name_length = strlen(*worktree_name);
+
+ /* This is an error condition, and the caller tell because the bare_refname is "" */
+ *bare_refname = *worktree_name + *worktree_name_length;
+ return REF_WORKTREE_OTHER;
+ }
+
+ *worktree_name_length = slash - *bare_refname;
+ *bare_refname = slash + 1;
+
+ if (is_current_worktree_ref(*bare_refname))
+ return REF_WORKTREE_OTHER;
+ }
+
+ *worktree_name = NULL;
+ *worktree_name_length = 0;
+
+ if (skip_prefix(maybe_worktree_ref, "main-worktree/", bare_refname)
+ && is_current_worktree_ref(*bare_refname))
+ return REF_WORKTREE_MAIN;
+
+ *bare_refname = maybe_worktree_ref;
+ if (is_current_worktree_ref(maybe_worktree_ref))
+ return REF_WORKTREE_CURRENT;
+
+ return REF_WORKTREE_SHARED;
}
long get_files_ref_lock_timeout_ms(void)
diff --git a/refs.h b/refs.h
index d6575b8c2b..8958717a17 100644
--- a/refs.h
+++ b/refs.h
@@ -820,15 +820,34 @@ int parse_hide_refs_config(const char *var, const char *value, const char *);
*/
int ref_is_hidden(const char *, const char *);
-enum ref_type {
- REF_TYPE_PER_WORKTREE, /* refs inside refs/ but not shared */
- REF_TYPE_PSEUDOREF, /* refs outside refs/ in current worktree */
- REF_TYPE_MAIN_PSEUDOREF, /* pseudo refs from the main worktree */
- REF_TYPE_OTHER_PSEUDOREF, /* pseudo refs from other worktrees */
- REF_TYPE_NORMAL, /* normal/shared refs inside refs/ */
+/* Is this a per-worktree ref living in the refs/ namespace? */
+int is_per_worktree_ref(const char *refname);
+
+/* Describes how a refname relates to worktrees */
+enum ref_worktree_type {
+ REF_WORKTREE_CURRENT, /* implicitly per worktree, eg. HEAD or
+ refs/bisect/SOMETHING */
+ REF_WORKTREE_MAIN, /* explicitly in main worktree, eg.
+ main-worktree/HEAD */
+ REF_WORKTREE_OTHER, /* explicitly in named worktree, eg.
+ worktrees/bla/HEAD */
+ REF_WORKTREE_SHARED, /* the default, eg. refs/heads/main */
};
-enum ref_type ref_type(const char *refname);
+/*
+ * Parse a `maybe_worktree_ref` as a ref that possibly refers to a worktree ref
+ * (ie. either REFNAME, main-worktree/REFNAME or worktree/WORKTREE/REFNAME). It
+ * returns what kind of ref was found, and in case of REF_WORKTREE_OTHER, the
+ * worktree name is returned in `worktree_name` (pointing into
+ * `maybe_worktree_ref`) and `worktree_name_length`. The bare refname (the
+ * refname stripped of prefixes) is returned in `bare_refname`. The
+ * `worktree_name`, `worktree_name_length` and `bare_refname` arguments may be
+ * NULL.
+ */
+enum ref_worktree_type parse_worktree_ref(const char *maybe_worktree_ref,
+ const char **worktree_name,
+ int *worktree_name_length,
+ const char **bare_refname);
enum expire_reflog_flags {
EXPIRE_REFLOGS_DRY_RUN = 1 << 0,
diff --git a/refs/files-backend.c b/refs/files-backend.c
index e4009b3c42..b89954355d 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -138,44 +138,30 @@ static struct files_ref_store *files_downcast(struct ref_store *ref_store,
return refs;
}
-static void files_reflog_path_other_worktrees(struct files_ref_store *refs,
- struct strbuf *sb,
- const char *refname)
-{
- const char *real_ref;
- const char *worktree_name;
- int length;
-
- if (parse_worktree_ref(refname, &worktree_name, &length, &real_ref))
- BUG("refname %s is not a other-worktree ref", refname);
-
- if (worktree_name)
- strbuf_addf(sb, "%s/worktrees/%.*s/logs/%s", refs->gitcommondir,
- length, worktree_name, real_ref);
- else
- strbuf_addf(sb, "%s/logs/%s", refs->gitcommondir,
- real_ref);
-}
-
static void files_reflog_path(struct files_ref_store *refs,
struct strbuf *sb,
const char *refname)
{
- switch (ref_type(refname)) {
- case REF_TYPE_PER_WORKTREE:
- case REF_TYPE_PSEUDOREF:
+ const char *bare_refname;
+ const char *wtname;
+ int wtname_len;
+ enum ref_worktree_type wt_type = parse_worktree_ref(
+ refname, &wtname, &wtname_len, &bare_refname);
+
+ switch (wt_type) {
+ case REF_WORKTREE_CURRENT:
strbuf_addf(sb, "%s/logs/%s", refs->base.gitdir, refname);
break;
- case REF_TYPE_OTHER_PSEUDOREF:
- case REF_TYPE_MAIN_PSEUDOREF:
- files_reflog_path_other_worktrees(refs, sb, refname);
+ case REF_WORKTREE_SHARED:
+ case REF_WORKTREE_MAIN:
+ strbuf_addf(sb, "%s/logs/%s", refs->gitcommondir, bare_refname);
break;
- case REF_TYPE_NORMAL:
- strbuf_addf(sb, "%s/logs/%s", refs->gitcommondir, refname);
+ case REF_WORKTREE_OTHER:
+ strbuf_addf(sb, "%s/worktrees/%.*s/logs/%s", refs->gitcommondir,
+ wtname_len, wtname, bare_refname);
break;
default:
- BUG("unknown ref type %d of ref %s",
- ref_type(refname), refname);
+ BUG("unknown ref type %d of ref %s", wt_type, refname);
}
}
@@ -183,22 +169,25 @@ static void files_ref_path(struct files_ref_store *refs,
struct strbuf *sb,
const char *refname)
{
- switch (ref_type(refname)) {
- case REF_TYPE_PER_WORKTREE:
- case REF_TYPE_PSEUDOREF:
+ const char *bare_refname;
+ const char *wtname;
+ int wtname_len;
+ enum ref_worktree_type wt_type = parse_worktree_ref(
+ refname, &wtname, &wtname_len, &bare_refname);
+ switch (wt_type) {
+ case REF_WORKTREE_CURRENT:
strbuf_addf(sb, "%s/%s", refs->base.gitdir, refname);
break;
- case REF_TYPE_MAIN_PSEUDOREF:
- if (!skip_prefix(refname, "main-worktree/", &refname))
- BUG("ref %s is not a main pseudoref", refname);
- /* fallthrough */
- case REF_TYPE_OTHER_PSEUDOREF:
- case REF_TYPE_NORMAL:
- strbuf_addf(sb, "%s/%s", refs->gitcommondir, refname);
+ case REF_WORKTREE_OTHER:
+ strbuf_addf(sb, "%s/worktrees/%.*s/%s", refs->gitcommondir,
+ wtname_len, wtname, bare_refname);
+ break;
+ case REF_WORKTREE_SHARED:
+ case REF_WORKTREE_MAIN:
+ strbuf_addf(sb, "%s/%s", refs->gitcommondir, bare_refname);
break;
default:
- BUG("unknown ref type %d of ref %s",
- ref_type(refname), refname);
+ BUG("unknown ref type %d of ref %s", wt_type, refname);
}
}
@@ -771,7 +760,8 @@ static int files_ref_iterator_advance(struct ref_iterator *ref_iterator)
while ((ok = ref_iterator_advance(iter->iter0)) == ITER_OK) {
if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
- ref_type(iter->iter0->refname) != REF_TYPE_PER_WORKTREE)
+ parse_worktree_ref(iter->iter0->refname, NULL, NULL,
+ NULL) != REF_WORKTREE_CURRENT)
continue;
if ((iter->flags & DO_FOR_EACH_OMIT_DANGLING_SYMREFS) &&
@@ -1178,7 +1168,8 @@ static int should_pack_ref(const char *refname,
unsigned int pack_flags)
{
/* Do not pack per-worktree refs: */
- if (ref_type(refname) != REF_TYPE_NORMAL)
+ if (parse_worktree_ref(refname, NULL, NULL, NULL) !=
+ REF_WORKTREE_SHARED)
return 0;
/* Do not pack non-tags unless PACK_REFS_ALL is set: */
@@ -2267,7 +2258,8 @@ static enum iterator_selection reflog_iterator_select(
*/
return ITER_SELECT_0;
} else if (iter_common) {
- if (ref_type(iter_common->refname) == REF_TYPE_NORMAL)
+ if (parse_worktree_ref(iter_common->refname, NULL, NULL,
+ NULL) == REF_WORKTREE_SHARED)
return ITER_SELECT_1;
/*
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index 43cdb97f8b..c1c71d183e 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -862,7 +862,7 @@ static int packed_ref_iterator_advance(struct ref_iterator *ref_iterator)
while ((ok = next_record(iter)) == ITER_OK) {
if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
- ref_type(iter->base.refname) != REF_TYPE_PER_WORKTREE)
+ !is_per_worktree_ref(iter->base.refname))
continue;
if (!(iter->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
diff --git a/revision.c b/revision.c
index 36e31942ce..0760e78936 100644
--- a/revision.c
+++ b/revision.c
@@ -47,13 +47,6 @@ static inline int want_ancestry(const struct rev_info *revs);
void show_object_with_name(FILE *out, struct object *obj, const char *name)
{
fprintf(out, "%s ", oid_to_hex(&obj->oid));
- /*
- * This "for (const char *p = ..." is made as a first step towards
- * making use of such declarations elsewhere in our codebase. If
- * it causes compilation problems on your platform, please report
- * it to the Git mailing list at git@vger.kernel.org. In the meantime,
- * adding -std=gnu99 to CFLAGS may help if you are with older GCC.
- */
for (const char *p = name; *p && *p != '\n'; p++)
fputc(*p, out);
fputc('\n', out);
@@ -2120,9 +2113,8 @@ static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int fl
int exclude_parent = 1;
if (mark[2]) {
- char *end;
- exclude_parent = strtoul(mark + 2, &end, 10);
- if (*end != '\0' || !exclude_parent)
+ if (strtol_i(mark + 2, 10, &exclude_parent) ||
+ exclude_parent < 1)
return -1;
}
diff --git a/run-command.c b/run-command.c
index 5ec3a46dcc..c772acd743 100644
--- a/run-command.c
+++ b/run-command.c
@@ -1496,16 +1496,8 @@ enum child_state {
GIT_CP_WAIT_CLEANUP,
};
-int run_processes_parallel_ungroup;
struct parallel_processes {
- void *data;
-
- int max_processes;
- int nr_processes;
-
- get_next_task_fn get_next_task;
- start_failure_fn start_failure;
- task_finished_fn task_finished;
+ size_t nr_processes;
struct {
enum child_state state;
@@ -1520,81 +1512,60 @@ struct parallel_processes {
struct pollfd *pfd;
unsigned shutdown : 1;
- unsigned ungroup : 1;
- int output_owner;
+ size_t output_owner;
struct strbuf buffered_output; /* of finished children */
};
-static int default_start_failure(struct strbuf *out,
- void *pp_cb,
- void *pp_task_cb)
-{
- return 0;
-}
+struct parallel_processes_for_signal {
+ const struct run_process_parallel_opts *opts;
+ const struct parallel_processes *pp;
+};
-static int default_task_finished(int result,
- struct strbuf *out,
- void *pp_cb,
- void *pp_task_cb)
+static void kill_children(const struct parallel_processes *pp,
+ const struct run_process_parallel_opts *opts,
+ int signo)
{
- return 0;
+ for (size_t i = 0; i < opts->processes; i++)
+ if (pp->children[i].state == GIT_CP_WORKING)
+ kill(pp->children[i].process.pid, signo);
}
-static void kill_children(struct parallel_processes *pp, int signo)
+static void kill_children_signal(const struct parallel_processes_for_signal *pp_sig,
+ int signo)
{
- int i, n = pp->max_processes;
-
- for (i = 0; i < n; i++)
- if (pp->children[i].state == GIT_CP_WORKING)
- kill(pp->children[i].process.pid, signo);
+ kill_children(pp_sig->pp, pp_sig->opts, signo);
}
-static struct parallel_processes *pp_for_signal;
+static struct parallel_processes_for_signal *pp_for_signal;
static void handle_children_on_signal(int signo)
{
- kill_children(pp_for_signal, signo);
+ kill_children_signal(pp_for_signal, signo);
sigchain_pop(signo);
raise(signo);
}
static void pp_init(struct parallel_processes *pp,
- int n,
- get_next_task_fn get_next_task,
- start_failure_fn start_failure,
- task_finished_fn task_finished,
- void *data, int ungroup)
+ const struct run_process_parallel_opts *opts,
+ struct parallel_processes_for_signal *pp_sig)
{
- int i;
+ const size_t n = opts->processes;
- if (n < 1)
- n = online_cpus();
+ if (!n)
+ BUG("you must provide a non-zero number of processes!");
- pp->max_processes = n;
+ trace_printf("run_processes_parallel: preparing to run up to %"PRIuMAX" tasks",
+ (uintmax_t)n);
- trace_printf("run_processes_parallel: preparing to run up to %d tasks", n);
-
- pp->data = data;
- if (!get_next_task)
+ if (!opts->get_next_task)
BUG("you need to specify a get_next_task function");
- pp->get_next_task = get_next_task;
-
- pp->start_failure = start_failure ? start_failure : default_start_failure;
- pp->task_finished = task_finished ? task_finished : default_task_finished;
- pp->nr_processes = 0;
- pp->output_owner = 0;
- pp->shutdown = 0;
- pp->ungroup = ungroup;
CALLOC_ARRAY(pp->children, n);
- if (pp->ungroup)
- pp->pfd = NULL;
- else
+ if (!opts->ungroup)
CALLOC_ARRAY(pp->pfd, n);
- strbuf_init(&pp->buffered_output, 0);
- for (i = 0; i < n; i++) {
+ for (size_t i = 0; i < n; i++) {
strbuf_init(&pp->children[i].err, 0);
child_process_init(&pp->children[i].process);
if (pp->pfd) {
@@ -1603,16 +1574,17 @@ static void pp_init(struct parallel_processes *pp,
}
}
- pp_for_signal = pp;
+ pp_sig->pp = pp;
+ pp_sig->opts = opts;
+ pp_for_signal = pp_sig;
sigchain_push_common(handle_children_on_signal);
}
-static void pp_cleanup(struct parallel_processes *pp)
+static void pp_cleanup(struct parallel_processes *pp,
+ const struct run_process_parallel_opts *opts)
{
- int i;
-
trace_printf("run_processes_parallel: done");
- for (i = 0; i < pp->max_processes; i++) {
+ for (size_t i = 0; i < opts->processes; i++) {
strbuf_release(&pp->children[i].err);
child_process_clear(&pp->children[i].process);
}
@@ -1637,39 +1609,45 @@ static void pp_cleanup(struct parallel_processes *pp)
* <0 no new job was started, user wishes to shutdown early. Use negative code
* to signal the children.
*/
-static int pp_start_one(struct parallel_processes *pp)
+static int pp_start_one(struct parallel_processes *pp,
+ const struct run_process_parallel_opts *opts)
{
- int i, code;
+ size_t i;
+ int code;
- for (i = 0; i < pp->max_processes; i++)
+ for (i = 0; i < opts->processes; i++)
if (pp->children[i].state == GIT_CP_FREE)
break;
- if (i == pp->max_processes)
+ if (i == opts->processes)
BUG("bookkeeping is hard");
- code = pp->get_next_task(&pp->children[i].process,
- pp->ungroup ? NULL : &pp->children[i].err,
- pp->data,
- &pp->children[i].data);
+ code = opts->get_next_task(&pp->children[i].process,
+ opts->ungroup ? NULL : &pp->children[i].err,
+ opts->data,
+ &pp->children[i].data);
if (!code) {
- if (!pp->ungroup) {
+ if (!opts->ungroup) {
strbuf_addbuf(&pp->buffered_output, &pp->children[i].err);
strbuf_reset(&pp->children[i].err);
}
return 1;
}
- if (!pp->ungroup) {
+ if (!opts->ungroup) {
pp->children[i].process.err = -1;
pp->children[i].process.stdout_to_stderr = 1;
}
pp->children[i].process.no_stdin = 1;
if (start_command(&pp->children[i].process)) {
- code = pp->start_failure(pp->ungroup ? NULL :
- &pp->children[i].err,
- pp->data,
- pp->children[i].data);
- if (!pp->ungroup) {
+ if (opts->start_failure)
+ code = opts->start_failure(opts->ungroup ? NULL :
+ &pp->children[i].err,
+ opts->data,
+ pp->children[i].data);
+ else
+ code = 0;
+
+ if (!opts->ungroup) {
strbuf_addbuf(&pp->buffered_output, &pp->children[i].err);
strbuf_reset(&pp->children[i].err);
}
@@ -1685,19 +1663,21 @@ static int pp_start_one(struct parallel_processes *pp)
return 0;
}
-static void pp_buffer_stderr(struct parallel_processes *pp, int output_timeout)
+static void pp_buffer_stderr(struct parallel_processes *pp,
+ const struct run_process_parallel_opts *opts,
+ int output_timeout)
{
int i;
- while ((i = poll(pp->pfd, pp->max_processes, output_timeout)) < 0) {
+ while ((i = poll(pp->pfd, opts->processes, output_timeout) < 0)) {
if (errno == EINTR)
continue;
- pp_cleanup(pp);
+ pp_cleanup(pp, opts);
die_errno("poll");
}
/* Buffer output from all pipes. */
- for (i = 0; i < pp->max_processes; i++) {
+ for (size_t i = 0; i < opts->processes; i++) {
if (pp->children[i].state == GIT_CP_WORKING &&
pp->pfd[i].revents & (POLLIN | POLLHUP)) {
int n = strbuf_read_once(&pp->children[i].err,
@@ -1712,9 +1692,9 @@ static void pp_buffer_stderr(struct parallel_processes *pp, int output_timeout)
}
}
-static void pp_output(struct parallel_processes *pp)
+static void pp_output(const struct parallel_processes *pp)
{
- int i = pp->output_owner;
+ size_t i = pp->output_owner;
if (pp->children[i].state == GIT_CP_WORKING &&
pp->children[i].err.len) {
@@ -1723,24 +1703,28 @@ static void pp_output(struct parallel_processes *pp)
}
}
-static int pp_collect_finished(struct parallel_processes *pp)
+static int pp_collect_finished(struct parallel_processes *pp,
+ const struct run_process_parallel_opts *opts)
{
- int i, code;
- int n = pp->max_processes;
+ int code;
+ size_t i;
int result = 0;
while (pp->nr_processes > 0) {
- for (i = 0; i < pp->max_processes; i++)
+ for (i = 0; i < opts->processes; i++)
if (pp->children[i].state == GIT_CP_WAIT_CLEANUP)
break;
- if (i == pp->max_processes)
+ if (i == opts->processes)
break;
code = finish_command(&pp->children[i].process);
- code = pp->task_finished(code, pp->ungroup ? NULL :
- &pp->children[i].err, pp->data,
- pp->children[i].data);
+ if (opts->task_finished)
+ code = opts->task_finished(code, opts->ungroup ? NULL :
+ &pp->children[i].err, opts->data,
+ pp->children[i].data);
+ else
+ code = 0;
if (code)
result = code;
@@ -1753,12 +1737,14 @@ static int pp_collect_finished(struct parallel_processes *pp)
pp->pfd[i].fd = -1;
child_process_init(&pp->children[i].process);
- if (pp->ungroup) {
+ if (opts->ungroup) {
; /* no strbuf_*() work to do here */
} else if (i != pp->output_owner) {
strbuf_addbuf(&pp->buffered_output, &pp->children[i].err);
strbuf_reset(&pp->children[i].err);
} else {
+ const size_t n = opts->processes;
+
strbuf_write(&pp->children[i].err, stderr);
strbuf_reset(&pp->children[i].err);
@@ -1783,76 +1769,60 @@ static int pp_collect_finished(struct parallel_processes *pp)
return result;
}
-int run_processes_parallel(int n,
- get_next_task_fn get_next_task,
- start_failure_fn start_failure,
- task_finished_fn task_finished,
- void *pp_cb)
+void run_processes_parallel(const struct run_process_parallel_opts *opts)
{
int i, code;
int output_timeout = 100;
int spawn_cap = 4;
- int ungroup = run_processes_parallel_ungroup;
- struct parallel_processes pp;
-
- /* unset for the next API user */
- run_processes_parallel_ungroup = 0;
-
- pp_init(&pp, n, get_next_task, start_failure, task_finished, pp_cb,
- ungroup);
+ struct parallel_processes_for_signal pp_sig;
+ struct parallel_processes pp = {
+ .buffered_output = STRBUF_INIT,
+ };
+ /* options */
+ const char *tr2_category = opts->tr2_category;
+ const char *tr2_label = opts->tr2_label;
+ const int do_trace2 = tr2_category && tr2_label;
+
+ if (do_trace2)
+ trace2_region_enter_printf(tr2_category, tr2_label, NULL,
+ "max:%d", opts->processes);
+
+ pp_init(&pp, opts, &pp_sig);
while (1) {
for (i = 0;
i < spawn_cap && !pp.shutdown &&
- pp.nr_processes < pp.max_processes;
+ pp.nr_processes < opts->processes;
i++) {
- code = pp_start_one(&pp);
+ code = pp_start_one(&pp, opts);
if (!code)
continue;
if (code < 0) {
pp.shutdown = 1;
- kill_children(&pp, -code);
+ kill_children(&pp, opts, -code);
}
break;
}
if (!pp.nr_processes)
break;
- if (ungroup) {
- int i;
-
- for (i = 0; i < pp.max_processes; i++)
+ if (opts->ungroup) {
+ for (size_t i = 0; i < opts->processes; i++)
pp.children[i].state = GIT_CP_WAIT_CLEANUP;
} else {
- pp_buffer_stderr(&pp, output_timeout);
+ pp_buffer_stderr(&pp, opts, output_timeout);
pp_output(&pp);
}
- code = pp_collect_finished(&pp);
+ code = pp_collect_finished(&pp, opts);
if (code) {
pp.shutdown = 1;
if (code < 0)
- kill_children(&pp, -code);
+ kill_children(&pp, opts,-code);
}
}
- pp_cleanup(&pp);
- return 0;
-}
-
-int run_processes_parallel_tr2(int n, get_next_task_fn get_next_task,
- start_failure_fn start_failure,
- task_finished_fn task_finished, void *pp_cb,
- const char *tr2_category, const char *tr2_label)
-{
- int result;
+ pp_cleanup(&pp, opts);
- trace2_region_enter_printf(tr2_category, tr2_label, NULL, "max:%d",
- ((n < 1) ? online_cpus() : n));
-
- result = run_processes_parallel(n, get_next_task, start_failure,
- task_finished, pp_cb);
-
- trace2_region_leave(tr2_category, tr2_label, NULL);
-
- return result;
+ if (do_trace2)
+ trace2_region_leave(tr2_category, tr2_label, NULL);
}
int run_auto_maintenance(int quiet)
diff --git a/run-command.h b/run-command.h
index 0e85e5846a..e3e1ea01ad 100644
--- a/run-command.h
+++ b/run-command.h
@@ -459,17 +459,64 @@ typedef int (*task_finished_fn)(int result,
void *pp_task_cb);
/**
- * Runs up to n processes at the same time. Whenever a process can be
- * started, the callback get_next_task_fn is called to obtain the data
+ * Option used by run_processes_parallel(), { 0 }-initialized means no
+ * options.
+ */
+struct run_process_parallel_opts
+{
+ /**
+ * tr2_category & tr2_label: sets the trace2 category and label for
+ * logging. These must either be unset, or both of them must be set.
+ */
+ const char *tr2_category;
+ const char *tr2_label;
+
+ /**
+ * processes: see 'processes' in run_processes_parallel() below.
+ */
+ size_t processes;
+
+ /**
+ * ungroup: see 'ungroup' in run_processes_parallel() below.
+ */
+ unsigned int ungroup:1;
+
+ /**
+ * get_next_task: See get_next_task_fn() above. This must be
+ * specified.
+ */
+ get_next_task_fn get_next_task;
+
+ /**
+ * start_failure: See start_failure_fn() above. This can be
+ * NULL to omit any special handling.
+ */
+ start_failure_fn start_failure;
+
+ /**
+ * task_finished: See task_finished_fn() above. This can be
+ * NULL to omit any special handling.
+ */
+ task_finished_fn task_finished;
+
+ /**
+ * data: user data, will be passed as "pp_cb" to the callback
+ * parameters.
+ */
+ void *data;
+};
+
+/**
+ * Options are passed via the "struct run_process_parallel_opts" above.
+ *
+ * Runs N 'processes' at the same time. Whenever a process can be
+ * started, the callback opts.get_next_task is called to obtain the data
* required to start another child process.
*
* The children started via this function run in parallel. Their output
* (both stdout and stderr) is routed to stderr in a manner that output
* from different tasks does not interleave (but see "ungroup" below).
*
- * start_failure_fn and task_finished_fn can be NULL to omit any
- * special handling.
- *
* If the "ungroup" option isn't specified, the API will set the
* "stdout_to_stderr" parameter in "struct child_process" and provide
* the callbacks with a "struct strbuf *out" parameter to write output
@@ -479,20 +526,8 @@ typedef int (*task_finished_fn)(int result,
* NULL "struct strbuf *out" parameter, and are responsible for
* emitting their own output, including dealing with any race
* conditions due to writing in parallel to stdout and stderr.
- * The "ungroup" option can be enabled by setting the global
- * "run_processes_parallel_ungroup" to "1" before invoking
- * run_processes_parallel(), it will be set back to "0" as soon as the
- * API reads that setting.
*/
-extern int run_processes_parallel_ungroup;
-int run_processes_parallel(int n,
- get_next_task_fn,
- start_failure_fn,
- task_finished_fn,
- void *pp_cb);
-int run_processes_parallel_tr2(int n, get_next_task_fn, start_failure_fn,
- task_finished_fn, void *pp_cb,
- const char *tr2_category, const char *tr2_label);
+void run_processes_parallel(const struct run_process_parallel_opts *opts);
/**
* Convenience function which prepares env for a command to be run in a
diff --git a/scalar.c b/scalar.c
index c5c1ce6891..6de9c0ee52 100644
--- a/scalar.c
+++ b/scalar.c
@@ -207,7 +207,10 @@ static int set_recommended_config(int reconfigure)
static int toggle_maintenance(int enable)
{
- return run_git("maintenance", enable ? "start" : "unregister", NULL);
+ return run_git("maintenance",
+ enable ? "start" : "unregister",
+ enable ? NULL : "--force",
+ NULL);
}
static int add_or_remove_enlistment(int add)
diff --git a/sequencer.c b/sequencer.c
index d26ede83c4..debb2ecbaf 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -915,7 +915,7 @@ int read_author_script(const char *path, char **name, char **email, char **date,
error(_("missing 'GIT_AUTHOR_EMAIL'"));
if (date_i == -2)
error(_("missing 'GIT_AUTHOR_DATE'"));
- if (date_i < 0 || email_i < 0 || date_i < 0 || err)
+ if (name_i < 0 || email_i < 0 || date_i < 0 || err)
goto finish;
*name = kv.items[name_i].util;
*email = kv.items[email_i].util;
@@ -6203,8 +6203,6 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)
return error(_("the script was already rearranged."));
}
- *commit_todo_item_at(&commit_todo, item->commit) = item;
-
parse_commit(item->commit);
commit_buffer = logmsg_reencode(item->commit, NULL, "UTF-8");
find_commit_subject(commit_buffer, &subject);
@@ -6271,6 +6269,8 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)
strhash(entry->subject));
hashmap_put(&subject2item, &entry->entry);
}
+
+ *commit_todo_item_at(&commit_todo, item->commit) = item;
}
if (rearranged) {
diff --git a/string-list.c b/string-list.c
index 549fc416d6..42bacaec55 100644
--- a/string-list.c
+++ b/string-list.c
@@ -156,7 +156,7 @@ void filter_string_list(struct string_list *list, int free_util,
list->nr = dst;
}
-static int item_is_not_empty(struct string_list_item *item, void *unused)
+static int item_is_not_empty(struct string_list_item *item, void *data UNUSED)
{
return *item->string != '\0';
}
diff --git a/string-list.h b/string-list.h
index d5a744e143..c7b0d5d000 100644
--- a/string-list.h
+++ b/string-list.h
@@ -141,7 +141,12 @@ void string_list_clear_func(struct string_list *list, string_list_clear_func_t c
int for_each_string_list(struct string_list *list,
string_list_each_func_t func, void *cb_data);
-/** Iterate over each item, as a macro. */
+/**
+ * Iterate over each item, as a macro.
+ *
+ * Be sure that 'list' is non-NULL. The macro cannot perform NULL
+ * checks due to -Werror=address errors.
+ */
#define for_each_string_list_item(item,list) \
for (item = (list)->items; \
item && item < (list)->items + (list)->nr; \
diff --git a/submodule-config.c b/submodule-config.c
index cd7ee236a1..4dc61b3a78 100644
--- a/submodule-config.c
+++ b/submodule-config.c
@@ -303,6 +303,8 @@ int parse_submodule_fetchjobs(const char *var, const char *value)
int fetchjobs = git_config_int(var, value);
if (fetchjobs < 0)
die(_("negative values not allowed for submodule.fetchJobs"));
+ if (!fetchjobs)
+ fetchjobs = online_cpus();
return fetchjobs;
}
diff --git a/submodule.c b/submodule.c
index 0a82aa9bdd..b958162d28 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1819,6 +1819,17 @@ int fetch_submodules(struct repository *r,
{
int i;
struct submodule_parallel_fetch spf = SPF_INIT;
+ const struct run_process_parallel_opts opts = {
+ .tr2_category = "submodule",
+ .tr2_label = "parallel/fetch",
+
+ .processes = max_parallel_jobs,
+
+ .get_next_task = get_next_submodule,
+ .start_failure = fetch_start_failure,
+ .task_finished = fetch_finish,
+ .data = &spf,
+ };
spf.r = r;
spf.command_line_option = command_line_option;
@@ -1840,12 +1851,7 @@ int fetch_submodules(struct repository *r,
calculate_changed_submodule_paths(r, &spf.changed_submodule_names);
string_list_sort(&spf.changed_submodule_names);
- run_processes_parallel_tr2(max_parallel_jobs,
- get_next_submodule,
- fetch_start_failure,
- fetch_finish,
- &spf,
- "submodule", "parallel/fetch");
+ run_processes_parallel(&opts);
if (spf.submodules_with_errors.len > 0)
fprintf(stderr, _("Errors during submodule fetch:\n%s"),
diff --git a/t/check-non-portable-shell.pl b/t/check-non-portable-shell.pl
index fd3303552b..dd8107cd7d 100755
--- a/t/check-non-portable-shell.pl
+++ b/t/check-non-portable-shell.pl
@@ -45,6 +45,7 @@ while (<>) {
/\bhead\s+-c\b/ and err 'head -c is not portable (use test_copy_bytes BYTES <file >out)';
/(?:\$\(seq|^\s*seq\b)/ and err 'seq is not portable (use test_seq)';
/\bgrep\b.*--file\b/ and err 'grep --file FILE is not portable (use grep -f FILE)';
+ /\b[ef]grep\b/ and err 'egrep/fgrep obsolescent (use grep -E/-F)';
/\bexport\s+[A-Za-z0-9_]*=/ and err '"export FOO=bar" is not portable (use FOO=bar && export FOO)';
/^\s*([A-Z0-9_]+=(\w*|(["']).*?\3)\s+)+(\w+)/ and exists($func{$4}) and
err '"FOO=bar shell_func" assignment extends beyond "shell_func"';
diff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c
index d20e1b7a18..f69709d674 100644
--- a/t/helper/test-path-utils.c
+++ b/t/helper/test-path-utils.c
@@ -8,7 +8,8 @@
* GIT_CEILING_DIRECTORIES. If the path is unusable for some reason,
* die with an explanation.
*/
-static int normalize_ceiling_entry(struct string_list_item *item, void *unused)
+static int normalize_ceiling_entry(struct string_list_item *item,
+ void *data UNUSED)
{
char *ceil = item->string;
diff --git a/t/helper/test-proc-receive.c b/t/helper/test-proc-receive.c
index cc08506cf0..a4b305f494 100644
--- a/t/helper/test-proc-receive.c
+++ b/t/helper/test-proc-receive.c
@@ -6,7 +6,7 @@
#include "test-tool.h"
static const char *proc_receive_usage[] = {
- "test-tool proc-receive [<options>...]",
+ "test-tool proc-receive [<options>]",
NULL
};
diff --git a/t/helper/test-run-command.c b/t/helper/test-run-command.c
index c9283b47af..3ecb830f4a 100644
--- a/t/helper/test-run-command.c
+++ b/t/helper/test-run-command.c
@@ -136,7 +136,7 @@ static const char * const testsuite_usage[] = {
static int testsuite(int argc, const char **argv)
{
struct testsuite suite = TESTSUITE_INIT;
- int max_jobs = 1, i, ret;
+ int max_jobs = 1, i, ret = 0;
DIR *dir;
struct dirent *d;
struct option options[] = {
@@ -152,6 +152,12 @@ static int testsuite(int argc, const char **argv)
"write JUnit-style XML files"),
OPT_END()
};
+ struct run_process_parallel_opts opts = {
+ .get_next_task = next_test,
+ .start_failure = test_failed,
+ .task_finished = test_finished,
+ .data = &suite,
+ };
argc = parse_options(argc, argv, NULL, options,
testsuite_usage, PARSE_OPT_STOP_AT_NON_OPTION);
@@ -192,8 +198,8 @@ static int testsuite(int argc, const char **argv)
fprintf(stderr, "Running %"PRIuMAX" tests (%d at a time)\n",
(uintmax_t)suite.tests.nr, max_jobs);
- ret = run_processes_parallel(max_jobs, next_test, test_failed,
- test_finished, &suite);
+ opts.processes = max_jobs;
+ run_processes_parallel(&opts);
if (suite.failed.nr > 0) {
ret = 1;
@@ -206,7 +212,7 @@ static int testsuite(int argc, const char **argv)
string_list_clear(&suite.tests, 0);
string_list_clear(&suite.failed, 0);
- return !!ret;
+ return ret;
}
static uint64_t my_random_next = 1234;
@@ -381,13 +387,17 @@ int cmd__run_command(int argc, const char **argv)
{
struct child_process proc = CHILD_PROCESS_INIT;
int jobs;
+ int ret;
+ struct run_process_parallel_opts opts = {
+ .data = &proc,
+ };
if (argc > 1 && !strcmp(argv[1], "testsuite"))
- exit(testsuite(argc - 1, argv + 1));
+ return testsuite(argc - 1, argv + 1);
if (!strcmp(argv[1], "inherited-handle"))
- exit(inherit_handle(argv[0]));
+ return inherit_handle(argv[0]);
if (!strcmp(argv[1], "inherited-handle-child"))
- exit(inherit_handle_child());
+ return inherit_handle_child();
if (argc >= 2 && !strcmp(argv[1], "quote-stress-test"))
return !!quote_stress_test(argc - 1, argv + 1);
@@ -404,41 +414,52 @@ int cmd__run_command(int argc, const char **argv)
argv += 2;
argc -= 2;
}
- if (argc < 3)
- return 1;
+ if (argc < 3) {
+ ret = 1;
+ goto cleanup;
+ }
strvec_pushv(&proc.args, (const char **)argv + 2);
if (!strcmp(argv[1], "start-command-ENOENT")) {
- if (start_command(&proc) < 0 && errno == ENOENT)
- return 0;
+ if (start_command(&proc) < 0 && errno == ENOENT) {
+ ret = 0;
+ goto cleanup;
+ }
fprintf(stderr, "FAIL %s\n", argv[1]);
return 1;
}
- if (!strcmp(argv[1], "run-command"))
- exit(run_command(&proc));
+ if (!strcmp(argv[1], "run-command")) {
+ ret = run_command(&proc);
+ goto cleanup;
+ }
if (!strcmp(argv[1], "--ungroup")) {
argv += 1;
argc -= 1;
- run_processes_parallel_ungroup = 1;
+ opts.ungroup = 1;
}
jobs = atoi(argv[2]);
strvec_clear(&proc.args);
strvec_pushv(&proc.args, (const char **)argv + 3);
- if (!strcmp(argv[1], "run-command-parallel"))
- exit(run_processes_parallel(jobs, parallel_next,
- NULL, NULL, &proc));
-
- if (!strcmp(argv[1], "run-command-abort"))
- exit(run_processes_parallel(jobs, parallel_next,
- NULL, task_finished, &proc));
-
- if (!strcmp(argv[1], "run-command-no-jobs"))
- exit(run_processes_parallel(jobs, no_job,
- NULL, task_finished, &proc));
-
- fprintf(stderr, "check usage\n");
- return 1;
+ if (!strcmp(argv[1], "run-command-parallel")) {
+ opts.get_next_task = parallel_next;
+ } else if (!strcmp(argv[1], "run-command-abort")) {
+ opts.get_next_task = parallel_next;
+ opts.task_finished = task_finished;
+ } else if (!strcmp(argv[1], "run-command-no-jobs")) {
+ opts.get_next_task = no_job;
+ opts.task_finished = task_finished;
+ } else {
+ ret = 1;
+ fprintf(stderr, "check usage\n");
+ goto cleanup;
+ }
+ opts.processes = jobs;
+ run_processes_parallel(&opts);
+ ret = 0;
+cleanup:
+ child_process_clear(&proc);
+ return ret;
}
diff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c
index e0e0c53d38..b7d117cd55 100644
--- a/t/helper/test-submodule.c
+++ b/t/helper/test-submodule.c
@@ -85,10 +85,17 @@ static int cmd__submodule_is_active(int argc, const char **argv)
return !is_submodule_active(the_repository, argv[0]);
}
-static int resolve_relative_url(int argc, const char **argv)
+static int cmd__submodule_resolve_relative_url(int argc, const char **argv)
{
char *remoteurl, *res;
const char *up_path, *url;
+ struct option options[] = {
+ OPT_END()
+ };
+ argc = parse_options(argc, argv, "test-tools", options,
+ submodule_resolve_relative_url_usage, 0);
+ if (argc != 3)
+ usage_with_options(submodule_resolve_relative_url_usage, options);
up_path = argv[0];
remoteurl = xstrdup(argv[1]);
@@ -104,19 +111,6 @@ static int resolve_relative_url(int argc, const char **argv)
return 0;
}
-static int cmd__submodule_resolve_relative_url(int argc, const char **argv)
-{
- struct option options[] = {
- OPT_END()
- };
- argc = parse_options(argc, argv, "test-tools", options,
- submodule_resolve_relative_url_usage, 0);
- if (argc != 3)
- usage_with_options(submodule_resolve_relative_url_usage, options);
-
- return resolve_relative_url(argc, argv);
-}
-
static struct test_cmd cmds[] = {
{ "check-name", cmd__submodule_check_name },
{ "is-active", cmd__submodule_is_active },
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index 497b9b9d92..706799391b 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -80,6 +80,8 @@ PassEnv LSAN_OPTIONS
PassEnv GIT_TRACE
PassEnv GIT_CONFIG_NOSYSTEM
PassEnv GIT_TEST_SIDEBAND_ALL
+PassEnv LANG
+PassEnv LC_ALL
Alias /dumb/ www/
Alias /auth/dumb/ www/auth/dumb/
diff --git a/t/perf/p2000-sparse-operations.sh b/t/perf/p2000-sparse-operations.sh
index fce8151d41..3242cfe91a 100755
--- a/t/perf/p2000-sparse-operations.sh
+++ b/t/perf/p2000-sparse-operations.sh
@@ -124,5 +124,6 @@ test_perf_on_all git read-tree -mu HEAD
test_perf_on_all git checkout-index -f --all
test_perf_on_all git update-index --add --remove $SPARSE_CONE/a
test_perf_on_all "git rm -f $SPARSE_CONE/a && git checkout HEAD -- $SPARSE_CONE/a"
+test_perf_on_all git grep --cached --sparse bogus -- "f2/f1/f1/*"
test_done
diff --git a/t/perf/run b/t/perf/run
index 33da4d2aba..34115edec3 100755
--- a/t/perf/run
+++ b/t/perf/run
@@ -232,10 +232,10 @@ then
)
elif test -n "$GIT_PERF_SUBSECTION"
then
- egrep "^$GIT_PERF_SUBSECTION\$" "$TEST_RESULTS_DIR"/run_subsections.names >/dev/null ||
+ grep -E "^$GIT_PERF_SUBSECTION\$" "$TEST_RESULTS_DIR"/run_subsections.names >/dev/null ||
die "subsection '$GIT_PERF_SUBSECTION' not found in '$GIT_PERF_CONFIG_FILE'"
- egrep "^$GIT_PERF_SUBSECTION\$" "$TEST_RESULTS_DIR"/run_subsections.names | while read -r subsec
+ grep -E "^$GIT_PERF_SUBSECTION\$" "$TEST_RESULTS_DIR"/run_subsections.names | while read -r subsec
do
(
GIT_PERF_SUBSECTION="$subsec"
diff --git a/t/t0033-safe-directory.sh b/t/t0033-safe-directory.sh
index aecb308cf6..dc3496897a 100755
--- a/t/t0033-safe-directory.sh
+++ b/t/t0033-safe-directory.sh
@@ -71,4 +71,13 @@ test_expect_success 'safe.directory=*, but is reset' '
expect_rejected_dir
'
+test_expect_success 'safe.directory in included file' '
+ cat >gitconfig-include <<-EOF &&
+ [safe]
+ directory = "$(pwd)"
+ EOF
+ git config --global --add include.path "$(pwd)/gitconfig-include" &&
+ git status
+'
+
test_done
diff --git a/t/t0035-safe-bare-repository.sh b/t/t0035-safe-bare-repository.sh
index ecbdc8238d..11c15a48aa 100755
--- a/t/t0035-safe-bare-repository.sh
+++ b/t/t0035-safe-bare-repository.sh
@@ -51,4 +51,13 @@ test_expect_success 'safe.bareRepository on the command line' '
-c safe.bareRepository=all
'
+test_expect_success 'safe.bareRepository in included file' '
+ cat >gitconfig-include <<-\EOF &&
+ [safe]
+ bareRepository = explicit
+ EOF
+ git config --global --add include.path "$(pwd)/gitconfig-include" &&
+ expect_rejected -C outer-repo/bare-repo
+'
+
test_done
diff --git a/t/t0410-partial-clone.sh b/t/t0410-partial-clone.sh
index 1e864cf317..5b7bee888d 100755
--- a/t/t0410-partial-clone.sh
+++ b/t/t0410-partial-clone.sh
@@ -215,6 +215,20 @@ test_expect_success 'fetching of missing objects' '
grep "$HASH" out
'
+test_expect_success 'fetching of a promised object that promisor remote no longer has' '
+ rm -f err &&
+ test_create_repo unreliable-server &&
+ git -C unreliable-server config uploadpack.allowanysha1inwant 1 &&
+ git -C unreliable-server config uploadpack.allowfilter 1 &&
+ test_commit -C unreliable-server foo &&
+
+ git clone --filter=blob:none --no-checkout "file://$(pwd)/unreliable-server" unreliable-client &&
+
+ rm -rf unreliable-server/.git/objects/* &&
+ test_must_fail git -C unreliable-client checkout HEAD 2>err &&
+ grep "could not fetch.*from promisor remote" err
+'
+
test_expect_success 'fetching of missing objects works with ref-in-want enabled' '
# ref-in-want requires protocol version 2
git -C server config protocol.version 2 &&
diff --git a/t/t0450-txt-doc-vs-help.sh b/t/t0450-txt-doc-vs-help.sh
new file mode 100755
index 0000000000..cd3969e852
--- /dev/null
+++ b/t/t0450-txt-doc-vs-help.sh
@@ -0,0 +1,172 @@
+#!/bin/sh
+
+test_description='assert (unbuilt) Documentation/*.txt and -h output
+
+Run this with --debug to see a summary of where we still fail to make
+the two versions consistent with one another.'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+test_expect_success 'setup: list of builtins' '
+ git --list-cmds=builtins >builtins
+'
+
+test_expect_success 'list of txt and help mismatches is sorted' '
+ sort -u "$TEST_DIRECTORY"/t0450/txt-help-mismatches >expect &&
+ if ! test_cmp expect "$TEST_DIRECTORY"/t0450/txt-help-mismatches
+ then
+ BUG "please keep the list of txt and help mismatches sorted"
+ fi
+'
+
+help_to_synopsis () {
+ builtin="$1" &&
+ out_dir="out/$builtin" &&
+ out="$out_dir/help.synopsis" &&
+ if test -f "$out"
+ then
+ echo "$out" &&
+ return 0
+ fi &&
+ mkdir -p "$out_dir" &&
+ test_expect_code 129 git $builtin -h >"$out.raw" 2>&1 &&
+ sed -n \
+ -e '1,/^$/ {
+ /^$/d;
+ s/^usage: //;
+ s/^ *or: //;
+ p;
+ }' <"$out.raw" >"$out" &&
+ echo "$out"
+}
+
+builtin_to_txt () {
+ echo "$GIT_BUILD_DIR/Documentation/git-$1.txt"
+}
+
+txt_to_synopsis () {
+ builtin="$1" &&
+ out_dir="out/$builtin" &&
+ out="$out_dir/txt.synopsis" &&
+ if test -f "$out"
+ then
+ echo "$out" &&
+ return 0
+ fi &&
+ b2t="$(builtin_to_txt "$builtin")" &&
+ sed -n \
+ -e '/^\[verse\]$/,/^$/ {
+ /^$/d;
+ /^\[verse\]$/d;
+
+ s/{litdd}/--/g;
+ s/'\''\(git[ a-z-]*\)'\''/\1/g;
+
+ p;
+ }' \
+ <"$b2t" >"$out" &&
+ echo "$out"
+}
+
+check_dashed_labels () {
+ ! grep -E "<[^>_-]+_" "$1"
+}
+
+HT=" "
+
+align_after_nl () {
+ builtin="$1" &&
+ len=$(printf "git %s " "$builtin" | wc -c) &&
+ pad=$(printf "%${len}s" "") &&
+
+ sed "s/^[ $HT][ $HT]*/$pad/"
+}
+
+test_debug '>failing'
+while read builtin
+do
+ # -h output assertions
+ test_expect_success "$builtin -h output has no \t" '
+ h2s="$(help_to_synopsis "$builtin")" &&
+ ! grep "$HT" "$h2s"
+ '
+
+ test_expect_success "$builtin -h output has dashed labels" '
+ check_dashed_labels "$(help_to_synopsis "$builtin")"
+ '
+
+ test_expect_success "$builtin -h output has consistent spacing" '
+ h2s="$(help_to_synopsis "$builtin")" &&
+ sed -n \
+ -e "/^ / {
+ s/[^ ].*//;
+ p;
+ }" \
+ <"$h2s" >help &&
+ sort -u help >help.ws &&
+ if test -s help.ws
+ then
+ test_line_count = 1 help.ws
+ fi
+ '
+
+ txt="$(builtin_to_txt "$builtin")" &&
+ preq="$(echo BUILTIN_TXT_$builtin | tr '[:lower:]-' '[:upper:]_')" &&
+
+ if test -f "$txt"
+ then
+ test_set_prereq "$preq"
+ fi &&
+
+ # *.txt output assertions
+ test_expect_success "$preq" "$builtin *.txt SYNOPSIS has dashed labels" '
+ check_dashed_labels "$(txt_to_synopsis "$builtin")"
+ '
+
+ # *.txt output consistency assertions
+ result=
+ if grep -q "^$builtin$" "$TEST_DIRECTORY"/t0450/txt-help-mismatches
+ then
+ result=failure
+ else
+ result=success
+ fi &&
+ test_expect_$result "$preq" "$builtin -h output and SYNOPSIS agree" '
+ t2s="$(txt_to_synopsis "$builtin")" &&
+ if test "$builtin" = "merge-tree"
+ then
+ test_when_finished "rm -f t2s.new" &&
+ sed -e '\''s/ (deprecated)$//g'\'' <"$t2s" >t2s.new
+ t2s=t2s.new
+ fi &&
+ h2s="$(help_to_synopsis "$builtin")" &&
+
+ # The *.txt and -h use different spacing for the
+ # alignment of continued usage output, normalize it.
+ align_after_nl "$builtin" <"$t2s" >txt &&
+ align_after_nl "$builtin" <"$h2s" >help &&
+ test_cmp txt help
+ '
+
+ if test_have_prereq "$preq" && test -e txt && test -e help
+ then
+ test_debug '
+ if test_cmp txt help >cmp 2>/dev/null
+ then
+ echo "=== DONE: $builtin ==="
+ else
+ echo "=== TODO: $builtin ===" &&
+ cat cmp
+ fi >>failing
+ '
+
+ # Not in test_expect_success in case --run is being
+ # used with --debug
+ rm -f txt help tmp 2>/dev/null
+ fi
+done <builtins
+
+test_debug 'say "$(cat failing)"'
+
+test_done
diff --git a/t/t0450/txt-help-mismatches b/t/t0450/txt-help-mismatches
new file mode 100644
index 0000000000..a0777acd66
--- /dev/null
+++ b/t/t0450/txt-help-mismatches
@@ -0,0 +1,58 @@
+add
+am
+apply
+archive
+bisect
+blame
+branch
+check-ref-format
+checkout
+checkout-index
+clone
+column
+config
+credential
+credential-cache
+credential-store
+fast-export
+fast-import
+fetch-pack
+fmt-merge-msg
+for-each-ref
+format-patch
+fsck-objects
+fsmonitor--daemon
+gc
+grep
+index-pack
+init-db
+log
+ls-files
+ls-tree
+mailinfo
+mailsplit
+maintenance
+merge
+merge-file
+merge-index
+merge-one-file
+multi-pack-index
+name-rev
+notes
+pack-objects
+push
+range-diff
+rebase
+remote
+remote-ext
+remote-fd
+repack
+reset
+restore
+rev-parse
+show
+stage
+switch
+update-index
+update-ref
+whatchanged
diff --git a/t/t1002-read-tree-m-u-2way.sh b/t/t1002-read-tree-m-u-2way.sh
index bd5313caec..cdc077ce12 100755
--- a/t/t1002-read-tree-m-u-2way.sh
+++ b/t/t1002-read-tree-m-u-2way.sh
@@ -154,7 +154,7 @@ test_expect_success \
read_tree_u_must_succeed --reset -u $treeH &&
echo frotz frotz >frotz &&
git update-index --add frotz &&
- if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi'
+ ! read_tree_u_must_succeed -m -u $treeH $treeM'
test_expect_success \
'9 - conflicting addition.' \
@@ -163,7 +163,7 @@ test_expect_success \
echo frotz frotz >frotz &&
git update-index --add frotz &&
echo frotz >frotz &&
- if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi'
+ ! read_tree_u_must_succeed -m -u $treeH $treeM'
test_expect_success \
'10 - path removed.' \
@@ -186,7 +186,7 @@ test_expect_success \
echo rezrov >rezrov &&
git update-index --add rezrov &&
echo rezrov rezrov >rezrov &&
- if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi'
+ ! read_tree_u_must_succeed -m -u $treeH $treeM'
test_expect_success \
'12 - unmatching local changes being removed.' \
@@ -194,7 +194,7 @@ test_expect_success \
read_tree_u_must_succeed --reset -u $treeH &&
echo rezrov rezrov >rezrov &&
git update-index --add rezrov &&
- if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi'
+ ! read_tree_u_must_succeed -m -u $treeH $treeM'
test_expect_success \
'13 - unmatching local changes being removed.' \
@@ -203,7 +203,7 @@ test_expect_success \
echo rezrov rezrov >rezrov &&
git update-index --add rezrov &&
echo rezrov >rezrov &&
- if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi'
+ ! read_tree_u_must_succeed -m -u $treeH $treeM'
cat >expected <<EOF
-100644 X 0 nitfol
@@ -251,7 +251,7 @@ test_expect_success \
read_tree_u_must_succeed --reset -u $treeH &&
echo bozbar bozbar >bozbar &&
git update-index --add bozbar &&
- if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi'
+ ! read_tree_u_must_succeed -m -u $treeH $treeM'
test_expect_success \
'17 - conflicting local change.' \
@@ -260,7 +260,7 @@ test_expect_success \
echo bozbar bozbar >bozbar &&
git update-index --add bozbar &&
echo bozbar bozbar bozbar >bozbar &&
- if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi'
+ ! read_tree_u_must_succeed -m -u $treeH $treeM'
test_expect_success \
'18 - local change already having a good result.' \
@@ -316,7 +316,7 @@ test_expect_success \
echo bozbar >bozbar &&
git update-index --add bozbar &&
echo gnusto gnusto >bozbar &&
- if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi'
+ ! read_tree_u_must_succeed -m -u $treeH $treeM'
# Also make sure we did not break DF vs DF/DF case.
test_expect_success \
diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh
index 4844922e57..801919009e 100755
--- a/t/t1092-sparse-checkout-compatibility.sh
+++ b/t/t1092-sparse-checkout-compatibility.sh
@@ -162,6 +162,19 @@ init_repos () {
git -C sparse-index sparse-checkout set deep
}
+init_repos_as_submodules () {
+ git reset --hard &&
+ init_repos &&
+ git submodule add ./full-checkout &&
+ git submodule add ./sparse-checkout &&
+ git submodule add ./sparse-index &&
+
+ git submodule status >actual &&
+ grep full-checkout actual &&
+ grep sparse-checkout actual &&
+ grep sparse-index actual
+}
+
run_on_sparse () {
(
cd sparse-checkout &&
@@ -1983,4 +1996,63 @@ test_expect_success 'sparse index is not expanded: rm' '
ensure_not_expanded rm -r deep
'
+test_expect_success 'grep with and --cached' '
+ init_repos &&
+
+ test_all_match git grep --cached a &&
+ test_all_match git grep --cached a -- "folder1/*"
+'
+
+test_expect_success 'grep is not expanded' '
+ init_repos &&
+
+ ensure_not_expanded grep a &&
+ ensure_not_expanded grep a -- deep/* &&
+
+ # All files within the folder1/* pathspec are sparse,
+ # so this command does not find any matches
+ ensure_not_expanded ! grep a -- folder1/* &&
+
+ # test out-of-cone pathspec with or without wildcard
+ ensure_not_expanded grep --cached a -- "folder1/a" &&
+ ensure_not_expanded grep --cached a -- "folder1/*" &&
+
+ # test in-cone pathspec with or without wildcard
+ ensure_not_expanded grep --cached a -- "deep/a" &&
+ ensure_not_expanded grep --cached a -- "deep/*"
+'
+
+# NEEDSWORK: when running `grep` in the superproject with --recurse-submodules,
+# Git expands the index of the submodules unexpectedly. Even though `grep`
+# builtin is marked as "command_requires_full_index = 0", this config is only
+# useful for the superproject. Namely, the submodules have their own configs,
+# which are _not_ populated by the one-time sparse-index feature switch.
+test_expect_failure 'grep within submodules is not expanded' '
+ init_repos_as_submodules &&
+
+ # do not use ensure_not_expanded() here, becasue `grep` should be
+ # run in the superproject, not in "./sparse-index"
+ GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
+ git grep --cached --recurse-submodules a -- "*/folder1/*" &&
+ test_region ! index ensure_full_index trace2.txt
+'
+
+# NEEDSWORK: this test is not actually testing the code. The design purpose
+# of this test is to verify the grep result when the submodules are using a
+# sparse-index. Namely, we want "folder1/" as a tree (a sparse directory); but
+# because of the index expansion, we are now grepping the "folder1/a" blob.
+# Because of the problem stated above 'grep within submodules is not expanded',
+# we don't have the ideal test environment yet.
+test_expect_success 'grep sparse directory within submodules' '
+ init_repos_as_submodules &&
+
+ cat >expect <<-\EOF &&
+ full-checkout/folder1/a:a
+ sparse-checkout/folder1/a:a
+ sparse-index/folder1/a:a
+ EOF
+ git grep --cached --recurse-submodules a -- "*/folder1/*" >actual &&
+ test_cmp actual expect
+'
+
test_done
diff --git a/t/t1304-default-acl.sh b/t/t1304-default-acl.sh
index 335d3f3211..c69ae41306 100755
--- a/t/t1304-default-acl.sh
+++ b/t/t1304-default-acl.sh
@@ -18,7 +18,7 @@ test_expect_success 'checking for a working acl setup' '
if setfacl -m d:m:rwx -m u:root:rwx . &&
getfacl . | grep user:root:rwx &&
touch should-have-readable-acl &&
- getfacl should-have-readable-acl | egrep "mask::?rw-"
+ getfacl should-have-readable-acl | grep -E "mask::?rw-"
then
test_set_prereq SETFACL
fi
@@ -34,7 +34,7 @@ check_perms_and_acl () {
getfacl "$1" > actual &&
grep -q "user:root:rwx" actual &&
grep -q "user:${LOGNAME}:rwx" actual &&
- egrep "mask::?r--" actual > /dev/null 2>&1 &&
+ grep -E "mask::?r--" actual > /dev/null 2>&1 &&
grep -q "group::---" actual || false
}
diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh
index 0c204089b8..d708acdb81 100755
--- a/t/t1401-symbolic-ref.sh
+++ b/t/t1401-symbolic-ref.sh
@@ -175,4 +175,18 @@ test_expect_success 'symbolic-ref allows top-level target for non-HEAD' '
test_cmp_rev top-level HEAD
'
+test_expect_success 'symbolic-ref pointing at another' '
+ git update-ref refs/heads/maint-2.37 HEAD &&
+ git symbolic-ref refs/heads/maint refs/heads/maint-2.37 &&
+ git checkout maint &&
+
+ git symbolic-ref HEAD >actual &&
+ echo refs/heads/maint-2.37 >expect &&
+ test_cmp expect actual &&
+
+ git symbolic-ref --no-recurse HEAD >actual &&
+ echo refs/heads/maint >expect &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 88b9c56e5c..7d8edff9c3 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -201,8 +201,8 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou
test_expect_success 'git branch -M baz bam should add entries to .git/logs/HEAD' '
msg="Branch: renamed refs/heads/baz to refs/heads/bam" &&
- grep " 0\{40\}.*$msg$" .git/logs/HEAD &&
- grep "^0\{40\}.*$msg$" .git/logs/HEAD
+ grep " $ZERO_OID.*$msg$" .git/logs/HEAD &&
+ grep "^$ZERO_OID.*$msg$" .git/logs/HEAD
'
test_expect_success 'git branch -M should leave orphaned HEAD alone' '
@@ -1382,6 +1382,9 @@ test_expect_success 'branch --delete --force removes dangling branch' '
'
test_expect_success 'use --edit-description' '
+ EDITOR=: git branch --edit-description &&
+ test_must_fail git config branch.main.description &&
+
write_script editor <<-\EOF &&
echo "New contents" >"$1"
EOF
diff --git a/t/t3202-show-branch.sh b/t/t3202-show-branch.sh
index f2b9199007..ea7cfd1951 100755
--- a/t/t3202-show-branch.sh
+++ b/t/t3202-show-branch.sh
@@ -7,6 +7,28 @@ test_description='test show-branch'
# arbitrary reference time: 2009-08-30 19:20:00
GIT_TEST_DATE_NOW=1251660000; export GIT_TEST_DATE_NOW
+test_expect_success 'error descriptions on empty repository' '
+ current=$(git branch --show-current) &&
+ cat >expect <<-EOF &&
+ error: No commit on branch '\''$current'\'' yet.
+ EOF
+ test_must_fail git branch --edit-description 2>actual &&
+ test_cmp expect actual &&
+ test_must_fail git branch --edit-description $current 2>actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'fatal descriptions on empty repository' '
+ current=$(git branch --show-current) &&
+ cat >expect <<-EOF &&
+ fatal: No commit on branch '\''$current'\'' yet.
+ EOF
+ test_must_fail git branch --set-upstream-to=non-existent 2>actual &&
+ test_cmp expect actual &&
+ test_must_fail git branch -c new-branch 2>actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'setup' '
test_commit initial &&
for i in $(test_seq 1 10)
@@ -175,4 +197,28 @@ done <<\EOF
--reflog --current
EOF
+test_expect_success 'error descriptions on non-existent branch' '
+ cat >expect <<-EOF &&
+ error: No branch named '\''non-existent'\'.'
+ EOF
+ test_must_fail git branch --edit-description non-existent 2>actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'fatal descriptions on non-existent branch' '
+ cat >expect <<-EOF &&
+ fatal: branch '\''non-existent'\'' does not exist
+ EOF
+ test_must_fail git branch --set-upstream-to=non-existent non-existent 2>actual &&
+ test_cmp expect actual &&
+
+ cat >expect <<-EOF &&
+ fatal: No branch named '\''non-existent'\''.
+ EOF
+ test_must_fail git branch -c non-existent new-branch 2>actual &&
+ test_cmp expect actual &&
+ test_must_fail git branch -m non-existent new-branch 2>actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t3204-branch-name-interpretation.sh b/t/t3204-branch-name-interpretation.sh
index 993a6b5eff..793bf4d269 100755
--- a/t/t3204-branch-name-interpretation.sh
+++ b/t/t3204-branch-name-interpretation.sh
@@ -133,4 +133,28 @@ test_expect_success 'checkout does not treat remote @{upstream} as a branch' '
expect_branch HEAD one
'
+test_expect_success 'edit-description via @{-1}' '
+ git checkout -b desc-branch &&
+ git checkout -b non-desc-branch &&
+ write_script editor <<-\EOF &&
+ echo "Branch description" >"$1"
+ EOF
+ EDITOR=./editor git branch --edit-description @{-1} &&
+ test_must_fail git config branch.non-desc-branch.description &&
+ git config branch.desc-branch.description >actual &&
+ printf "Branch description\n\n" >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'modify branch upstream via "@{-1}" and "@{-1}@{upstream}"' '
+ git checkout -b upstream-branch &&
+ git checkout -b upstream-other -t upstream-branch &&
+ git branch --set-upstream-to upstream-other @{-1} &&
+ git config branch.upstream-branch.merge >actual &&
+ echo "refs/heads/upstream-other" >expect &&
+ test_cmp expect actual &&
+ git branch --unset-upstream @{-1}@{upstream} &&
+ test_must_fail git config branch.upstream-other.merge
+'
+
test_done
diff --git a/t/t3305-notes-fanout.sh b/t/t3305-notes-fanout.sh
index 22ffe5bcb9..1ec1fb6715 100755
--- a/t/t3305-notes-fanout.sh
+++ b/t/t3305-notes-fanout.sh
@@ -9,7 +9,7 @@ path_has_fanout() {
path=$1 &&
fanout=$2 &&
after_last_slash=$(($(test_oid hexsz) - $fanout * 2)) &&
- echo $path | grep -q "^\([0-9a-f]\{2\}/\)\{$fanout\}[0-9a-f]\{$after_last_slash\}$"
+ echo $path | grep -q -E "^([0-9a-f]{2}/){$fanout}[0-9a-f]{$after_last_slash}$"
}
touched_one_note_with_fanout() {
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 688b01e3eb..4f5abb5ad2 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -1244,9 +1244,9 @@ test_expect_success 'short commit ID collide' '
test $colliding_id = "$(git rev-parse HEAD | cut -c 1-4)" &&
grep "^pick $colliding_id " \
.git/rebase-merge/git-rebase-todo.tmp &&
- grep "^pick [0-9a-f]\{$hexsz\}" \
+ grep -E "^pick [0-9a-f]{$hexsz}" \
.git/rebase-merge/git-rebase-todo &&
- grep "^pick [0-9a-f]\{$hexsz\}" \
+ grep -E "^pick [0-9a-f]{$hexsz}" \
.git/rebase-merge/git-rebase-todo.backup &&
git rebase --continue
) &&
@@ -1261,7 +1261,7 @@ test_expect_success 'respect core.abbrev' '
set_cat_todo_editor &&
test_must_fail git rebase -i HEAD~4 >todo-list
) &&
- test 4 = $(grep -c "pick [0-9a-f]\{12,\}" todo-list)
+ test 4 = $(grep -c -E "pick [0-9a-f]{12,}" todo-list)
'
test_expect_success 'todo count' '
diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh
index 78c27496d6..a364530d76 100755
--- a/t/t3415-rebase-autosquash.sh
+++ b/t/t3415-rebase-autosquash.sh
@@ -232,6 +232,19 @@ test_expect_success 'auto squash that matches longer sha1' '
test_line_count = 1 actual
'
+test_expect_success 'auto squash of fixup commit that matches branch name which points back to fixup commit' '
+ git reset --hard base &&
+ git commit --allow-empty -m "fixup! self-cycle" &&
+ git branch self-cycle &&
+ GIT_SEQUENCE_EDITOR="cat >tmp" git rebase --autosquash -i HEAD^^ &&
+ sed -ne "/^[^#]/{s/[0-9a-f]\{7,\}/HASH/g;p;}" tmp >actual &&
+ cat <<-EOF >expect &&
+ pick HASH second commit
+ pick HASH fixup! self-cycle # empty
+ EOF
+ test_cmp expect actual
+'
+
test_auto_commit_flags () {
git reset --hard base &&
echo 1 >file1 &&
diff --git a/t/t3419-rebase-patch-id.sh b/t/t3419-rebase-patch-id.sh
index 295040f2fe..7181f176b8 100755
--- a/t/t3419-rebase-patch-id.sh
+++ b/t/t3419-rebase-patch-id.sh
@@ -43,15 +43,26 @@ test_expect_success 'setup: 500 lines' '
git add newfile &&
git commit -q -m "add small file" &&
- git cherry-pick main >/dev/null 2>&1
-'
+ git cherry-pick main >/dev/null 2>&1 &&
+
+ git branch -f squashed main &&
+ git checkout -q -f squashed &&
+ git reset -q --soft HEAD~2 &&
+ git commit -q -m squashed &&
+
+ git branch -f mode main &&
+ git checkout -q -f mode &&
+ test_chmod +x file &&
+ git commit -q -a --amend &&
-test_expect_success 'setup attributes' '
- echo "file binary" >.gitattributes
+ git branch -f modeother other &&
+ git checkout -q -f modeother &&
+ test_chmod +x file &&
+ git commit -q -a --amend
'
test_expect_success 'detect upstream patch' '
- git checkout -q main &&
+ git checkout -q main^{} &&
scramble file &&
git add file &&
git commit -q -m "change big file again" &&
@@ -61,14 +72,46 @@ test_expect_success 'detect upstream patch' '
test_must_be_empty revs
'
+test_expect_success 'detect upstream patch binary' '
+ echo "file binary" >.gitattributes &&
+ git checkout -q other^{} &&
+ git rebase main &&
+ git rev-list main...HEAD~ >revs &&
+ test_must_be_empty revs &&
+ test_when_finished "rm .gitattributes"
+'
+
+test_expect_success 'detect upstream patch modechange' '
+ git checkout -q modeother^{} &&
+ git rebase mode &&
+ git rev-list mode...HEAD~ >revs &&
+ test_must_be_empty revs
+'
+
test_expect_success 'do not drop patch' '
- git branch -f squashed main &&
- git checkout -q -f squashed &&
- git reset -q --soft HEAD~2 &&
- git commit -q -m squashed &&
git checkout -q other^{} &&
test_must_fail git rebase squashed &&
- git rebase --quit
+ test_when_finished "git rebase --abort"
+'
+
+test_expect_success 'do not drop patch binary' '
+ echo "file binary" >.gitattributes &&
+ git checkout -q other^{} &&
+ test_must_fail git rebase squashed &&
+ test_when_finished "git rebase --abort" &&
+ test_when_finished "rm .gitattributes"
+'
+
+test_expect_success 'do not drop patch modechange' '
+ git checkout -q modeother^{} &&
+ git rebase other &&
+ cat >expected <<-\EOF &&
+ diff --git a/file b/file
+ old mode 100644
+ new mode 100755
+ EOF
+ git diff HEAD~ >modediff &&
+ test_cmp expected modediff
'
test_done
diff --git a/t/t3435-rebase-gpg-sign.sh b/t/t3435-rebase-gpg-sign.sh
index 5f8ba2c739..6aa2aeb628 100755
--- a/t/t3435-rebase-gpg-sign.sh
+++ b/t/t3435-rebase-gpg-sign.sh
@@ -64,14 +64,6 @@ test_rebase_gpg_sign ! true -i --no-gpg-sign
test_rebase_gpg_sign ! true -i --gpg-sign --no-gpg-sign
test_rebase_gpg_sign false -i --no-gpg-sign --gpg-sign
-test_expect_failure 'rebase -p --no-gpg-sign override commit.gpgsign' '
- test_when_finished "git clean -f" &&
- git reset --hard merged &&
- git config commit.gpgsign true &&
- git rebase -p --no-gpg-sign --onto=one fork-point main &&
- test_must_fail git verify-commit HEAD
-'
-
test_expect_success 'rebase -r, merge strategy, --gpg-sign will sign commit' '
git reset --hard merged &&
test_unconfig commit.gpgsign &&
diff --git a/t/t3438-rebase-broken-files.sh b/t/t3438-rebase-broken-files.sh
new file mode 100755
index 0000000000..b92a3ce46b
--- /dev/null
+++ b/t/t3438-rebase-broken-files.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+
+test_description='rebase behavior when on-disk files are broken'
+. ./test-lib.sh
+
+test_expect_success 'set up conflicting branches' '
+ test_commit base file &&
+ git checkout -b branch1 &&
+ test_commit one file &&
+ git checkout -b branch2 HEAD^ &&
+ test_commit two file
+'
+
+create_conflict () {
+ test_when_finished "git rebase --abort" &&
+ git checkout -B tmp branch2 &&
+ test_must_fail git rebase branch1
+}
+
+check_resolve_fails () {
+ echo resolved >file &&
+ git add file &&
+ test_must_fail git rebase --continue
+}
+
+for item in NAME EMAIL DATE
+do
+ test_expect_success "detect missing GIT_AUTHOR_$item" '
+ create_conflict &&
+
+ grep -v $item .git/rebase-merge/author-script >tmp &&
+ mv tmp .git/rebase-merge/author-script &&
+
+ check_resolve_fails
+ '
+done
+
+for item in NAME EMAIL DATE
+do
+ test_expect_success "detect duplicate GIT_AUTHOR_$item" '
+ create_conflict &&
+
+ grep -i $item .git/rebase-merge/author-script >tmp &&
+ cat tmp >>.git/rebase-merge/author-script &&
+
+ check_resolve_fails
+ '
+done
+
+test_expect_success 'unknown key in author-script' '
+ create_conflict &&
+
+ echo "GIT_AUTHOR_BOGUS=${SQ}whatever${SQ}" \
+ >>.git/rebase-merge/author-script &&
+
+ check_resolve_fails
+'
+
+test_done
diff --git a/t/t3700-add.sh b/t/t3700-add.sh
index 8689b48589..51afbd7b24 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -291,7 +291,7 @@ test_expect_success BSLASHPSPEC "git add 'fo\\[ou\\]bar' ignores foobar" '
git reset --hard &&
touch fo\[ou\]bar foobar &&
git add '\''fo\[ou\]bar'\'' &&
- git ls-files fo\[ou\]bar | fgrep fo\[ou\]bar &&
+ git ls-files fo\[ou\]bar | grep -F fo\[ou\]bar &&
! ( git ls-files foobar | grep foobar )
'
diff --git a/t/t3702-add-edit.sh b/t/t3702-add-edit.sh
index a1801a8cbd..82bfb2fd2a 100755
--- a/t/t3702-add-edit.sh
+++ b/t/t3702-add-edit.sh
@@ -100,7 +100,7 @@ EOF
echo "#!$SHELL_PATH" >fake-editor.sh
cat >> fake-editor.sh <<\EOF
-egrep -v '^index' "$1" >orig-patch &&
+grep -E -v '^index' "$1" >orig-patch &&
mv -f patch "$1"
EOF
diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh
index c509143c81..c64d9d2f40 100755
--- a/t/t4012-diff-binary.sh
+++ b/t/t4012-diff-binary.sh
@@ -113,20 +113,20 @@ test_expect_success 'diff --no-index with binary creation' '
'
cat >expect <<EOF
- binfile | Bin 0 -> 1026 bytes
- textfile | 10000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ binfilë | Bin 0 -> 1026 bytes
+ tëxtfilë | 10000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EOF
test_expect_success 'diff --stat with binary files and big change count' '
- printf "\01\00%1024d" 1 >binfile &&
- git add binfile &&
+ printf "\01\00%1024d" 1 >binfilë &&
+ git add binfilë &&
i=0 &&
while test $i -lt 10000; do
echo $i &&
i=$(($i + 1)) || return 1
- done >textfile &&
- git add textfile &&
- git diff --cached --stat binfile textfile >output &&
+ done >tëxtfilë &&
+ git add tëxtfilë &&
+ git -c core.quotepath=false diff --cached --stat binfilë tëxtfilë >output &&
grep " | " output >actual &&
test_cmp expect actual
'
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index ad5c029279..de1da4673d 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -1457,7 +1457,7 @@ append_signoff()
C=$(git commit-tree HEAD^^{tree} -p HEAD) &&
git format-patch --stdout --signoff $C^..$C >append_signoff.patch &&
sed -n -e "1,/^---$/p" append_signoff.patch |
- egrep -n "^Subject|Sign|^$"
+ grep -E -n "^Subject|Sign|^$"
}
test_expect_success 'signoff: commit with no body' '
@@ -2274,10 +2274,10 @@ test_expect_success 'format-patch --base with --attach' '
test_expect_success 'format-patch --attach cover-letter only is non-multipart' '
test_when_finished "rm -fr patches" &&
git format-patch -o patches --cover-letter --attach=mimemime --base=HEAD~ -1 &&
- ! egrep "^--+mimemime" patches/0000*.patch &&
- egrep "^--+mimemime$" patches/0001*.patch >output &&
+ ! grep -E "^--+mimemime" patches/0000*.patch &&
+ grep -E "^--+mimemime$" patches/0001*.patch >output &&
test_line_count = 2 output &&
- egrep "^--+mimemime--$" patches/0001*.patch >output &&
+ grep -E "^--+mimemime--$" patches/0001*.patch >output &&
test_line_count = 1 output
'
diff --git a/t/t4038-diff-combined.sh b/t/t4038-diff-combined.sh
index 9a292bac70..2ce26e585c 100755
--- a/t/t4038-diff-combined.sh
+++ b/t/t4038-diff-combined.sh
@@ -80,11 +80,21 @@ test_expect_success 'check combined output (1)' '
verify_helper sidewithone
'
+test_expect_success 'check combined output (1) with git diff <rev>^!' '
+ git diff sidewithone^! -- >sidewithone &&
+ verify_helper sidewithone
+'
+
test_expect_success 'check combined output (2)' '
git show sidesansone -- >sidesansone &&
verify_helper sidesansone
'
+test_expect_success 'check combined output (2) with git diff <rev>^!' '
+ git diff sidesansone^! -- >sidesansone &&
+ verify_helper sidesansone
+'
+
test_expect_success 'diagnose truncated file' '
>file &&
git add file &&
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index cc15cb4ff6..2ce2b41174 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -249,6 +249,15 @@ test_expect_success 'log --grep' '
test_cmp expect actual
'
+for noop_opt in --invert-grep --all-match
+do
+ test_expect_success "log $noop_opt without --grep is a NOOP" '
+ git log >expect &&
+ git log $noop_opt >actual &&
+ test_cmp expect actual
+ '
+done
+
cat > expect << EOF
second
initial
diff --git a/t/t4204-patch-id.sh b/t/t4204-patch-id.sh
index a730c0db98..a7fa94ce0a 100755
--- a/t/t4204-patch-id.sh
+++ b/t/t4204-patch-id.sh
@@ -8,13 +8,13 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
test_expect_success 'setup' '
- as="a a a a a a a a" && # eight a
- test_write_lines $as >foo &&
- test_write_lines $as >bar &&
+ str="ab cd ef gh ij kl mn op" &&
+ test_write_lines $str >foo &&
+ test_write_lines $str >bar &&
git add foo bar &&
git commit -a -m initial &&
- test_write_lines $as b >foo &&
- test_write_lines $as b >bar &&
+ test_write_lines $str b >foo &&
+ test_write_lines $str b >bar &&
git commit -a -m first &&
git checkout -b same main &&
git commit --amend -m same-msg &&
@@ -22,8 +22,23 @@ test_expect_success 'setup' '
echo c >foo &&
echo c >bar &&
git commit --amend -a -m notsame-msg &&
+ git checkout -b with_space main~ &&
+ cat >foo <<-\EOF &&
+ a b
+ c d
+ e f
+ g h
+ i j
+ k l
+ m n
+ op
+ EOF
+ cp foo bar &&
+ git add foo bar &&
+ git commit --amend -m "with spaces" &&
test_write_lines bar foo >bar-then-foo &&
test_write_lines foo bar >foo-then-bar
+
'
test_expect_success 'patch-id output is well-formed' '
@@ -42,7 +57,7 @@ calc_patch_id () {
}
get_top_diff () {
- git log -p -1 "$@" -O bar-then-foo --
+ git log -p -1 "$@" -O bar-then-foo --full-index --
}
get_patch_id () {
@@ -61,6 +76,33 @@ test_expect_success 'patch-id detects inequality' '
get_patch_id notsame &&
! test_cmp patch-id_main patch-id_notsame
'
+test_expect_success 'patch-id detects equality binary' '
+ cat >.gitattributes <<-\EOF &&
+ foo binary
+ bar binary
+ EOF
+ get_patch_id main &&
+ get_patch_id same &&
+ git log -p -1 --binary main >top-diff.output &&
+ calc_patch_id <top-diff.output main_binpatch &&
+ git log -p -1 --binary same >top-diff.output &&
+ calc_patch_id <top-diff.output same_binpatch &&
+ test_cmp patch-id_main patch-id_main_binpatch &&
+ test_cmp patch-id_same patch-id_same_binpatch &&
+ test_cmp patch-id_main patch-id_same &&
+ test_when_finished "rm .gitattributes"
+'
+
+test_expect_success 'patch-id detects inequality binary' '
+ cat >.gitattributes <<-\EOF &&
+ foo binary
+ bar binary
+ EOF
+ get_patch_id main &&
+ get_patch_id notsame &&
+ ! test_cmp patch-id_main patch-id_notsame &&
+ test_when_finished "rm .gitattributes"
+'
test_expect_success 'patch-id supports git-format-patch output' '
get_patch_id main &&
@@ -101,9 +143,21 @@ test_patch_id_file_order () {
git format-patch -1 --stdout -O foo-then-bar >format-patch.output &&
calc_patch_id <format-patch.output "ordered-$name" "$@" &&
cmp_patch_id $relevant "$name" "ordered-$name"
+}
+test_patch_id_whitespace () {
+ relevant="$1"
+ shift
+ name="ws-${1}-$relevant"
+ shift
+ get_top_diff "main~" >top-diff.output &&
+ calc_patch_id <top-diff.output "$name" "$@" &&
+ get_top_diff "with_space" >top-diff.output &&
+ calc_patch_id <top-diff.output "ws-$name" "$@" &&
+ cmp_patch_id $relevant "$name" "ws-$name"
}
+
# combined test for options: add more tests here to make them
# run with all options
test_patch_id () {
@@ -119,6 +173,14 @@ test_expect_success 'file order is relevant with --unstable' '
test_patch_id_file_order relevant --unstable --unstable
'
+test_expect_success 'whitespace is relevant with --verbatim' '
+ test_patch_id_whitespace relevant --verbatim --verbatim
+'
+
+test_expect_success 'whitespace is irrelevant without --verbatim' '
+ test_patch_id_whitespace irrelevant --stable --stable
+'
+
#Now test various option combinations.
test_expect_success 'default is unstable' '
test_patch_id relevant default
@@ -134,6 +196,17 @@ test_expect_success 'patchid.stable = false is unstable' '
test_patch_id relevant patchid.stable=false
'
+test_expect_success 'patchid.verbatim = true is correct and stable' '
+ test_config patchid.verbatim true &&
+ test_patch_id_whitespace relevant patchid.verbatim=true &&
+ test_patch_id irrelevant patchid.verbatim=true
+'
+
+test_expect_success 'patchid.verbatim = false is unstable' '
+ test_config patchid.verbatim false &&
+ test_patch_id relevant patchid.verbatim=false
+'
+
test_expect_success '--unstable overrides patchid.stable = true' '
test_config patchid.stable true &&
test_patch_id relevant patchid.stable=true--unstable --unstable
@@ -144,6 +217,11 @@ test_expect_success '--stable overrides patchid.stable = false' '
test_patch_id irrelevant patchid.stable=false--stable --stable
'
+test_expect_success '--verbatim overrides patchid.stable = false' '
+ test_config patchid.stable false &&
+ test_patch_id_whitespace relevant stable=false--verbatim --verbatim
+'
+
test_expect_success 'patch-id supports git-format-patch MIME output' '
get_patch_id main &&
git checkout same &&
@@ -198,7 +276,10 @@ test_expect_success 'patch-id handles no-nl-at-eof markers' '
EOF
calc_patch_id nonl <nonl &&
calc_patch_id withnl <withnl &&
- test_cmp patch-id_nonl patch-id_withnl
+ test_cmp patch-id_nonl patch-id_withnl &&
+ calc_patch_id nonl-inc-ws --verbatim <nonl &&
+ calc_patch_id withnl-inc-ws --verbatim <withnl &&
+ ! test_cmp patch-id_nonl-inc-ws patch-id_withnl-inc-ws
'
test_expect_success 'patch-id handles diffs with one line of before/after' '
diff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh
index 28ca5c38bb..013b77144b 100755
--- a/t/t4301-merge-tree-write-tree.sh
+++ b/t/t4301-merge-tree-write-tree.sh
@@ -810,4 +810,13 @@ test_expect_success 'can override merge of unrelated histories' '
test_cmp expect actual
'
+test_expect_success SANITY 'merge-ort fails gracefully in a read-only repository' '
+ git init --bare read-only &&
+ git push read-only side1 side2 side3 &&
+ test_when_finished "chmod -R u+w read-only" &&
+ chmod -R a-w read-only &&
+ test_must_fail git -C read-only merge-tree side1 side3 &&
+ test_must_fail git -C read-only merge-tree side1 side2
+'
+
test_done
diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh
index cebad1048c..db11cababd 100755
--- a/t/t5100-mailinfo.sh
+++ b/t/t5100-mailinfo.sh
@@ -201,13 +201,13 @@ test_expect_success 'mailinfo -b double [PATCH]' '
test z"$subj" = z"Subject: message"
'
-test_expect_failure 'mailinfo -b trailing [PATCH]' '
+test_expect_success 'mailinfo -b trailing [PATCH]' '
subj="$(echo "Subject: [other] [PATCH] message" |
git mailinfo -b /dev/null /dev/null)" &&
test z"$subj" = z"Subject: [other] message"
'
-test_expect_failure 'mailinfo -b separated double [PATCH]' '
+test_expect_success 'mailinfo -b separated double [PATCH]' '
subj="$(echo "Subject: [PATCH] [other] [PATCH] message" |
git mailinfo -b /dev/null /dev/null)" &&
test z"$subj" = z"Subject: [other] message"
diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh
index afbe93f162..b5f9b10922 100755
--- a/t/t5319-multi-pack-index.sh
+++ b/t/t5319-multi-pack-index.sh
@@ -784,6 +784,70 @@ test_expect_success 'repack creates a new pack' '
)
'
+test_expect_success 'repack (all) ignores cruft pack' '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ test_commit base &&
+ test_commit --no-tag unreachable &&
+
+ git reset --hard base &&
+ git reflog expire --all --expire=all &&
+ git repack --cruft -d &&
+
+ git multi-pack-index write &&
+
+ find $objdir/pack | sort >before &&
+ git multi-pack-index repack --batch-size=0 &&
+ find $objdir/pack | sort >after &&
+
+ test_cmp before after
+ )
+'
+
+test_expect_success 'repack (--batch-size) ignores cruft pack' '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ test_commit_bulk 5 &&
+ test_commit --no-tag unreachable &&
+
+ git reset --hard HEAD^ &&
+ git reflog expire --all --expire=all &&
+ git repack --cruft -d &&
+
+ test_commit four &&
+
+ find $objdir/pack -type f -name "*.pack" | sort >before &&
+ git repack -d &&
+ find $objdir/pack -type f -name "*.pack" | sort >after &&
+
+ pack="$(comm -13 before after)" &&
+ test_file_size "$pack" >sz &&
+ # Set --batch-size to twice the size of the pack created
+ # in the previous step, since this is enough to
+ # accommodate it and the cruft pack.
+ #
+ # This means that the MIDX machinery *could* combine the
+ # new and cruft packs together.
+ #
+ # We ensure that it does not below.
+ batch="$((($(cat sz) * 2)))" &&
+
+ git multi-pack-index write &&
+
+ find $objdir/pack | sort >before &&
+ git multi-pack-index repack --batch-size=$batch &&
+ find $objdir/pack | sort >after &&
+
+ test_cmp before after
+ )
+'
+
test_expect_success 'expire removes repacked packs' '
(
cd dup &&
@@ -847,6 +911,36 @@ test_expect_success 'expire respects .keep files' '
)
'
+test_expect_success 'expiring unreferenced cruft pack retains pack' '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ test_commit base &&
+ test_commit --no-tag unreachable &&
+ unreachable=$(git rev-parse HEAD) &&
+
+ git reset --hard base &&
+ git reflog expire --all --expire=all &&
+ git repack --cruft -d &&
+ mtimes="$(ls $objdir/pack/pack-*.mtimes)" &&
+
+ echo "base..$unreachable" >in &&
+ pack="$(git pack-objects --revs --delta-base-offset \
+ $objdir/pack/pack <in)" &&
+
+ # Preferring the contents of "$pack" will leave the
+ # cruft pack unreferenced (ie., none of the objects
+ # contained in the cruft pack will have their MIDX copy
+ # selected from the cruft pack).
+ git multi-pack-index write --preferred-pack="pack-$pack.pack" &&
+ git multi-pack-index expire &&
+
+ test_path_is_file "$mtimes"
+ )
+'
+
test_expect_success 'repack --batch-size=0 repacks everything' '
cp -r dup dup2 &&
(
diff --git a/t/t5320-delta-islands.sh b/t/t5320-delta-islands.sh
index 124d47603d..406363381f 100755
--- a/t/t5320-delta-islands.sh
+++ b/t/t5320-delta-islands.sh
@@ -134,7 +134,7 @@ test_expect_success 'island core places core objects first' '
repack -adfi &&
git verify-pack -v .git/objects/pack/*.pack |
cut -d" " -f1 |
- egrep "$root|$two" >actual &&
+ grep -E "$root|$two" >actual &&
test_cmp expect actual
'
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index ad6eea5fa0..0882cbb6e4 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -410,4 +410,28 @@ test_expect_success 'preferred pack change with existing MIDX bitmap' '
)
'
+test_expect_success 'tagged commits are selected for bitmapping' '
+ rm -fr repo &&
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ test_commit --annotate base &&
+ git repack -d &&
+
+ # Remove refs/heads/main which points at the commit directly,
+ # leaving only a reference to the annotated tag.
+ git branch -M main &&
+ git checkout base &&
+ git branch -d main &&
+
+ git multi-pack-index write --bitmap &&
+
+ git rev-parse HEAD >want &&
+ test-tool bitmap list-commits >actual &&
+ grep $(cat want) actual
+ )
+'
+
test_done
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 9006196ac6..43b7bcd715 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -902,6 +902,17 @@ test_expect_success 'rename a remote renames repo remote.pushDefault but keeps g
)
'
+test_expect_success 'rename handles remote without fetch refspec' '
+ git clone --bare one no-refspec.git &&
+ # confirm assumption that bare clone does not create refspec
+ test_expect_code 5 \
+ git -C no-refspec.git config --unset-all remote.origin.fetch &&
+ git -C no-refspec.git config remote.origin.url >expect &&
+ git -C no-refspec.git remote rename origin foo &&
+ git -C no-refspec.git config remote.foo.url >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'rename does not update a non-default fetch refspec' '
git clone one four.one &&
(
diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh
index 3c44f19612..75da8acf8f 100755
--- a/t/t5526-fetch-submodules.sh
+++ b/t/t5526-fetch-submodules.sh
@@ -715,7 +715,13 @@ test_expect_success 'fetching submodules respects parallel settings' '
GIT_TRACE=$(pwd)/trace.out git fetch &&
grep "8 tasks" trace.out &&
GIT_TRACE=$(pwd)/trace.out git fetch --jobs 9 &&
- grep "9 tasks" trace.out
+ grep "9 tasks" trace.out &&
+ >trace.out &&
+
+ GIT_TRACE=$(pwd)/trace.out git -c submodule.fetchJobs=0 fetch &&
+ grep "preparing to run up to [0-9]* tasks" trace.out &&
+ ! grep "up to 0 tasks" trace.out &&
+ >trace.out
)
'
diff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh
index d7cf85ffea..8f182a3cbf 100755
--- a/t/t5550-http-fetch-dumb.sh
+++ b/t/t5550-http-fetch-dumb.sh
@@ -234,7 +234,7 @@ test_expect_success 'http-fetch --packfile' '
--index-pack-arg=--keep \
"$HTTPD_URL"/dumb/repo_pack.git/$p >out &&
- grep "^keep.[0-9a-f]\{16,\}$" out &&
+ grep -E "^keep.[0-9a-f]{16,}$" out &&
cut -c6- out >packhash &&
# Ensure that the expected files are generated
diff --git a/t/t5606-clone-options.sh b/t/t5606-clone-options.sh
index f6bb02ab94..cf221e92c4 100755
--- a/t/t5606-clone-options.sh
+++ b/t/t5606-clone-options.sh
@@ -42,11 +42,12 @@ test_expect_success 'rejects invalid -o/--origin' '
'
-test_expect_success 'disallows --bare with --origin' '
+test_expect_success 'clone --bare -o' '
- test_must_fail git clone -o foo --bare parent clone-bare-o 2>err &&
- test_debug "cat err" &&
- test_i18ngrep -e "options .--bare. and .--origin foo. cannot be used together" err
+ git clone -o foo --bare parent clone-bare-o &&
+ (cd parent && pwd) >expect &&
+ git -C clone-bare-o config remote.foo.url >actual &&
+ test_cmp expect actual
'
diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh
index 5d42a355a8..b33cd4afca 100755
--- a/t/t5702-protocol-v2.sh
+++ b/t/t5702-protocol-v2.sh
@@ -1001,7 +1001,7 @@ test_expect_success 'part of packfile response provided as URI' '
do
git verify-pack --object-format=$(test_oid algo) --verbose $idx >out &&
{
- grep "^[0-9a-f]\{16,\} " out || :
+ grep -E "^[0-9a-f]{16,} " out || :
} >out.objectlist &&
if test_line_count = 1 out.objectlist
then
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index e18a218952..f6aebe92ff 100755
--- a/t/t7003-filter-branch.sh
+++ b/t/t7003-filter-branch.sh
@@ -49,7 +49,7 @@ test_expect_success 'result is really identical' '
test_expect_success 'rewrite bare repository identically' '
(git config core.bare true && cd .git &&
git filter-branch branch > filter-output 2>&1 &&
- ! fgrep fatal filter-output)
+ ! grep fatal filter-output)
'
git config core.bare false
test_expect_success 'result is really identical' '
@@ -506,7 +506,7 @@ test_expect_success 'rewrite repository including refs that point at non-commit
git tag -a -m "tag to a tree" treetag $new_tree &&
git reset --hard HEAD &&
git filter-branch -f -- --all >filter-output 2>&1 &&
- ! fgrep fatal filter-output
+ ! grep fatal filter-output
'
test_expect_success 'filter-branch handles ref deletion' '
diff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh
index d419085379..4abc74db2b 100755
--- a/t/t7527-builtin-fsmonitor.sh
+++ b/t/t7527-builtin-fsmonitor.sh
@@ -943,9 +943,9 @@ test_expect_success CASE_INSENSITIVE_FS 'case insensitive+preserving' '
# directories and files that we touched. We may or may not get a
# trailing slash on modified directories.
#
- egrep "^event: abc/?$" ./insensitive.trace &&
- egrep "^event: abc/def/?$" ./insensitive.trace &&
- egrep "^event: abc/def/xyz$" ./insensitive.trace
+ grep -E "^event: abc/?$" ./insensitive.trace &&
+ grep -E "^event: abc/def/?$" ./insensitive.trace &&
+ grep -E "^event: abc/def/xyz$" ./insensitive.trace
'
# The variable "unicode_debug" is defined in the following library
@@ -987,20 +987,20 @@ test_expect_success !UNICODE_COMPOSITION_SENSITIVE 'Unicode nfc/nfd' '
then
# We should have seen NFC event from OS.
# We should not have synthesized an NFD event.
- egrep "^event: nfc/c_${utf8_nfc}/?$" ./unicode.trace &&
- egrep -v "^event: nfc/c_${utf8_nfd}/?$" ./unicode.trace
+ grep -E "^event: nfc/c_${utf8_nfc}/?$" ./unicode.trace &&
+ grep -E -v "^event: nfc/c_${utf8_nfd}/?$" ./unicode.trace
else
# We should have seen NFD event from OS.
# We should have synthesized an NFC event.
- egrep "^event: nfc/c_${utf8_nfd}/?$" ./unicode.trace &&
- egrep "^event: nfc/c_${utf8_nfc}/?$" ./unicode.trace
+ grep -E "^event: nfc/c_${utf8_nfd}/?$" ./unicode.trace &&
+ grep -E "^event: nfc/c_${utf8_nfc}/?$" ./unicode.trace
fi &&
# We assume UNICODE_NFD_PRESERVED.
# We should have seen explicit NFD from OS.
# We should have synthesized an NFC event.
- egrep "^event: nfd/d_${utf8_nfd}/?$" ./unicode.trace &&
- egrep "^event: nfd/d_${utf8_nfc}/?$" ./unicode.trace
+ grep -E "^event: nfd/d_${utf8_nfd}/?$" ./unicode.trace &&
+ grep -E "^event: nfd/d_${utf8_nfc}/?$" ./unicode.trace
'
test_done
diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh
index ca45c4cd2c..5be483bf88 100755
--- a/t/t7700-repack.sh
+++ b/t/t7700-repack.sh
@@ -426,12 +426,73 @@ test_expect_success '--write-midx -b packs non-kept objects' '
)
'
+test_expect_success '--write-midx removes stale pack-based bitmaps' '
+ rm -fr repo &&
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+ test_commit base &&
+ GIT_TEST_MULTI_PACK_INDEX=0 git repack -Ab &&
+
+ pack_bitmap=$(ls $objdir/pack/pack-*.bitmap) &&
+ test_path_is_file "$pack_bitmap" &&
+
+ test_commit tip &&
+ GIT_TEST_MULTI_PACK_INDEX=0 git repack -bm &&
+
+ test_path_is_file $midx &&
+ test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
+ test_path_is_missing $pack_bitmap
+ )
+'
+
+test_expect_success '--write-midx with --pack-kept-objects' '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ test_commit one &&
+ test_commit two &&
+
+ one="$(echo "one" | git pack-objects --revs $objdir/pack/pack)" &&
+ two="$(echo "one..two" | git pack-objects --revs $objdir/pack/pack)" &&
+
+ keep="$objdir/pack/pack-$one.keep" &&
+ touch "$keep" &&
+
+ git repack --write-midx --write-bitmap-index --geometric=2 -d \
+ --pack-kept-objects &&
+
+ test_path_is_file $keep &&
+ test_path_is_file $midx &&
+ test_path_is_file $midx-$(midx_checksum $objdir).bitmap
+ )
+'
+
test_expect_success TTY '--quiet disables progress' '
test_terminal env GIT_PROGRESS_DELAY=0 \
git -C midx repack -ad --quiet --write-midx 2>stderr &&
test_must_be_empty stderr
'
+test_expect_success 'clean up .tmp-* packs on error' '
+ test_must_fail ok=sigpipe git \
+ -c repack.cruftwindow=bogus \
+ repack -ad --cruft &&
+ find $objdir/pack -name '.tmp-*' >tmpfiles &&
+ test_must_be_empty tmpfiles
+'
+
+test_expect_success 'repack -ad cleans up old .tmp-* packs' '
+ git rev-parse HEAD >input &&
+ git pack-objects $objdir/pack/.tmp-1234 <input &&
+ git repack -ad &&
+ find $objdir/pack -name '.tmp-*' >tmpfiles &&
+ test_must_be_empty tmpfiles
+'
+
test_expect_success 'setup for update-server-info' '
git init update-server-info &&
test_commit -C update-server-info message
diff --git a/t/t7701-repack-unpack-unreachable.sh b/t/t7701-repack-unpack-unreachable.sh
index 937f89ee8c..b7ac4f598a 100755
--- a/t/t7701-repack-unpack-unreachable.sh
+++ b/t/t7701-repack-unpack-unreachable.sh
@@ -35,7 +35,7 @@ test_expect_success '-A with -d option leaves unreachable objects unpacked' '
git repack -A -d -l &&
# verify objects are packed in repository
test 3 = $(git verify-pack -v -- .git/objects/pack/*.idx |
- egrep "^($fsha1|$csha1|$tsha1) " |
+ grep -E "^($fsha1|$csha1|$tsha1) " |
sort | uniq | wc -l) &&
git show $fsha1 &&
git show $csha1 &&
@@ -49,7 +49,7 @@ test_expect_success '-A with -d option leaves unreachable objects unpacked' '
git repack -A -d -l &&
# verify objects are retained unpacked
test 0 = $(git verify-pack -v -- .git/objects/pack/*.idx |
- egrep "^($fsha1|$csha1|$tsha1) " |
+ grep -E "^($fsha1|$csha1|$tsha1) " |
sort | uniq | wc -l) &&
git show $fsha1 &&
git show $csha1 &&
diff --git a/t/t7703-repack-geometric.sh b/t/t7703-repack-geometric.sh
index da87f8b2d8..8821fbd2dd 100755
--- a/t/t7703-repack-geometric.sh
+++ b/t/t7703-repack-geometric.sh
@@ -176,8 +176,12 @@ test_expect_success '--geometric ignores kept packs' '
# be repacked, too.
git repack --geometric 2 -d --pack-kept-objects &&
+ # After repacking, two packs remain: one new one (containing the
+ # objects in both the .keep and non-kept pack), and the .keep
+ # pack (since `--pack-kept-objects -d` does not actually delete
+ # the kept pack).
find $objdir/pack -name "*.pack" >after &&
- test_line_count = 1 after
+ test_line_count = 2 after
)
'
diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh
index 0f937990a0..8eded6ab27 100755
--- a/t/t7810-grep.sh
+++ b/t/t7810-grep.sh
@@ -18,6 +18,9 @@ test_invalid_grep_expression() {
'
}
+LC_ALL=en_US.UTF-8 test-tool regex '^.$' '¿' &&
+ test_set_prereq MB_REGEX
+
cat >hello.c <<EOF
#include <assert.h>
#include <stdio.h>
@@ -88,6 +91,10 @@ test_expect_success setup '
echo unusual >"\"unusual\" pathname" &&
echo unusual >"t/nested \"unusual\" pathname"
fi &&
+ if test_have_prereq MB_REGEX
+ then
+ echo "¿" >reverse-question-mark
+ fi &&
git add . &&
test_tick &&
git commit -m initial
@@ -569,6 +576,14 @@ do
'
done
+test_expect_success MB_REGEX 'grep exactly one char in single-char multibyte file' '
+ LC_ALL=en_US.UTF-8 git grep "^.$" reverse-question-mark
+'
+
+test_expect_success MB_REGEX 'grep two chars in single-char multibyte file' '
+ LC_ALL=en_US.UTF-8 test_expect_code 1 git grep ".." reverse-question-mark
+'
+
cat >expected <<EOF
file
EOF
diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh
index 2724a44fe3..96bdd42045 100755
--- a/t/t7900-maintenance.sh
+++ b/t/t7900-maintenance.sh
@@ -480,6 +480,11 @@ test_expect_success 'maintenance.strategy inheritance' '
test_expect_success 'register and unregister' '
test_when_finished git config --global --unset-all maintenance.repo &&
+
+ test_must_fail git maintenance unregister 2>err &&
+ grep "is not registered" err &&
+ git maintenance unregister --force &&
+
git config --global --add maintenance.repo /existing1 &&
git config --global --add maintenance.repo /existing2 &&
git config --global --get-all maintenance.repo >before &&
@@ -493,7 +498,11 @@ test_expect_success 'register and unregister' '
git maintenance unregister &&
git config --global --get-all maintenance.repo >actual &&
- test_cmp before actual
+ test_cmp before actual &&
+
+ test_must_fail git maintenance unregister 2>err &&
+ grep "is not registered" err &&
+ git maintenance unregister --force
'
test_expect_success !MINGW 'register and unregister with regex metacharacters' '
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index 01c74b8b07..1130ef21b3 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -1519,7 +1519,7 @@ test_expect_success $PREREQ 'asks about and fixes 8bit encodings' '
grep "do not declare a Content-Transfer-Encoding" stdout &&
grep email-using-8bit stdout &&
grep "Which 8bit encoding" stdout &&
- egrep "Content|MIME" msgtxt1 >actual &&
+ grep -E "Content|MIME" msgtxt1 >actual &&
test_cmp content-type-decl actual
'
@@ -1530,7 +1530,7 @@ test_expect_success $PREREQ 'sendemail.8bitEncoding works' '
git send-email --from=author@example.com --to=nobody@example.com \
--smtp-server="$(pwd)/fake.sendmail" \
email-using-8bit >stdout &&
- egrep "Content|MIME" msgtxt1 >actual &&
+ grep -E "Content|MIME" msgtxt1 >actual &&
test_cmp content-type-decl actual
'
@@ -1545,7 +1545,7 @@ test_expect_success $PREREQ 'sendemail.8bitEncoding in .git/config overrides --g
git send-email --from=author@example.com --to=nobody@example.com \
--smtp-server="$(pwd)/fake.sendmail" \
email-using-8bit >stdout &&
- egrep "Content|MIME" msgtxt1 >actual &&
+ grep -E "Content|MIME" msgtxt1 >actual &&
test_cmp content-type-decl actual
'
@@ -1557,7 +1557,7 @@ test_expect_success $PREREQ '--8bit-encoding overrides sendemail.8bitEncoding' '
--smtp-server="$(pwd)/fake.sendmail" \
--8bit-encoding=UTF-8 \
email-using-8bit >stdout &&
- egrep "Content|MIME" msgtxt1 >actual &&
+ grep -E "Content|MIME" msgtxt1 >actual &&
test_cmp content-type-decl actual
'
diff --git a/t/t9133-git-svn-nested-git-repo.sh b/t/t9133-git-svn-nested-git-repo.sh
index f894860867..d8d536269c 100755
--- a/t/t9133-git-svn-nested-git-repo.sh
+++ b/t/t9133-git-svn-nested-git-repo.sh
@@ -35,7 +35,7 @@ test_expect_success 'SVN-side change outside of .git' '
echo b >> a &&
svn_cmd commit -m "SVN-side change outside of .git" &&
svn_cmd up &&
- svn_cmd log -v | fgrep "SVN-side change outside of .git"
+ svn_cmd log -v | grep -F "SVN-side change outside of .git"
)
'
@@ -59,7 +59,7 @@ test_expect_success 'SVN-side change inside of .git' '
svn_cmd add --force .git &&
svn_cmd commit -m "SVN-side change inside of .git" &&
svn_cmd up &&
- svn_cmd log -v | fgrep "SVN-side change inside of .git"
+ svn_cmd log -v | grep -F "SVN-side change inside of .git"
)
'
@@ -82,7 +82,7 @@ test_expect_success 'SVN-side change in and out of .git' '
git commit -m "add a inside an SVN repo" &&
svn_cmd commit -m "SVN-side change in and out of .git" &&
svn_cmd up &&
- svn_cmd log -v | fgrep "SVN-side change in and out of .git"
+ svn_cmd log -v | grep -F "SVN-side change in and out of .git"
)
'
diff --git a/t/t9134-git-svn-ignore-paths.sh b/t/t9134-git-svn-ignore-paths.sh
index 4a77eb9f60..3188400226 100755
--- a/t/t9134-git-svn-ignore-paths.sh
+++ b/t/t9134-git-svn-ignore-paths.sh
@@ -43,7 +43,7 @@ test_expect_success 'init+fetch an SVN repository with ignored www directory' '
test_expect_success 'verify ignore-paths config saved by clone' '
(
cd g &&
- git config --get svn-remote.svn.ignore-paths | fgrep "www"
+ git config --get svn-remote.svn.ignore-paths | grep www
)
'
@@ -53,7 +53,7 @@ test_expect_success 'SVN-side change outside of www' '
echo b >> qqq/test_qqq.txt &&
svn_cmd commit -m "SVN-side change outside of www" &&
svn_cmd up &&
- svn_cmd log -v | fgrep "SVN-side change outside of www"
+ svn_cmd log -v | grep "SVN-side change outside of www"
)
'
@@ -85,7 +85,7 @@ test_expect_success 'SVN-side change inside of ignored www' '
echo zaq >> www/test_www.txt &&
svn_cmd commit -m "SVN-side change inside of www/test_www.txt" &&
svn_cmd up &&
- svn_cmd log -v | fgrep "SVN-side change inside of www/test_www.txt"
+ svn_cmd log -v | grep -F "SVN-side change inside of www/test_www.txt"
)
'
@@ -118,7 +118,7 @@ test_expect_success 'SVN-side change in and out of ignored www' '
echo ygg >> qqq/test_qqq.txt &&
svn_cmd commit -m "SVN-side change in and out of ignored www" &&
svn_cmd up &&
- svn_cmd log -v | fgrep "SVN-side change in and out of ignored www"
+ svn_cmd log -v | grep "SVN-side change in and out of ignored www"
)
'
diff --git a/t/t9140-git-svn-reset.sh b/t/t9140-git-svn-reset.sh
index e855904629..a420b2a87a 100755
--- a/t/t9140-git-svn-reset.sh
+++ b/t/t9140-git-svn-reset.sh
@@ -43,7 +43,7 @@ test_expect_success 'fetch fails on modified hidden file' '
git svn find-rev refs/remotes/git-svn > ../expect &&
test_must_fail git svn fetch 2> ../errors &&
git svn find-rev refs/remotes/git-svn > ../expect2 ) &&
- fgrep "not found in commit" errors &&
+ grep "not found in commit" errors &&
test_cmp expect expect2
'
@@ -59,7 +59,7 @@ test_expect_success 'refetch succeeds not ignoring any files' '
( cd g &&
git svn fetch &&
git svn rebase &&
- fgrep "mod hidden" hid/hid.txt
+ grep "mod hidden" hid/hid.txt
)
'
diff --git a/t/t9147-git-svn-include-paths.sh b/t/t9147-git-svn-include-paths.sh
index 257fc8f2f8..63fa0b6732 100755
--- a/t/t9147-git-svn-include-paths.sh
+++ b/t/t9147-git-svn-include-paths.sh
@@ -45,7 +45,7 @@ test_expect_success 'init+fetch an SVN repository with included qqq directory' '
test_expect_success 'verify include-paths config saved by clone' '
(
cd g &&
- git config --get svn-remote.svn.include-paths | fgrep "qqq"
+ git config --get svn-remote.svn.include-paths | grep qqq
)
'
@@ -55,7 +55,7 @@ test_expect_success 'SVN-side change outside of www' '
echo b >> qqq/test_qqq.txt &&
svn_cmd commit -m "SVN-side change outside of www" &&
svn_cmd up &&
- svn_cmd log -v | fgrep "SVN-side change outside of www"
+ svn_cmd log -v | grep "SVN-side change outside of www"
)
'
@@ -87,7 +87,7 @@ test_expect_success 'SVN-side change inside of ignored www' '
echo zaq >> www/test_www.txt &&
svn_cmd commit -m "SVN-side change inside of www/test_www.txt" &&
svn_cmd up &&
- svn_cmd log -v | fgrep "SVN-side change inside of www/test_www.txt"
+ svn_cmd log -v | grep "SVN-side change inside of www/test_www.txt"
)
'
@@ -120,7 +120,7 @@ test_expect_success 'SVN-side change in and out of included qqq' '
echo ygg >> qqq/test_qqq.txt &&
svn_cmd commit -m "SVN-side change in and out of ignored www" &&
svn_cmd up &&
- svn_cmd log -v | fgrep "SVN-side change in and out of ignored www"
+ svn_cmd log -v | grep "SVN-side change in and out of ignored www"
)
'
diff --git a/t/t9210-scalar.sh b/t/t9210-scalar.sh
index 14ca575a21..be51a8bb7a 100755
--- a/t/t9210-scalar.sh
+++ b/t/t9210-scalar.sh
@@ -116,7 +116,10 @@ test_expect_success 'scalar unregister' '
test_must_fail git config --get --global --fixed-value \
maintenance.repo "$(pwd)/vanish/src" &&
scalar list >scalar.repos &&
- ! grep -F "$(pwd)/vanish/src" scalar.repos
+ ! grep -F "$(pwd)/vanish/src" scalar.repos &&
+
+ # scalar unregister should be idempotent
+ scalar unregister vanish
'
test_expect_success 'set up repository to clone' '
diff --git a/t/t9700-perl-git.sh b/t/t9700-perl-git.sh
index 4aa5d90d32..b105d6d9d5 100755
--- a/t/t9700-perl-git.sh
+++ b/t/t9700-perl-git.sh
@@ -45,6 +45,10 @@ test_expect_success \
git config --add test.pathmulti bar
'
+test_expect_success 'set up bare repository' '
+ git init --bare bare.git
+'
+
test_expect_success 'use t9700/test.pl to test Git.pm' '
"$PERL_PATH" "$TEST_DIRECTORY"/t9700/test.pl 2>stderr &&
test_must_be_empty stderr
diff --git a/t/t9700/test.pl b/t/t9700/test.pl
index e046f7db76..6d753708d2 100755
--- a/t/t9700/test.pl
+++ b/t/t9700/test.pl
@@ -30,6 +30,18 @@ BEGIN { use_ok('Git') }
# set up
our $abs_repo_dir = cwd();
ok(our $r = Git->repository(Directory => "."), "open repository");
+{
+ local $ENV{GIT_TEST_ASSUME_DIFFERENT_OWNER} = 1;
+ my $failed;
+
+ $failed = eval { Git->repository(Directory => $abs_repo_dir) };
+ ok(!$failed, "reject unsafe non-bare repository");
+ like($@, qr/not a git repository/i, "unsafe error message");
+
+ $failed = eval { Git->repository(Directory => "$abs_repo_dir/bare.git") };
+ ok(!$failed, "reject unsafe bare repository");
+ like($@, qr/not a git repository/i, "unsafe error message");
+}
# config
is($r->config("test.string"), "value", "config scalar: string");
diff --git a/t/t9814-git-p4-rename.sh b/t/t9814-git-p4-rename.sh
index 468767cbf4..2a9838f37f 100755
--- a/t/t9814-git-p4-rename.sh
+++ b/t/t9814-git-p4-rename.sh
@@ -216,7 +216,7 @@ test_expect_success 'detect copies' '
# variable exists, which allows admins to disable the "p4 move" command.
test_lazy_prereq P4D_HAVE_CONFIGURABLE_RUN_MOVE_ALLOW '
p4 configure show run.move.allow >out &&
- egrep ^run.move.allow: out
+ grep -E ^run.move.allow: out
'
# If move can be disabled, turn it off and test p4 move handling
diff --git a/t/t9815-git-p4-submit-fail.sh b/t/t9815-git-p4-submit-fail.sh
index 9779dc0d11..0ca9937de6 100755
--- a/t/t9815-git-p4-submit-fail.sh
+++ b/t/t9815-git-p4-submit-fail.sh
@@ -417,8 +417,8 @@ test_expect_success 'cleanup chmod after submit cancel' '
! p4 fstat -T action text &&
test_path_is_file text+x &&
! p4 fstat -T action text+x &&
- ls -l text | egrep ^-r-- &&
- ls -l text+x | egrep ^-r-x
+ ls -l text | grep -E ^-r-- &&
+ ls -l text+x | grep -E ^-r-x
)
'
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index c6479f24eb..527a714500 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -897,7 +897,7 @@ test_path_is_symlink () {
test_dir_is_empty () {
test "$#" -ne 1 && BUG "1 param"
test_path_is_dir "$1" &&
- if test -n "$(ls -a1 "$1" | egrep -v '^\.\.?$')"
+ if test -n "$(ls -a1 "$1" | grep -E -v '^\.\.?$')"
then
echo "Directory '$1' is not empty, it contains:"
ls -la "$1"
diff --git a/t/test-lib.sh b/t/test-lib.sh
index a65df2fd22..6db377f68b 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -47,6 +47,16 @@ then
echo "PANIC: Running in a $TEST_DIRECTORY that doesn't end in '/t'?" >&2
exit 1
fi
+if test -f "$GIT_BUILD_DIR/GIT-BUILD-DIR"
+then
+ GIT_BUILD_DIR="$(cat "$GIT_BUILD_DIR/GIT-BUILD-DIR")" || exit 1
+ # On Windows, we must convert Windows paths lest they contain a colon
+ case "$(uname -s)" in
+ *MINGW*)
+ GIT_BUILD_DIR="$(cygpath -au "$GIT_BUILD_DIR")"
+ ;;
+ esac
+fi
# Prepend a string to a VAR using an arbitrary ":" delimiter, not
# adding the delimiter if VAR or VALUE is empty. I.e. a generalized:
@@ -563,9 +573,11 @@ case $GIT_TEST_FSYNC in
esac
# Add libc MALLOC and MALLOC_PERTURB test only if we are not executing
-# the test with valgrind and have not compiled with SANITIZE=address.
+# the test with valgrind and have not compiled with conflict SANITIZE
+# options.
if test -n "$valgrind" ||
test -n "$SANITIZE_ADDRESS" ||
+ test -n "$SANITIZE_LEAK" ||
test -n "$TEST_NO_MALLOC_CHECK"
then
setup_malloc_check () {
diff --git a/tmp-objdir.c b/tmp-objdir.c
index adf6033549..2a2012eb6d 100644
--- a/tmp-objdir.c
+++ b/tmp-objdir.c
@@ -18,7 +18,7 @@ struct tmp_objdir {
/*
* Allow only one tmp_objdir at a time in a running process, which simplifies
- * our signal/atexit cleanup routines. It's doubtful callers will ever need
+ * our atexit cleanup routines. It's doubtful callers will ever need
* more than one, and we can expand later if so. You can have many such
* tmp_objdirs simultaneously in many processes, of course.
*/
@@ -31,7 +31,7 @@ static void tmp_objdir_free(struct tmp_objdir *t)
free(t);
}
-static int tmp_objdir_destroy_1(struct tmp_objdir *t, int on_signal)
+int tmp_objdir_destroy(struct tmp_objdir *t)
{
int err;
@@ -41,44 +41,21 @@ static int tmp_objdir_destroy_1(struct tmp_objdir *t, int on_signal)
if (t == the_tmp_objdir)
the_tmp_objdir = NULL;
- if (!on_signal && t->prev_odb)
+ if (t->prev_odb)
restore_primary_odb(t->prev_odb, t->path.buf);
- /*
- * This may use malloc via strbuf_grow(), but we should
- * have pre-grown t->path sufficiently so that this
- * doesn't happen in practice.
- */
err = remove_dir_recursively(&t->path, 0);
- /*
- * When we are cleaning up due to a signal, we won't bother
- * freeing memory; it may cause a deadlock if the signal
- * arrived while libc's allocator lock is held.
- */
- if (!on_signal)
- tmp_objdir_free(t);
+ tmp_objdir_free(t);
return err;
}
-int tmp_objdir_destroy(struct tmp_objdir *t)
-{
- return tmp_objdir_destroy_1(t, 0);
-}
-
static void remove_tmp_objdir(void)
{
tmp_objdir_destroy(the_tmp_objdir);
}
-static void remove_tmp_objdir_on_signal(int signo)
-{
- tmp_objdir_destroy_1(the_tmp_objdir, 1);
- sigchain_pop(signo);
- raise(signo);
-}
-
void tmp_objdir_discard_objects(struct tmp_objdir *t)
{
remove_dir_recursively(&t->path, REMOVE_DIR_KEEP_TOPLEVEL);
@@ -152,14 +129,6 @@ struct tmp_objdir *tmp_objdir_create(const char *prefix)
*/
strbuf_addf(&t->path, "%s/tmp_objdir-%s-XXXXXX", get_object_directory(), prefix);
- /*
- * Grow the strbuf beyond any filename we expect to be placed in it.
- * If tmp_objdir_destroy() is called by a signal handler, then
- * we should be able to use the strbuf to remove files without
- * having to call malloc.
- */
- strbuf_grow(&t->path, 1024);
-
if (!mkdtemp(t->path.buf)) {
/* free, not destroy, as we never touched the filesystem */
tmp_objdir_free(t);
@@ -169,7 +138,6 @@ struct tmp_objdir *tmp_objdir_create(const char *prefix)
the_tmp_objdir = t;
if (!installed_handlers) {
atexit(remove_tmp_objdir);
- sigchain_push_common(remove_tmp_objdir_on_signal);
installed_handlers++;
}
diff --git a/worktree.c b/worktree.c
index 257ba4cf1e..aa43c64119 100644
--- a/worktree.c
+++ b/worktree.c
@@ -489,62 +489,17 @@ int submodule_uses_worktrees(const char *path)
return ret;
}
-int parse_worktree_ref(const char *worktree_ref, const char **name,
- int *name_length, const char **ref)
-{
- if (skip_prefix(worktree_ref, "main-worktree/", &worktree_ref)) {
- if (!*worktree_ref)
- return -1;
- if (name)
- *name = NULL;
- if (name_length)
- *name_length = 0;
- if (ref)
- *ref = worktree_ref;
- return 0;
- }
- if (skip_prefix(worktree_ref, "worktrees/", &worktree_ref)) {
- const char *slash = strchr(worktree_ref, '/');
-
- if (!slash || slash == worktree_ref || !slash[1])
- return -1;
- if (name)
- *name = worktree_ref;
- if (name_length)
- *name_length = slash - worktree_ref;
- if (ref)
- *ref = slash + 1;
- return 0;
- }
- return -1;
-}
-
void strbuf_worktree_ref(const struct worktree *wt,
struct strbuf *sb,
const char *refname)
{
- switch (ref_type(refname)) {
- case REF_TYPE_PSEUDOREF:
- case REF_TYPE_PER_WORKTREE:
- if (wt && !wt->is_current) {
- if (is_main_worktree(wt))
- strbuf_addstr(sb, "main-worktree/");
- else
- strbuf_addf(sb, "worktrees/%s/", wt->id);
- }
- break;
-
- case REF_TYPE_MAIN_PSEUDOREF:
- case REF_TYPE_OTHER_PSEUDOREF:
- break;
-
- case REF_TYPE_NORMAL:
- /*
- * For shared refs, don't prefix worktrees/ or
- * main-worktree/. It's not necessary and
- * files-backend.c can't handle it anyway.
- */
- break;
+ if (parse_worktree_ref(refname, NULL, NULL, NULL) ==
+ REF_WORKTREE_CURRENT &&
+ wt && !wt->is_current) {
+ if (is_main_worktree(wt))
+ strbuf_addstr(sb, "main-worktree/");
+ else
+ strbuf_addf(sb, "worktrees/%s/", wt->id);
}
strbuf_addstr(sb, refname);
}
diff --git a/worktree.h b/worktree.h
index e9e839926b..9dcea6fc8c 100644
--- a/worktree.h
+++ b/worktree.h
@@ -167,16 +167,6 @@ const char *worktree_git_path(const struct worktree *wt,
__attribute__((format (printf, 2, 3)));
/*
- * Parse a worktree ref (i.e. with prefix main-worktree/ or
- * worktrees/) and return the position of the worktree's name and
- * length (or NULL and zero if it's main worktree), and ref.
- *
- * All name, name_length and ref arguments could be NULL.
- */
-int parse_worktree_ref(const char *worktree_ref, const char **name,
- int *name_length, const char **ref);
-
-/*
* Return a refname suitable for access from the current ref store.
*/
void strbuf_worktree_ref(const struct worktree *wt,
diff --git a/write-or-die.c b/write-or-die.c
index c4fd91b5b4..aaa0318e82 100644
--- a/write-or-die.c
+++ b/write-or-die.c
@@ -23,6 +23,7 @@ void maybe_flush_or_die(FILE *f, const char *desc)
if (f == stdout) {
if (skip_stdout_flush < 0) {
+ /* NEEDSWORK: make this a normal Boolean */
cp = getenv("GIT_FLUSH");
if (cp)
skip_stdout_flush = (atoi(cp) == 0);