diff options
298 files changed, 2725 insertions, 1062 deletions
diff --git a/Documentation/Makefile b/Documentation/Makefile index 5cd35df61c..b629176d7d 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -144,14 +144,16 @@ man5dir = $(mandir)/man5 man7dir = $(mandir)/man7 # DESTDIR = +GIT_DATE := $(shell git show --quiet --pretty='%as') + ASCIIDOC = asciidoc ASCIIDOC_EXTRA = ASCIIDOC_HTML = xhtml11 ASCIIDOC_DOCBOOK = docbook ASCIIDOC_CONF = -f asciidoc.conf ASCIIDOC_COMMON = $(ASCIIDOC) $(ASCIIDOC_EXTRA) $(ASCIIDOC_CONF) \ - -amanversion=$(GIT_VERSION) \ - -amanmanual='Git Manual' -amansource='Git' + -amanmanual='Git Manual' -amansource='Git $(GIT_VERSION)' \ + -arevdate='$(GIT_DATE)' ASCIIDOC_DEPS = asciidoc.conf GIT-ASCIIDOCFLAGS TXT_TO_HTML = $(ASCIIDOC_COMMON) -b $(ASCIIDOC_HTML) TXT_TO_XML = $(ASCIIDOC_COMMON) -b $(ASCIIDOC_DOCBOOK) diff --git a/Documentation/MyFirstContribution.txt b/Documentation/MyFirstContribution.txt index 2f8b7d597f..56130e4bec 100644 --- a/Documentation/MyFirstContribution.txt +++ b/Documentation/MyFirstContribution.txt @@ -1164,7 +1164,7 @@ After you run this command, `format-patch` will output the patches to the `psuh/ directory, alongside the v1 patches. Using a single directory makes it easy to refer to the old v1 patches while proofreading the v2 patches, but you will need to be careful to send out only the v2 patches. We will use a pattern like -"psuh/v2-*.patch" (not "psuh/*.patch", which would match v1 and v2 patches). +`psuh/v2-*.patch` (not `psuh/*.patch`, which would match v1 and v2 patches). Edit your cover letter again. Now is a good time to mention what's different between your last version and now, if it's something significant. You do not diff --git a/Documentation/RelNotes/2.30.9.txt b/Documentation/RelNotes/2.30.9.txt new file mode 100644 index 0000000000..708d626ce6 --- /dev/null +++ b/Documentation/RelNotes/2.30.9.txt @@ -0,0 +1,43 @@ +Git v2.30.9 Release Notes +========================= + +This release addresses the security issues CVE-2023-25652, +CVE-2023-25815, and CVE-2023-29007. + + +Fixes since v2.30.8 +------------------- + + * CVE-2023-25652: + + By feeding specially crafted input to `git apply --reject`, a + path outside the working tree can be overwritten with partially + controlled contents (corresponding to the rejected hunk(s) from + the given patch). + + * CVE-2023-25815: + + When Git is compiled with runtime prefix support and runs without + translated messages, it still used the gettext machinery to + display messages, which subsequently potentially looked for + translated messages in unexpected places. This allowed for + malicious placement of crafted messages. + + * CVE-2023-29007: + + When renaming or deleting a section from a configuration file, + certain malicious configuration values may be misinterpreted as + the beginning of a new configuration section, leading to arbitrary + configuration injection. + +Credit for finding CVE-2023-25652 goes to Ry0taK, and the fix was +developed by Taylor Blau, Junio C Hamano and Johannes Schindelin, +with the help of Linus Torvalds. + +Credit for finding CVE-2023-25815 goes to Maxime Escourbiac and +Yassine BENGANA of Michelin, and the fix was developed by Johannes +Schindelin. + +Credit for finding CVE-2023-29007 goes to André Baptista and VÃtor Pinho +of Ethiack, and the fix was developed by Taylor Blau, and Johannes +Schindelin, with help from Jeff King, and Patrick Steinhardt. diff --git a/Documentation/RelNotes/2.31.8.txt b/Documentation/RelNotes/2.31.8.txt new file mode 100644 index 0000000000..0aa3080780 --- /dev/null +++ b/Documentation/RelNotes/2.31.8.txt @@ -0,0 +1,6 @@ +Git v2.31.8 Release Notes +========================= + +This release merges the fixes that appear in v2.30.9 to address the +security issues CVE-2023-25652, CVE-2023-25815, and CVE-2023-29007; +see the release notes for that version for details. diff --git a/Documentation/RelNotes/2.32.7.txt b/Documentation/RelNotes/2.32.7.txt new file mode 100644 index 0000000000..7bb35388b5 --- /dev/null +++ b/Documentation/RelNotes/2.32.7.txt @@ -0,0 +1,7 @@ +Git v2.32.7 Release Notes +========================= + +This release merges the fixes that appear in v2.30.9 and v2.31.8 to +address the security issues CVE-2023-25652, CVE-2023-25815, and +CVE-2023-29007; see the release notes for these versions for +details. diff --git a/Documentation/RelNotes/2.33.8.txt b/Documentation/RelNotes/2.33.8.txt new file mode 100644 index 0000000000..d8cf4c7f3a --- /dev/null +++ b/Documentation/RelNotes/2.33.8.txt @@ -0,0 +1,7 @@ +Git v2.33.8 Release Notes +========================= + +This release merges the fixes that appear in v2.30.9, v2.31.8 and +v2.32.7 to address the security issues CVE-2023-25652, +CVE-2023-25815, and CVE-2023-29007; see the release notes for these +versions for details. diff --git a/Documentation/RelNotes/2.34.8.txt b/Documentation/RelNotes/2.34.8.txt new file mode 100644 index 0000000000..2b5bd7d9a3 --- /dev/null +++ b/Documentation/RelNotes/2.34.8.txt @@ -0,0 +1,7 @@ +Git v2.34.8 Release Notes +========================= + +This release merges the fixes that appear in v2.30.9, v2.31.8, +v2.32.7 and v2.33.8 to address the security issues CVE-2023-25652, +CVE-2023-25815, and CVE-2023-29007; see the release notes for these +versions for details. diff --git a/Documentation/RelNotes/2.35.8.txt b/Documentation/RelNotes/2.35.8.txt new file mode 100644 index 0000000000..3c9c094c2b --- /dev/null +++ b/Documentation/RelNotes/2.35.8.txt @@ -0,0 +1,7 @@ +Git v2.35.8 Release Notes +========================= + +This release merges the fixes that appear in v2.30.9, v2.31.8, +v2.32.7, v2.33.8 and v2.34.8 to address the security issues +CVE-2023-25652, CVE-2023-25815, and CVE-2023-29007; see the release +notes for these versions for details. diff --git a/Documentation/RelNotes/2.36.6.txt b/Documentation/RelNotes/2.36.6.txt new file mode 100644 index 0000000000..e1edebcc43 --- /dev/null +++ b/Documentation/RelNotes/2.36.6.txt @@ -0,0 +1,7 @@ +Git v2.36.6 Release Notes +========================= + +This release merges the fixes that appear in v2.30.9, v2.31.8, +v2.32.7, v2.33.8, v2.34.8 and v2.35.8 to address the security issues +CVE-2023-25652, CVS-2023-25815, and CVE-2023-29007; see the release +notes for these versions for details. diff --git a/Documentation/RelNotes/2.37.7.txt b/Documentation/RelNotes/2.37.7.txt new file mode 100644 index 0000000000..4b8165f4b5 --- /dev/null +++ b/Documentation/RelNotes/2.37.7.txt @@ -0,0 +1,7 @@ +Git v2.37.7 Release Notes +========================= + +This release merges up the fix that appears in v2.30.9, v2.31.8, +v2.32.7, v2.33.8, v2.34.8, v2.35.8 and v2.36.6 to address the +security issues CVE-2023-25652, CVE-2023-25815, and CVE-2023-29007; +see the release notes for these versions for details. diff --git a/Documentation/RelNotes/2.38.5.txt b/Documentation/RelNotes/2.38.5.txt new file mode 100644 index 0000000000..2d1f3b1249 --- /dev/null +++ b/Documentation/RelNotes/2.38.5.txt @@ -0,0 +1,8 @@ +Git v2.38.5 Release Notes +========================= + +This release merges up the fix that appears in v2.30.9, v2.31.8, +v2.32.7, v2.33.8, v2.34.8, v2.35.8, v2.36.6 and v2.37.7 to address +the security issues CVE-2023-25652, CVE-2023-25815, and +CVE-2023-29007; see the release notes for these versions for +details. diff --git a/Documentation/RelNotes/2.39.3.txt b/Documentation/RelNotes/2.39.3.txt index dddff53627..66351b65c2 100644 --- a/Documentation/RelNotes/2.39.3.txt +++ b/Documentation/RelNotes/2.39.3.txt @@ -1,9 +1,15 @@ Git v2.39.3 Release Notes ========================= -This release is primarily to merge fixes accumulated on the 'master' -front to prepare for 2.40 release that are still relevant to 2.39.x -maintenance track. +This release merges up the fix that appears in v2.30.9, v2.31.8, +v2.32.7, v2.33.8, v2.34.8, v2.35.8, v2.36.6, v2.37.7 and v2.38.5 to +address the security issues CVE-2023-25652, CVE-2023-25815, and +CVE-2023-29007; see the release notes for these versions for +details. + +This release also merges fixes that have accumulated on the 'master' +front to prepare for the 2.40 release that are still relevant to +2.39.x maintenance track. Fixes since v2.39.2 ------------------- diff --git a/Documentation/RelNotes/2.40.1.txt b/Documentation/RelNotes/2.40.1.txt new file mode 100644 index 0000000000..e72f6b1b25 --- /dev/null +++ b/Documentation/RelNotes/2.40.1.txt @@ -0,0 +1,8 @@ +Git v2.40.1 Release Notes +========================= + +This release merges up the fix that appears in v2.30.9, v2.31.8, +v2.32.7, v2.33.8, v2.34.8, v2.35.8, v2.36.6, v2.37.7, v2.38.5 +and v2.39.3 to address the security issues CVE-2023-25652, +CVE-2023-25815, and CVE-2023-29007; see the release notes for these +versions for details. diff --git a/Documentation/RelNotes/2.41.0.txt b/Documentation/RelNotes/2.41.0.txt index 0fc82a83fc..e7f371466b 100644 --- a/Documentation/RelNotes/2.41.0.txt +++ b/Documentation/RelNotes/2.41.0.txt @@ -50,6 +50,29 @@ UI, Workflows & Features choice of the hash algorithm from the source repository to the newly created repository. + * "git mergetool" and "git difftool" learns a new configuration + guiDefault to optionally favor configured guitool over non-gui-tool + automatically when $DISPLAY is set. + + * "git branch -d origin/master" would say "no such branch", but it is + likely a missed "-r" if refs/remotes/origin/master exists. The + command has been taught to give such a hint in its error message. + + * Clean-up of the code path that deals with merge strategy option + handling in "git rebase". + + * "git clone --local" stops copying from an original repository that + has symbolic links inside its $GIT_DIR; an error message when that + happens has been updated. + + * "git branch --format=..." and "git format-patch --format=..." + learns "--omit-empty" to hide refs that whose formatting result + becomes an empty string from the output. + + * The sendemail-validate validate hook learned to pass the total + number of input files and where in the sequence each invocation is + via environment variables. + Performance, Internal Implementation, Development Support etc. @@ -88,6 +111,14 @@ Performance, Internal Implementation, Development Support etc. * "git sparse-checkout" command learns a debugging aid for the sparse rule definitions. + * "git write-tree" learns to work better with sparse-index. + + * The on-disk reverse index that allows mapping from the pack offset + to the object name for the object stored at the offset has been + enabled by default. + + * "git fsck" learned to validate the on-disk pack reverse index files. + Fixes since v2.40 ----------------- @@ -193,6 +224,40 @@ Fixes since v2.40 /usr/bin/perl, which have been corrected. (merge c1917156a0 jk/use-perl-path-consistently later to maint). + * Documentation mark-up fix. + (merge 78b6369e67 la/mfc-markup-fix later to maint). + + * Doc toolchain update to remove old workaround for AsciiDoc. + (merge 8806120de6 fc/remove-header-workarounds-for-asciidoc later to maint). + + * The userdiff regexp patterns for various filetypes that are built + into the system have been updated to avoid triggering regexp errors + from UTF-8 aware regex engines. + (merge be39144954 rs/userdiff-multibyte-regex later to maint). + + * The approxidate() API has been simplified by losing an extra + function that did the same thing as another one. + (merge 8a7f0b666f rs/remove-approxidate-relative later to maint). + + * Code clean-up to replace a hardcoded constant with a CPP macro. + (merge c870de6502 rs/get-tar-commit-id-use-defined-const later to maint). + + * Doc build simplification. + (merge 9a09ed3229 fc/doc-stop-using-manversion later to maint). + + * "git archive" run from a subdirectory mishandled attributes and + paths outside the current directory. + (merge 92b1dd1b9e rs/archive-from-subdirectory-fixes later to maint). + + * The code to parse capability list for v0 on-wire protocol fell into + an infinite loop when a capability appears multiple times, which + has been corrected. + + * Geometric repacking ("git repack --geometric=<n>") in a repository + that borrows from an alternate object database had various corner + case bugs, which have been corrected. + (merge d85cd18777 ps/fix-geom-repack-with-alternates later to maint). + * Other code cleanup, docfix, build fix, etc. (merge f7111175df as/doc-markup-fix later to maint). (merge 90ff7c9898 fc/test-aggregation-clean-up later to maint). @@ -208,3 +273,4 @@ Fixes since v2.40 (merge cc48ddd937 jk/chainlint-fixes later to maint). (merge 4833b08426 ow/ref-format-remove-unused-member later to maint). (merge d0ea2ca1cf dw/doc-submittingpatches-grammofix later to maint). + (merge fd72637423 ar/t2024-checkout-output-fix later to maint). diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf index 3e4c13971b..60f76f43ed 100644 --- a/Documentation/asciidoc.conf +++ b/Documentation/asciidoc.conf @@ -51,25 +51,6 @@ ifdef::doctype-manpage[] endif::doctype-manpage[] endif::backend-docbook[] -ifdef::doctype-manpage[] -ifdef::backend-docbook[] -[header] -template::[header-declarations] -<refentry> -<refmeta> -<refentrytitle>{mantitle}</refentrytitle> -<manvolnum>{manvolnum}</manvolnum> -<refmiscinfo class="source">{mansource}</refmiscinfo> -<refmiscinfo class="version">{manversion}</refmiscinfo> -<refmiscinfo class="manual">{manmanual}</refmiscinfo> -</refmeta> -<refnamediv> - <refname>{manname}</refname> - <refpurpose>{manpurpose}</refpurpose> -</refnamediv> -endif::backend-docbook[] -endif::doctype-manpage[] - ifdef::backend-xhtml11[] [attributes] git-relative-html-prefix= diff --git a/Documentation/config/difftool.txt b/Documentation/config/difftool.txt index a3f8211210..447c40d85a 100644 --- a/Documentation/config/difftool.txt +++ b/Documentation/config/difftool.txt @@ -34,3 +34,10 @@ See the `--trust-exit-code` option in linkgit:git-difftool[1] for more details. difftool.prompt:: Prompt before each invocation of the diff tool. + +difftool.guiDefault:: + Set `true` to use the `diff.guitool` by default (equivalent to specifying + the `--gui` argument), or `auto` to select `diff.guitool` or `diff.tool` + depending on the presence of a `DISPLAY` environment variable value. The + default is `false`, where the `--gui` argument must be provided + explicitly for the `diff.guitool` to be used. diff --git a/Documentation/config/mergetool.txt b/Documentation/config/mergetool.txt index e779a122d8..56a7eeeffb 100644 --- a/Documentation/config/mergetool.txt +++ b/Documentation/config/mergetool.txt @@ -85,3 +85,10 @@ mergetool.writeToTemp:: mergetool.prompt:: Prompt before each invocation of the merge resolution program. + +mergetool.guiDefault:: + Set `true` to use the `merge.guitool` by default (equivalent to + specifying the `--gui` argument), or `auto` to select `merge.guitool` + or `merge.tool` depending on the presence of a `DISPLAY` environment + variable value. The default is `false`, where the `--gui` argument + must be provided explicitly for the `merge.guitool` to be used. diff --git a/Documentation/config/pack.txt b/Documentation/config/pack.txt index 53093d9996..d4c7c9d4e4 100644 --- a/Documentation/config/pack.txt +++ b/Documentation/config/pack.txt @@ -171,9 +171,15 @@ pack.writeBitmapLookupTable:: beneficial in repositories that have relatively large bitmap indexes. Defaults to false. +pack.readReverseIndex:: + When true, git will read any .rev file(s) that may be available + (see: linkgit:gitformat-pack[5]). When false, the reverse index + will be generated from scratch and stored in memory. Defaults to + true. + pack.writeReverseIndex:: When true, git will write a corresponding .rev file (see: linkgit:gitformat-pack[5]) for each new packfile that it writes in all places except for linkgit:git-fast-import[1] and in the bulk checkin mechanism. - Defaults to false. + Defaults to true. diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index d382ac69f7..d207da9101 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -156,6 +156,10 @@ in another worktree linked to the same repository. --ignore-case:: Sorting and filtering branches are case insensitive. +--omit-empty:: + Do not print a newline after formatted refs where the format expands + to the empty string. + --column[=<options>]:: --no-column:: Display branch listing in columns. See configuration variable diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index 6bb32ab460..4af0904f47 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -483,14 +483,11 @@ $ git checkout -b foo # or "git switch -c foo" <1> $ git branch foo <2> $ git tag foo <3> ------------ - <1> creates a new branch `foo`, which refers to commit `f`, and then updates `HEAD` to refer to branch `foo`. In other words, we'll no longer be in detached `HEAD` state after this command. - <2> similarly creates a new branch `foo`, which refers to commit `f`, but leaves `HEAD` detached. - <3> creates a new tag `foo`, which refers to commit `f`, leaving `HEAD` detached. @@ -519,84 +516,89 @@ to checkout these paths out of the index. EXAMPLES -------- -. The following sequence checks out the `master` branch, reverts - the `Makefile` to two revisions back, deletes `hello.c` by - mistake, and gets it back from the index. -+ +=== 1. Paths + +The following sequence checks out the `master` branch, reverts +the `Makefile` to two revisions back, deletes `hello.c` by +mistake, and gets it back from the index. + ------------ $ git checkout master <1> $ git checkout master~2 Makefile <2> $ rm -f hello.c $ git checkout hello.c <3> ------------ -+ <1> switch branch <2> take a file out of another commit <3> restore `hello.c` from the index -+ + If you want to check out _all_ C source files out of the index, you can say -+ + ------------ $ git checkout -- '*.c' ------------ -+ + Note the quotes around `*.c`. The file `hello.c` will also be checked out, even though it is no longer in the working tree, because the file globbing is used to match entries in the index (not in the working tree by the shell). -+ + If you have an unfortunate branch that is named `hello.c`, this step would be confused as an instruction to switch to that branch. You should instead write: -+ + ------------ $ git checkout -- hello.c ------------ -. After working in the wrong branch, switching to the correct - branch would be done using: -+ +=== 2. Merge + +After working in the wrong branch, switching to the correct +branch would be done using: + ------------ $ git checkout mytopic ------------ -+ + However, your "wrong" branch and correct `mytopic` branch may differ in files that you have modified locally, in which case the above checkout would fail like this: -+ + ------------ $ git checkout mytopic error: You have local changes to 'frotz'; not switching branches. ------------ -+ + You can give the `-m` flag to the command, which would try a three-way merge: -+ + ------------ $ git checkout -m mytopic Auto-merging frotz ------------ -+ + After this three-way merge, the local modifications are _not_ registered in your index file, so `git diff` would show you what changes you made since the tip of the new branch. -. When a merge conflict happens during switching branches with - the `-m` option, you would see something like this: -+ +=== 3. Merge conflict + +When a merge conflict happens during switching branches with +the `-m` option, you would see something like this: + ------------ $ git checkout -m mytopic Auto-merging frotz ERROR: Merge conflict in frotz fatal: merge program failed ------------ -+ + At this point, `git diff` shows the changes cleanly merged as in the previous example, as well as the changes in the conflicted files. Edit and resolve the conflict and mark it resolved with `git add` as usual: -+ + ------------ $ edit frotz $ git add frotz diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index d6434d262d..c37c4a37f7 100644 --- a/Documentation/git-clone.txt +++ b/Documentation/git-clone.txt @@ -58,6 +58,11 @@ never use the local optimizations). Specifying `--no-local` will override the default when `/path/to/repo` is given, using the regular Git transport instead. + +If the repository's `$GIT_DIR/objects` has symbolic links or is a +symbolic link, the clone will fail. This is a security measure to +prevent the unintentional copying of files by dereferencing the symbolic +links. ++ *NOTE*: this operation can race with concurrent modification to the source repository, similar to running `cp -r src dst` while modifying `src`. diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt index 9d14c3c9f0..ac0ac6fa02 100644 --- a/Documentation/git-difftool.txt +++ b/Documentation/git-difftool.txt @@ -97,10 +97,12 @@ instead. `--no-symlinks` is the default on Windows. --[no-]gui:: When 'git-difftool' is invoked with the `-g` or `--gui` option the default diff tool will be read from the configured - `diff.guitool` variable instead of `diff.tool`. The `--no-gui` - option can be used to override this setting. If `diff.guitool` - is not set, we will fallback in the order of `merge.guitool`, - `diff.tool`, `merge.tool` until a tool is found. + `diff.guitool` variable instead of `diff.tool`. This may be + selected automatically using the configuration variable + `difftool.guiDefault`. The `--no-gui` option can be used to + override these settings. If `diff.guitool` is not set, we will + fallback in the order of `merge.guitool`, `diff.tool`, + `merge.tool` until a tool is found. --[no-]trust-exit-code:: 'git-difftool' invokes a diff tool individually on each file. diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt index 0713e49b49..1e215d4e73 100644 --- a/Documentation/git-for-each-ref.txt +++ b/Documentation/git-for-each-ref.txt @@ -98,6 +98,10 @@ OPTIONS --ignore-case:: Sorting and filtering refs are case insensitive. +--omit-empty:: + Do not print a newline after formatted refs where the format expands + to the empty string. + FIELD NAMES ----------- diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index 508f3ae2c0..b1c13fb39a 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -173,8 +173,7 @@ series, where the head is chosen from the cover letter, the threading makes every mail a reply to the previous one. + The default is `--no-thread`, unless the `format.thread` configuration -is set. If `--thread` is specified without a style, it defaults to the -style specified by `format.thread` if any, or else `shallow`. +is set. `--thread` without an argument is equivalent to `--thread=shallow`. + Beware that the default for 'git send-email' is to thread emails itself. If you want `git format-patch` to take care of threading, you diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt index c44e205629..07535f6576 100644 --- a/Documentation/git-mergetool.txt +++ b/Documentation/git-mergetool.txt @@ -85,12 +85,13 @@ success of the resolution after the custom tool has exited. the default merge tool will be read from the configured `merge.guitool` variable instead of `merge.tool`. If `merge.guitool` is not set, we will fallback to the tool - configured under `merge.tool`. + configured under `merge.tool`. This may be autoselected using + the configuration variable `mergetool.guiDefault`. --no-gui:: - This overrides a previous `-g` or `--gui` setting and reads the - default merge tool will be read from the configured `merge.tool` - variable. + This overrides a previous `-g` or `--gui` setting or + `mergetool.guiDefault` configuration and reads the default merge + tool from the configured `merge.tool` variable. -O<orderfile>:: Process files in the order specified in the diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index fdc72b5875..7f61c1edb3 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -131,6 +131,10 @@ options for details. --ignore-case:: Sorting and filtering tags are case insensitive. +--omit-empty:: + Do not print a newline after formatted refs where the format expands + to the empty string. + --column[=<options>]:: --no-column:: Display tag listing in columns. See configuration variable diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt index 62908602e7..c8e55b2613 100644 --- a/Documentation/githooks.txt +++ b/Documentation/githooks.txt @@ -600,6 +600,28 @@ the name of the file that holds the e-mail to be sent. Exiting with a non-zero status causes `git send-email` to abort before sending any e-mails. +The following environment variables are set when executing the hook. + +`GIT_SENDEMAIL_FILE_COUNTER`:: + A 1-based counter incremented by one for every file holding an e-mail + to be sent (excluding any FIFOs). This counter does not follow the + patch series counter scheme. It will always start at 1 and will end at + GIT_SENDEMAIL_FILE_TOTAL. + +`GIT_SENDEMAIL_FILE_TOTAL`:: + The total number of files that will be sent (excluding any FIFOs). This + counter does not follow the patch series counter scheme. It will always + be equal to the number of files being sent, whether there is a cover + letter or not. + +These variables may for instance be used to validate patch series. + +The sample `sendemail-validate` hook that comes with Git checks that all sent +patches (excluding the cover letter) can be applied on top of the upstream +repository default branch without conflicts. Some placeholders are left for +additional validation steps to be performed after all patches of a given series +have been applied. + fsmonitor-watchman ~~~~~~~~~~~~~~~~~~ @@ -1032,6 +1032,7 @@ LIB_OBJS += fsmonitor.o LIB_OBJS += fsmonitor-ipc.o LIB_OBJS += fsmonitor-settings.o LIB_OBJS += gettext.o +LIB_OBJS += git-zlib.o LIB_OBJS += gpg-interface.o LIB_OBJS += graph.o LIB_OBJS += grep.o @@ -1192,7 +1193,6 @@ LIB_OBJS += write-or-die.o LIB_OBJS += ws.o LIB_OBJS += wt-status.o LIB_OBJS += xdiff-interface.o -LIB_OBJS += zlib.o BUILTIN_OBJS += builtin/add.o BUILTIN_OBJS += builtin/am.o diff --git a/add-patch.c b/add-patch.c index 1e1ee2df59..8d770d203f 100644 --- a/add-patch.c +++ b/add-patch.c @@ -1,8 +1,11 @@ #include "cache.h" #include "add-interactive.h" +#include "advice.h" #include "alloc.h" +#include "editor.h" #include "environment.h" #include "gettext.h" +#include "object-name.h" #include "strbuf.h" #include "run-command.h" #include "strvec.h" @@ -3,6 +3,7 @@ #include "alloc.h" #include "config.h" #include "gettext.h" +#include "strbuf.h" #include "string-list.h" struct config_alias_data { @@ -46,6 +47,23 @@ void list_aliases(struct string_list *list) read_early_config(config_alias_cb, &data); } +void quote_cmdline(struct strbuf *buf, const char **argv) +{ + for (const char **argp = argv; *argp; argp++) { + if (argp != argv) + strbuf_addch(buf, ' '); + strbuf_addch(buf, '"'); + for (const char *p = *argp; *p; p++) { + const char c = *p; + + if (c == '"' || c =='\\') + strbuf_addch(buf, '\\'); + strbuf_addch(buf, c); + } + strbuf_addch(buf, '"'); + } +} + #define SPLIT_CMDLINE_BAD_ENDING 1 #define SPLIT_CMDLINE_UNCLOSED_QUOTE 2 #define SPLIT_CMDLINE_ARGC_OVERFLOW 3 @@ -1,9 +1,12 @@ #ifndef ALIAS_H #define ALIAS_H +struct strbuf; struct string_list; char *alias_lookup(const char *alias); +/* Quote argv so buf can be parsed by split_cmdline() */ +void quote_cmdline(struct strbuf *buf, const char **argv); int split_cmdline(char *cmdline, const char ***argv); /* Takes a negative value returned by split_cmdline */ const char *split_cmdline_strerror(int cmdline_errno); @@ -22,6 +22,8 @@ #include "xdiff-interface.h" #include "ll-merge.h" #include "lockfile.h" +#include "object-name.h" +#include "object-file.h" #include "parse-options.h" #include "quote.h" #include "rerere.h" @@ -4586,7 +4588,7 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch) FILE *rej; char namebuf[PATH_MAX]; struct fragment *frag; - int cnt = 0; + int fd, cnt = 0; struct strbuf sb = STRBUF_INIT; for (cnt = 0, frag = patch->fragments; frag; frag = frag->next) { @@ -4626,7 +4628,17 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch) memcpy(namebuf, patch->new_name, cnt); memcpy(namebuf + cnt, ".rej", 5); - rej = fopen(namebuf, "w"); + fd = open(namebuf, O_CREAT | O_EXCL | O_WRONLY, 0666); + if (fd < 0) { + if (errno != EEXIST) + return error_errno(_("cannot open %s"), namebuf); + if (unlink(namebuf)) + return error_errno(_("cannot unlink '%s'"), namebuf); + fd = open(namebuf, O_CREAT | O_EXCL | O_WRONLY, 0666); + if (fd < 0) + return error_errno(_("cannot open %s"), namebuf); + } + rej = fdopen(fd, "w"); if (!rej) return error_errno(_("cannot open %s"), namebuf); diff --git a/archive-tar.c b/archive-tar.c index 497dad0b3a..4cd81d8161 100644 --- a/archive-tar.c +++ b/archive-tar.c @@ -5,6 +5,7 @@ #include "alloc.h" #include "config.h" #include "gettext.h" +#include "git-zlib.h" #include "hex.h" #include "tar.h" #include "archive.h" diff --git a/archive-zip.c b/archive-zip.c index e6f5c10a14..ef538a90df 100644 --- a/archive-zip.c +++ b/archive-zip.c @@ -5,6 +5,7 @@ #include "config.h" #include "archive.h" #include "gettext.h" +#include "git-zlib.h" #include "hex.h" #include "streaming.h" #include "utf8.h" @@ -2,6 +2,7 @@ #include "abspath.h" #include "alloc.h" #include "config.h" +#include "convert.h" #include "environment.h" #include "gettext.h" #include "hex.h" @@ -173,6 +174,29 @@ static int write_archive_entry(const struct object_id *oid, const char *base, args->convert = check_attr_export_subst(check); } + if (args->prefix) { + static struct strbuf new_path = STRBUF_INIT; + static struct strbuf buf = STRBUF_INIT; + const char *rel; + + rel = relative_path(path_without_prefix, args->prefix, &buf); + + /* + * We don't add an entry for the current working + * directory when we are at the root; skip it also when + * we're in a subdirectory or submodule. Skip entries + * higher up as well. + */ + if (!strcmp(rel, "./") || starts_with(rel, "../")) + return S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0; + + /* rel can refer to path, so don't edit it in place */ + strbuf_reset(&new_path); + strbuf_add(&new_path, args->base, args->baselen); + strbuf_addstr(&new_path, rel); + strbuf_swap(&path, &new_path); + } + if (args->verbose) fprintf(stderr, "%.*s\n", (int)path.len, path.buf); @@ -408,6 +432,27 @@ static int reject_entry(const struct object_id *oid UNUSED, return ret; } +static int reject_outside(const struct object_id *oid UNUSED, + struct strbuf *base, const char *filename, + unsigned mode, void *context) +{ + struct archiver_args *args = context; + struct strbuf buf = STRBUF_INIT; + struct strbuf path = STRBUF_INIT; + int ret = 0; + + if (S_ISDIR(mode)) + return READ_TREE_RECURSIVE; + + strbuf_addbuf(&path, base); + strbuf_addstr(&path, filename); + if (starts_with(relative_path(path.buf, args->prefix, &buf), "../")) + ret = -1; + strbuf_release(&buf); + strbuf_release(&path); + return ret; +} + static int path_exists(struct archiver_args *args, const char *path) { const char *paths[] = { path, NULL }; @@ -415,8 +460,13 @@ static int path_exists(struct archiver_args *args, const char *path) int ret; ctx.args = args; - parse_pathspec(&ctx.pathspec, 0, 0, "", paths); + parse_pathspec(&ctx.pathspec, 0, PATHSPEC_PREFER_CWD, + args->prefix, paths); ctx.pathspec.recursive = 1; + if (args->prefix && read_tree(args->repo, args->tree, &ctx.pathspec, + reject_outside, args)) + die(_("pathspec '%s' matches files outside the " + "current directory"), path); ret = read_tree(args->repo, args->tree, &ctx.pathspec, reject_entry, &ctx); @@ -432,9 +482,8 @@ static void parse_pathspec_arg(const char **pathspec, * Also if pathspec patterns are dependent, we're in big * trouble as we test each one separately */ - parse_pathspec(&ar_args->pathspec, 0, - PATHSPEC_PREFER_FULL, - "", pathspec); + parse_pathspec(&ar_args->pathspec, 0, PATHSPEC_PREFER_CWD, + ar_args->prefix, pathspec); ar_args->pathspec.recursive = 1; if (pathspec) { while (*pathspec) { @@ -446,8 +495,7 @@ static void parse_pathspec_arg(const char **pathspec, } static void parse_treeish_arg(const char **argv, - struct archiver_args *ar_args, const char *prefix, - int remote) + struct archiver_args *ar_args, int remote) { const char *name = argv[0]; const struct object_id *commit_oid; @@ -487,20 +535,6 @@ static void parse_treeish_arg(const char **argv, if (!tree) die(_("not a tree object: %s"), oid_to_hex(&oid)); - if (prefix) { - struct object_id tree_oid; - unsigned short mode; - int err; - - err = get_tree_entry(ar_args->repo, - &tree->object.oid, - prefix, &tree_oid, - &mode); - if (err || !S_ISDIR(mode)) - die(_("current working directory is untracked")); - - tree = parse_tree_indirect(&tree_oid); - } ar_args->refname = ref; ar_args->tree = tree; ar_args->commit_oid = commit_oid; @@ -718,7 +752,7 @@ int write_archive(int argc, const char **argv, const char *prefix, setup_git_directory(); } - parse_treeish_arg(argv, &args, prefix, remote); + parse_treeish_arg(argv, &args, remote); parse_pathspec_arg(argv + 1, &args); rc = ar->write_archive(ar, &args); @@ -1,8 +1,9 @@ #ifndef ARCHIVE_H #define ARCHIVE_H -#include "cache.h" +#include "object-name.h" #include "pathspec.h" +#include "string-list.h" struct repository; struct pretty_print_context; @@ -1,4 +1,4 @@ -#include "cache.h" +#include "git-compat-util.h" #include "config.h" #include "commit.h" #include "diff.h" @@ -17,6 +17,7 @@ #include "strvec.h" #include "commit-slab.h" #include "commit-reach.h" +#include "object-name.h" #include "object-store.h" #include "dir.h" @@ -3,12 +3,14 @@ #include "object-store.h" #include "cache-tree.h" #include "mergesort.h" +#include "convert.h" #include "diff.h" #include "diffcore.h" #include "gettext.h" #include "hex.h" #include "setup.h" #include "tag.h" +#include "trace2.h" #include "blame.h" #include "alloc.h" #include "commit-slab.h" @@ -1,10 +1,11 @@ #include "git-compat-util.h" -#include "cache.h" +#include "advice.h" #include "config.h" #include "branch.h" #include "environment.h" #include "gettext.h" #include "hex.h" +#include "object-name.h" #include "refs.h" #include "refspec.h" #include "remote.h" diff --git a/builtin/add.c b/builtin/add.c index f12054d9be..76cc026a68 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -5,9 +5,11 @@ */ #define USE_THE_INDEX_VARIABLE #include "cache.h" +#include "advice.h" #include "config.h" #include "builtin.h" #include "lockfile.h" +#include "editor.h" #include "dir.h" #include "gettext.h" #include "pathspec.h" diff --git a/builtin/am.c b/builtin/am.c index cd1e20f24e..5c83f2e003 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -6,8 +6,10 @@ #define USE_THE_INDEX_VARIABLE #include "cache.h" #include "abspath.h" +#include "advice.h" #include "config.h" #include "builtin.h" +#include "editor.h" #include "environment.h" #include "exec-cmd.h" #include "gettext.h" @@ -26,6 +28,7 @@ #include "diffcore.h" #include "unpack-trees.h" #include "branch.h" +#include "object-name.h" #include "sequencer.h" #include "revision.h" #include "merge-recursive.h" @@ -37,6 +40,7 @@ #include "apply.h" #include "string-list.h" #include "packfile.h" +#include "pager.h" #include "repository.h" #include "pretty.h" #include "wrapper.h" diff --git a/builtin/bisect.c b/builtin/bisect.c index 26f07357a0..4b2143d455 100644 --- a/builtin/bisect.c +++ b/builtin/bisect.c @@ -3,12 +3,14 @@ #include "environment.h" #include "gettext.h" #include "hex.h" +#include "object-name.h" #include "parse-options.h" #include "bisect.h" #include "refs.h" #include "dir.h" #include "strvec.h" #include "run-command.h" +#include "oid-array.h" #include "prompt.h" #include "quote.h" #include "revision.h" diff --git a/builtin/blame.c b/builtin/blame.c index a8d2114adc..2df6039a6e 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -28,7 +28,9 @@ #include "line-log.h" #include "dir.h" #include "progress.h" +#include "object-name.h" #include "object-store.h" +#include "pager.h" #include "blame.h" #include "refs.h" #include "setup.h" diff --git a/builtin/branch.c b/builtin/branch.c index 6413a016c5..501c47657c 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -8,11 +8,13 @@ #include "cache.h" #include "config.h" #include "color.h" +#include "editor.h" #include "environment.h" #include "refs.h" #include "commit.h" #include "builtin.h" #include "gettext.h" +#include "object-name.h" #include "remote.h" #include "parse-options.h" #include "branch.h" @@ -44,6 +46,7 @@ static const char *head; static struct object_id head_oid; static int recurse_submodules = 0; static int submodule_propagate_branches = 0; +static int omit_empty = 0; static int branch_use_color = -1; static char branch_colors[][COLOR_MAXLEN] = { @@ -220,10 +223,11 @@ static int delete_branches(int argc, const char **argv, int force, int kinds, struct string_list refs_to_delete = STRING_LIST_INIT_DUP; struct string_list_item *item; int branch_name_pos; + const char *fmt_remotes = "refs/remotes/%s"; switch (kinds) { case FILTER_REFS_REMOTES: - fmt = "refs/remotes/%s"; + fmt = fmt_remotes; /* For subsequent UI messages */ remote_branch = 1; allowed_interpret = INTERPRET_BRANCH_REMOTE; @@ -267,9 +271,25 @@ static int delete_branches(int argc, const char **argv, int force, int kinds, | RESOLVE_REF_ALLOW_BAD_NAME, &oid, &flags); if (!target) { - error(remote_branch - ? _("remote-tracking branch '%s' not found.") - : _("branch '%s' not found."), bname.buf); + if (remote_branch) { + error(_("remote-tracking branch '%s' not found."), bname.buf); + } else { + char *virtual_name = mkpathdup(fmt_remotes, bname.buf); + char *virtual_target = resolve_refdup(virtual_name, + RESOLVE_REF_READING + | RESOLVE_REF_NO_RECURSE + | RESOLVE_REF_ALLOW_BAD_NAME, + &oid, &flags); + FREE_AND_NULL(virtual_name); + + if (virtual_target) + error(_("branch '%s' not found.\n" + "Did you forget --remote?"), + bname.buf); + else + error(_("branch '%s' not found."), bname.buf); + FREE_AND_NULL(virtual_target); + } ret = 1; continue; } @@ -466,7 +486,8 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin string_list_append(output, out.buf); } else { fwrite(out.buf, 1, out.len, stdout); - putchar('\n'); + if (out.len || !omit_empty) + putchar('\n'); } } @@ -675,6 +696,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix) OPT_BIT('D', NULL, &delete, N_("delete branch (even if not merged)"), 2), OPT_BIT('m', "move", &rename, N_("move/rename a branch and its reflog"), 1), OPT_BIT('M', NULL, &rename, N_("move/rename a branch, even if target exists"), 2), + OPT_BOOL(0, "omit-empty", &omit_empty, + N_("do not output a newline after empty formatted refs")), OPT_BIT('c', "copy", ©, N_("copy a branch and its reflog"), 1), OPT_BIT('C', NULL, ©, N_("copy a branch, even if target exists"), 2), OPT_BOOL('l', "list", &list, N_("list branch names")), diff --git a/builtin/bugreport.c b/builtin/bugreport.c index 52955e1d38..daf6c23657 100644 --- a/builtin/bugreport.c +++ b/builtin/bugreport.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "abspath.h" +#include "editor.h" #include "gettext.h" #include "parse-options.h" #include "strbuf.h" @@ -8,6 +9,7 @@ #include "hook.h" #include "hook-list.h" #include "diagnose.h" +#include "object-file.h" #include "setup.h" #include "wrapper.h" diff --git a/builtin/cat-file.c b/builtin/cat-file.c index 04d4bb6c77..0bafc14e6c 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -7,6 +7,7 @@ #include "cache.h" #include "alloc.h" #include "config.h" +#include "convert.h" #include "builtin.h" #include "diff.h" #include "environment.h" @@ -19,6 +20,8 @@ #include "tree-walk.h" #include "oid-array.h" #include "packfile.h" +#include "object-file.h" +#include "object-name.h" #include "object-store.h" #include "replace-object.h" #include "promisor-remote.h" diff --git a/builtin/check-attr.c b/builtin/check-attr.c index 1dbe9d6ca8..037bf1aaa2 100644 --- a/builtin/check-attr.c +++ b/builtin/check-attr.c @@ -5,6 +5,7 @@ #include "attr.h" #include "environment.h" #include "gettext.h" +#include "object-name.h" #include "quote.h" #include "setup.h" #include "parse-options.h" diff --git a/builtin/checkout.c b/builtin/checkout.c index 38a8cd6a96..6f5d82ed3d 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -15,7 +15,9 @@ #include "hook.h" #include "ll-merge.h" #include "lockfile.h" +#include "mem-pool.h" #include "merge-recursive.h" +#include "object-name.h" #include "object-store.h" #include "parse-options.h" #include "refs.h" @@ -26,6 +28,7 @@ #include "setup.h" #include "submodule.h" #include "submodule-config.h" +#include "trace2.h" #include "tree.h" #include "tree-walk.h" #include "unpack-trees.h" diff --git a/builtin/clone.c b/builtin/clone.c index 6dc89f1058..186845ef0b 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -11,6 +11,7 @@ #define USE_THE_INDEX_VARIABLE #include "builtin.h" #include "abspath.h" +#include "advice.h" #include "config.h" #include "environment.h" #include "gettext.h" @@ -20,6 +21,7 @@ #include "fetch-pack.h" #include "refs.h" #include "refspec.h" +#include "object-file.h" #include "object-store.h" #include "tree.h" #include "tree-walk.h" @@ -40,6 +42,7 @@ #include "hook.h" #include "bundle.h" #include "bundle-uri.h" +#include "wrapper.h" /* * Overall FIXMEs: @@ -331,8 +334,18 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest, iter = dir_iterator_begin(src->buf, DIR_ITERATOR_PEDANTIC); - if (!iter) + if (!iter) { + if (errno == ENOTDIR) { + int saved_errno = errno; + struct stat st; + + if (!lstat(src->buf, &st) && S_ISLNK(st.st_mode)) + die(_("'%s' is a symlink, refusing to clone with --local"), + src->buf); + errno = saved_errno; + } die_errno(_("failed to start iterator over '%s'"), src->buf); + } strbuf_addch(src, '/'); src_len = src->len; diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c index 9011426976..a3d00fa232 100644 --- a/builtin/commit-graph.c +++ b/builtin/commit-graph.c @@ -12,6 +12,7 @@ #include "progress.h" #include "replace-object.h" #include "tag.h" +#include "trace2.h" #define BUILTIN_COMMIT_GRAPH_VERIFY_USAGE \ N_("git commit-graph verify [--object-dir <dir>] [--shallow] [--[no-]progress]") diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c index 15be167f87..d1d251c3de 100644 --- a/builtin/commit-tree.c +++ b/builtin/commit-tree.c @@ -7,6 +7,7 @@ #include "config.h" #include "gettext.h" #include "hex.h" +#include "object-name.h" #include "object-store.h" #include "repository.h" #include "commit.h" diff --git a/builtin/commit.c b/builtin/commit.c index 9d8e1ea91a..e67c4be221 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -7,11 +7,13 @@ #define USE_THE_INDEX_VARIABLE #include "cache.h" +#include "advice.h" #include "config.h" #include "lockfile.h" #include "cache-tree.h" #include "color.h" #include "dir.h" +#include "editor.h" #include "environment.h" #include "builtin.h" #include "diff.h" @@ -26,6 +28,7 @@ #include "log-tree.h" #include "strbuf.h" #include "utf8.h" +#include "object-name.h" #include "parse-options.h" #include "string-list.h" #include "rerere.h" diff --git a/builtin/config.c b/builtin/config.c index fe79fb60c4..9401f1e5e3 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -3,6 +3,7 @@ #include "alloc.h" #include "config.h" #include "color.h" +#include "editor.h" #include "environment.h" #include "gettext.h" #include "ident.h" diff --git a/builtin/credential-cache--daemon.c b/builtin/credential-cache--daemon.c index 62c09a271d..4e571d9951 100644 --- a/builtin/credential-cache--daemon.c +++ b/builtin/credential-cache--daemon.c @@ -2,6 +2,7 @@ #include "abspath.h" #include "alloc.h" #include "gettext.h" +#include "object-file.h" #include "parse-options.h" #ifndef NO_UNIX_SOCKETS diff --git a/builtin/describe.c b/builtin/describe.c index 0125d4ddba..55b4baaa22 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -11,6 +11,7 @@ #include "refs.h" #include "builtin.h" #include "exec-cmd.h" +#include "object-name.h" #include "parse-options.h" #include "revision.h" #include "diff.h" @@ -658,6 +659,8 @@ int cmd_describe(int argc, const char **argv, const char *prefix) int fd, result; setup_work_tree(); + prepare_repo_settings(the_repository); + the_repository->settings.command_requires_full_index = 0; repo_read_index(the_repository); refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL); diff --git a/builtin/diagnose.c b/builtin/diagnose.c index 0f8b64994c..4f22eb2b55 100644 --- a/builtin/diagnose.c +++ b/builtin/diagnose.c @@ -1,6 +1,7 @@ #include "builtin.h" #include "abspath.h" #include "gettext.h" +#include "object-file.h" #include "parse-options.h" #include "diagnose.h" diff --git a/builtin/difftool.c b/builtin/difftool.c index e010a21bfb..f09d24d37f 100644 --- a/builtin/difftool.c +++ b/builtin/difftool.c @@ -25,6 +25,7 @@ #include "strvec.h" #include "strbuf.h" #include "lockfile.h" +#include "object-file.h" #include "object-store.h" #include "dir.h" #include "entry.h" @@ -691,7 +692,7 @@ static int run_file_diff(int prompt, const char *prefix, int cmd_difftool(int argc, const char **argv, const char *prefix) { - int use_gui_tool = 0, dir_diff = 0, prompt = -1, symlinks = 0, + int use_gui_tool = -1, dir_diff = 0, prompt = -1, symlinks = 0, tool_help = 0, no_index = 0; static char *difftool_cmd = NULL, *extcmd = NULL; struct option builtin_difftool_options[] = { @@ -741,13 +742,21 @@ int cmd_difftool(int argc, const char **argv, const char *prefix) } else if (dir_diff) die(_("options '%s' and '%s' cannot be used together"), "--dir-diff", "--no-index"); - die_for_incompatible_opt3(use_gui_tool, "--gui", + die_for_incompatible_opt3(use_gui_tool == 1, "--gui", !!difftool_cmd, "--tool", !!extcmd, "--extcmd"); - if (use_gui_tool) + /* + * Explicitly specified GUI option is forwarded to git-mergetool--lib.sh; + * empty or unset means "use the difftool.guiDefault config or default to + * false". + */ + if (use_gui_tool == 1) setenv("GIT_MERGETOOL_GUI", "true", 1); - else if (difftool_cmd) { + else if (use_gui_tool == 0) + setenv("GIT_MERGETOOL_GUI", "false", 1); + + if (difftool_cmd) { if (*difftool_cmd) setenv("GIT_DIFF_TOOL", difftool_cmd, 1); else diff --git a/builtin/fast-export.c b/builtin/fast-export.c index 8224bf4bc1..9a95f6a1a8 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -10,6 +10,7 @@ #include "hex.h" #include "refs.h" #include "refspec.h" +#include "object-file.h" #include "object-store.h" #include "commit.h" #include "object.h" diff --git a/builtin/fast-import.c b/builtin/fast-import.c index 1fb95275d7..bbd9b2b3e7 100644 --- a/builtin/fast-import.c +++ b/builtin/fast-import.c @@ -19,6 +19,8 @@ #include "dir.h" #include "run-command.h" #include "packfile.h" +#include "object-file.h" +#include "object-name.h" #include "object-store.h" #include "mem-pool.h" #include "commit-reach.h" diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c index 5f341b794d..3ba0fe5a39 100644 --- a/builtin/fetch-pack.c +++ b/builtin/fetch-pack.c @@ -2,6 +2,7 @@ #include "alloc.h" #include "gettext.h" #include "hex.h" +#include "object-file.h" #include "pkt-line.h" #include "fetch-pack.h" #include "remote.h" diff --git a/builtin/fetch.c b/builtin/fetch.c index 85bd280103..ab623f41b4 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -2,6 +2,7 @@ * "git fetch" */ #include "cache.h" +#include "advice.h" #include "config.h" #include "gettext.h" #include "environment.h" @@ -9,8 +10,10 @@ #include "repository.h" #include "refs.h" #include "refspec.h" +#include "object-name.h" #include "object-store.h" #include "oidset.h" +#include "oid-array.h" #include "commit.h" #include "builtin.h" #include "string-list.h" @@ -25,12 +28,15 @@ #include "strvec.h" #include "utf8.h" #include "packfile.h" +#include "pager.h" #include "list-objects-filter-options.h" #include "commit-reach.h" #include "branch.h" #include "promisor-remote.h" #include "commit-graph.h" #include "shallow.h" +#include "trace.h" +#include "trace2.h" #include "worktree.h" #include "bundle-uri.h" diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index 0bdc49a6e1..695fc8f4a5 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -22,7 +22,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix) int i; struct ref_sorting *sorting; struct string_list sorting_options = STRING_LIST_INIT_DUP; - int maxcount = 0, icase = 0; + int maxcount = 0, icase = 0, omit_empty = 0; struct ref_array array; struct ref_filter filter; struct ref_format format = REF_FORMAT_INIT; @@ -40,6 +40,8 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix) N_("quote placeholders suitably for python"), QUOTE_PYTHON), OPT_BIT(0 , "tcl", &format.quote_style, N_("quote placeholders suitably for Tcl"), QUOTE_TCL), + OPT_BOOL(0, "omit-empty", &omit_empty, + N_("do not output a newline after empty formatted refs")), OPT_GROUP(""), OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")), @@ -112,7 +114,8 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix) if (format_ref_array_item(array.items[i], &format, &output, &err)) die("%s", err.buf); fwrite(output.buf, 1, output.len, stdout); - putchar('\n'); + if (output.len || !omit_empty) + putchar('\n'); } strbuf_release(&err); diff --git a/builtin/fsck.c b/builtin/fsck.c index 095b39d398..2cd461b84c 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -19,11 +19,14 @@ #include "streaming.h" #include "decorate.h" #include "packfile.h" +#include "object-file.h" +#include "object-name.h" #include "object-store.h" #include "replace-object.h" #include "resolve-undo.h" #include "run-command.h" #include "worktree.h" +#include "pack-revindex.h" #define REACHABLE 0x0001 #define SEEN 0x0002 @@ -53,6 +56,7 @@ static int name_objects; #define ERROR_REFS 010 #define ERROR_COMMIT_GRAPH 020 #define ERROR_MULTI_PACK_INDEX 040 +#define ERROR_PACK_REV_INDEX 0100 static const char *describe_object(const struct object_id *oid) { @@ -856,6 +860,38 @@ static int mark_packed_for_connectivity(const struct object_id *oid, return 0; } +static int check_pack_rev_indexes(struct repository *r, int show_progress) +{ + struct progress *progress = NULL; + uint32_t pack_count = 0; + int res = 0; + + if (show_progress) { + for (struct packed_git *p = get_all_packs(the_repository); p; p = p->next) + pack_count++; + progress = start_delayed_progress("Verifying reverse pack-indexes", pack_count); + pack_count = 0; + } + + for (struct packed_git *p = get_all_packs(the_repository); p; p = p->next) { + int load_error = load_pack_revindex_from_disk(p); + + if (load_error < 0) { + error(_("unable to load rev-index for pack '%s'"), p->pack_name); + res = ERROR_PACK_REV_INDEX; + } else if (!load_error && + !load_pack_revindex(the_repository, p) && + verify_pack_revindex(p)) { + error(_("invalid rev-index for pack '%s'"), p->pack_name); + res = ERROR_PACK_REV_INDEX; + } + display_progress(progress, ++pack_count); + } + stop_progress(&progress); + + return res; +} + static char const * const fsck_usage[] = { N_("git fsck [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]\n" " [--[no-]full] [--strict] [--verbose] [--lost-found]\n" @@ -1019,6 +1055,8 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) free_worktrees(worktrees); } + errors_found |= check_pack_rev_indexes(the_repository, show_progress); + check_connectivity(); if (the_repository->settings.core_commit_graph) { diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c index 42af6a2cc7..f6dd9a784c 100644 --- a/builtin/fsmonitor--daemon.c +++ b/builtin/fsmonitor--daemon.c @@ -14,6 +14,7 @@ #include "simple-ipc.h" #include "khash.h" #include "pkt-line.h" +#include "trace2.h" static const char * const builtin_fsmonitor__daemon_usage[] = { N_("git fsmonitor--daemon start [<options>]"), diff --git a/builtin/gc.c b/builtin/gc.c index ece01e966f..c9f8557335 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -25,6 +25,7 @@ #include "commit.h" #include "commit-graph.h" #include "packfile.h" +#include "object-file.h" #include "object-store.h" #include "pack.h" #include "pack-objects.h" @@ -37,6 +38,7 @@ #include "gettext.h" #include "hook.h" #include "setup.h" +#include "trace2.h" #include "wrapper.h" #define FAILED_RUN "failed to run %s" diff --git a/builtin/get-tar-commit-id.c b/builtin/get-tar-commit-id.c index d5b871b21d..564cfcac4f 100644 --- a/builtin/get-tar-commit-id.c +++ b/builtin/get-tar-commit-id.c @@ -35,7 +35,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv UNUSED, const char *prefix die_errno("git get-tar-commit-id: read error"); if (n != HEADERSIZE) die_errno("git get-tar-commit-id: EOF before reading tar header"); - if (header->typeflag[0] != 'g') + if (header->typeflag[0] != TYPEFLAG_GLOBAL_HEADER) return 1; len = strtol(content, &end, 10); diff --git a/builtin/grep.c b/builtin/grep.c index a1b68d90bd..b86c754def 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -26,8 +26,11 @@ #include "setup.h" #include "submodule.h" #include "submodule-config.h" +#include "object-file.h" +#include "object-name.h" #include "object-store.h" #include "packfile.h" +#include "pager.h" #include "write-or-die.h" static const char *grep_prefix; diff --git a/builtin/hash-object.c b/builtin/hash-object.c index a15fe4fd3f..a380121166 100644 --- a/builtin/hash-object.c +++ b/builtin/hash-object.c @@ -9,6 +9,7 @@ #include "config.h" #include "gettext.h" #include "hex.h" +#include "object-file.h" #include "object-store.h" #include "blob.h" #include "quote.h" diff --git a/builtin/help.c b/builtin/help.c index 87333a02ec..128aa83099 100644 --- a/builtin/help.c +++ b/builtin/help.c @@ -6,6 +6,7 @@ #include "builtin.h" #include "exec-cmd.h" #include "gettext.h" +#include "pager.h" #include "parse-options.h" #include "run-command.h" #include "config-list.h" diff --git a/builtin/index-pack.c b/builtin/index-pack.c index b17e79cd40..bb67e16655 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -17,7 +17,10 @@ #include "streaming.h" #include "thread-utils.h" #include "packfile.h" +#include "pack-revindex.h" +#include "object-file.h" #include "object-store.h" +#include "oid-array.h" #include "replace-object.h" #include "promisor-remote.h" #include "setup.h" @@ -1753,12 +1756,13 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix) fsck_options.walk = mark_link; reset_pack_idx_option(&opts); + opts.flags |= WRITE_REV; git_config(git_index_pack_config, &opts); if (prefix && chdir(prefix)) die(_("Cannot come back to cwd")); - if (git_env_bool(GIT_TEST_WRITE_REV_INDEX, 0)) - rev_index = 1; + if (git_env_bool(GIT_TEST_NO_WRITE_REV_INDEX, 0)) + rev_index = 0; else rev_index = !!(opts.flags & (WRITE_REV_VERIFY | WRITE_REV)); diff --git a/builtin/init-db.c b/builtin/init-db.c index ba6e0b20fa..6183f3fb3f 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -11,6 +11,7 @@ #include "refs.h" #include "builtin.h" #include "exec-cmd.h" +#include "object-file.h" #include "parse-options.h" #include "setup.h" #include "worktree.h" diff --git a/builtin/log.c b/builtin/log.c index 7d19578963..4f162ff4d0 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -12,7 +12,10 @@ #include "gettext.h" #include "hex.h" #include "refs.h" +#include "object-file.h" +#include "object-name.h" #include "object-store.h" +#include "pager.h" #include "color.h" #include "commit.h" #include "diff.h" @@ -20,6 +23,7 @@ #include "revision.h" #include "log-tree.h" #include "builtin.h" +#include "oid-array.h" #include "tag.h" #include "reflog-walk.h" #include "patch-ids.h" diff --git a/builtin/ls-files.c b/builtin/ls-files.c index ed35fa8d8e..625f48f0d6 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -8,10 +8,12 @@ #include "cache.h" #include "repository.h" #include "config.h" +#include "convert.h" #include "quote.h" #include "dir.h" #include "builtin.h" #include "gettext.h" +#include "object-name.h" #include "strbuf.h" #include "tree.h" #include "cache-tree.h" diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c index f32e6be219..077977a461 100644 --- a/builtin/ls-tree.c +++ b/builtin/ls-tree.c @@ -7,6 +7,7 @@ #include "config.h" #include "gettext.h" #include "hex.h" +#include "object-name.h" #include "object-store.h" #include "blob.h" #include "tree.h" diff --git a/builtin/merge-base.c b/builtin/merge-base.c index 3f22273b40..854019a32d 100644 --- a/builtin/merge-base.c +++ b/builtin/merge-base.c @@ -7,6 +7,7 @@ #include "refs.h" #include "diff.h" #include "revision.h" +#include "object-name.h" #include "parse-options.h" #include "repository.h" #include "commit-reach.h" diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c index 91ed55f3ab..708a8ffabe 100644 --- a/builtin/merge-recursive.c +++ b/builtin/merge-recursive.c @@ -1,9 +1,11 @@ #include "cache.h" #include "builtin.h" +#include "advice.h" #include "commit.h" #include "gettext.h" #include "tag.h" #include "merge-recursive.h" +#include "object-name.h" #include "xdiff-interface.h" static const char builtin_merge_recursive_usage[] = diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index 803e380856..6b9f006ec1 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -8,6 +8,7 @@ #include "commit.h" #include "commit-reach.h" #include "merge-ort.h" +#include "object-name.h" #include "object-store.h" #include "parse-options.h" #include "repository.h" diff --git a/builtin/merge.c b/builtin/merge.c index a99be9610e..8da3e46abb 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -9,11 +9,14 @@ #define USE_THE_INDEX_VARIABLE #include "cache.h" #include "abspath.h" +#include "advice.h" #include "alloc.h" #include "config.h" +#include "editor.h" #include "environment.h" #include "gettext.h" #include "hex.h" +#include "object-name.h" #include "parse-options.h" #include "builtin.h" #include "lockfile.h" diff --git a/builtin/mktag.c b/builtin/mktag.c index b3f6d7ea38..44fa56eff3 100644 --- a/builtin/mktag.c +++ b/builtin/mktag.c @@ -4,6 +4,7 @@ #include "parse-options.h" #include "tag.h" #include "replace-object.h" +#include "object-file.h" #include "object-store.h" #include "fsck.h" #include "config.h" diff --git a/builtin/mv.c b/builtin/mv.c index b7c5ffbd8c..32935af48e 100644 --- a/builtin/mv.c +++ b/builtin/mv.c @@ -6,10 +6,12 @@ #define USE_THE_INDEX_VARIABLE #include "builtin.h" #include "abspath.h" +#include "advice.h" #include "alloc.h" #include "config.h" #include "environment.h" #include "gettext.h" +#include "object-file.h" #include "pathspec.h" #include "lockfile.h" #include "dir.h" diff --git a/builtin/name-rev.c b/builtin/name-rev.c index 831d360a78..593f0506a1 100644 --- a/builtin/name-rev.c +++ b/builtin/name-rev.c @@ -8,6 +8,8 @@ #include "commit.h" #include "tag.h" #include "refs.h" +#include "object-name.h" +#include "pager.h" #include "parse-options.h" #include "prio-queue.h" #include "hash-lookup.h" diff --git a/builtin/notes.c b/builtin/notes.c index 4ff44f1e3d..d5788352b6 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -10,9 +10,11 @@ #include "cache.h" #include "config.h" #include "builtin.h" +#include "editor.h" #include "gettext.h" #include "hex.h" #include "notes.h" +#include "object-name.h" #include "object-store.h" #include "repository.h" #include "blob.h" diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 77d88f85b0..a5b466839b 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -33,6 +33,7 @@ #include "strvec.h" #include "list.h" #include "packfile.h" +#include "object-file.h" #include "object-store.h" #include "replace-object.h" #include "dir.h" @@ -3359,16 +3360,16 @@ static void read_packs_list_from_stdin(void) } string_list_sort(&include_packs); + string_list_remove_duplicates(&include_packs, 0); string_list_sort(&exclude_packs); + string_list_remove_duplicates(&exclude_packs, 0); for (p = get_all_packs(the_repository); p; p = p->next) { const char *pack_name = pack_basename(p); - item = string_list_lookup(&include_packs, pack_name); - if (!item) - item = string_list_lookup(&exclude_packs, pack_name); - - if (item) + if ((item = string_list_lookup(&include_packs, pack_name))) + item->util = p; + if ((item = string_list_lookup(&exclude_packs, pack_name))) item->util = p; } @@ -4293,9 +4294,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) } reset_pack_idx_option(&pack_idx_opts); + pack_idx_opts.flags |= WRITE_REV; git_config(git_pack_config, NULL); - if (git_env_bool(GIT_TEST_WRITE_REV_INDEX, 0)) - pack_idx_opts.flags |= WRITE_REV; + if (git_env_bool(GIT_TEST_NO_WRITE_REV_INDEX, 0)) + pack_idx_opts.flags &= ~WRITE_REV; progress = isatty(2); argc = parse_options(argc, argv, prefix, pack_objects_options, diff --git a/builtin/prune.c b/builtin/prune.c index 5c0952f5c6..5dc9b20720 100644 --- a/builtin/prune.c +++ b/builtin/prune.c @@ -11,6 +11,8 @@ #include "progress.h" #include "prune-packed.h" #include "replace-object.h" +#include "object-file.h" +#include "object-name.h" #include "object-store.h" #include "shallow.h" diff --git a/builtin/pull.c b/builtin/pull.c index 5405d09f22..967368ebc6 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -7,10 +7,12 @@ */ #define USE_THE_INDEX_VARIABLE #include "cache.h" +#include "advice.h" #include "config.h" #include "builtin.h" #include "gettext.h" #include "hex.h" +#include "object-name.h" #include "parse-options.h" #include "exec-cmd.h" #include "run-command.h" diff --git a/builtin/push.c b/builtin/push.c index fa550b8f80..6001e4ae0a 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -2,6 +2,7 @@ * "git push" */ #include "cache.h" +#include "advice.h" #include "branch.h" #include "config.h" #include "environment.h" @@ -16,6 +17,7 @@ #include "submodule.h" #include "submodule-config.h" #include "send-pack.h" +#include "trace2.h" #include "color.h" static const char * const push_usage[] = { diff --git a/builtin/range-diff.c b/builtin/range-diff.c index b72af527f0..04339a92ea 100644 --- a/builtin/range-diff.c +++ b/builtin/range-diff.c @@ -1,6 +1,7 @@ #include "cache.h" #include "builtin.h" #include "gettext.h" +#include "object-name.h" #include "parse-options.h" #include "range-diff.h" #include "config.h" diff --git a/builtin/read-tree.c b/builtin/read-tree.c index 600d4f748f..d61cbad96d 100644 --- a/builtin/read-tree.c +++ b/builtin/read-tree.c @@ -11,6 +11,7 @@ #include "hex.h" #include "lockfile.h" #include "object.h" +#include "object-name.h" #include "tree.h" #include "tree-walk.h" #include "cache-tree.h" diff --git a/builtin/rebase.c b/builtin/rebase.c index 680fe3c145..ace1d5e8d1 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -21,6 +21,8 @@ #include "cache-tree.h" #include "unpack-trees.h" #include "lockfile.h" +#include "object-file.h" +#include "object-name.h" #include "parse-options.h" #include "commit.h" #include "diff.h" @@ -32,6 +34,7 @@ #include "sequencer.h" #include "rebase-interactive.h" #include "reset.h" +#include "trace2.h" #include "hook.h" #include "wrapper.h" @@ -121,7 +124,8 @@ struct rebase_options { struct string_list exec; int allow_empty_message; int rebase_merges, rebase_cousins; - char *strategy, *strategy_opts; + char *strategy; + struct string_list strategy_opts; struct strbuf git_format_patch_opt; int reschedule_failed_exec; int reapply_cherry_picks; @@ -150,6 +154,7 @@ struct rebase_options { .config_rebase_merges = -1, \ .update_refs = -1, \ .config_update_refs = -1, \ + .strategy_opts = STRING_LIST_INIT_NODUP,\ } static struct replay_opts get_replay_opts(const struct rebase_options *opts) @@ -183,8 +188,8 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts) replay.default_strategy = NULL; } - if (opts->strategy_opts) - parse_strategy_opts(&replay, opts->strategy_opts); + for (size_t i = 0; i < opts->strategy_opts.nr; i++) + strvec_push(&replay.xopts, opts->strategy_opts.items[i].string); if (opts->squash_onto) { oidcpy(&replay.squash_onto, opts->squash_onto); @@ -492,24 +497,6 @@ static int read_basic_state(struct rebase_options *opts) opts->gpg_sign_opt = xstrdup(buf.buf); } - if (file_exists(state_dir_path("strategy", opts))) { - strbuf_reset(&buf); - if (!read_oneliner(&buf, state_dir_path("strategy", opts), - READ_ONELINER_WARN_MISSING)) - return -1; - free(opts->strategy); - opts->strategy = xstrdup(buf.buf); - } - - if (file_exists(state_dir_path("strategy_opts", opts))) { - strbuf_reset(&buf); - if (!read_oneliner(&buf, state_dir_path("strategy_opts", opts), - READ_ONELINER_WARN_MISSING)) - return -1; - free(opts->strategy_opts); - opts->strategy_opts = xstrdup(buf.buf); - } - strbuf_release(&buf); return 0; @@ -527,12 +514,6 @@ static int rebase_write_basic_state(struct rebase_options *opts) write_file(state_dir_path("quiet", opts), "%s", ""); if (opts->flags & REBASE_VERBOSE) write_file(state_dir_path("verbose", opts), "%s", ""); - if (opts->strategy) - write_file(state_dir_path("strategy", opts), "%s", - opts->strategy); - if (opts->strategy_opts) - write_file(state_dir_path("strategy_opts", opts), "%s", - opts->strategy_opts); if (opts->allow_rerere_autoupdate > 0) write_file(state_dir_path("allow_rerere_autoupdate", opts), "-%s-rerere-autoupdate", @@ -1089,7 +1070,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) struct object_id branch_base; int ignore_whitespace = 0; const char *gpg_sign = NULL; - struct string_list strategy_options = STRING_LIST_INIT_NODUP; struct object_id squash_onto; char *squash_onto_name = NULL; char *keep_base_onto_name = NULL; @@ -1197,7 +1177,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) N_("use 'merge-base --fork-point' to refine upstream")), OPT_STRING('s', "strategy", &options.strategy, N_("strategy"), N_("use the given merge strategy")), - OPT_STRING_LIST('X', "strategy-option", &strategy_options, + OPT_STRING_LIST('X', "strategy-option", &options.strategy_opts, N_("option"), N_("pass the argument through to the merge " "strategy")), @@ -1500,23 +1480,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) } else { /* REBASE_MERGE */ if (ignore_whitespace) { - string_list_append(&strategy_options, + string_list_append(&options.strategy_opts, "ignore-space-change"); } } - if (strategy_options.nr) { - int i; - - if (!options.strategy) - options.strategy = "ort"; - - strbuf_reset(&buf); - for (i = 0; i < strategy_options.nr; i++) - strbuf_addf(&buf, " --%s", - strategy_options.items[i].string); - options.strategy_opts = xstrdup(buf.buf); - } + if (options.strategy_opts.nr && !options.strategy) + options.strategy = "ort"; if (options.strategy) { options.strategy = xstrdup(options.strategy); @@ -1898,10 +1868,9 @@ cleanup: free(options.gpg_sign_opt); string_list_clear(&options.exec, 0); free(options.strategy); - free(options.strategy_opts); + string_list_clear(&options.strategy_opts, 0); strbuf_release(&options.git_format_patch_opt); free(squash_onto_name); free(keep_base_onto_name); - string_list_clear(&strategy_options, 0); return !!ret; } diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 9109552533..d22180435c 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -29,9 +29,12 @@ #include "tmp-objdir.h" #include "oidset.h" #include "packfile.h" +#include "object-name.h" #include "object-store.h" #include "protocol.h" #include "commit-reach.h" +#include "trace.h" +#include "trace2.h" #include "worktree.h" #include "shallow.h" #include "parse-options.h" @@ -2093,7 +2096,7 @@ static struct command *read_head_info(struct packet_reader *reader, const char *feature_list = reader->line + linelen + 1; const char *hash = NULL; const char *client_sid; - int len = 0; + size_t len = 0; if (parse_feature_request(feature_list, "report-status")) report_status = 1; if (parse_feature_request(feature_list, "report-status-v2")) diff --git a/builtin/repack.c b/builtin/repack.c index d9eee15c2f..bb7bf60e7c 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -325,7 +325,8 @@ static int geometry_cmp(const void *va, const void *vb) } static void init_pack_geometry(struct pack_geometry **geometry_p, - struct string_list *existing_kept_packs) + struct string_list *existing_kept_packs, + const struct pack_objects_args *args) { struct packed_git *p; struct pack_geometry *geometry; @@ -335,6 +336,14 @@ static void init_pack_geometry(struct pack_geometry **geometry_p, geometry = *geometry_p; for (p = get_all_packs(the_repository); p; p = p->next) { + if (args->local && !p->pack_local) + /* + * When asked to only repack local packfiles we skip + * over any packfiles that are borrowed from alternate + * object directories. + */ + continue; + if (!pack_kept_objects) { /* * Any pack that has its pack_keep bit set will appear @@ -448,8 +457,10 @@ static void split_pack_geometry(struct pack_geometry *geometry, int factor) geometry->split = split; } -static struct packed_git *get_largest_active_pack(struct pack_geometry *geometry) +static struct packed_git *get_preferred_pack(struct pack_geometry *geometry) { + uint32_t i; + if (!geometry) { /* * No geometry means either an all-into-one repack (in which @@ -464,7 +475,21 @@ static struct packed_git *get_largest_active_pack(struct pack_geometry *geometry } if (geometry->split == geometry->pack_nr) return NULL; - return geometry->pack[geometry->pack_nr - 1]; + + /* + * The preferred pack is the largest pack above the split line. In + * other words, it is the largest pack that does not get rolled up in + * the geometric repack. + */ + for (i = geometry->pack_nr; i > geometry->split; i--) + /* + * A pack that is not local would never be included in a + * multi-pack index. We thus skip over any non-local packs. + */ + if (geometry->pack[i - 1]->pack_local) + return geometry->pack[i - 1]; + + return NULL; } static void clear_pack_geometry(struct pack_geometry *geometry) @@ -558,6 +583,17 @@ static void midx_included_packs(struct string_list *include, for (i = geometry->split; i < geometry->pack_nr; i++) { struct packed_git *p = geometry->pack[i]; + /* + * The multi-pack index never refers to packfiles part + * of an alternate object database, so we skip these. + * While git-multi-pack-index(1) would silently ignore + * them anyway, this allows us to skip executing the + * command completely when we have only non-local + * packfiles. + */ + if (!p->pack_local) + continue; + strbuf_addstr(&buf, pack_basename(p)); strbuf_strip_suffix(&buf, ".pack"); strbuf_addstr(&buf, ".idx"); @@ -591,7 +627,7 @@ static int write_midx_included_packs(struct string_list *include, { struct child_process cmd = CHILD_PROCESS_INIT; struct string_list_item *item; - struct packed_git *largest = get_largest_active_pack(geometry); + struct packed_git *preferred = get_preferred_pack(geometry); FILE *in; int ret; @@ -612,9 +648,9 @@ static int write_midx_included_packs(struct string_list *include, if (write_bitmaps) strvec_push(&cmd.args, "--bitmap"); - if (largest) + if (preferred) strvec_pushf(&cmd.args, "--preferred-pack=%s", - pack_basename(largest)); + pack_basename(preferred)); if (refs_snapshot) strvec_pushf(&cmd.args, "--refs-snapshot=%s", refs_snapshot); @@ -853,6 +889,18 @@ int cmd_repack(int argc, const char **argv, const char *prefix) if (write_bitmaps && !(pack_everything & ALL_INTO_ONE) && !write_midx) die(_(incremental_bitmap_conflict_error)); + if (write_bitmaps && po_args.local && has_alt_odb(the_repository)) { + /* + * When asked to do a local repack, but we have + * packfiles that are inherited from an alternate, then + * we cannot guarantee that the multi-pack-index would + * have full coverage of all objects. We thus disable + * writing bitmaps in that case. + */ + warning(_("disabling bitmap writing, as some objects are not being packed")); + write_bitmaps = 0; + } + if (write_midx && write_bitmaps) { struct strbuf path = STRBUF_INIT; @@ -875,7 +923,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix) if (geometric_factor) { if (pack_everything) die(_("options '%s' and '%s' cannot be used together"), "--geometric", "-A/-a"); - init_pack_geometry(&geometry, &existing_kept_packs); + init_pack_geometry(&geometry, &existing_kept_packs, &po_args); split_pack_geometry(geometry, geometric_factor); } diff --git a/builtin/replace.c b/builtin/replace.c index d2adc8ab61..981f189443 100644 --- a/builtin/replace.c +++ b/builtin/replace.c @@ -11,12 +11,15 @@ #include "cache.h" #include "config.h" #include "builtin.h" +#include "editor.h" #include "environment.h" #include "gettext.h" #include "hex.h" #include "refs.h" #include "parse-options.h" #include "run-command.h" +#include "object-file.h" +#include "object-name.h" #include "object-store.h" #include "replace-object.h" #include "repository.h" diff --git a/builtin/reset.c b/builtin/reset.c index 0ed329236c..f99f32d580 100644 --- a/builtin/reset.c +++ b/builtin/reset.c @@ -9,6 +9,7 @@ */ #define USE_THE_INDEX_VARIABLE #include "builtin.h" +#include "advice.h" #include "config.h" #include "environment.h" #include "gettext.h" @@ -23,12 +24,15 @@ #include "diffcore.h" #include "tree.h" #include "branch.h" +#include "object-name.h" #include "parse-options.h" #include "unpack-trees.h" #include "cache-tree.h" #include "setup.h" #include "submodule.h" #include "submodule-config.h" +#include "trace.h" +#include "trace2.h" #include "dir.h" #include "add-interactive.h" diff --git a/builtin/rev-list.c b/builtin/rev-list.c index a3dbbb6338..6dc8be492a 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -10,6 +10,8 @@ #include "list-objects-filter.h" #include "list-objects-filter-options.h" #include "object.h" +#include "object-name.h" +#include "object-file.h" #include "object-store.h" #include "pack.h" #include "pack-bitmap.h" diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 1af2089f9b..852e49e340 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -15,6 +15,7 @@ #include "refs.h" #include "quote.h" #include "builtin.h" +#include "object-name.h" #include "parse-options.h" #include "diff.h" #include "revision.h" diff --git a/builtin/revert.c b/builtin/revert.c index f72761bf88..0240ec8593 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -45,20 +45,6 @@ static const char * const *revert_or_cherry_pick_usage(struct replay_opts *opts) return opts->action == REPLAY_REVERT ? revert_usage : cherry_pick_usage; } -static int option_parse_x(const struct option *opt, - const char *arg, int unset) -{ - struct replay_opts **opts_ptr = opt->value; - struct replay_opts *opts = *opts_ptr; - - if (unset) - return 0; - - ALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc); - opts->xopts[opts->xopts_nr++] = xstrdup(arg); - return 0; -} - static int option_parse_m(const struct option *opt, const char *arg, int unset) { @@ -116,8 +102,8 @@ static int run_sequencer(int argc, const char **argv, const char *prefix, N_("select mainline parent"), option_parse_m), OPT_RERERE_AUTOUPDATE(&opts->allow_rerere_auto), OPT_STRING(0, "strategy", &opts->strategy, N_("strategy"), N_("merge strategy")), - OPT_CALLBACK('X', "strategy-option", &opts, N_("option"), - N_("option for merge strategy"), option_parse_x), + OPT_STRVEC('X', "strategy-option", &opts->xopts, N_("option"), + N_("option for merge strategy")), { OPTION_STRING, 'S', "gpg-sign", &opts->gpg_sign, N_("key-id"), N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, OPT_END() @@ -178,7 +164,7 @@ static int run_sequencer(int argc, const char **argv, const char *prefix, "--signoff", opts->signoff, "--mainline", opts->mainline, "--strategy", opts->strategy ? 1 : 0, - "--strategy-option", opts->xopts ? 1 : 0, + "--strategy-option", opts->xopts.nr ? 1 : 0, "-x", opts->record_origin, "--ff", opts->allow_ff, "--rerere-autoupdate", opts->allow_rerere_auto == RERERE_AUTOUPDATE, diff --git a/builtin/rm.c b/builtin/rm.c index 6be9281742..d36072252e 100644 --- a/builtin/rm.c +++ b/builtin/rm.c @@ -13,6 +13,7 @@ #include "cache-tree.h" #include "gettext.h" #include "tree-walk.h" +#include "object-name.h" #include "parse-options.h" #include "string-list.h" #include "setup.h" diff --git a/builtin/show-branch.c b/builtin/show-branch.c index 463a8d11c3..20030b75e3 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -8,6 +8,7 @@ #include "builtin.h" #include "color.h" #include "strvec.h" +#include "object-name.h" #include "parse-options.h" #include "dir.h" #include "commit-slab.h" diff --git a/builtin/show-ref.c b/builtin/show-ref.c index 138d30a005..a2243b4219 100644 --- a/builtin/show-ref.c +++ b/builtin/show-ref.c @@ -4,6 +4,7 @@ #include "gettext.h" #include "hex.h" #include "refs.h" +#include "object-name.h" #include "object-store.h" #include "object.h" #include "tag.h" diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c index 5e917ead7b..40d420f06c 100644 --- a/builtin/sparse-checkout.c +++ b/builtin/sparse-checkout.c @@ -4,6 +4,8 @@ #include "dir.h" #include "environment.h" #include "gettext.h" +#include "object-file.h" +#include "object-name.h" #include "parse-options.h" #include "pathspec.h" #include "repository.h" diff --git a/builtin/stash.c b/builtin/stash.c index 735d27039e..a7e17ffe38 100644 --- a/builtin/stash.c +++ b/builtin/stash.c @@ -5,6 +5,7 @@ #include "environment.h" #include "gettext.h" #include "hex.h" +#include "object-name.h" #include "parse-options.h" #include "refs.h" #include "lockfile.h" diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 569068e6a2..6bf8d666ce 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -24,6 +24,8 @@ #include "revision.h" #include "diffcore.h" #include "diff.h" +#include "object-file.h" +#include "object-name.h" #include "object-store.h" #include "advice.h" #include "branch.h" diff --git a/builtin/tag.c b/builtin/tag.c index 782bb3aa2f..1850a6a6fd 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -7,12 +7,15 @@ */ #include "cache.h" +#include "advice.h" #include "config.h" #include "builtin.h" +#include "editor.h" #include "environment.h" #include "gettext.h" #include "hex.h" #include "refs.h" +#include "object-name.h" #include "object-store.h" #include "tag.h" #include "run-command.h" @@ -41,6 +44,7 @@ static const char * const git_tag_usage[] = { static unsigned int colopts; static int force_sign_annotate; static int config_sign_tag = -1; /* unspecified */ +static int omit_empty = 0; static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, struct ref_format *format) @@ -79,7 +83,8 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, if (format_ref_array_item(array.items[i], format, &output, &err)) die("%s", err.buf); fwrite(output.buf, 1, output.len, stdout); - putchar('\n'); + if (output.len || !omit_empty) + putchar('\n'); } strbuf_release(&err); @@ -474,6 +479,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix) OPT_WITHOUT(&filter.no_commit, N_("print only tags that don't contain the commit")), OPT_MERGED(&filter, N_("print only tags that are merged")), OPT_NO_MERGED(&filter, N_("print only tags that are not merged")), + OPT_BOOL(0, "omit-empty", &omit_empty, + N_("do not output a newline after empty formatted refs")), OPT_REF_SORT(&sorting_options), { OPTION_CALLBACK, 0, "points-at", &filter.points_at, N_("object"), diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c index 00179180c7..b35a4b9dfe 100644 --- a/builtin/unpack-file.c +++ b/builtin/unpack-file.c @@ -1,6 +1,7 @@ #include "builtin.h" #include "config.h" #include "hex.h" +#include "object-name.h" #include "object-store.h" #include "wrapper.h" diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c index 585e81b106..2c52c3a741 100644 --- a/builtin/unpack-objects.c +++ b/builtin/unpack-objects.c @@ -4,6 +4,7 @@ #include "config.h" #include "environment.h" #include "gettext.h" +#include "git-zlib.h" #include "hex.h" #include "object-store.h" #include "object.h" diff --git a/builtin/update-index.c b/builtin/update-index.c index 03cda5e60d..33b00cef15 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -15,6 +15,7 @@ #include "cache-tree.h" #include "tree-walk.h" #include "builtin.h" +#include "object-file.h" #include "refs.h" #include "resolve-undo.h" #include "parse-options.h" diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 3ffd75b3e7..6ca85420c3 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -3,6 +3,7 @@ #include "gettext.h" #include "refs.h" #include "builtin.h" +#include "object-name.h" #include "parse-options.h" #include "quote.h" #include "strvec.h" diff --git a/builtin/var.c b/builtin/var.c index acb988d2d5..2149998980 100644 --- a/builtin/var.c +++ b/builtin/var.c @@ -5,7 +5,9 @@ */ #include "builtin.h" #include "config.h" +#include "editor.h" #include "ident.h" +#include "pager.h" #include "refs.h" static const char var_usage[] = "git var (-l | <variable>)"; diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c index 4d10aa98b1..5d99b82a64 100644 --- a/builtin/verify-commit.c +++ b/builtin/verify-commit.c @@ -9,6 +9,7 @@ #include "config.h" #include "builtin.h" #include "gettext.h" +#include "object-name.h" #include "object-store.h" #include "repository.h" #include "commit.h" diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c index 28d0da6845..c6019a0ad8 100644 --- a/builtin/verify-tag.c +++ b/builtin/verify-tag.c @@ -11,6 +11,7 @@ #include "gettext.h" #include "tag.h" #include "run-command.h" +#include "object-name.h" #include "parse-options.h" #include "gpg-interface.h" #include "ref-filter.h" diff --git a/builtin/worktree.c b/builtin/worktree.c index 39e9e5c9ce..a61bc32189 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -7,6 +7,8 @@ #include "environment.h" #include "gettext.h" #include "hex.h" +#include "object-file.h" +#include "object-name.h" #include "parse-options.h" #include "strvec.h" #include "branch.h" diff --git a/builtin/write-tree.c b/builtin/write-tree.c index 6085f64d10..32e302a813 100644 --- a/builtin/write-tree.c +++ b/builtin/write-tree.c @@ -41,6 +41,9 @@ int cmd_write_tree(int argc, const char **argv, const char *cmd_prefix) argc = parse_options(argc, argv, cmd_prefix, write_tree_options, write_tree_usage, 0); + prepare_repo_settings(the_repository); + the_repository->settings.command_requires_full_index = 0; + ret = write_index_as_tree(&oid, &the_index, get_index_file(), flags, tree_prefix); switch (ret) { diff --git a/bulk-checkin.c b/bulk-checkin.c index 6362b6aabc..d843279715 100644 --- a/bulk-checkin.c +++ b/bulk-checkin.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2011, Google Inc. */ -#include "cache.h" +#include "git-compat-util.h" #include "alloc.h" #include "bulk-checkin.h" #include "environment.h" @@ -15,7 +15,9 @@ #include "string-list.h" #include "tmp-objdir.h" #include "packfile.h" +#include "object-file.h" #include "object-store.h" +#include "wrapper.h" static int odb_transaction_nesting; @@ -1,4 +1,4 @@ -#include "cache.h" +#include "git-compat-util.h" #include "lockfile.h" #include "bundle.h" #include "environment.h" diff --git a/cache-tree.c b/cache-tree.c index ff14b527da..ebfe649b33 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -7,10 +7,13 @@ #include "tree-walk.h" #include "cache-tree.h" #include "bulk-checkin.h" +#include "object-file.h" #include "object-store.h" #include "replace-object.h" #include "promisor-remote.h" #include "sparse-index.h" +#include "trace.h" +#include "trace2.h" #ifndef DEBUG_CACHE_TREE #define DEBUG_CACHE_TREE 0 @@ -4,46 +4,11 @@ #include "git-compat-util.h" #include "strbuf.h" #include "hashmap.h" -#include "list.h" -#include "advice.h" #include "gettext.h" -#include "convert.h" -#include "trace.h" -#include "trace2.h" #include "string-list.h" -#include "pack-revindex.h" -#include "hash.h" -#include "path.h" #include "pathspec.h" #include "object.h" -#include "oid-array.h" -#include "repository.h" #include "statinfo.h" -#include "mem-pool.h" - -typedef struct git_zstream { - z_stream z; - unsigned long avail_in; - unsigned long avail_out; - unsigned long total_in; - unsigned long total_out; - unsigned char *next_in; - unsigned char *next_out; -} git_zstream; - -void git_inflate_init(git_zstream *); -void git_inflate_init_gzip_only(git_zstream *); -void git_inflate_end(git_zstream *); -int git_inflate(git_zstream *, int flush); - -void git_deflate_init(git_zstream *, int level); -void git_deflate_init_gzip(git_zstream *, int level); -void git_deflate_init_raw(git_zstream *, int level); -void git_deflate_end(git_zstream *); -int git_deflate_abort(git_zstream *); -int git_deflate_end_gently(git_zstream *); -int git_deflate(git_zstream *, int flush); -unsigned long git_deflate_bound(git_zstream *, unsigned long); #if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT) #define DTYPE(de) ((de)->d_type) @@ -59,18 +24,6 @@ unsigned long git_deflate_bound(git_zstream *, unsigned long); #define DTYPE(de) DT_UNKNOWN #endif -/* unknown mode (impossible combination S_IFIFO|S_IFCHR) */ -#define S_IFINVALID 0030000 - -/* - * A "directory link" is a link to another git directory. - * - * The value 0160000 is not normally a valid mode, and - * also just happens to be S_IFDIR + S_IFLNK - */ -#define S_IFGITLINK 0160000 -#define S_ISGITLINK(m) (((m) & S_IFMT) == S_IFGITLINK) - /* * Some mode bits are also used internally for computations. * @@ -87,27 +40,6 @@ unsigned long git_deflate_bound(git_zstream *, unsigned long); /* - * Intensive research over the course of many years has shown that - * port 9418 is totally unused by anything else. Or - * - * Your search - "port 9418" - did not match any documents. - * - * as www.google.com puts it. - * - * This port has been properly assigned for git use by IANA: - * git (Assigned-9418) [I06-050728-0001]. - * - * git 9418/tcp git pack transfer service - * git 9418/udp git pack transfer service - * - * with Linus Torvalds <torvalds@osdl.org> as the point of - * contact. September 2005. - * - * See http://www.iana.org/assignments/port-numbers - */ -#define DEFAULT_GIT_PORT 9418 - -/* * Basic data structures for the directory cache */ @@ -186,11 +118,8 @@ struct cache_entry { #error "CE_EXTENDED_FLAGS out of range" #endif -#define S_ISSPARSEDIR(m) ((m) == S_IFDIR) - /* Forward structure decls */ struct pathspec; -struct child_process; struct tree; /* @@ -228,17 +157,6 @@ static inline unsigned create_ce_flags(unsigned stage) #define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE) #define ce_intent_to_add(ce) ((ce)->ce_flags & CE_INTENT_TO_ADD) -#define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644) -static inline unsigned int create_ce_mode(unsigned int mode) -{ - if (S_ISLNK(mode)) - return S_IFLNK; - if (S_ISSPARSEDIR(mode)) - return S_IFDIR; - if (S_ISDIR(mode) || S_ISGITLINK(mode)) - return S_IFGITLINK; - return S_IFREG | ce_permissions(mode); -} static inline unsigned int ce_mode_from_stat(const struct cache_entry *ce, unsigned int mode) { @@ -265,16 +183,6 @@ static inline int ce_to_dtype(const struct cache_entry *ce) else return DT_UNKNOWN; } -static inline unsigned int canon_mode(unsigned int mode) -{ - if (S_ISREG(mode)) - return S_IFREG | ce_permissions(mode); - if (S_ISLNK(mode)) - return S_IFLNK; - if (S_ISDIR(mode)) - return S_IFDIR; - return S_IFGITLINK; -} static inline int ce_path_match(struct index_state *istate, const struct cache_entry *ce, @@ -445,13 +353,6 @@ void prefetch_cache_entries(const struct index_state *istate, extern struct index_state the_index; #endif -static inline enum object_type object_type(unsigned int mode) -{ - return S_ISDIR(mode) ? OBJ_TREE : - S_ISGITLINK(mode) ? OBJ_COMMIT : - OBJ_BLOB; -} - #define INIT_DB_QUIET 0x0001 #define INIT_DB_EXIST_OK 0x0002 @@ -626,13 +527,6 @@ int has_racy_timestamp(struct index_state *istate); int ie_match_stat(struct index_state *, const struct cache_entry *, struct stat *, unsigned int); int ie_modified(struct index_state *, const struct cache_entry *, struct stat *, unsigned int); -#define HASH_WRITE_OBJECT 1 -#define HASH_FORMAT_CHECK 2 -#define HASH_RENORMALIZE 4 -#define HASH_SILENT 8 -int index_fd(struct index_state *istate, struct object_id *oid, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags); -int index_path(struct index_state *istate, struct object_id *oid, const char *path, struct stat *st, unsigned flags); - /* * Record to sd the data from st that we use to check whether a file * might have changed. @@ -684,8 +578,6 @@ void set_alternate_index_output(const char *); extern int verify_index_checksum; extern int verify_ce_order; -extern int quote_path_fully; - #define MTIME_CHANGED 0x0001 #define CTIME_CHANGED 0x0002 #define OWNER_CHANGED 0x0004 @@ -694,213 +586,6 @@ extern int quote_path_fully; #define DATA_CHANGED 0x0020 #define TYPE_CHANGED 0x0040 -/* - * Return an abbreviated sha1 unique within this repository's object database. - * The result will be at least `len` characters long, and will be NUL - * terminated. - * - * The non-`_r` version returns a static buffer which remains valid until 4 - * more calls to repo_find_unique_abbrev are made. - * - * The `_r` variant writes to a buffer supplied by the caller, which must be at - * least `GIT_MAX_HEXSZ + 1` bytes. The return value is the number of bytes - * written (excluding the NUL terminator). - * - * Note that while this version avoids the static buffer, it is not fully - * reentrant, as it calls into other non-reentrant git code. - */ -const char *repo_find_unique_abbrev(struct repository *r, const struct object_id *oid, int len); -int repo_find_unique_abbrev_r(struct repository *r, char *hex, const struct object_id *oid, int len); - -/* - * Create the directory containing the named path, using care to be - * somewhat safe against races. Return one of the scld_error values to - * indicate success/failure. On error, set errno to describe the - * problem. - * - * SCLD_VANISHED indicates that one of the ancestor directories of the - * path existed at one point during the function call and then - * suddenly vanished, probably because another process pruned the - * directory while we were working. To be robust against this kind of - * race, callers might want to try invoking the function again when it - * returns SCLD_VANISHED. - * - * safe_create_leading_directories() temporarily changes path while it - * is working but restores it before returning. - * safe_create_leading_directories_const() doesn't modify path, even - * temporarily. Both these variants adjust the permissions of the - * created directories to honor core.sharedRepository, so they are best - * suited for files inside the git dir. For working tree files, use - * safe_create_leading_directories_no_share() instead, as it ignores - * the core.sharedRepository setting. - */ -enum scld_error { - SCLD_OK = 0, - SCLD_FAILED = -1, - SCLD_PERMS = -2, - SCLD_EXISTS = -3, - SCLD_VANISHED = -4 -}; -enum scld_error safe_create_leading_directories(char *path); -enum scld_error safe_create_leading_directories_const(const char *path); -enum scld_error safe_create_leading_directories_no_share(char *path); - -int mkdir_in_gitdir(const char *path); - -int git_open_cloexec(const char *name, int flags); -#define git_open(name) git_open_cloexec(name, O_RDONLY) - -/** - * unpack_loose_header() initializes the data stream needed to unpack - * a loose object header. - * - * Returns: - * - * - ULHR_OK on success - * - ULHR_BAD on error - * - ULHR_TOO_LONG if the header was too long - * - * It will only parse up to MAX_HEADER_LEN bytes unless an optional - * "hdrbuf" argument is non-NULL. This is intended for use with - * OBJECT_INFO_ALLOW_UNKNOWN_TYPE to extract the bad type for (error) - * reporting. The full header will be extracted to "hdrbuf" for use - * with parse_loose_header(), ULHR_TOO_LONG will still be returned - * from this function to indicate that the header was too long. - */ -enum unpack_loose_header_result { - ULHR_OK, - ULHR_BAD, - ULHR_TOO_LONG, -}; -enum unpack_loose_header_result unpack_loose_header(git_zstream *stream, - unsigned char *map, - unsigned long mapsize, - void *buffer, - unsigned long bufsiz, - struct strbuf *hdrbuf); - -/** - * parse_loose_header() parses the starting "<type> <len>\0" of an - * object. If it doesn't follow that format -1 is returned. To check - * the validity of the <type> populate the "typep" in the "struct - * object_info". It will be OBJ_BAD if the object type is unknown. The - * parsed <len> can be retrieved via "oi->sizep", and from there - * passed to unpack_loose_rest(). - */ -struct object_info; -int parse_loose_header(const char *hdr, struct object_info *oi); - -/** - * With in-core object data in "buf", rehash it to make sure the - * object name actually matches "oid" to detect object corruption. - * - * A negative value indicates an error, usually that the OID is not - * what we expected, but it might also indicate another error. - */ -int check_object_signature(struct repository *r, const struct object_id *oid, - void *map, unsigned long size, - enum object_type type); - -/** - * A streaming version of check_object_signature(). - * Try reading the object named with "oid" using - * the streaming interface and rehash it to do the same. - */ -int stream_object_signature(struct repository *r, const struct object_id *oid); - -int finalize_object_file(const char *tmpfile, const char *filename); - -/* Helper to check and "touch" a file */ -int check_and_freshen_file(const char *fn, int freshen); - -/* Convert to/from hex/sha1 representation */ -#define MINIMUM_ABBREV minimum_abbrev -#define DEFAULT_ABBREV default_abbrev - -/* used when the code does not know or care what the default abbrev is */ -#define FALLBACK_DEFAULT_ABBREV 7 - -struct object_context { - unsigned short mode; - /* - * symlink_path is only used by get_tree_entry_follow_symlinks, - * and only for symlinks that point outside the repository. - */ - struct strbuf symlink_path; - /* - * If GET_OID_RECORD_PATH is set, this will record path (if any) - * found when resolving the name. The caller is responsible for - * releasing the memory. - */ - char *path; -}; - -int repo_get_oid(struct repository *r, const char *str, struct object_id *oid); -__attribute__((format (printf, 2, 3))) -int get_oidf(struct object_id *oid, const char *fmt, ...); -int repo_get_oid_commit(struct repository *r, const char *str, struct object_id *oid); -int repo_get_oid_committish(struct repository *r, const char *str, struct object_id *oid); -int repo_get_oid_tree(struct repository *r, const char *str, struct object_id *oid); -int repo_get_oid_treeish(struct repository *r, const char *str, struct object_id *oid); -int repo_get_oid_blob(struct repository *r, const char *str, struct object_id *oid); -int repo_get_oid_mb(struct repository *r, const char *str, struct object_id *oid); -void maybe_die_on_misspelt_object_name(struct repository *repo, - const char *name, - const char *prefix); -enum get_oid_result get_oid_with_context(struct repository *repo, const char *str, - unsigned flags, struct object_id *oid, - struct object_context *oc); - -typedef int each_abbrev_fn(const struct object_id *oid, void *); -int repo_for_each_abbrev(struct repository *r, const char *prefix, each_abbrev_fn, void *); - -int set_disambiguate_hint_config(const char *var, const char *value); - -/* - * This reads short-hand syntax that not only evaluates to a commit - * object name, but also can act as if the end user spelled the name - * of the branch from the command line. - * - * - "@{-N}" finds the name of the Nth previous branch we were on, and - * places the name of the branch in the given buf and returns the - * number of characters parsed if successful. - * - * - "<branch>@{upstream}" finds the name of the other ref that - * <branch> is configured to merge with (missing <branch> defaults - * to the current branch), and places the name of the branch in the - * given buf and returns the number of characters parsed if - * successful. - * - * If the input is not of the accepted format, it returns a negative - * number to signal an error. - * - * If the input was ok but there are not N branch switches in the - * reflog, it returns 0. - */ -#define INTERPRET_BRANCH_LOCAL (1<<0) -#define INTERPRET_BRANCH_REMOTE (1<<1) -#define INTERPRET_BRANCH_HEAD (1<<2) -struct interpret_branch_name_options { - /* - * If "allowed" is non-zero, it is a treated as a bitfield of allowable - * expansions: local branches ("refs/heads/"), remote branches - * ("refs/remotes/"), or "HEAD". If no "allowed" bits are set, any expansion is - * allowed, even ones to refs outside of those namespaces. - */ - unsigned allowed; - - /* - * If ^{upstream} or ^{push} (or equivalent) is requested, and the - * branch in question does not have such a reference, return -1 instead - * of die()-ing. - */ - unsigned nonfatal_dangling_mark : 1; -}; -int repo_interpret_branch_name(struct repository *r, - const char *str, int len, - struct strbuf *buf, - const struct interpret_branch_name_options *options); - int base_name_compare(const char *name1, size_t len1, int mode1, const char *name2, size_t len2, int mode2); int df_name_compare(const char *name1, size_t len1, int mode1, @@ -908,21 +593,6 @@ int df_name_compare(const char *name1, size_t len1, int mode1, int name_compare(const char *name1, size_t len1, const char *name2, size_t len2); int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2); -void *read_object_with_reference(struct repository *r, - const struct object_id *oid, - enum object_type required_type, - unsigned long *size, - struct object_id *oid_ret); - -struct object *repo_peel_to_type(struct repository *r, - const char *name, int namelen, - struct object *o, enum object_type); - -const char *git_editor(void); -const char *git_sequence_editor(void); -const char *git_pager(int stdout_is_tty); -int is_terminal_dumb(void); - struct cache_def { struct strbuf path; int flags; @@ -959,36 +629,15 @@ struct pack_entry { struct packed_git *p; }; -/* - * Set this to 0 to prevent oid_object_info_extended() from fetching missing - * blobs. This has a difference only if extensions.partialClone is set. - * - * Its default value is 1. - */ -extern int fetch_if_missing; - /* Dumb servers support */ int update_server_info(int); -extern const char *git_mailmap_file; -extern const char *git_mailmap_blob; - #define COPY_READ_ERROR (-2) #define COPY_WRITE_ERROR (-3) int copy_fd(int ifd, int ofd); int copy_file(const char *dst, const char *src, int mode); int copy_file_with_time(const char *dst, const char *src, int mode); -/* pager.c */ -void setup_pager(void); -int pager_in_use(void); -extern int pager_use_color; -int term_columns(void); -void term_clear_line(void); -int decimal_width(uintmax_t); -int check_pager_config(const char *cmd); -void prepare_pager_args(struct child_process *, const char *pager); - /* base85 */ int decode_85(char *dst, const char *line, int linelen); void encode_85(char *buf, const unsigned char *data, int bytes); diff --git a/chdir-notify.c b/chdir-notify.c index 929ec01b3a..0d7bc04607 100644 --- a/chdir-notify.c +++ b/chdir-notify.c @@ -1,8 +1,10 @@ -#include "cache.h" +#include "git-compat-util.h" #include "abspath.h" #include "chdir-notify.h" #include "list.h" +#include "path.h" #include "strbuf.h" +#include "trace.h" struct chdir_notify_entry { const char *name; diff --git a/checkout.c b/checkout.c index 1247b88224..04238b2713 100644 --- a/checkout.c +++ b/checkout.c @@ -1,8 +1,10 @@ -#include "cache.h" +#include "git-compat-util.h" +#include "object-name.h" #include "remote.h" #include "refspec.h" #include "checkout.h" #include "config.h" +#include "strbuf.h" struct tracking_name_data { /* const */ char *src_ref; diff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh index b098e10f52..a18b13a41d 100755 --- a/ci/run-build-and-tests.sh +++ b/ci/run-build-and-tests.sh @@ -27,7 +27,7 @@ linux-TEST-vars) export GIT_TEST_MULTI_PACK_INDEX=1 export GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=1 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master - export GIT_TEST_WRITE_REV_INDEX=1 + export GIT_TEST_NO_WRITE_REV_INDEX=1 export GIT_TEST_CHECKOUT_WORKERS=2 ;; linux-clang) @@ -1,8 +1,10 @@ #include "cache.h" #include "config.h" #include "color.h" +#include "editor.h" #include "gettext.h" #include "hex.h" +#include "pager.h" static int git_use_color_default = GIT_COLOR_AUTO; int color_stdout_is_tty = -1; @@ -1,7 +1,8 @@ -#include "cache.h" +#include "git-compat-util.h" #include "config.h" #include "column.h" #include "string-list.h" +#include "pager.h" #include "parse-options.h" #include "run-command.h" #include "utf8.h" diff --git a/combine-diff.c b/combine-diff.c index 44ef6a1a81..f7e9fb5747 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -1,11 +1,13 @@ #include "cache.h" #include "object-store.h" #include "commit.h" +#include "convert.h" #include "blob.h" #include "diff.h" #include "diffcore.h" #include "environment.h" #include "hex.h" +#include "object-name.h" #include "quote.h" #include "xdiff-interface.h" #include "xdiff/xmacros.h" @@ -14,6 +16,7 @@ #include "userdiff.h" #include "oid-array.h" #include "revision.h" +#include "wrapper.h" static int compare_paths(const struct combine_diff_path *one, const struct diff_filespec *two) diff --git a/commit-graph.c b/commit-graph.c index b1e737c01b..43558b4d9b 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -1,4 +1,4 @@ -#include "cache.h" +#include "git-compat-util.h" #include "config.h" #include "gettext.h" #include "hex.h" @@ -11,7 +11,9 @@ #include "revision.h" #include "hash-lookup.h" #include "commit-graph.h" +#include "object-file.h" #include "object-store.h" +#include "oid-array.h" #include "alloc.h" #include "hashmap.h" #include "replace-object.h" @@ -1,4 +1,4 @@ -#include "cache.h" +#include "git-compat-util.h" #include "tag.h" #include "commit.h" #include "commit-graph.h" @@ -6,6 +6,7 @@ #include "gettext.h" #include "hex.h" #include "repository.h" +#include "object-name.h" #include "object-store.h" #include "pkt-line.h" #include "utf8.h" diff --git a/common-main.c b/common-main.c index b83cb5cf06..f319317353 100644 --- a/common-main.c +++ b/common-main.c @@ -3,6 +3,7 @@ #include "gettext.h" #include "attr.h" #include "setup.h" +#include "trace2.h" /* * Many parts of Git have subprograms communicate via pipe, expect the diff --git a/compat/fsmonitor/fsm-listen-win32.c b/compat/fsmonitor/fsm-listen-win32.c index 7b07b74ba5..677b1bbdec 100644 --- a/compat/fsmonitor/fsm-listen-win32.c +++ b/compat/fsmonitor/fsm-listen-win32.c @@ -4,6 +4,7 @@ #include "fsm-listen.h" #include "fsmonitor--daemon.h" #include "gettext.h" +#include "trace2.h" /* * The documentation of ReadDirectoryChangesW() states that the maximum diff --git a/compat/mingw.c b/compat/mingw.c index 94c5a1daa4..abbc3faf32 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -12,6 +12,7 @@ #include "win32/lazyload.h" #include "../config.h" #include "../environment.h" +#include "../trace2.h" #include "../wrapper.h" #include "dir.h" #include "gettext.h" diff --git a/compat/pread.c b/compat/pread.c index 978cac4ec9..484e6d4c71 100644 --- a/compat/pread.c +++ b/compat/pread.c @@ -1,4 +1,5 @@ #include "../git-compat-util.h" +#include "../wrapper.h" ssize_t git_pread(int fd, void *buf, size_t count, off_t offset) { diff --git a/compat/simple-ipc/ipc-unix-socket.c b/compat/simple-ipc/ipc-unix-socket.c index 152db60a31..b2f4f22ce4 100644 --- a/compat/simple-ipc/ipc-unix-socket.c +++ b/compat/simple-ipc/ipc-unix-socket.c @@ -1,9 +1,10 @@ -#include "cache.h" +#include "git-compat-util.h" #include "gettext.h" #include "simple-ipc.h" #include "strbuf.h" #include "pkt-line.h" #include "thread-utils.h" +#include "trace2.h" #include "unix-socket.h" #include "unix-stream-server.h" diff --git a/compat/simple-ipc/ipc-win32.c b/compat/simple-ipc/ipc-win32.c index 997f614434..6adce3c650 100644 --- a/compat/simple-ipc/ipc-win32.c +++ b/compat/simple-ipc/ipc-win32.c @@ -5,6 +5,8 @@ #include "strbuf.h" #include "pkt-line.h" #include "thread-utils.h" +#include "trace.h" +#include "trace2.h" #include "accctrl.h" #include "aclapi.h" diff --git a/compat/win32/trace2_win32_process_info.c b/compat/win32/trace2_win32_process_info.c index a53fd92434..e3e895c78a 100644 --- a/compat/win32/trace2_win32_process_info.c +++ b/compat/win32/trace2_win32_process_info.c @@ -1,5 +1,6 @@ #include "../../cache.h" #include "../../json-writer.h" +#include "../../trace2.h" #include "lazyload.h" #include <Psapi.h> #include <tlHelp32.h> @@ -7,27 +7,33 @@ */ #include "cache.h" #include "abspath.h" +#include "advice.h" #include "alloc.h" #include "date.h" #include "branch.h" #include "config.h" +#include "convert.h" #include "environment.h" #include "gettext.h" #include "ident.h" #include "repository.h" #include "lockfile.h" +#include "mailmap.h" #include "exec-cmd.h" #include "strbuf.h" #include "quote.h" #include "hashmap.h" #include "string-list.h" +#include "object-name.h" #include "object-store.h" +#include "pager.h" #include "utf8.h" #include "dir.h" #include "color.h" #include "replace-object.h" #include "refs.h" #include "setup.h" +#include "trace2.h" #include "worktree.h" #include "wrapper.h" #include "write-or-die.h" @@ -3652,9 +3658,10 @@ void git_config_set_multivar(const char *key, const char *value, flags); } -static int section_name_match (const char *buf, const char *name) +static size_t section_name_match (const char *buf, const char *name) { - int i = 0, j = 0, dot = 0; + size_t i = 0, j = 0; + int dot = 0; if (buf[i] != '[') return 0; for (i = 1; buf[i] && buf[i] != ']'; i++) { @@ -3707,6 +3714,8 @@ static int section_name_is_ok(const char *name) return 1; } +#define GIT_CONFIG_MAX_LINE_LEN (512 * 1024) + /* if new_name == NULL, the section is removed instead */ static int git_config_copy_or_rename_section_in_file(const char *config_filename, const char *old_name, @@ -3716,11 +3725,12 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename char *filename_buf = NULL; struct lock_file lock = LOCK_INIT; int out_fd; - char buf[1024]; + struct strbuf buf = STRBUF_INIT; FILE *config_file = NULL; struct stat st; struct strbuf copystr = STRBUF_INIT; struct config_store_data store; + uint32_t line_nr = 0; memset(&store, 0, sizeof(store)); @@ -3757,16 +3767,25 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename goto out; } - while (fgets(buf, sizeof(buf), config_file)) { - unsigned i; - int length; + while (!strbuf_getwholeline(&buf, config_file, '\n')) { + size_t i, length; int is_section = 0; - char *output = buf; - for (i = 0; buf[i] && isspace(buf[i]); i++) + char *output = buf.buf; + + line_nr++; + + if (buf.len >= GIT_CONFIG_MAX_LINE_LEN) { + ret = error(_("refusing to work with overly long line " + "in '%s' on line %"PRIuMAX), + config_filename, (uintmax_t)line_nr); + goto out; + } + + for (i = 0; buf.buf[i] && isspace(buf.buf[i]); i++) ; /* do nothing */ - if (buf[i] == '[') { + if (buf.buf[i] == '[') { /* it's a section */ - int offset; + size_t offset; is_section = 1; /* @@ -3783,7 +3802,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename strbuf_reset(©str); } - offset = section_name_match(&buf[i], old_name); + offset = section_name_match(&buf.buf[i], old_name); if (offset > 0) { ret++; if (!new_name) { @@ -3858,6 +3877,7 @@ out: out_no_rollback: free(filename_buf); config_store_data_clear(&store); + strbuf_release(&buf); return ret; } @@ -1,5 +1,4 @@ #include "git-compat-util.h" -#include "cache.h" #include "config.h" #include "environment.h" #include "gettext.h" @@ -14,6 +13,7 @@ #include "string-list.h" #include "oid-array.h" #include "transport.h" +#include "trace2.h" #include "strbuf.h" #include "version.h" #include "protocol.h" @@ -22,7 +22,7 @@ static char *server_capabilities_v1; static struct strvec server_capabilities_v2 = STRVEC_INIT; -static const char *next_server_feature_value(const char *feature, int *len, int *offset); +static const char *next_server_feature_value(const char *feature, size_t *len, size_t *offset); static int check_ref(const char *name, unsigned int flags) { @@ -205,10 +205,10 @@ reject: static void annotate_refs_with_symref_info(struct ref *ref) { struct string_list symref = STRING_LIST_INIT_DUP; - int offset = 0; + size_t offset = 0; while (1) { - int len; + size_t len; const char *val; val = next_server_feature_value("symref", &len, &offset); @@ -231,7 +231,7 @@ static void annotate_refs_with_symref_info(struct ref *ref) static void process_capabilities(struct packet_reader *reader, int *linelen) { const char *feat_val; - int feat_len; + size_t feat_len; const char *line = reader->line; int nul_location = strlen(line); if (nul_location == *linelen) @@ -263,7 +263,8 @@ static int process_dummy_ref(const struct packet_reader *reader) return 0; name++; - return oideq(null_oid(), &oid) && !strcmp(name, "capabilities^{}"); + return oideq(reader->hash_algo->null_oid, &oid) && + !strcmp(name, "capabilities^{}"); } static void check_no_capabilities(const char *line, int len) @@ -595,9 +596,10 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader, return list; } -const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp, int *offset) +const char *parse_feature_value(const char *feature_list, const char *feature, size_t *lenp, size_t *offset) { - int len; + const char *orig_start = feature_list; + size_t len; if (!feature_list) return NULL; @@ -616,19 +618,19 @@ const char *parse_feature_value(const char *feature_list, const char *feature, i if (lenp) *lenp = 0; if (offset) - *offset = found + len - feature_list; + *offset = found + len - orig_start; return value; } /* feature with a value (e.g., "agent=git/1.2.3") */ else if (*value == '=') { - int end; + size_t end; value++; end = strcspn(value, " \t\n"); if (lenp) *lenp = end; if (offset) - *offset = value + end - feature_list; + *offset = value + end - orig_start; return value; } /* @@ -643,8 +645,8 @@ const char *parse_feature_value(const char *feature_list, const char *feature, i int server_supports_hash(const char *desired, int *feature_supported) { - int offset = 0; - int len; + size_t offset = 0; + size_t len; const char *hash; hash = next_server_feature_value("object-format", &len, &offset); @@ -668,12 +670,12 @@ int parse_feature_request(const char *feature_list, const char *feature) return !!parse_feature_value(feature_list, feature, NULL, NULL); } -static const char *next_server_feature_value(const char *feature, int *len, int *offset) +static const char *next_server_feature_value(const char *feature, size_t *len, size_t *offset) { return parse_feature_value(server_capabilities_v1, feature, len, offset); } -const char *server_feature_value(const char *feature, int *len) +const char *server_feature_value(const char *feature, size_t *len) { return parse_feature_value(server_capabilities_v1, feature, len, NULL); } @@ -12,14 +12,14 @@ int finish_connect(struct child_process *conn); int git_connection_is_socket(struct child_process *conn); int server_supports(const char *feature); int parse_feature_request(const char *features, const char *feature); -const char *server_feature_value(const char *feature, int *len_ret); +const char *server_feature_value(const char *feature, size_t *len_ret); int url_is_local_not_ssh(const char *url); struct packet_reader; enum protocol_version discover_version(struct packet_reader *reader); int server_supports_hash(const char *desired, int *feature_supported); -const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp, int *offset); +const char *parse_feature_value(const char *feature_list, const char *feature, size_t *lenp, size_t *offset); int server_supports_v2(const char *c); void ensure_server_supports_v2(const char *c); int server_feature_v2(const char *c, const char **v); @@ -1,5 +1,7 @@ #include "cache.h" +#include "advice.h" #include "config.h" +#include "convert.h" #include "gettext.h" #include "hex.h" #include "object-store.h" @@ -9,6 +11,7 @@ #include "sigchain.h" #include "pkt-line.h" #include "sub-process.h" +#include "trace.h" #include "utf8.h" #include "ll-merge.h" #include "wrapper.h" @@ -4,6 +4,7 @@ #include "config.h" #include "environment.h" #include "pkt-line.h" +#include "protocol.h" #include "run-command.h" #include "setup.h" #include "strbuf.h" @@ -7,6 +7,7 @@ #include "cache.h" #include "date.h" #include "gettext.h" +#include "pager.h" /* * This is like mktime, but without normalization of tm_wday and tm_yday. @@ -1366,20 +1367,6 @@ static timestamp_t approxidate_str(const char *date, return (timestamp_t)update_tm(&tm, &now, 0); } -timestamp_t approxidate_relative(const char *date) -{ - struct timeval tv; - timestamp_t timestamp; - int offset; - int errors = 0; - - if (!parse_date_basic(date, ×tamp, &offset)) - return timestamp; - - get_time(&tv); - return approxidate_str(date, (const struct timeval *) &tv, &errors); -} - timestamp_t approxidate_careful(const char *date, int *error_ret) { struct timeval tv; @@ -68,7 +68,6 @@ int parse_expiry_date(const char *date, timestamp_t *timestamp); void datestamp(struct strbuf *out); #define approxidate(s) approxidate_careful((s), NULL) timestamp_t approxidate_careful(const char *, int *); -timestamp_t approxidate_relative(const char *date); int date_overflows(timestamp_t date); time_t tm_to_time_t(const struct tm *tm); #endif diff --git a/delta-islands.c b/delta-islands.c index 40f2ccfb55..c824a5f6a4 100644 --- a/delta-islands.c +++ b/delta-islands.c @@ -1,4 +1,4 @@ -#include "cache.h" +#include "git-compat-util.h" #include "alloc.h" #include "attr.h" #include "object.h" diff --git a/diff-lib.c b/diff-lib.c index 4169dd8cb1..d292405a26 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -8,11 +8,13 @@ #include "diffcore.h" #include "gettext.h" #include "hex.h" +#include "object-name.h" #include "revision.h" #include "cache-tree.h" #include "unpack-trees.h" #include "refs.h" #include "submodule.h" +#include "trace.h" #include "dir.h" #include "fsmonitor.h" #include "commit-reach.h" diff --git a/diff-no-index.c b/diff-no-index.c index 934a24bee5..4296940f90 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -4,7 +4,7 @@ * Copyright (c) 2008 by Junio C Hamano */ -#include "cache.h" +#include "git-compat-util.h" #include "abspath.h" #include "color.h" #include "commit.h" @@ -5,6 +5,7 @@ #include "abspath.h" #include "alloc.h" #include "config.h" +#include "convert.h" #include "environment.h" #include "gettext.h" #include "tempfile.h" @@ -28,11 +29,15 @@ #include "string-list.h" #include "strvec.h" #include "graph.h" +#include "oid-array.h" #include "packfile.h" +#include "pager.h" #include "parse-options.h" #include "help.h" #include "promisor-remote.h" #include "dir.h" +#include "object-file.h" +#include "object-name.h" #include "setup.h" #include "strmap.h" #include "wrapper.h" @@ -9,9 +9,11 @@ #include "abspath.h" #include "alloc.h" #include "config.h" +#include "convert.h" #include "dir.h" #include "environment.h" #include "gettext.h" +#include "object-file.h" #include "object-store.h" #include "attr.h" #include "refs.h" @@ -23,6 +25,7 @@ #include "fsmonitor.h" #include "setup.h" #include "submodule-config.h" +#include "trace2.h" #include "wrapper.h" /* @@ -1,12 +1,16 @@ -#include "cache.h" +#include "git-compat-util.h" #include "abspath.h" +#include "advice.h" #include "config.h" +#include "editor.h" #include "environment.h" #include "gettext.h" +#include "pager.h" #include "strbuf.h" #include "strvec.h" #include "run-command.h" #include "sigchain.h" +#include "wrapper.h" #ifndef DEFAULT_EDITOR #define DEFAULT_EDITOR "vi" @@ -129,3 +133,31 @@ int launch_sequence_editor(const char *path, struct strbuf *buffer, { return launch_specified_editor(git_sequence_editor(), path, buffer, env); } + +int strbuf_edit_interactively(struct strbuf *buffer, const char *path, + const char *const *env) +{ + char *path2 = NULL; + int fd, res = 0; + + if (!is_absolute_path(path)) + path = path2 = xstrdup(git_path("%s", path)); + + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (fd < 0) + res = error_errno(_("could not open '%s' for writing"), path); + else if (write_in_full(fd, buffer->buf, buffer->len) < 0) { + res = error_errno(_("could not write to '%s'"), path); + close(fd); + } else if (close(fd) < 0) + res = error_errno(_("could not close '%s'"), path); + else { + strbuf_reset(buffer); + if (launch_editor(path, buffer, env) < 0) + res = error_errno(_("could not edit '%s'"), path); + unlink(path); + } + + free(path2); + return res; +} diff --git a/editor.h b/editor.h new file mode 100644 index 0000000000..8016bb5e00 --- /dev/null +++ b/editor.h @@ -0,0 +1,34 @@ +#ifndef EDITOR_H +#define EDITOR_H + +struct strbuf; + +const char *git_editor(void); +const char *git_sequence_editor(void); +int is_terminal_dumb(void); + +/** + * Launch the user preferred editor to edit a file and fill the buffer + * with the file's contents upon the user completing their editing. The + * third argument can be used to set the environment which the editor is + * run in. If the buffer is NULL the editor is launched as usual but the + * file's contents are not read into the buffer upon completion. + */ +int launch_editor(const char *path, struct strbuf *buffer, + const char *const *env); + +int launch_sequence_editor(const char *path, struct strbuf *buffer, + const char *const *env); + +/* + * In contrast to `launch_editor()`, this function writes out the contents + * of the specified file first, then clears the `buffer`, then launches + * the editor and reads back in the file contents into the `buffer`. + * Finally, it deletes the temporary file. + * + * If `path` is relative, it refers to a file in the `.git` directory. + */ +int strbuf_edit_interactively(struct strbuf *buffer, const char *path, + const char *const *env); + +#endif diff --git a/environment.c b/environment.c index 63c697e7e9..8a96997539 100644 --- a/environment.c +++ b/environment.c @@ -10,6 +10,7 @@ #include "cache.h" #include "abspath.h" #include "branch.h" +#include "convert.h" #include "environment.h" #include "gettext.h" #include "repository.h" @@ -18,12 +19,14 @@ #include "fmt-merge-msg.h" #include "commit.h" #include "strvec.h" +#include "object-file.h" #include "object-store.h" #include "replace-object.h" #include "tmp-objdir.h" #include "chdir-notify.h" #include "setup.h" #include "shallow.h" +#include "trace.h" #include "wrapper.h" #include "write-or-die.h" @@ -56,7 +59,6 @@ size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE; size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT; size_t delta_base_cache_limit = 96 * 1024 * 1024; unsigned long big_file_threshold = 512 * 1024 * 1024; -int pager_use_color = 1; const char *editor_program; const char *askpass_program; const char *excludes_file; diff --git a/exec-cmd.c b/exec-cmd.c index fae0d4b244..6f61846389 100644 --- a/exec-cmd.c +++ b/exec-cmd.c @@ -5,6 +5,8 @@ #include "gettext.h" #include "quote.h" #include "strvec.h" +#include "trace.h" +#include "trace2.h" #if defined(RUNTIME_PREFIX) diff --git a/fetch-pack.c b/fetch-pack.c index 368f2ed25a..6fa6e8af9a 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -1,4 +1,4 @@ -#include "cache.h" +#include "git-compat-util.h" #include "alloc.h" #include "repository.h" #include "config.h" @@ -17,6 +17,7 @@ #include "remote.h" #include "run-command.h" #include "connect.h" +#include "trace2.h" #include "transport.h" #include "version.h" #include "oid-array.h" @@ -1099,7 +1100,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, struct ref *ref = copy_ref_list(orig_ref); struct object_id oid; const char *agent_feature; - int agent_len; + size_t agent_len; struct fetch_negotiator negotiator_alloc; struct fetch_negotiator *negotiator; @@ -1117,7 +1118,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, agent_supported = 1; if (agent_len) print_verbose(args, _("Server version is %.*s"), - agent_len, agent_feature); + (int)agent_len, agent_feature); } if (!server_supports("session-id")) diff --git a/fmt-merge-msg.c b/fmt-merge-msg.c index 1886c92ddb..5af0d4715b 100644 --- a/fmt-merge-msg.c +++ b/fmt-merge-msg.c @@ -1,8 +1,9 @@ -#include "cache.h" +#include "git-compat-util.h" #include "alloc.h" #include "config.h" #include "environment.h" #include "refs.h" +#include "object-name.h" #include "object-store.h" #include "diff.h" #include "diff-merges.h" @@ -1,4 +1,4 @@ -#include "cache.h" +#include "git-compat-util.h" #include "alloc.h" #include "hex.h" #include "object-store.h" diff --git a/fsmonitor.c b/fsmonitor.c index c956a347a2..28c083d4d8 100644 --- a/fsmonitor.c +++ b/fsmonitor.c @@ -7,6 +7,7 @@ #include "fsmonitor-ipc.h" #include "run-command.h" #include "strbuf.h" +#include "trace2.h" #define INDEX_EXTENSION_VERSION1 (1) #define INDEX_EXTENSION_VERSION2 (2) diff --git a/fsmonitor.h b/fsmonitor.h index 778707b131..c67e0ebc09 100644 --- a/fsmonitor.h +++ b/fsmonitor.h @@ -4,6 +4,7 @@ #include "cache.h" #include "dir.h" #include "fsmonitor-settings.h" +#include "trace.h" extern struct trace_key trace_fsmonitor; @@ -102,6 +102,8 @@ static void init_gettext_charset(const char *domain) setlocale(LC_CTYPE, "C"); } +int git_gettext_enabled = 0; + void git_setup_gettext(void) { const char *podir = getenv(GIT_TEXT_DOMAIN_DIR_ENVIRONMENT); @@ -121,6 +123,8 @@ void git_setup_gettext(void) init_gettext_charset("git"); textdomain("git"); + git_gettext_enabled = 1; + free(p); } @@ -29,9 +29,11 @@ #define FORMAT_PRESERVING(n) __attribute__((format_arg(n))) #ifndef NO_GETTEXT +extern int git_gettext_enabled; void git_setup_gettext(void); int gettext_width(const char *s); #else +#define git_gettext_enabled (0) static inline void git_setup_gettext(void) { } @@ -45,12 +47,16 @@ static inline FORMAT_PRESERVING(1) const char *_(const char *msgid) { if (!*msgid) return ""; + if (!git_gettext_enabled) + return msgid; return gettext(msgid); } static inline FORMAT_PRESERVING(1) FORMAT_PRESERVING(2) const char *Q_(const char *msgid, const char *plu, unsigned long n) { + if (!git_gettext_enabled) + return n == 1 ? msgid : plu; return ngettext(msgid, plu, n); } diff --git a/git-compat-util.h b/git-compat-util.h index 4a200a9fb4..5b2b99c17c 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -878,12 +878,6 @@ int git_lstat(const char *, struct stat *); #define pread git_pread ssize_t git_pread(int fd, void *buf, size_t count, off_t offset); #endif -/* - * Forward decl that will remind us if its twin in cache.h changes. - * This function is used in compat/pread.c. But we can't include - * cache.h there. - */ -ssize_t read_in_full(int fd, void *buf, size_t count); #ifdef NO_SETENV #define setenv gitsetenv diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh index 992124cc67..e4e820e680 100755 --- a/git-difftool--helper.sh +++ b/git-difftool--helper.sh @@ -75,6 +75,11 @@ then merge_tool="$GIT_DIFF_TOOL" else merge_tool="$(get_merge_tool)" + subshell_exit_status=$? + if test $subshell_exit_status -gt 1 + then + exit $subshell_exit_status + fi fi fi diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh index 9f99201bcc..1ff26170ff 100644 --- a/git-mergetool--lib.sh +++ b/git-mergetool--lib.sh @@ -97,7 +97,42 @@ merge_mode () { test "$TOOL_MODE" = merge } +get_gui_default () { + if diff_mode + then + GUI_DEFAULT_KEY="difftool.guiDefault" + else + GUI_DEFAULT_KEY="mergetool.guiDefault" + fi + GUI_DEFAULT_CONFIG_LCASE=$(git config --default false --get "$GUI_DEFAULT_KEY" | tr 'A-Z' 'a-z') + if test "$GUI_DEFAULT_CONFIG_LCASE" = "auto" + then + if test -n "$DISPLAY" + then + GUI_DEFAULT=true + else + GUI_DEFAULT=false + fi + else + GUI_DEFAULT=$(git config --default false --bool --get "$GUI_DEFAULT_KEY") + subshell_exit_status=$? + if test $subshell_exit_status -ne 0 + then + exit $subshell_exit_status + fi + fi + echo $GUI_DEFAULT +} + gui_mode () { + if test -z "$GIT_MERGETOOL_GUI" + then + GIT_MERGETOOL_GUI=$(get_gui_default) + if test $? -ne 0 + then + exit 2 + fi + fi test "$GIT_MERGETOOL_GUI" = true } @@ -467,6 +502,11 @@ get_merge_tool () { is_guessed=false # Check if a merge tool has been configured merge_tool=$(get_configured_merge_tool) + subshell_exit_status=$? + if test $subshell_exit_status -gt "1" + then + exit $subshell_exit_status + fi # Try to guess an appropriate merge tool if no tool has been set. if test -z "$merge_tool" then diff --git a/git-mergetool.sh b/git-mergetool.sh index f751d9cfe2..8a922893f7 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -451,7 +451,7 @@ print_noop_and_exit () { main () { prompt=$(git config --bool mergetool.prompt) - GIT_MERGETOOL_GUI=false + GIT_MERGETOOL_GUI= guessed_merge_tool=false orderfile= @@ -511,9 +511,14 @@ main () { if test -z "$merge_tool" then - if ! merge_tool=$(get_merge_tool) + merge_tool=$(get_merge_tool) + subshell_exit_status=$? + if test $subshell_exit_status = 1 then guessed_merge_tool=true + elif test $subshell_exit_status -gt 1 + then + exit $subshell_exit_status fi fi merge_keep_backup="$(git config --bool mergetool.keepBackup || echo true)" diff --git a/git-send-email.perl b/git-send-email.perl index fd8cd0d46f..66c9171109 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -795,11 +795,26 @@ if (@rev_list_opts) { @files = handle_backup_files(@files); if ($validate) { + # FIFOs can only be read once, exclude them from validation. + my @real_files = (); foreach my $f (@files) { unless (-p $f) { - validate_patch($f, $target_xfer_encoding); + push(@real_files, $f); } } + + # Run the loop once again to avoid gaps in the counter due to FIFO + # arguments provided by the user. + my $num = 1; + my $num_files = scalar @real_files; + $ENV{GIT_SENDEMAIL_FILE_TOTAL} = "$num_files"; + foreach my $r (@real_files) { + $ENV{GIT_SENDEMAIL_FILE_COUNTER} = "$num"; + validate_patch($r, $target_xfer_encoding); + $num += 1; + } + delete $ENV{GIT_SENDEMAIL_FILE_COUNTER}; + delete $ENV{GIT_SENDEMAIL_FILE_TOTAL}; } if (@files) { @@ -2,7 +2,8 @@ * zlib wrappers to make sure we don't silently miss errors * at init time. */ -#include "cache.h" +#include "git-compat-util.h" +#include "git-zlib.h" static const char *zerr_to_string(int status) { diff --git a/git-zlib.h b/git-zlib.h new file mode 100644 index 0000000000..d8a670aff9 --- /dev/null +++ b/git-zlib.h @@ -0,0 +1,28 @@ +#ifndef GIT_ZLIB_H +#define GIT_ZLIB_H + +typedef struct git_zstream { + z_stream z; + unsigned long avail_in; + unsigned long avail_out; + unsigned long total_in; + unsigned long total_out; + unsigned char *next_in; + unsigned char *next_out; +} git_zstream; + +void git_inflate_init(git_zstream *); +void git_inflate_init_gzip_only(git_zstream *); +void git_inflate_end(git_zstream *); +int git_inflate(git_zstream *, int flush); + +void git_deflate_init(git_zstream *, int level); +void git_deflate_init_gzip(git_zstream *, int level); +void git_deflate_init_raw(git_zstream *, int level); +void git_deflate_end(git_zstream *); +int git_deflate_abort(git_zstream *); +int git_deflate_end_gently(git_zstream *); +int git_deflate(git_zstream *, int flush); +unsigned long git_deflate_bound(git_zstream *, unsigned long); + +#endif /* GIT_ZLIB_H */ @@ -4,11 +4,14 @@ #include "exec-cmd.h" #include "gettext.h" #include "help.h" +#include "pager.h" #include "run-command.h" #include "alias.h" #include "replace-object.h" #include "setup.h" #include "shallow.h" +#include "trace.h" +#include "trace2.h" #define RUN_SETUP (1<<0) #define RUN_SETUP_GENTLY (1<<1) @@ -11,6 +11,7 @@ #include "commit.h" #include "quote.h" #include "help.h" +#include "wrapper.h" static int grep_source_load(struct grep_source *gs); static int grep_source_is_binary(struct grep_source *gs, diff --git a/http-backend.c b/http-backend.c index 89aad1b42c..ac146d85c5 100644 --- a/http-backend.c +++ b/http-backend.c @@ -1,7 +1,8 @@ -#include "cache.h" +#include "git-compat-util.h" #include "alloc.h" #include "config.h" #include "environment.h" +#include "git-zlib.h" #include "hex.h" #include "repository.h" #include "refs.h" diff --git a/http-fetch.c b/http-fetch.c index c874d3402d..fffda59267 100644 --- a/http-fetch.c +++ b/http-fetch.c @@ -1,4 +1,4 @@ -#include "cache.h" +#include "git-compat-util.h" #include "config.h" #include "exec-cmd.h" #include "gettext.h" diff --git a/http-push.c b/http-push.c index 88b70f2c44..76ab5dbb09 100644 --- a/http-push.c +++ b/http-push.c @@ -1,4 +1,4 @@ -#include "cache.h" +#include "git-compat-util.h" #include "environment.h" #include "hex.h" #include "repository.h" diff --git a/http-walker.c b/http-walker.c index e5dadae377..bba306b2d5 100644 --- a/http-walker.c +++ b/http-walker.c @@ -1,4 +1,4 @@ -#include "cache.h" +#include "git-compat-util.h" #include "repository.h" #include "commit.h" #include "hex.h" @@ -12,10 +12,12 @@ #include "version.h" #include "pkt-line.h" #include "gettext.h" +#include "trace.h" #include "transport.h" #include "packfile.h" #include "protocol.h" #include "string-list.h" +#include "object-file.h" #include "object-store.h" static struct trace_key trace_curl = TRACE_KEY_INIT(CURL); @@ -1,7 +1,9 @@ #ifndef HTTP_H #define HTTP_H -#include "cache.h" +struct packed_git; + +#include "git-zlib.h" #include <curl/curl.h> #include <curl/easy.h> diff --git a/list-objects-filter.c b/list-objects-filter.c index 298ca08711..5d270ce598 100644 --- a/list-objects-filter.c +++ b/list-objects-filter.c @@ -1,4 +1,4 @@ -#include "cache.h" +#include "git-compat-util.h" #include "alloc.h" #include "dir.h" #include "gettext.h" @@ -15,6 +15,7 @@ #include "list-objects-filter-options.h" #include "oidmap.h" #include "oidset.h" +#include "object-name.h" #include "object-store.h" /* Remember to update object flag allocation in object.h */ diff --git a/list-objects.c b/list-objects.c index df18d10306..eecca721ac 100644 --- a/list-objects.c +++ b/list-objects.c @@ -1,4 +1,4 @@ -#include "cache.h" +#include "git-compat-util.h" #include "tag.h" #include "commit.h" #include "gettext.h" diff --git a/ll-merge.c b/ll-merge.c index 8be38d3bd4..28bc94c45d 100644 --- a/ll-merge.c +++ b/ll-merge.c @@ -6,6 +6,7 @@ #include "cache.h" #include "config.h" +#include "convert.h" #include "attr.h" #include "xdiff-interface.h" #include "run-command.h" diff --git a/log-tree.c b/log-tree.c index dbb088473e..143b86fecf 100644 --- a/log-tree.c +++ b/log-tree.c @@ -1,9 +1,10 @@ -#include "cache.h" +#include "git-compat-util.h" #include "commit-reach.h" #include "config.h" #include "diff.h" #include "environment.h" #include "hex.h" +#include "object-name.h" #include "object-store.h" #include "repository.h" #include "tmp-objdir.h" @@ -1,7 +1,8 @@ -#include "cache.h" +#include "git-compat-util.h" #include "environment.h" #include "string-list.h" #include "mailmap.h" +#include "object-name.h" #include "object-store.h" #include "setup.h" @@ -3,6 +3,9 @@ struct string_list; +extern const char *git_mailmap_file; +extern const char *git_mailmap_blob; + int read_mailmap(struct string_list *map); void clear_mailmap(struct string_list *map); diff --git a/merge-ort.c b/merge-ort.c index 5bf64354d1..2c6a9ed9a4 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -31,12 +31,16 @@ #include "hex.h" #include "entry.h" #include "ll-merge.h" +#include "mem-pool.h" +#include "object-name.h" #include "object-store.h" +#include "oid-array.h" #include "promisor-remote.h" #include "revision.h" #include "strmap.h" #include "submodule-config.h" #include "submodule.h" +#include "trace2.h" #include "tree.h" #include "unpack-trees.h" #include "xdiff-interface.h" diff --git a/merge-recursive.c b/merge-recursive.c index ed5534eb57..9875bdb11c 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -22,6 +22,8 @@ #include "hex.h" #include "ll-merge.h" #include "lockfile.h" +#include "object-file.h" +#include "object-name.h" #include "object-store.h" #include "repository.h" #include "revision.h" @@ -8,6 +8,7 @@ #include "hex.h" #include "lockfile.h" #include "packfile.h" +#include "object-file.h" #include "object-store.h" #include "hash-lookup.h" #include "midx.h" @@ -1330,17 +1331,17 @@ static int write_midx_internal(const char *object_dir, } if (preferred_pack_name) { - int found = 0; + ctx.preferred_pack_idx = -1; + for (i = 0; i < ctx.nr; i++) { if (!cmp_idx_or_pack_name(preferred_pack_name, ctx.info[i].pack_name)) { ctx.preferred_pack_idx = i; - found = 1; break; } } - if (!found) + if (ctx.preferred_pack_idx == -1) warning(_("unknown preferred pack: '%s'"), preferred_pack_name); } else if (ctx.nr && diff --git a/name-hash.c b/name-hash.c index 2c2861efd1..fb13716e43 100644 --- a/name-hash.c +++ b/name-hash.c @@ -9,6 +9,7 @@ #include "environment.h" #include "gettext.h" #include "thread-utils.h" +#include "trace.h" #include "trace2.h" #include "sparse-index.h" diff --git a/notes-merge.c b/notes-merge.c index c40107c3aa..233e49e319 100644 --- a/notes-merge.c +++ b/notes-merge.c @@ -1,7 +1,10 @@ -#include "cache.h" +#include "git-compat-util.h" +#include "advice.h" #include "commit.h" #include "gettext.h" #include "refs.h" +#include "object-file.h" +#include "object-name.h" #include "object-store.h" #include "repository.h" #include "diff.h" @@ -13,6 +16,7 @@ #include "notes.h" #include "notes-merge.h" #include "strbuf.h" +#include "trace.h" #include "notes-utils.h" #include "commit-reach.h" #include "wrapper.h" @@ -1,8 +1,9 @@ -#include "cache.h" +#include "git-compat-util.h" #include "config.h" #include "environment.h" #include "hex.h" #include "notes.h" +#include "object-name.h" #include "object-store.h" #include "blob.h" #include "tree.h" diff --git a/object-file.c b/object-file.c index 76b22ca75c..af18e38527 100644 --- a/object-file.c +++ b/object-file.c @@ -10,6 +10,7 @@ #include "abspath.h" #include "alloc.h" #include "config.h" +#include "convert.h" #include "environment.h" #include "gettext.h" #include "hex.h" @@ -35,6 +36,7 @@ #include "mergesort.h" #include "quote.h" #include "packfile.h" +#include "object-file.h" #include "object-store.h" #include "promisor-remote.h" #include "setup.h" @@ -951,6 +953,12 @@ void prepare_alt_odb(struct repository *r) r->objects->loaded_alternates = 1; } +int has_alt_odb(struct repository *r) +{ + prepare_alt_odb(r); + return !!r->objects->odb->next; +} + /* Returns 1 if we have successfully freshened the file, 0 otherwise. */ static int freshen_file(const char *fn) { diff --git a/object-file.h b/object-file.h new file mode 100644 index 0000000000..e0cfc3a5db --- /dev/null +++ b/object-file.h @@ -0,0 +1,129 @@ +#ifndef OBJECT_FILE_H +#define OBJECT_FILE_H + +#include "git-zlib.h" +#include "object.h" + +/* + * Set this to 0 to prevent oid_object_info_extended() from fetching missing + * blobs. This has a difference only if extensions.partialClone is set. + * + * Its default value is 1. + */ +extern int fetch_if_missing; + +#define HASH_WRITE_OBJECT 1 +#define HASH_FORMAT_CHECK 2 +#define HASH_RENORMALIZE 4 +#define HASH_SILENT 8 +int index_fd(struct index_state *istate, struct object_id *oid, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags); +int index_path(struct index_state *istate, struct object_id *oid, const char *path, struct stat *st, unsigned flags); + +/* + * Create the directory containing the named path, using care to be + * somewhat safe against races. Return one of the scld_error values to + * indicate success/failure. On error, set errno to describe the + * problem. + * + * SCLD_VANISHED indicates that one of the ancestor directories of the + * path existed at one point during the function call and then + * suddenly vanished, probably because another process pruned the + * directory while we were working. To be robust against this kind of + * race, callers might want to try invoking the function again when it + * returns SCLD_VANISHED. + * + * safe_create_leading_directories() temporarily changes path while it + * is working but restores it before returning. + * safe_create_leading_directories_const() doesn't modify path, even + * temporarily. Both these variants adjust the permissions of the + * created directories to honor core.sharedRepository, so they are best + * suited for files inside the git dir. For working tree files, use + * safe_create_leading_directories_no_share() instead, as it ignores + * the core.sharedRepository setting. + */ +enum scld_error { + SCLD_OK = 0, + SCLD_FAILED = -1, + SCLD_PERMS = -2, + SCLD_EXISTS = -3, + SCLD_VANISHED = -4 +}; +enum scld_error safe_create_leading_directories(char *path); +enum scld_error safe_create_leading_directories_const(const char *path); +enum scld_error safe_create_leading_directories_no_share(char *path); + +int mkdir_in_gitdir(const char *path); + +int git_open_cloexec(const char *name, int flags); +#define git_open(name) git_open_cloexec(name, O_RDONLY) + +/** + * unpack_loose_header() initializes the data stream needed to unpack + * a loose object header. + * + * Returns: + * + * - ULHR_OK on success + * - ULHR_BAD on error + * - ULHR_TOO_LONG if the header was too long + * + * It will only parse up to MAX_HEADER_LEN bytes unless an optional + * "hdrbuf" argument is non-NULL. This is intended for use with + * OBJECT_INFO_ALLOW_UNKNOWN_TYPE to extract the bad type for (error) + * reporting. The full header will be extracted to "hdrbuf" for use + * with parse_loose_header(), ULHR_TOO_LONG will still be returned + * from this function to indicate that the header was too long. + */ +enum unpack_loose_header_result { + ULHR_OK, + ULHR_BAD, + ULHR_TOO_LONG, +}; +enum unpack_loose_header_result unpack_loose_header(git_zstream *stream, + unsigned char *map, + unsigned long mapsize, + void *buffer, + unsigned long bufsiz, + struct strbuf *hdrbuf); + +/** + * parse_loose_header() parses the starting "<type> <len>\0" of an + * object. If it doesn't follow that format -1 is returned. To check + * the validity of the <type> populate the "typep" in the "struct + * object_info". It will be OBJ_BAD if the object type is unknown. The + * parsed <len> can be retrieved via "oi->sizep", and from there + * passed to unpack_loose_rest(). + */ +struct object_info; +int parse_loose_header(const char *hdr, struct object_info *oi); + +/** + * With in-core object data in "buf", rehash it to make sure the + * object name actually matches "oid" to detect object corruption. + * + * A negative value indicates an error, usually that the OID is not + * what we expected, but it might also indicate another error. + */ +int check_object_signature(struct repository *r, const struct object_id *oid, + void *map, unsigned long size, + enum object_type type); + +/** + * A streaming version of check_object_signature(). + * Try reading the object named with "oid" using + * the streaming interface and rehash it to do the same. + */ +int stream_object_signature(struct repository *r, const struct object_id *oid); + +int finalize_object_file(const char *tmpfile, const char *filename); + +/* Helper to check and "touch" a file */ +int check_and_freshen_file(const char *fn, int freshen); + +void *read_object_with_reference(struct repository *r, + const struct object_id *oid, + enum object_type required_type, + unsigned long *size, + struct object_id *oid_ret); + +#endif /* OBJECT_FILE_H */ diff --git a/object-name.c b/object-name.c index f1edc0035b..538e8a8f62 100644 --- a/object-name.c +++ b/object-name.c @@ -1,4 +1,6 @@ #include "cache.h" +#include "object-name.h" +#include "advice.h" #include "config.h" #include "environment.h" #include "gettext.h" diff --git a/object-name.h b/object-name.h new file mode 100644 index 0000000000..1d63698f42 --- /dev/null +++ b/object-name.h @@ -0,0 +1,121 @@ +#ifndef OBJECT_NAME_H +#define OBJECT_NAME_H + +#include "object.h" +#include "strbuf.h" + +struct object_id; +struct repository; + +struct object_context { + unsigned short mode; + /* + * symlink_path is only used by get_tree_entry_follow_symlinks, + * and only for symlinks that point outside the repository. + */ + struct strbuf symlink_path; + /* + * If GET_OID_RECORD_PATH is set, this will record path (if any) + * found when resolving the name. The caller is responsible for + * releasing the memory. + */ + char *path; +}; + +/* + * Return an abbreviated sha1 unique within this repository's object database. + * The result will be at least `len` characters long, and will be NUL + * terminated. + * + * The non-`_r` version returns a static buffer which remains valid until 4 + * more calls to repo_find_unique_abbrev are made. + * + * The `_r` variant writes to a buffer supplied by the caller, which must be at + * least `GIT_MAX_HEXSZ + 1` bytes. The return value is the number of bytes + * written (excluding the NUL terminator). + * + * Note that while this version avoids the static buffer, it is not fully + * reentrant, as it calls into other non-reentrant git code. + */ +const char *repo_find_unique_abbrev(struct repository *r, const struct object_id *oid, int len); +int repo_find_unique_abbrev_r(struct repository *r, char *hex, const struct object_id *oid, int len); + +int repo_get_oid(struct repository *r, const char *str, struct object_id *oid); +__attribute__((format (printf, 2, 3))) +int get_oidf(struct object_id *oid, const char *fmt, ...); +int repo_get_oid_commit(struct repository *r, const char *str, struct object_id *oid); +int repo_get_oid_committish(struct repository *r, const char *str, struct object_id *oid); +int repo_get_oid_tree(struct repository *r, const char *str, struct object_id *oid); +int repo_get_oid_treeish(struct repository *r, const char *str, struct object_id *oid); +int repo_get_oid_blob(struct repository *r, const char *str, struct object_id *oid); +int repo_get_oid_mb(struct repository *r, const char *str, struct object_id *oid); +void maybe_die_on_misspelt_object_name(struct repository *repo, + const char *name, + const char *prefix); +enum get_oid_result get_oid_with_context(struct repository *repo, const char *str, + unsigned flags, struct object_id *oid, + struct object_context *oc); + + +typedef int each_abbrev_fn(const struct object_id *oid, void *); +int repo_for_each_abbrev(struct repository *r, const char *prefix, each_abbrev_fn, void *); + +int set_disambiguate_hint_config(const char *var, const char *value); + +/* + * This reads short-hand syntax that not only evaluates to a commit + * object name, but also can act as if the end user spelled the name + * of the branch from the command line. + * + * - "@{-N}" finds the name of the Nth previous branch we were on, and + * places the name of the branch in the given buf and returns the + * number of characters parsed if successful. + * + * - "<branch>@{upstream}" finds the name of the other ref that + * <branch> is configured to merge with (missing <branch> defaults + * to the current branch), and places the name of the branch in the + * given buf and returns the number of characters parsed if + * successful. + * + * If the input is not of the accepted format, it returns a negative + * number to signal an error. + * + * If the input was ok but there are not N branch switches in the + * reflog, it returns 0. + */ +#define INTERPRET_BRANCH_LOCAL (1<<0) +#define INTERPRET_BRANCH_REMOTE (1<<1) +#define INTERPRET_BRANCH_HEAD (1<<2) +struct interpret_branch_name_options { + /* + * If "allowed" is non-zero, it is a treated as a bitfield of allowable + * expansions: local branches ("refs/heads/"), remote branches + * ("refs/remotes/"), or "HEAD". If no "allowed" bits are set, any expansion is + * allowed, even ones to refs outside of those namespaces. + */ + unsigned allowed; + + /* + * If ^{upstream} or ^{push} (or equivalent) is requested, and the + * branch in question does not have such a reference, return -1 instead + * of die()-ing. + */ + unsigned nonfatal_dangling_mark : 1; +}; +int repo_interpret_branch_name(struct repository *r, + const char *str, int len, + struct strbuf *buf, + const struct interpret_branch_name_options *options); + +struct object *repo_peel_to_type(struct repository *r, + const char *name, int namelen, + struct object *o, enum object_type); + +/* Convert to/from hex/sha1 representation */ +#define MINIMUM_ABBREV minimum_abbrev +#define DEFAULT_ABBREV default_abbrev + +/* used when the code does not know or care what the default abbrev is */ +#define FALLBACK_DEFAULT_ABBREV 7 + +#endif /* OBJECT_NAME_H */ diff --git a/object-store.h b/object-store.h index f9d225783a..4ac91e375d 100644 --- a/object-store.h +++ b/object-store.h @@ -56,6 +56,7 @@ KHASH_INIT(odb_path_map, const char * /* key: odb_path */, struct object_directory *, 1, fspathhash, fspatheq) void prepare_alt_odb(struct repository *r); +int has_alt_odb(struct repository *r); char *compute_alternate_path(const char *path, struct strbuf *err); struct object_directory *find_odb(struct repository *r, const char *obj_dir); typedef int alt_odb_fn(struct object_directory *, void *); @@ -3,6 +3,7 @@ #include "hex.h" #include "object.h" #include "replace-object.h" +#include "object-file.h" #include "object-store.h" #include "blob.h" #include "tree.h" @@ -101,6 +101,50 @@ enum object_type { OBJ_MAX }; +/* unknown mode (impossible combination S_IFIFO|S_IFCHR) */ +#define S_IFINVALID 0030000 + +/* + * A "directory link" is a link to another git directory. + * + * The value 0160000 is not normally a valid mode, and + * also just happens to be S_IFDIR + S_IFLNK + */ +#define S_IFGITLINK 0160000 +#define S_ISGITLINK(m) (((m) & S_IFMT) == S_IFGITLINK) + +#define S_ISSPARSEDIR(m) ((m) == S_IFDIR) + +static inline enum object_type object_type(unsigned int mode) +{ + return S_ISDIR(mode) ? OBJ_TREE : + S_ISGITLINK(mode) ? OBJ_COMMIT : + OBJ_BLOB; +} + +#define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644) +static inline unsigned int create_ce_mode(unsigned int mode) +{ + if (S_ISLNK(mode)) + return S_IFLNK; + if (S_ISSPARSEDIR(mode)) + return S_IFDIR; + if (S_ISDIR(mode) || S_ISGITLINK(mode)) + return S_IFGITLINK; + return S_IFREG | ce_permissions(mode); +} + +static inline unsigned int canon_mode(unsigned int mode) +{ + if (S_ISREG(mode)) + return S_IFREG | ce_permissions(mode); + if (S_ISLNK(mode)) + return S_IFLNK; + if (S_ISDIR(mode)) + return S_IFDIR; + return S_IFGITLINK; +} + /* * The object type is stored in 3 bits. */ diff --git a/pack-bitmap-write.c b/pack-bitmap-write.c index 7f5f489beb..faf67c94d3 100644 --- a/pack-bitmap-write.c +++ b/pack-bitmap-write.c @@ -1,4 +1,4 @@ -#include "cache.h" +#include "git-compat-util.h" #include "alloc.h" #include "environment.h" #include "gettext.h" diff --git a/pack-bitmap.c b/pack-bitmap.c index b2e7d06d60..e0fad723bf 100644 --- a/pack-bitmap.c +++ b/pack-bitmap.c @@ -1,4 +1,4 @@ -#include "cache.h" +#include "git-compat-util.h" #include "alloc.h" #include "commit.h" #include "gettext.h" @@ -15,6 +15,8 @@ #include "pack-objects.h" #include "packfile.h" #include "repository.h" +#include "trace2.h" +#include "object-file.h" #include "object-store.h" #include "list-objects-filter-options.h" #include "midx.h" @@ -379,7 +381,7 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git, goto cleanup; } - if (load_midx_revindex(bitmap_git->midx) < 0) { + if (load_midx_revindex(bitmap_git->midx)) { warning(_("multi-pack bitmap is missing required reverse index")); goto cleanup; } @@ -463,7 +465,7 @@ static int open_pack_bitmap_1(struct bitmap_index *bitmap_git, struct packed_git return 0; } -static int load_reverse_index(struct bitmap_index *bitmap_git) +static int load_reverse_index(struct repository *r, struct bitmap_index *bitmap_git) { if (bitmap_is_midx(bitmap_git)) { uint32_t i; @@ -477,23 +479,23 @@ static int load_reverse_index(struct bitmap_index *bitmap_git) * since we will need to make use of them in pack-objects. */ for (i = 0; i < bitmap_git->midx->num_packs; i++) { - ret = load_pack_revindex(bitmap_git->midx->packs[i]); + ret = load_pack_revindex(r, bitmap_git->midx->packs[i]); if (ret) return ret; } return 0; } - return load_pack_revindex(bitmap_git->pack); + return load_pack_revindex(r, bitmap_git->pack); } -static int load_bitmap(struct bitmap_index *bitmap_git) +static int load_bitmap(struct repository *r, struct bitmap_index *bitmap_git) { assert(bitmap_git->map); bitmap_git->bitmaps = kh_init_oid_map(); bitmap_git->ext_index.positions = kh_init_oid_pos(); - if (load_reverse_index(bitmap_git)) + if (load_reverse_index(r, bitmap_git)) goto failed; if (!(bitmap_git->commits = read_bitmap_1(bitmap_git)) || @@ -580,7 +582,7 @@ struct bitmap_index *prepare_bitmap_git(struct repository *r) { struct bitmap_index *bitmap_git = xcalloc(1, sizeof(*bitmap_git)); - if (!open_bitmap(r, bitmap_git) && !load_bitmap(bitmap_git)) + if (!open_bitmap(r, bitmap_git) && !load_bitmap(r, bitmap_git)) return bitmap_git; free_bitmap_index(bitmap_git); @@ -589,9 +591,10 @@ struct bitmap_index *prepare_bitmap_git(struct repository *r) struct bitmap_index *prepare_midx_bitmap_git(struct multi_pack_index *midx) { + struct repository *r = the_repository; struct bitmap_index *bitmap_git = xcalloc(1, sizeof(*bitmap_git)); - if (!open_midx_bitmap_1(bitmap_git, midx) && !load_bitmap(bitmap_git)) + if (!open_midx_bitmap_1(bitmap_git, midx) && !load_bitmap(r, bitmap_git)) return bitmap_git; free_bitmap_index(bitmap_git); @@ -1592,7 +1595,7 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs, * from disk. this is the point of no return; after this the rev_list * becomes invalidated and we must perform the revwalk through bitmaps */ - if (load_bitmap(bitmap_git) < 0) + if (load_bitmap(revs->repo, bitmap_git) < 0) goto cleanup; object_array_clear(&revs->pending); @@ -1742,6 +1745,7 @@ int reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git, uint32_t *entries, struct bitmap **reuse_out) { + struct repository *r = the_repository; struct packed_git *pack; struct bitmap *result = bitmap_git->result; struct bitmap *reuse; @@ -1752,7 +1756,7 @@ int reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git, assert(result); - load_reverse_index(bitmap_git); + load_reverse_index(r, bitmap_git); if (bitmap_is_midx(bitmap_git)) pack = bitmap_git->midx->packs[midx_preferred_pack(bitmap_git)]; @@ -2132,12 +2136,13 @@ int rebuild_bitmap(const uint32_t *reposition, uint32_t *create_bitmap_mapping(struct bitmap_index *bitmap_git, struct packing_data *mapping) { + struct repository *r = the_repository; uint32_t i, num_objects; uint32_t *reposition; if (!bitmap_is_midx(bitmap_git)) - load_reverse_index(bitmap_git); - else if (load_midx_revindex(bitmap_git->midx) < 0) + load_reverse_index(r, bitmap_git); + else if (load_midx_revindex(bitmap_git->midx)) BUG("rebuild_existing_bitmaps: missing required rev-cache " "extension"); diff --git a/pack-check.c b/pack-check.c index 6974e40a95..049f2f0bfc 100644 --- a/pack-check.c +++ b/pack-check.c @@ -1,4 +1,4 @@ -#include "cache.h" +#include "git-compat-util.h" #include "environment.h" #include "hex.h" #include "repository.h" @@ -6,6 +6,7 @@ #include "pack-revindex.h" #include "progress.h" #include "packfile.h" +#include "object-file.h" #include "object-store.h" struct idx_entry { diff --git a/pack-mtimes.c b/pack-mtimes.c index afed632190..020a37f8fe 100644 --- a/pack-mtimes.c +++ b/pack-mtimes.c @@ -1,6 +1,7 @@ -#include "cache.h" +#include "git-compat-util.h" #include "gettext.h" #include "pack-mtimes.h" +#include "object-file.h" #include "object-store.h" #include "packfile.h" diff --git a/pack-revindex.c b/pack-revindex.c index 03c7e81f9d..1f51b712e8 100644 --- a/pack-revindex.c +++ b/pack-revindex.c @@ -1,10 +1,13 @@ -#include "cache.h" +#include "git-compat-util.h" #include "gettext.h" #include "pack-revindex.h" +#include "object-file.h" #include "object-store.h" #include "packfile.h" +#include "trace2.h" #include "config.h" #include "midx.h" +#include "csum-file.h" struct revindex_entry { off_t offset; @@ -205,10 +208,14 @@ static int load_revindex_from_disk(char *revindex_name, size_t revindex_size; struct revindex_header *hdr; + if (git_env_bool(GIT_TEST_REV_INDEX_DIE_ON_DISK, 0)) + die("dying as requested by '%s'", GIT_TEST_REV_INDEX_DIE_ON_DISK); + fd = git_open(revindex_name); if (fd < 0) { - ret = -1; + /* "No file" means return 1. */ + ret = 1; goto cleanup; } if (fstat(fd, &st)) { @@ -260,7 +267,7 @@ cleanup: return ret; } -static int load_pack_revindex_from_disk(struct packed_git *p) +int load_pack_revindex_from_disk(struct packed_git *p) { char *revindex_name; int ret; @@ -283,18 +290,58 @@ cleanup: return ret; } -int load_pack_revindex(struct packed_git *p) +int load_pack_revindex(struct repository *r, struct packed_git *p) { if (p->revindex || p->revindex_data) return 0; - if (!load_pack_revindex_from_disk(p)) + prepare_repo_settings(r); + + if (r->settings.pack_read_reverse_index && + !load_pack_revindex_from_disk(p)) return 0; else if (!create_pack_revindex_in_memory(p)) return 0; return -1; } +/* + * verify_pack_revindex verifies that the on-disk rev-index for the given + * pack-file is the same that would be created if written from scratch. + * + * A negative number is returned on error. + */ +int verify_pack_revindex(struct packed_git *p) +{ + int res = 0; + + /* Do not bother checking if not initialized. */ + if (!p->revindex_map || !p->revindex_data) + return res; + + if (!hashfile_checksum_valid((const unsigned char *)p->revindex_map, p->revindex_size)) { + error(_("invalid checksum")); + res = -1; + } + + /* This may fail due to a broken .idx. */ + if (create_pack_revindex_in_memory(p)) + return res; + + for (size_t i = 0; i < p->num_objects; i++) { + uint32_t nr = p->revindex[i].nr; + uint32_t rev_val = get_be32(p->revindex_data + i); + + if (nr != rev_val) { + error(_("invalid rev-index position at %"PRIu64": %"PRIu32" != %"PRIu32""), + (uint64_t)i, nr, rev_val); + res = -1; + } + } + + return res; +} + int load_midx_revindex(struct multi_pack_index *m) { struct strbuf revindex_name = STRBUF_INIT; @@ -356,7 +403,7 @@ int offset_to_pack_pos(struct packed_git *p, off_t ofs, uint32_t *pos) { unsigned lo, hi; - if (load_pack_revindex(p) < 0) + if (load_pack_revindex(the_repository, p) < 0) return -1; lo = 0; diff --git a/pack-revindex.h b/pack-revindex.h index 4974e75eb4..6dd47efea1 100644 --- a/pack-revindex.h +++ b/pack-revindex.h @@ -34,11 +34,13 @@ #define RIDX_SIGNATURE 0x52494458 /* "RIDX" */ #define RIDX_VERSION 1 -#define GIT_TEST_WRITE_REV_INDEX "GIT_TEST_WRITE_REV_INDEX" +#define GIT_TEST_NO_WRITE_REV_INDEX "GIT_TEST_NO_WRITE_REV_INDEX" #define GIT_TEST_REV_INDEX_DIE_IN_MEMORY "GIT_TEST_REV_INDEX_DIE_IN_MEMORY" +#define GIT_TEST_REV_INDEX_DIE_ON_DISK "GIT_TEST_REV_INDEX_DIE_ON_DISK" struct packed_git; struct multi_pack_index; +struct repository; /* * load_pack_revindex populates the revindex's internal data-structures for the @@ -47,7 +49,23 @@ struct multi_pack_index; * If a '.rev' file is present it is mmap'd, and pointers are assigned into it * (instead of using the in-memory variant). */ -int load_pack_revindex(struct packed_git *p); +int load_pack_revindex(struct repository *r, struct packed_git *p); + +/* + * Specifically load a pack revindex from disk. + * + * Returns 0 on success, 1 on "no .rev file", and -1 when there is an + * error parsing the .rev file. + */ +int load_pack_revindex_from_disk(struct packed_git *p); + +/* + * verify_pack_revindex verifies that the on-disk rev-index for the given + * pack-file is the same that would be created if written from scratch. + * + * A negative number is returned on error. + */ +int verify_pack_revindex(struct packed_git *p); /* * load_midx_revindex loads the '.rev' file corresponding to the given diff --git a/pack-write.c b/pack-write.c index 4da0ccc5f5..3b3ce89de6 100644 --- a/pack-write.c +++ b/pack-write.c @@ -1,4 +1,4 @@ -#include "cache.h" +#include "git-compat-util.h" #include "environment.h" #include "gettext.h" #include "hex.h" @@ -9,6 +9,8 @@ #include "pack-mtimes.h" #include "oidmap.h" #include "pack-objects.h" +#include "pack-revindex.h" +#include "wrapper.h" void reset_pack_idx_option(struct pack_idx_option *opts) { @@ -569,6 +571,7 @@ void stage_tmp_packfiles(struct strbuf *name_buffer, if (mtimes_tmp_name) rename_tmp_packfile(name_buffer, mtimes_tmp_name, "mtimes"); + free((char *)rev_tmp_name); free(mtimes_tmp_name); } diff --git a/packfile.c b/packfile.c index b120405ccc..57df0c1956 100644 --- a/packfile.c +++ b/packfile.c @@ -15,11 +15,14 @@ #include "commit.h" #include "object.h" #include "tag.h" +#include "trace.h" #include "tree-walk.h" #include "tree.h" +#include "object-file.h" #include "object-store.h" #include "midx.h" #include "commit-graph.h" +#include "pack-revindex.h" #include "promisor-remote.h" #include "wrapper.h" @@ -2151,7 +2154,7 @@ int for_each_object_in_pack(struct packed_git *p, int r = 0; if (flags & FOR_EACH_OBJECT_PACK_ORDER) { - if (load_pack_revindex(p)) + if (load_pack_revindex(the_repository, p)) return -1; } @@ -1,9 +1,13 @@ -#include "cache.h" +#include "git-compat-util.h" #include "config.h" +#include "editor.h" +#include "pager.h" #include "run-command.h" #include "sigchain.h" #include "alias.h" +int pager_use_color = 1; + #ifndef DEFAULT_PAGER #define DEFAULT_PAGER "less" #endif diff --git a/pager.h b/pager.h new file mode 100644 index 0000000000..b77433026d --- /dev/null +++ b/pager.h @@ -0,0 +1,17 @@ +#ifndef PAGER_H +#define PAGER_H + +struct child_process; + +const char *git_pager(int stdout_is_tty); +void setup_pager(void); +int pager_in_use(void); +int term_columns(void); +void term_clear_line(void); +int decimal_width(uintmax_t); +int check_pager_config(const char *cmd); +void prepare_pager_args(struct child_process *, const char *pager); + +extern int pager_use_color; + +#endif /* PAGER_H */ diff --git a/parse-options-cb.c b/parse-options-cb.c index 2488e6c030..298decf48f 100644 --- a/parse-options-cb.c +++ b/parse-options-cb.c @@ -1,11 +1,11 @@ #include "git-compat-util.h" #include "parse-options.h" #include "branch.h" -#include "cache.h" #include "commit.h" #include "color.h" #include "environment.h" #include "gettext.h" +#include "object-name.h" #include "string-list.h" #include "strvec.h" #include "oid-array.h" @@ -210,6 +210,22 @@ int parse_opt_string_list(const struct option *opt, const char *arg, int unset) return 0; } +int parse_opt_strvec(const struct option *opt, const char *arg, int unset) +{ + struct strvec *v = opt->value; + + if (unset) { + strvec_clear(v); + return 0; + } + + if (!arg) + return -1; + + strvec_push(v, arg); + return 0; +} + int parse_opt_noop_cb(const struct option *opt, const char *arg, int unset) { return 0; diff --git a/parse-options.h b/parse-options.h index 6f6462fdf9..8e48efe524 100644 --- a/parse-options.h +++ b/parse-options.h @@ -287,6 +287,15 @@ struct option { .help = (h), \ .callback = &parse_opt_string_list, \ } +#define OPT_STRVEC(s, l, v, a, h) { \ + .type = OPTION_CALLBACK, \ + .short_name = (s), \ + .long_name = (l), \ + .value = (v), \ + .argh = (a), \ + .help = (h), \ + .callback = &parse_opt_strvec, \ +} #define OPT_UYN(s, l, v, h) { \ .type = OPTION_CALLBACK, \ .short_name = (s), \ @@ -480,6 +489,7 @@ int parse_opt_commits(const struct option *, const char *, int); int parse_opt_commit(const struct option *, const char *, int); int parse_opt_tertiary(const struct option *, const char *, int); int parse_opt_string_list(const struct option *, const char *, int); +int parse_opt_strvec(const struct option *, const char *, int); int parse_opt_noop_cb(const struct option *, const char *, int); int parse_opt_passthru(const struct option *, const char *, int); int parse_opt_passthru_argv(const struct option *, const char *, int); @@ -18,6 +18,7 @@ #include "object-store.h" #include "lockfile.h" #include "exec-cmd.h" +#include "wrapper.h" static int get_st_mode_bits(const char *path, int *mode) { diff --git a/pkt-line.c b/pkt-line.c index 36ae0fea4a..3561d85358 100644 --- a/pkt-line.c +++ b/pkt-line.c @@ -3,6 +3,7 @@ #include "gettext.h" #include "hex.h" #include "run-command.h" +#include "trace.h" #include "wrapper.h" #include "write-or-die.h" diff --git a/preload-index.c b/preload-index.c index 52544d004e..4abf9c983b 100644 --- a/preload-index.c +++ b/preload-index.c @@ -11,6 +11,7 @@ #include "progress.h" #include "thread-utils.h" #include "repository.h" +#include "trace2.h" /* * Mostly randomly chosen maximum thread counts: we @@ -1,4 +1,4 @@ -#include "cache.h" +#include "git-compat-util.h" #include "alloc.h" #include "config.h" #include "commit.h" @@ -7,6 +7,7 @@ #include "hex.h" #include "utf8.h" #include "diff.h" +#include "pager.h" #include "revision.h" #include "string-list.h" #include "mailmap.h" diff --git a/progress.c b/progress.c index 44c784d75f..72d5e0c73c 100644 --- a/progress.c +++ b/progress.c @@ -9,10 +9,12 @@ */ #define GIT_TEST_PROGRESS_ONLY -#include "cache.h" +#include "git-compat-util.h" +#include "pager.h" #include "progress.h" #include "strbuf.h" #include "trace.h" +#include "trace2.h" #include "utf8.h" #include "config.h" diff --git a/promisor-remote.c b/promisor-remote.c index a8dbb788e8..1adcd6fb0a 100644 --- a/promisor-remote.c +++ b/promisor-remote.c @@ -1,9 +1,10 @@ -#include "cache.h" +#include "git-compat-util.h" #include "gettext.h" #include "hex.h" #include "object-store.h" #include "promisor-remote.h" #include "config.h" +#include "trace2.h" #include "transport.h" #include "strvec.h" #include "packfile.h" diff --git a/protocol.c b/protocol.c index bdb32e1eeb..079ba75acf 100644 --- a/protocol.c +++ b/protocol.c @@ -1,7 +1,8 @@ -#include "cache.h" +#include "git-compat-util.h" #include "config.h" #include "environment.h" #include "protocol.h" +#include "trace2.h" static enum protocol_version parse_protocol_version(const char *value) { diff --git a/protocol.h b/protocol.h index cef1a4a01c..de66bf80f8 100644 --- a/protocol.h +++ b/protocol.h @@ -1,6 +1,27 @@ #ifndef PROTOCOL_H #define PROTOCOL_H +/* + * Intensive research over the course of many years has shown that + * port 9418 is totally unused by anything else. Or + * + * Your search - "port 9418" - did not match any documents. + * + * as www.google.com puts it. + * + * This port has been properly assigned for git use by IANA: + * git (Assigned-9418) [I06-050728-0001]. + * + * git 9418/tcp git pack transfer service + * git 9418/udp git pack transfer service + * + * with Linus Torvalds <torvalds@osdl.org> as the point of + * contact. September 2005. + * + * See http://www.iana.org/assignments/port-numbers + */ +#define DEFAULT_GIT_PORT 9418 + enum protocol_version { protocol_unknown_version = -1, protocol_v0 = 0, @@ -1,5 +1,6 @@ -#include "cache.h" +#include "git-compat-util.h" #include "alloc.h" +#include "path.h" #include "quote.h" #include "strbuf.h" #include "strvec.h" @@ -3,6 +3,8 @@ struct strbuf; +extern int quote_path_fully; + /* Help to copy the thing properly quoted for the shell safety. * any single quote is replaced with '\'', any exclamation point * is replaced with '\!', and the whole thing is enclosed in a diff --git a/range-diff.c b/range-diff.c index d1ed3b8ee5..a1e0cffb9f 100644 --- a/range-diff.c +++ b/range-diff.c @@ -2,6 +2,7 @@ #include "environment.h" #include "gettext.h" #include "range-diff.h" +#include "object-name.h" #include "string-list.h" #include "run-command.h" #include "strvec.h" @@ -10,6 +11,7 @@ #include "linear-assignment.h" #include "diffcore.h" #include "commit.h" +#include "pager.h" #include "pretty.h" #include "userdiff.h" #include "apply.h" diff --git a/read-cache.c b/read-cache.c index 2a49178633..e919af3c77 100644 --- a/read-cache.c +++ b/read-cache.c @@ -14,15 +14,20 @@ #include "cache-tree.h" #include "refs.h" #include "dir.h" +#include "object-file.h" #include "object-store.h" +#include "oid-array.h" #include "tree.h" #include "commit.h" #include "blob.h" #include "environment.h" #include "gettext.h" +#include "mem-pool.h" +#include "object-name.h" #include "resolve-undo.h" #include "run-command.h" #include "strbuf.h" +#include "trace2.h" #include "varint.h" #include "split-index.h" #include "utf8.h" diff --git a/rebase-interactive.c b/rebase-interactive.c index 79ed61b9fa..789f407361 100644 --- a/rebase-interactive.c +++ b/rebase-interactive.c @@ -1,5 +1,6 @@ -#include "cache.h" +#include "git-compat-util.h" #include "commit.h" +#include "editor.h" #include "environment.h" #include "gettext.h" #include "sequencer.h" @@ -8,6 +9,7 @@ #include "commit-slab.h" #include "config.h" #include "dir.h" +#include "object-name.h" #include "wrapper.h" static const char edit_todo_list_advice[] = diff --git a/ref-filter.c b/ref-filter.c index 72175612f3..10aab14f03 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -6,7 +6,9 @@ #include "parse-options.h" #include "refs.h" #include "wildmatch.h" +#include "object-name.h" #include "object-store.h" +#include "oid-array.h" #include "repository.h" #include "commit.h" #include "remote.h" @@ -2,7 +2,8 @@ * The backend-independent part of the reference module. */ -#include "cache.h" +#include "git-compat-util.h" +#include "advice.h" #include "alloc.h" #include "config.h" #include "environment.h" @@ -15,6 +16,7 @@ #include "refs/refs-internal.h" #include "run-command.h" #include "hook.h" +#include "object-name.h" #include "object-store.h" #include "object.h" #include "tag.h" diff --git a/refs/files-backend.c b/refs/files-backend.c index e6a6971381..d0581ee41a 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -12,6 +12,7 @@ #include "../dir-iterator.h" #include "../lockfile.h" #include "../object.h" +#include "../object-file.h" #include "../dir.h" #include "../chdir-notify.h" #include "../setup.h" diff --git a/refs/packed-backend.c b/refs/packed-backend.c index 1eba1015dd..2333ed5a1f 100644 --- a/refs/packed-backend.c +++ b/refs/packed-backend.c @@ -9,6 +9,7 @@ #include "../iterator.h" #include "../lockfile.h" #include "../chdir-notify.h" +#include "../wrapper.h" #include "../write-or-die.h" enum mmap_strategy { diff --git a/refs/ref-cache.h b/refs/ref-cache.h index 850d9d3744..cf4ad9070b 100644 --- a/refs/ref-cache.h +++ b/refs/ref-cache.h @@ -1,7 +1,7 @@ #ifndef REFS_REF_CACHE_H #define REFS_REF_CACHE_H -#include "cache.h" +#include "hash.h" struct ref_dir; struct ref_store; diff --git a/remote-curl.c b/remote-curl.c index db3bc431fc..acf7b2bb40 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -21,6 +21,7 @@ #include "setup.h" #include "protocol.h" #include "quote.h" +#include "trace2.h" #include "transport.h" #include "write-or-die.h" @@ -1,4 +1,4 @@ -#include "cache.h" +#include "git-compat-util.h" #include "abspath.h" #include "alloc.h" #include "config.h" @@ -9,6 +9,7 @@ #include "urlmatch.h" #include "refs.h" #include "refspec.h" +#include "object-name.h" #include "object-store.h" #include "commit.h" #include "diff.h" diff --git a/repo-settings.c b/repo-settings.c index a8d0b98794..d220c5dd9f 100644 --- a/repo-settings.c +++ b/repo-settings.c @@ -61,6 +61,7 @@ void prepare_repo_settings(struct repository *r) repo_cfg_bool(r, "core.multipackindex", &r->settings.core_multi_pack_index, 1); repo_cfg_bool(r, "index.sparse", &r->settings.sparse_index, 0); repo_cfg_bool(r, "index.skiphash", &r->settings.index_skip_hash, r->settings.index_skip_hash); + repo_cfg_bool(r, "pack.readreverseindex", &r->settings.pack_read_reverse_index, 1); /* * The GIT_TEST_MULTI_PACK_INDEX variable is special in that diff --git a/repository.c b/repository.c index f6d9f5db08..c53e480e32 100644 --- a/repository.c +++ b/repository.c @@ -14,6 +14,7 @@ #include "setup.h" #include "submodule-config.h" #include "sparse-index.h" +#include "trace2.h" #include "promisor-remote.h" /* The main repository */ diff --git a/repository.h b/repository.h index 50eb0ce391..1a13ff2867 100644 --- a/repository.h +++ b/repository.h @@ -36,6 +36,7 @@ struct repo_settings { int fetch_write_commit_graph; int command_requires_full_index; int sparse_index; + int pack_read_reverse_index; struct fsmonitor_settings *fsmonitor; /* lazily loaded */ @@ -1,4 +1,4 @@ -#include "git-compat-util.h" +#include "cache.h" #include "abspath.h" #include "alloc.h" #include "config.h" @@ -13,6 +13,7 @@ #include "ll-merge.h" #include "attr.h" #include "pathspec.h" +#include "object-file.h" #include "object-store.h" #include "hash-lookup.h" #include "strmap.h" @@ -3,6 +3,7 @@ #include "gettext.h" #include "hex.h" #include "lockfile.h" +#include "object-name.h" #include "refs.h" #include "reset.h" #include "run-command.h" diff --git a/resolve-undo.h b/resolve-undo.h index 2b3f0f901e..d1ea972771 100644 --- a/resolve-undo.h +++ b/resolve-undo.h @@ -1,7 +1,12 @@ #ifndef RESOLVE_UNDO_H #define RESOLVE_UNDO_H -#include "cache.h" +struct cache_entry; +struct index_state; +struct pathspec; +struct string_list; + +#include "hash.h" struct resolve_undo_info { unsigned int mode[3]; diff --git a/revision.c b/revision.c index 106ca1ce6c..b33cc1d106 100644 --- a/revision.c +++ b/revision.c @@ -1,9 +1,11 @@ -#include "git-compat-util.h" +#include "cache.h" #include "alloc.h" #include "config.h" #include "environment.h" #include "gettext.h" #include "hex.h" +#include "object-name.h" +#include "object-file.h" #include "object-store.h" #include "tag.h" #include "blob.h" @@ -31,6 +33,7 @@ #include "worktree.h" #include "setup.h" #include "strvec.h" +#include "trace2.h" #include "commit-reach.h" #include "commit-graph.h" #include "prio-queue.h" diff --git a/run-command.c b/run-command.c index 614d48fa9a..e64bb08a5b 100644 --- a/run-command.c +++ b/run-command.c @@ -8,6 +8,8 @@ #include "thread-utils.h" #include "strbuf.h" #include "string-list.h" +#include "trace.h" +#include "trace2.h" #include "quote.h" #include "config.h" #include "packfile.h" @@ -2,7 +2,7 @@ * The Scalar command-line interface. */ -#include "cache.h" +#include "git-compat-util.h" #include "abspath.h" #include "gettext.h" #include "parse-options.h" @@ -16,6 +16,7 @@ #include "packfile.h" #include "help.h" #include "setup.h" +#include "trace2.h" static void setup_enlistment_directory(int argc, const char **argv, const char * const *usagestr, diff --git a/send-pack.c b/send-pack.c index f81bbb28d7..2089143555 100644 --- a/send-pack.c +++ b/send-pack.c @@ -14,6 +14,7 @@ #include "quote.h" #include "transport.h" #include "version.h" +#include "wrapper.h" #include "oid-array.h" #include "gpg-interface.h" #include "shallow.h" @@ -538,7 +539,7 @@ int send_pack(struct send_pack_args *args, die(_("the receiving end does not support this repository's hash algorithm")); if (args->push_cert != SEND_PACK_PUSH_CERT_NEVER) { - int len; + size_t len; push_cert_nonce = server_feature_value("push-cert", &len); if (push_cert_nonce) { reject_invalid_nonce(push_cert_nonce, len); diff --git a/sequencer.c b/sequencer.c index 6985ca526a..c88d1d9553 100644 --- a/sequencer.c +++ b/sequencer.c @@ -1,5 +1,6 @@ #include "cache.h" #include "abspath.h" +#include "advice.h" #include "alloc.h" #include "config.h" #include "environment.h" @@ -7,8 +8,11 @@ #include "hex.h" #include "lockfile.h" #include "dir.h" +#include "object-file.h" +#include "object-name.h" #include "object-store.h" #include "object.h" +#include "pager.h" #include "commit.h" #include "sequencer.h" #include "tag.h" @@ -359,9 +363,7 @@ void replay_opts_release(struct replay_opts *opts) free(opts->reflog_action); free(opts->default_strategy); free(opts->strategy); - for (size_t i = 0; i < opts->xopts_nr; i++) - free(opts->xopts[i]); - free(opts->xopts); + strvec_clear (&opts->xopts); strbuf_release(&opts->current_fixups); if (opts->revs) release_revisions(opts->revs); @@ -699,8 +701,8 @@ static int do_recursive_merge(struct repository *r, next_tree = next ? repo_get_commit_tree(r, next) : empty_tree(r); base_tree = base ? repo_get_commit_tree(r, base) : empty_tree(r); - for (i = 0; i < opts->xopts_nr; i++) - parse_merge_opt(&o, opts->xopts[i]); + for (i = 0; i < opts->xopts.nr; i++) + parse_merge_opt(&o, opts->xopts.v[i]); if (!opts->strategy || !strcmp(opts->strategy, "ort")) { memset(&result, 0, sizeof(result)); @@ -2336,7 +2338,7 @@ static int do_pick_commit(struct repository *r, commit_list_insert(base, &common); commit_list_insert(next, &remotes); res |= try_merge_command(r, opts->strategy, - opts->xopts_nr, (const char **)opts->xopts, + opts->xopts.nr, opts->xopts.v, common, oid_to_hex(&head), remotes); free_commit_list(common); free_commit_list(remotes); @@ -2909,8 +2911,7 @@ static int populate_opts_cb(const char *key, const char *value, void *data) else if (!strcmp(key, "options.gpg-sign")) git_config_string_dup(&opts->gpg_sign, key, value); else if (!strcmp(key, "options.strategy-option")) { - ALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc); - opts->xopts[opts->xopts_nr++] = xstrdup(value); + strvec_push(&opts->xopts, value); } else if (!strcmp(key, "options.allow-rerere-auto")) opts->allow_rerere_auto = git_config_bool_or_int(key, value, &error_flag) ? @@ -2927,27 +2928,27 @@ static int populate_opts_cb(const char *key, const char *value, void *data) return 0; } -void parse_strategy_opts(struct replay_opts *opts, char *raw_opts) +static void parse_strategy_opts(struct replay_opts *opts, char *raw_opts) { int i; int count; + const char **argv; char *strategy_opts_string = raw_opts; if (*strategy_opts_string == ' ') strategy_opts_string++; - count = split_cmdline(strategy_opts_string, - (const char ***)&opts->xopts); + count = split_cmdline(strategy_opts_string, &argv); if (count < 0) - die(_("could not split '%s': %s"), strategy_opts_string, + BUG("could not split '%s': %s", strategy_opts_string, split_cmdline_strerror(count)); - opts->xopts_nr = count; - for (i = 0; i < opts->xopts_nr; i++) { - const char *arg = opts->xopts[i]; + for (i = 0; i < count; i++) { + const char *arg = argv[i]; skip_prefix(arg, "--", &arg); - opts->xopts[i] = xstrdup(arg); + strvec_push(&opts->xopts, arg); } + free(argv); } static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf) @@ -2955,7 +2956,6 @@ static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf) strbuf_reset(buf); if (!read_oneliner(buf, rebase_path_strategy(), 0)) return; - free(opts->strategy); opts->strategy = strbuf_detach(buf, NULL); if (!read_oneliner(buf, rebase_path_strategy_opts(), 0)) return; @@ -3064,12 +3064,13 @@ done_rebase_i: static void write_strategy_opts(struct replay_opts *opts) { - int i; struct strbuf buf = STRBUF_INIT; - for (i = 0; i < opts->xopts_nr; ++i) - strbuf_addf(&buf, " --%s", opts->xopts[i]); - + /* + * Quote strategy options so that they can be read correctly + * by split_cmdline(). + */ + quote_cmdline(&buf, opts->xopts.v); write_file(rebase_path_strategy_opts(), "%s\n", buf.buf); strbuf_release(&buf); } @@ -3092,7 +3093,7 @@ int write_basic_state(struct replay_opts *opts, const char *head_name, write_file(rebase_path_verbose(), "%s", ""); if (opts->strategy) write_file(rebase_path_strategy(), "%s\n", opts->strategy); - if (opts->xopts_nr > 0) + if (opts->xopts.nr > 0) write_strategy_opts(opts); if (opts->allow_rerere_auto == RERERE_AUTOUPDATE) @@ -3461,13 +3462,10 @@ static int save_opts(struct replay_opts *opts) if (opts->gpg_sign) res |= git_config_set_in_file_gently(opts_file, "options.gpg-sign", opts->gpg_sign); - if (opts->xopts) { - int i; - for (i = 0; i < opts->xopts_nr; i++) - res |= git_config_set_multivar_in_file_gently(opts_file, - "options.strategy-option", - opts->xopts[i], "^$", 0); - } + for (size_t i = 0; i < opts->xopts.nr; i++) + res |= git_config_set_multivar_in_file_gently(opts_file, + "options.strategy-option", + opts->xopts.v[i], "^$", 0); if (opts->allow_rerere_auto) res |= git_config_set_in_file_gently(opts_file, "options.allow-rerere-auto", @@ -3879,7 +3877,7 @@ static int do_merge(struct repository *r, struct commit *head_commit, *merge_commit, *i; struct commit_list *bases, *j; struct commit_list *to_merge = NULL, **tail = &to_merge; - const char *strategy = !opts->xopts_nr && + const char *strategy = !opts->xopts.nr && (!opts->strategy || !strcmp(opts->strategy, "recursive") || !strcmp(opts->strategy, "ort")) ? @@ -4063,9 +4061,9 @@ static int do_merge(struct repository *r, strvec_push(&cmd.args, "octopus"); else { strvec_push(&cmd.args, strategy); - for (k = 0; k < opts->xopts_nr; k++) + for (k = 0; k < opts->xopts.nr; k++) strvec_pushf(&cmd.args, - "-X%s", opts->xopts[k]); + "-X%s", opts->xopts.v[k]); } if (!(flags & TODO_EDIT_MERGE_MSG)) strvec_push(&cmd.args, "--no-edit"); diff --git a/sequencer.h b/sequencer.h index 33dbaf5b66..913a0f652d 100644 --- a/sequencer.h +++ b/sequencer.h @@ -2,6 +2,7 @@ #define SEQUENCER_H #include "strbuf.h" +#include "strvec.h" #include "wt-status.h" struct commit; @@ -60,8 +61,7 @@ struct replay_opts { /* Merge strategy */ char *default_strategy; /* from config options */ char *strategy; - char **xopts; - size_t xopts_nr, xopts_alloc; + struct strvec xopts; /* Reflog */ char *reflog_action; @@ -80,7 +80,12 @@ struct replay_opts { /* Private use */ const char *reflog_message; }; -#define REPLAY_OPTS_INIT { .edit = -1, .action = -1, .current_fixups = STRBUF_INIT } +#define REPLAY_OPTS_INIT { \ + .edit = -1, \ + .action = -1, \ + .current_fixups = STRBUF_INIT, \ + .xopts = STRVEC_INIT, \ +} /* * Note that ordering matters in this enum. Not only must it match the mapping @@ -247,7 +252,6 @@ int read_oneliner(struct strbuf *buf, const char *path, unsigned flags); int read_author_script(const char *path, char **name, char **email, char **date, int allow_missing); -void parse_strategy_opts(struct replay_opts *opts, char *raw_opts); int write_basic_state(struct replay_opts *opts, const char *head_name, struct commit *onto, const struct object_id *orig_head); void sequencer_post_commit_cleanup(struct repository *r, int verbose); diff --git a/server-info.c b/server-info.c index 355b6e01a5..68098ddd1a 100644 --- a/server-info.c +++ b/server-info.c @@ -9,6 +9,7 @@ #include "commit.h" #include "tag.h" #include "packfile.h" +#include "object-file.h" #include "object-store.h" #include "strbuf.h" #include "wrapper.h" @@ -1,7 +1,8 @@ -#include "cache.h" +#include "git-compat-util.h" #include "abspath.h" #include "environment.h" #include "gettext.h" +#include "object-name.h" #include "repository.h" #include "config.h" #include "dir.h" @@ -10,6 +11,8 @@ #include "chdir-notify.h" #include "promisor-remote.h" #include "quote.h" +#include "trace2.h" +#include "wrapper.h" static int inside_git_dir = -1; static int inside_work_tree = -1; @@ -17,6 +17,7 @@ #include "list-objects.h" #include "commit-reach.h" #include "shallow.h" +#include "trace.h" #include "wrapper.h" void set_alternate_shallow_file(struct repository *r, const char *path, int override) diff --git a/sideband.c b/sideband.c index 0af582858b..6cbfd391c4 100644 --- a/sideband.c +++ b/sideband.c @@ -1,6 +1,7 @@ -#include "cache.h" +#include "git-compat-util.h" #include "color.h" #include "config.h" +#include "editor.h" #include "gettext.h" #include "sideband.h" #include "help.h" diff --git a/split-index.c b/split-index.c index c98807c655..5602b74994 100644 --- a/split-index.c +++ b/split-index.c @@ -1,6 +1,7 @@ #include "cache.h" #include "alloc.h" #include "gettext.h" +#include "mem-pool.h" #include "split-index.h" #include "ewah/ewok.h" diff --git a/split-index.h b/split-index.h index 7a435ca2c9..1a153f47ba 100644 --- a/split-index.h +++ b/split-index.h @@ -1,7 +1,7 @@ #ifndef SPLIT_INDEX_H #define SPLIT_INDEX_H -#include "cache.h" +#include "hash.h" struct index_state; struct strbuf; @@ -1,9 +1,10 @@ -#include "cache.h" +#include "git-compat-util.h" #include "abspath.h" #include "alloc.h" #include "environment.h" #include "gettext.h" #include "hex.h" +#include "object-name.h" #include "refs.h" #include "string-list.h" #include "utf8.h" @@ -1179,34 +1180,6 @@ int strbuf_normalize_path(struct strbuf *src) return 0; } -int strbuf_edit_interactively(struct strbuf *buffer, const char *path, - const char *const *env) -{ - char *path2 = NULL; - int fd, res = 0; - - if (!is_absolute_path(path)) - path = path2 = xstrdup(git_path("%s", path)); - - fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666); - if (fd < 0) - res = error_errno(_("could not open '%s' for writing"), path); - else if (write_in_full(fd, buffer->buf, buffer->len) < 0) { - res = error_errno(_("could not write to '%s'"), path); - close(fd); - } else if (close(fd) < 0) - res = error_errno(_("could not close '%s'"), path); - else { - strbuf_reset(buffer); - if (launch_editor(path, buffer, env) < 0) - res = error_errno(_("could not edit '%s'"), path); - unlink(path); - } - - free(path2); - return res; -} - void strbuf_strip_file_from_path(struct strbuf *sb) { char *path_sep = find_last_dir_sep(sb->buf); @@ -640,30 +640,6 @@ void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo, void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid, int abbrev_len); -/** - * Launch the user preferred editor to edit a file and fill the buffer - * with the file's contents upon the user completing their editing. The - * third argument can be used to set the environment which the editor is - * run in. If the buffer is NULL the editor is launched as usual but the - * file's contents are not read into the buffer upon completion. - */ -int launch_editor(const char *path, struct strbuf *buffer, - const char *const *env); - -int launch_sequence_editor(const char *path, struct strbuf *buffer, - const char *const *env); - -/* - * In contrast to `launch_editor()`, this function writes out the contents - * of the specified file first, then clears the `buffer`, then launches - * the editor and reads back in the file contents into the `buffer`. - * Finally, it deletes the temporary file. - * - * If `path` is relative, it refers to a file in the `.git` directory. - */ -int strbuf_edit_interactively(struct strbuf *buffer, const char *path, - const char *const *env); - /* * Remove the filename from the provided path string. If the path * contains a trailing separator, then the path is considered a directory diff --git a/streaming.c b/streaming.c index 024fd796b7..21e39585e8 100644 --- a/streaming.c +++ b/streaming.c @@ -1,10 +1,12 @@ /* * Copyright (c) 2011, Google Inc. */ -#include "cache.h" +#include "git-compat-util.h" +#include "convert.h" #include "environment.h" #include "streaming.h" #include "repository.h" +#include "object-file.h" #include "object-store.h" #include "replace-object.h" #include "packfile.h" diff --git a/submodule-config.c b/submodule-config.c index ecf0fcf007..7fc0812b64 100644 --- a/submodule-config.c +++ b/submodule-config.c @@ -1,4 +1,4 @@ -#include "cache.h" +#include "git-compat-util.h" #include "alloc.h" #include "dir.h" #include "environment.h" @@ -9,6 +9,7 @@ #include "submodule-config.h" #include "submodule.h" #include "strbuf.h" +#include "object-name.h" #include "object-store.h" #include "parse-options.h" #include "tree-walk.h" diff --git a/submodule.c b/submodule.c index 94644fac0a..2e78f51349 100644 --- a/submodule.c +++ b/submodule.c @@ -24,10 +24,13 @@ #include "remote.h" #include "worktree.h" #include "parse-options.h" +#include "object-file.h" +#include "object-name.h" #include "object-store.h" #include "commit-reach.h" #include "setup.h" #include "shallow.h" +#include "trace2.h" static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF; static int initialized_fetch_ref_tips; @@ -475,7 +475,7 @@ GIT_TEST_DEFAULT_HASH=<hash-algo> specifies which hash algorithm to use in the test scripts. Recognized values for <hash-algo> are "sha1" and "sha256". -GIT_TEST_WRITE_REV_INDEX=<boolean>, when true enables the +GIT_TEST_NO_WRITE_REV_INDEX=<boolean>, when true disables the 'pack.writeReverseIndex' setting. GIT_TEST_SPARSE_INDEX=<boolean>, when true enables index writes to use the diff --git a/t/helper/test-chmtime.c b/t/helper/test-chmtime.c index dc28890a18..0e5538833a 100644 --- a/t/helper/test-chmtime.c +++ b/t/helper/test-chmtime.c @@ -94,7 +94,7 @@ int cmd__chmtime(int argc, const char **argv) if (timespec_arg(argv[i], &set_time, &set_eq)) { ++i; } else { - if (get == 0) { + if (get == 0 && verbose == 0) { fprintf(stderr, "Not a base-10 integer: %s\n", argv[i] + 1); goto usage; } diff --git a/t/helper/test-date.c b/t/helper/test-date.c index cd6a6df702..0683d46574 100644 --- a/t/helper/test-date.c +++ b/t/helper/test-date.c @@ -1,6 +1,6 @@ #include "test-tool.h" -#include "cache.h" #include "date.h" +#include "trace.h" static const char *usage_msg = "\n" " test-tool date relative [time_t]...\n" @@ -81,7 +81,7 @@ static void parse_approxidate(const char **argv) { for (; *argv; argv++) { timestamp_t t; - t = approxidate_relative(*argv); + t = approxidate(*argv); printf("%s -> %s\n", *argv, show_date(t, 0, DATE_MODE(ISO8601))); } } @@ -90,7 +90,7 @@ static void parse_approx_timestamp(const char **argv) { for (; *argv; argv++) { timestamp_t t; - t = approxidate_relative(*argv); + t = approxidate(*argv); printf("%s -> %"PRItime"\n", *argv, t); } } diff --git a/t/helper/test-fast-rebase.c b/t/helper/test-fast-rebase.c index fd48e0ee2c..d1d63feaa9 100644 --- a/t/helper/test-fast-rebase.c +++ b/t/helper/test-fast-rebase.c @@ -20,6 +20,7 @@ #include "hex.h" #include "lockfile.h" #include "merge-ort.h" +#include "object-name.h" #include "refs.h" #include "revision.h" #include "sequencer.h" diff --git a/t/helper/test-lazy-init-name-hash.c b/t/helper/test-lazy-init-name-hash.c index 06ce3a47cc..f23d983c11 100644 --- a/t/helper/test-lazy-init-name-hash.c +++ b/t/helper/test-lazy-init-name-hash.c @@ -4,6 +4,7 @@ #include "environment.h" #include "parse-options.h" #include "setup.h" +#include "trace.h" static int single; static int multi; diff --git a/t/helper/test-match-trees.c b/t/helper/test-match-trees.c index 508eb7066a..35a2b8005c 100644 --- a/t/helper/test-match-trees.c +++ b/t/helper/test-match-trees.c @@ -1,6 +1,7 @@ #include "test-tool.h" #include "cache.h" #include "hex.h" +#include "object-name.h" #include "setup.h" #include "tree.h" diff --git a/t/helper/test-mergesort.c b/t/helper/test-mergesort.c index 335e5bb3a9..737e0c5235 100644 --- a/t/helper/test-mergesort.c +++ b/t/helper/test-mergesort.c @@ -1,5 +1,6 @@ #include "test-tool.h" #include "cache.h" +#include "mem-pool.h" #include "mergesort.h" static uint32_t minstd_rand(uint32_t *state) diff --git a/t/helper/test-oidmap.c b/t/helper/test-oidmap.c index a7b7b38df1..1b0e7eecb4 100644 --- a/t/helper/test-oidmap.c +++ b/t/helper/test-oidmap.c @@ -1,6 +1,6 @@ #include "test-tool.h" -#include "cache.h" #include "hex.h" +#include "object-name.h" #include "oidmap.h" #include "setup.h" #include "strbuf.h" diff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c index 4f5ac2fadc..6355c9e4b6 100644 --- a/t/helper/test-path-utils.c +++ b/t/helper/test-path-utils.c @@ -4,6 +4,7 @@ #include "environment.h" #include "setup.h" #include "string-list.h" +#include "trace.h" #include "utf8.h" /* diff --git a/t/helper/test-reach.c b/t/helper/test-reach.c index b0deaa106a..5b6f217441 100644 --- a/t/helper/test-reach.c +++ b/t/helper/test-reach.c @@ -1,11 +1,11 @@ #include "test-tool.h" -#include "cache.h" #include "alloc.h" #include "commit.h" #include "commit-reach.h" #include "config.h" #include "gettext.h" #include "hex.h" +#include "object-name.h" #include "parse-options.h" #include "ref-filter.h" #include "setup.h" diff --git a/t/helper/test-submodule-config.c b/t/helper/test-submodule-config.c index 40a6ee45af..5e462faa9d 100644 --- a/t/helper/test-submodule-config.c +++ b/t/helper/test-submodule-config.c @@ -1,6 +1,6 @@ #include "test-tool.h" -#include "cache.h" #include "config.h" +#include "object-name.h" #include "setup.h" #include "submodule-config.h" #include "submodule.h" diff --git a/t/perf/p2000-sparse-operations.sh b/t/perf/p2000-sparse-operations.sh index e4a132f593..60d1de0662 100755 --- a/t/perf/p2000-sparse-operations.sh +++ b/t/perf/p2000-sparse-operations.sh @@ -43,6 +43,7 @@ test_expect_success 'setup repo and indexes' ' done && git sparse-checkout init --cone && + git tag -a v1.0 -m "Final" && git sparse-checkout set $SPARSE_CONE && git checkout -b wide $OLD_COMMIT && @@ -125,5 +126,8 @@ 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 bogus -- "f2/f1/f1/*" +test_perf_on_all git write-tree +test_perf_on_all git describe --dirty +test_perf_on_all 'echo >>new && git describe --dirty' test_done diff --git a/t/perf/p5312-pack-bitmaps-revs.sh b/t/perf/p5312-pack-bitmaps-revs.sh index 0684b690af..ceec60656b 100755 --- a/t/perf/p5312-pack-bitmaps-revs.sh +++ b/t/perf/p5312-pack-bitmaps-revs.sh @@ -12,8 +12,7 @@ test_lookup_pack_bitmap () { test_perf_large_repo test_expect_success 'setup bitmap config' ' - git config pack.writebitmaps true && - git config pack.writeReverseIndex true + git config pack.writebitmaps true ' # we need to create the tag up front such that it is covered by the repack and diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh index 801919009e..0c784813f1 100755 --- a/t/t1092-sparse-checkout-compatibility.sh +++ b/t/t1092-sparse-checkout-compatibility.sh @@ -1514,6 +1514,31 @@ test_expect_success 'sparse-index is not expanded: stash' ' ensure_not_expanded stash pop ' +test_expect_success 'describe tested on all' ' + init_repos && + + # Add tag to be read by describe + + run_on_all git tag -a v1.0 -m "Version 1" && + test_all_match git describe --dirty && + run_on_all rm g && + test_all_match git describe --dirty +' + + +test_expect_success 'sparse-index is not expanded: describe' ' + init_repos && + + # Add tag to be read by describe + + git -C sparse-index tag -a v1.0 -m "Version 1" && + + ensure_not_expanded describe --dirty && + echo "test" >>sparse-index/g && + ensure_not_expanded describe --dirty && + ensure_not_expanded describe +' + test_expect_success 'sparse index is not expanded: diff' ' init_repos && @@ -2055,4 +2080,32 @@ test_expect_success 'grep sparse directory within submodules' ' test_cmp actual expect ' +test_expect_success 'write-tree on all' ' + init_repos && + + write_script edit-contents <<-\EOF && + echo text >>"$1" + EOF + + run_on_all ../edit-contents deep/a && + run_on_all git update-index deep/a && + test_all_match git write-tree && + + run_on_all mkdir -p folder1 && + run_on_all cp a folder1/a && + run_on_all ../edit-contents folder1/a && + run_on_all git update-index folder1/a && + test_all_match git write-tree +' + +test_expect_success 'sparse-index is not expanded: write-tree' ' + init_repos && + + ensure_not_expanded write-tree && + + echo "test1" >>sparse-index/a && + git -C sparse-index update-index a && + ensure_not_expanded write-tree +' + test_done diff --git a/t/t1300-config.sh b/t/t1300-config.sh index 2575279ab8..f1d42b62b0 100755 --- a/t/t1300-config.sh +++ b/t/t1300-config.sh @@ -617,6 +617,36 @@ test_expect_success 'renaming to bogus section is rejected' ' test_must_fail git config --rename-section branch.zwei "bogus name" ' +test_expect_success 'renaming a section with a long line' ' + { + printf "[b]\\n" && + printf " c = d %1024s [a] e = f\\n" " " && + printf "[a] g = h\\n" + } >y && + git config -f y --rename-section a xyz && + test_must_fail git config -f y b.e +' + +test_expect_success 'renaming an embedded section with a long line' ' + { + printf "[b]\\n" && + printf " c = d %1024s [a] [foo] e = f\\n" " " && + printf "[a] g = h\\n" + } >y && + git config -f y --rename-section a xyz && + test_must_fail git config -f y foo.e +' + +test_expect_success 'renaming a section with an overly-long line' ' + { + printf "[b]\\n" && + printf " c = d %525000s e" " " && + printf "[a] g = h\\n" + } >y && + test_must_fail git config -f y --rename-section a xyz 2>err && + grep "refusing to work with overly long line in .y. on line 2" err +' + cat >> .git/config << EOF [branch "zwei"] a = 1 [branch "vier"] EOF diff --git a/t/t2024-checkout-dwim.sh b/t/t2024-checkout-dwim.sh index 4a1c901456..74049a9812 100755 --- a/t/t2024-checkout-dwim.sh +++ b/t/t2024-checkout-dwim.sh @@ -305,10 +305,13 @@ test_expect_success 'loosely defined local base branch is reported correctly' ' test_config branch.strict.merge refs/heads/main && test_config branch.loose.merge main && - git checkout strict | sed -e "s/strict/BRANCHNAME/g" >expect && + git checkout strict >expect.raw 2>&1 && + sed -e "s/strict/BRANCHNAME/g" <expect.raw >expect && status_uno_is_clean && - git checkout loose | sed -e "s/loose/BRANCHNAME/g" >actual && + git checkout loose >actual.raw 2>&1 && + sed -e "s/loose/BRANCHNAME/g" <actual.raw >actual && status_uno_is_clean && + grep BRANCHNAME actual && test_cmp expect actual ' diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh index 1c0f7ea24e..93f8295339 100755 --- a/t/t3203-branch-output.sh +++ b/t/t3203-branch-output.sh @@ -355,6 +355,30 @@ test_expect_success 'git branch with --format=%(rest) must fail' ' test_must_fail git branch --format="%(rest)" >actual ' +test_expect_success 'git branch --format --omit-empty' ' + cat >expect <<-\EOF && + Refname is (HEAD detached from fromtag) + Refname is refs/heads/ambiguous + Refname is refs/heads/branch-one + Refname is refs/heads/branch-two + + Refname is refs/heads/ref-to-branch + Refname is refs/heads/ref-to-remote + EOF + git branch --format="%(if:notequals=refs/heads/main)%(refname)%(then)Refname is %(refname)%(end)" >actual && + test_cmp expect actual && + cat >expect <<-\EOF && + Refname is (HEAD detached from fromtag) + Refname is refs/heads/ambiguous + Refname is refs/heads/branch-one + Refname is refs/heads/branch-two + Refname is refs/heads/ref-to-branch + Refname is refs/heads/ref-to-remote + EOF + git branch --omit-empty --format="%(if:notequals=refs/heads/main)%(refname)%(then)Refname is %(refname)%(end)" >actual && + test_cmp expect actual +' + test_expect_success 'worktree colors correct' ' cat >expect <<-EOF && * <GREEN>(HEAD detached from fromtag)<RESET> diff --git a/t/t3402-rebase-merge.sh b/t/t3402-rebase-merge.sh index 7e46f4ca85..79b0640c00 100755 --- a/t/t3402-rebase-merge.sh +++ b/t/t3402-rebase-merge.sh @@ -131,27 +131,6 @@ test_expect_success 'picking rebase' ' esac ' -test_expect_success 'rebase -s funny -Xopt' ' - test_when_finished "rm -fr test-bin funny.was.run" && - mkdir test-bin && - cat >test-bin/git-merge-funny <<-EOF && - #!$SHELL_PATH - case "\$1" in --opt) ;; *) exit 2 ;; esac - shift && - >funny.was.run && - exec git merge-recursive "\$@" - EOF - chmod +x test-bin/git-merge-funny && - git reset --hard && - git checkout -b test-funny main^ && - test_commit funny && - ( - PATH=./test-bin:$PATH && - git rebase -s funny -Xopt main - ) && - test -f funny.was.run -' - test_expect_success 'rebase --skip works with two conflicts in a row' ' git checkout second-side && tr "[A-Z]" "[a-z]" <newfile >tmp && diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh index 130e2f9b55..2d0789e554 100755 --- a/t/t3418-rebase-continue.sh +++ b/t/t3418-rebase-continue.sh @@ -62,61 +62,39 @@ test_expect_success 'rebase --continue remembers merge strategy and options' ' rm -fr .git/rebase-* && git reset --hard commit-new-file-F2-on-topic-branch && test_commit "commit-new-file-F3-on-topic-branch" F3 32 && - test_when_finished "rm -fr test-bin funny.was.run" && + test_when_finished "rm -fr test-bin" && mkdir test-bin && - cat >test-bin/git-merge-funny <<-EOF && - #!$SHELL_PATH - case "\$1" in --opt) ;; *) exit 2 ;; esac - shift && - >funny.was.run && - exec git merge-recursive "\$@" + + write_script test-bin/git-merge-funny <<-\EOF && + printf "[%s]\n" $# "$1" "$2" "$3" "$5" >actual + shift 3 && + exec git merge-recursive "$@" EOF - chmod +x test-bin/git-merge-funny && - ( - PATH=./test-bin:$PATH && - test_must_fail git rebase -s funny -Xopt main topic - ) && - test -f funny.was.run && - rm funny.was.run && - echo "Resolved" >F2 && - git add F2 && - ( - PATH=./test-bin:$PATH && - git rebase --continue - ) && - test -f funny.was.run -' -test_expect_success 'rebase -i --continue handles merge strategy and options' ' - rm -fr .git/rebase-* && - git reset --hard commit-new-file-F2-on-topic-branch && - test_commit "commit-new-file-F3-on-topic-branch-for-dash-i" F3 32 && - test_when_finished "rm -fr test-bin funny.was.run funny.args" && - mkdir test-bin && - cat >test-bin/git-merge-funny <<-EOF && - #!$SHELL_PATH - echo "\$@" >>funny.args - case "\$1" in --opt) ;; *) exit 2 ;; esac - case "\$2" in --foo) ;; *) exit 2 ;; esac - case "\$4" in --) ;; *) exit 2 ;; esac - shift 2 && - >funny.was.run && - exec git merge-recursive "\$@" + cat >expect <<-\EOF && + [7] + [--option=arg with space] + [--op"tion\] + [--new + line ] + [--] EOF - chmod +x test-bin/git-merge-funny && + + rm -f actual && ( PATH=./test-bin:$PATH && - test_must_fail git rebase -i -s funny -Xopt -Xfoo main topic + test_must_fail git rebase -s funny -X"option=arg with space" \ + -Xop\"tion\\ -X"new${LF}line " main topic ) && - test -f funny.was.run && - rm funny.was.run && + test_cmp expect actual && + rm actual && echo "Resolved" >F2 && git add F2 && ( PATH=./test-bin:$PATH && git rebase --continue ) && - test -f funny.was.run + test_cmp expect actual ' test_expect_success 'rebase -r passes merge strategy options correctly' ' diff --git a/t/t3436-rebase-more-options.sh b/t/t3436-rebase-more-options.sh index c3184c9ade..94671d3c46 100755 --- a/t/t3436-rebase-more-options.sh +++ b/t/t3436-rebase-more-options.sh @@ -40,24 +40,6 @@ test_expect_success 'setup' ' EOF ' -test_expect_success 'bad -X <strategy-option> arguments: unclosed quote' ' - cat >expect <<-\EOF && - fatal: could not split '\''--bad'\'': unclosed quote - EOF - test_expect_code 128 git rebase -X"bad argument\"" side main >out 2>actual && - test_must_be_empty out && - test_cmp expect actual -' - -test_expect_success 'bad -X <strategy-option> arguments: bad escape' ' - cat >expect <<-\EOF && - fatal: could not split '\''--bad'\'': cmdline ends with \ - EOF - test_expect_code 128 git rebase -X"bad escape \\" side main >out 2>actual && - test_must_be_empty out && - test_cmp expect actual -' - test_expect_success '--ignore-whitespace works with apply backend' ' test_must_fail git rebase --apply main side && git rebase --abort && diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index 7f1d4e8d58..3cf2b7a7fb 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -470,6 +470,11 @@ test_expect_success 'thread' ' check_threading expect.thread --thread main ' +test_expect_success '--thread overrides format.thread=deep' ' + test_config format.thread deep && + check_threading expect.thread --thread main +' + cat >expect.in-reply-to <<EOF --- Message-ID: <0> diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh index 15764ee9ac..74586f3813 100755 --- a/t/t4034-diff-words.sh +++ b/t/t4034-diff-words.sh @@ -69,6 +69,10 @@ test_language_driver () { echo "* diff='"$lang"'" >.gitattributes && word_diff --color-words ' + test_expect_success "diff driver '$lang' in Islandic" ' + LANG=is_IS.UTF-8 LANGUAGE=is LC_ALL="$is_IS_locale" \ + word_diff --color-words + ' } test_expect_success setup ' diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh index 65ac7df2d7..e95e6d4e7d 100755 --- a/t/t4115-apply-symlink.sh +++ b/t/t4115-apply-symlink.sh @@ -126,4 +126,19 @@ test_expect_success SYMLINKS 'symlink escape when deleting file' ' test_path_is_file .git/delete-me ' +test_expect_success SYMLINKS '--reject removes .rej symlink if it exists' ' + test_when_finished "git reset --hard && git clean -dfx" && + + test_commit file && + echo modified >file.t && + git diff -- file.t >patch && + echo modified-again >file.t && + + ln -s foo file.t.rej && + test_must_fail git apply patch --reject 2>err && + test_i18ngrep "Rejected hunk" err && + test_path_is_missing foo && + test_path_is_file file.t.rej +' + test_done diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index f0bd70dbd6..4b4c3315d8 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -426,6 +426,19 @@ test_expect_success 'catch non-matching pathspec' ' test_must_fail git archive -v HEAD -- "*.abc" >/dev/null ' +test_expect_success 'reject paths outside the current directory' ' + test_must_fail git -C a/bin archive HEAD .. >/dev/null 2>err && + grep "outside the current directory" err +' + +test_expect_success 'allow pathspecs that resolve to the current directory' ' + git -C a/bin archive -v HEAD ../bin >/dev/null 2>actual && + cat >expect <<-\EOF && + sh + EOF + test_cmp expect actual +' + # Pull the size and date of each entry in a tarfile using the system tar. # # We'll pull out only the year from the date; that avoids any question of diff --git a/t/t5001-archive-attr.sh b/t/t5001-archive-attr.sh index 04d300eeda..0ff47a239d 100755 --- a/t/t5001-archive-attr.sh +++ b/t/t5001-archive-attr.sh @@ -33,6 +33,13 @@ test_expect_success 'setup' ' echo ignored-by-tree.d export-ignore >>.gitattributes && git add ignored-by-tree ignored-by-tree.d .gitattributes && + mkdir subdir && + >subdir/included && + >subdir/ignored-by-subtree && + >subdir/ignored-by-tree && + echo ignored-by-subtree export-ignore >subdir/.gitattributes && + git add subdir && + echo ignored by worktree >ignored-by-worktree && echo ignored-by-worktree export-ignore >.gitattributes && git add ignored-by-worktree && @@ -93,6 +100,15 @@ test_expect_exists archive-pathspec-wildcard/ignored-by-worktree test_expect_missing archive-pathspec-wildcard/excluded-by-pathspec.d test_expect_missing archive-pathspec-wildcard/excluded-by-pathspec.d/file +test_expect_success 'git -C subdir archive' ' + git -C subdir archive HEAD >archive-subdir.tar && + extract_tar_to_dir archive-subdir +' + +test_expect_exists archive-subdir/included +test_expect_missing archive-subdir/ignored-by-subtree +test_expect_missing archive-subdir/ignored-by-tree + test_expect_success 'git archive with worktree attributes' ' git archive --worktree-attributes HEAD >worktree.tar && (mkdir worktree && cd worktree && "$TAR" xf -) <worktree.tar diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index f8a0f309e2..d2ce236d61 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -589,141 +589,6 @@ test_expect_success 'prefetch objects' ' test_line_count = 1 donelines ' -test_expect_success 'setup for --stdin-packs tests' ' - git init stdin-packs && - ( - cd stdin-packs && - - test_commit A && - test_commit B && - test_commit C && - - for id in A B C - do - git pack-objects .git/objects/pack/pack-$id \ - --incremental --revs <<-EOF || exit 1 - refs/tags/$id - EOF - done && - - ls -la .git/objects/pack - ) -' - -test_expect_success '--stdin-packs with excluded packs' ' - ( - cd stdin-packs && - - PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" && - PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" && - PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" && - - git pack-objects test --stdin-packs <<-EOF && - $PACK_A - ^$PACK_B - $PACK_C - EOF - - ( - git show-index <$(ls .git/objects/pack/pack-A-*.idx) && - git show-index <$(ls .git/objects/pack/pack-C-*.idx) - ) >expect.raw && - git show-index <$(ls test-*.idx) >actual.raw && - - cut -d" " -f2 <expect.raw | sort >expect && - cut -d" " -f2 <actual.raw | sort >actual && - test_cmp expect actual - ) -' - -test_expect_success '--stdin-packs is incompatible with --filter' ' - ( - cd stdin-packs && - test_must_fail git pack-objects --stdin-packs --stdout \ - --filter=blob:none </dev/null 2>err && - test_i18ngrep "cannot use --filter with --stdin-packs" err - ) -' - -test_expect_success '--stdin-packs is incompatible with --revs' ' - ( - cd stdin-packs && - test_must_fail git pack-objects --stdin-packs --revs out \ - </dev/null 2>err && - test_i18ngrep "cannot use internal rev list with --stdin-packs" err - ) -' - -test_expect_success '--stdin-packs with loose objects' ' - ( - cd stdin-packs && - - PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" && - PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" && - PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" && - - test_commit D && # loose - - git pack-objects test2 --stdin-packs --unpacked <<-EOF && - $PACK_A - ^$PACK_B - $PACK_C - EOF - - ( - git show-index <$(ls .git/objects/pack/pack-A-*.idx) && - git show-index <$(ls .git/objects/pack/pack-C-*.idx) && - git rev-list --objects --no-object-names \ - refs/tags/C..refs/tags/D - - ) >expect.raw && - ls -la . && - git show-index <$(ls test2-*.idx) >actual.raw && - - cut -d" " -f2 <expect.raw | sort >expect && - cut -d" " -f2 <actual.raw | sort >actual && - test_cmp expect actual - ) -' - -test_expect_success '--stdin-packs with broken links' ' - ( - cd stdin-packs && - - # make an unreachable object with a bogus parent - git cat-file -p HEAD >commit && - sed "s/$(git rev-parse HEAD^)/$(test_oid zero)/" <commit | - git hash-object -w -t commit --stdin >in && - - git pack-objects .git/objects/pack/pack-D <in && - - PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" && - PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" && - PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" && - PACK_D="$(basename .git/objects/pack/pack-D-*.pack)" && - - git pack-objects test3 --stdin-packs --unpacked <<-EOF && - $PACK_A - ^$PACK_B - $PACK_C - $PACK_D - EOF - - ( - git show-index <$(ls .git/objects/pack/pack-A-*.idx) && - git show-index <$(ls .git/objects/pack/pack-C-*.idx) && - git show-index <$(ls .git/objects/pack/pack-D-*.idx) && - git rev-list --objects --no-object-names \ - refs/tags/C..refs/tags/D - ) >expect.raw && - git show-index <$(ls test3-*.idx) >actual.raw && - - cut -d" " -f2 <expect.raw | sort >expect && - cut -d" " -f2 <actual.raw | sort >actual && - test_cmp expect actual - ) -' - test_expect_success 'negative window clamps to 0' ' git pack-objects --progress --window=-1 neg-window <obj-list 2>stderr && check_deltas stderr = 0 diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh index 499d5d4c78..0883c7c6bd 100755 --- a/t/t5319-multi-pack-index.sh +++ b/t/t5319-multi-pack-index.sh @@ -183,6 +183,18 @@ test_expect_success 'write midx with --stdin-packs' ' compare_results_with_midx "mixed mode (one pack + extra)" +test_expect_success 'write with no objects and preferred pack' ' + test_when_finished "rm -rf empty" && + git init empty && + test_must_fail git -C empty multi-pack-index write \ + --stdin-packs --preferred-pack=does-not-exist </dev/null 2>err && + cat >expect <<-EOF && + warning: unknown preferred pack: ${SQ}does-not-exist${SQ} + error: no pack files to index. + EOF + test_cmp expect err +' + test_expect_success 'write progress off for redirected stderr' ' git multi-pack-index --object-dir=$objdir write 2>err && test_line_count = 0 err diff --git a/t/t5325-reverse-index.sh b/t/t5325-reverse-index.sh index d042d26f2b..431a603ca0 100755 --- a/t/t5325-reverse-index.sh +++ b/t/t5325-reverse-index.sh @@ -1,17 +1,20 @@ #!/bin/sh test_description='on-disk reverse index' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # The below tests want control over the 'pack.writeReverseIndex' setting # themselves to assert various combinations of it with other options. -sane_unset GIT_TEST_WRITE_REV_INDEX +sane_unset GIT_TEST_NO_WRITE_REV_INDEX packdir=.git/objects/pack test_expect_success 'setup' ' test_commit base && + test_config pack.writeReverseIndex false && pack=$(git pack-objects --all $packdir/pack) && rev=$packdir/pack-$pack.rev && @@ -94,6 +97,17 @@ test_expect_success 'reverse index is not generated when available on disk' ' --batch-check="%(objectsize:disk)" <tip ' +test_expect_success 'reverse index is ignored when pack.readReverseIndex is false' ' + test_index_pack true && + test_path_is_file $rev && + + test_config pack.readReverseIndex false && + + git rev-parse HEAD >tip && + GIT_TEST_REV_INDEX_DIE_ON_DISK=1 git cat-file \ + --batch-check="%(objectsize:disk)" <tip +' + test_expect_success 'revindex in-memory vs on-disk' ' git init repo && test_when_finished "rm -fr repo" && @@ -117,4 +131,78 @@ test_expect_success 'revindex in-memory vs on-disk' ' test_cmp on-disk in-core ) ' + +test_expect_success 'fsck succeeds on good rev-index' ' + test_when_finished rm -fr repo && + git init repo && + ( + cd repo && + + test_commit commit && + git -c pack.writeReverseIndex=true repack -ad && + git fsck 2>err && + test_must_be_empty err + ) +' + +test_expect_success 'set up rev-index corruption tests' ' + git init corrupt && + ( + cd corrupt && + + test_commit commit && + git -c pack.writeReverseIndex=true repack -ad && + + revfile=$(ls .git/objects/pack/pack-*.rev) && + chmod a+w $revfile && + cp $revfile $revfile.bak + ) +' + +corrupt_rev_and_verify () { + ( + pos="$1" && + value="$2" && + error="$3" && + + cd corrupt && + revfile=$(ls .git/objects/pack/pack-*.rev) && + + # Reset to original rev-file. + cp $revfile.bak $revfile && + + printf "$value" | dd of=$revfile bs=1 seek="$pos" conv=notrunc && + test_must_fail git fsck 2>err && + grep "$error" err + ) +} + +test_expect_success 'fsck catches invalid checksum' ' + revfile=$(ls corrupt/.git/objects/pack/pack-*.rev) && + orig_size=$(wc -c <$revfile) && + hashpos=$((orig_size - 10)) && + corrupt_rev_and_verify $hashpos bogus \ + "invalid checksum" +' + +test_expect_success 'fsck catches invalid row position' ' + corrupt_rev_and_verify 14 "\07" \ + "invalid rev-index position" +' + +test_expect_success 'fsck catches invalid header: magic number' ' + corrupt_rev_and_verify 1 "\07" \ + "reverse-index file .* has unknown signature" +' + +test_expect_success 'fsck catches invalid header: version' ' + corrupt_rev_and_verify 7 "\02" \ + "reverse-index file .* has unsupported version" +' + +test_expect_success 'fsck catches invalid header: hash function' ' + corrupt_rev_and_verify 11 "\03" \ + "reverse-index file .* has unsupported hash id" +' + test_done diff --git a/t/t5331-pack-objects-stdin.sh b/t/t5331-pack-objects-stdin.sh new file mode 100755 index 0000000000..acab31667a --- /dev/null +++ b/t/t5331-pack-objects-stdin.sh @@ -0,0 +1,240 @@ +#!/bin/sh + +test_description='pack-objects --stdin' +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +packed_objects () { + git show-index <"$1" >tmp-object-list && + cut -d' ' -f2 tmp-object-list | sort && + rm tmp-object-list + } + +test_expect_success 'setup for --stdin-packs tests' ' + git init stdin-packs && + ( + cd stdin-packs && + + test_commit A && + test_commit B && + test_commit C && + + for id in A B C + do + git pack-objects .git/objects/pack/pack-$id \ + --incremental --revs <<-EOF || exit 1 + refs/tags/$id + EOF + done && + + ls -la .git/objects/pack + ) +' + +test_expect_success '--stdin-packs with excluded packs' ' + ( + cd stdin-packs && + + PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" && + PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" && + PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" && + + git pack-objects test --stdin-packs <<-EOF && + $PACK_A + ^$PACK_B + $PACK_C + EOF + + ( + git show-index <$(ls .git/objects/pack/pack-A-*.idx) && + git show-index <$(ls .git/objects/pack/pack-C-*.idx) + ) >expect.raw && + git show-index <$(ls test-*.idx) >actual.raw && + + cut -d" " -f2 <expect.raw | sort >expect && + cut -d" " -f2 <actual.raw | sort >actual && + test_cmp expect actual + ) +' + +test_expect_success '--stdin-packs is incompatible with --filter' ' + ( + cd stdin-packs && + test_must_fail git pack-objects --stdin-packs --stdout \ + --filter=blob:none </dev/null 2>err && + test_i18ngrep "cannot use --filter with --stdin-packs" err + ) +' + +test_expect_success '--stdin-packs is incompatible with --revs' ' + ( + cd stdin-packs && + test_must_fail git pack-objects --stdin-packs --revs out \ + </dev/null 2>err && + test_i18ngrep "cannot use internal rev list with --stdin-packs" err + ) +' + +test_expect_success '--stdin-packs with loose objects' ' + ( + cd stdin-packs && + + PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" && + PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" && + PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" && + + test_commit D && # loose + + git pack-objects test2 --stdin-packs --unpacked <<-EOF && + $PACK_A + ^$PACK_B + $PACK_C + EOF + + ( + git show-index <$(ls .git/objects/pack/pack-A-*.idx) && + git show-index <$(ls .git/objects/pack/pack-C-*.idx) && + git rev-list --objects --no-object-names \ + refs/tags/C..refs/tags/D + + ) >expect.raw && + ls -la . && + git show-index <$(ls test2-*.idx) >actual.raw && + + cut -d" " -f2 <expect.raw | sort >expect && + cut -d" " -f2 <actual.raw | sort >actual && + test_cmp expect actual + ) +' + +test_expect_success '--stdin-packs with broken links' ' + ( + cd stdin-packs && + + # make an unreachable object with a bogus parent + git cat-file -p HEAD >commit && + sed "s/$(git rev-parse HEAD^)/$(test_oid zero)/" <commit | + git hash-object -w -t commit --stdin >in && + + git pack-objects .git/objects/pack/pack-D <in && + + PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" && + PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" && + PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" && + PACK_D="$(basename .git/objects/pack/pack-D-*.pack)" && + + git pack-objects test3 --stdin-packs --unpacked <<-EOF && + $PACK_A + ^$PACK_B + $PACK_C + $PACK_D + EOF + + ( + git show-index <$(ls .git/objects/pack/pack-A-*.idx) && + git show-index <$(ls .git/objects/pack/pack-C-*.idx) && + git show-index <$(ls .git/objects/pack/pack-D-*.idx) && + git rev-list --objects --no-object-names \ + refs/tags/C..refs/tags/D + ) >expect.raw && + git show-index <$(ls test3-*.idx) >actual.raw && + + cut -d" " -f2 <expect.raw | sort >expect && + cut -d" " -f2 <actual.raw | sort >actual && + test_cmp expect actual + ) +' + +test_expect_success 'pack-objects --stdin with duplicate packfile' ' + test_when_finished "rm -fr repo" && + + git init repo && + ( + cd repo && + test_commit "commit" && + git repack -ad && + + { + basename .git/objects/pack/pack-*.pack && + basename .git/objects/pack/pack-*.pack + } >packfiles && + + git pack-objects --stdin-packs generated-pack <packfiles && + packed_objects .git/objects/pack/pack-*.idx >expect && + packed_objects generated-pack-*.idx >actual && + test_cmp expect actual + ) +' + +test_expect_success 'pack-objects --stdin with same packfile excluded and included' ' + test_when_finished "rm -fr repo" && + + git init repo && + ( + cd repo && + test_commit "commit" && + git repack -ad && + + { + basename .git/objects/pack/pack-*.pack && + printf "^%s\n" "$(basename .git/objects/pack/pack-*.pack)" + } >packfiles && + + git pack-objects --stdin-packs generated-pack <packfiles && + packed_objects generated-pack-*.idx >packed-objects && + test_must_be_empty packed-objects + ) +' + +test_expect_success 'pack-objects --stdin with packfiles from alternate object database' ' + test_when_finished "rm -fr shared member" && + + # Set up a shared repository with a single packfile. + git init shared && + test_commit -C shared "shared-objects" && + git -C shared repack -ad && + basename shared/.git/objects/pack/pack-*.pack >packfile && + + # Set up a repository that is connected to the shared repository. This + # repository has no objects on its own, but we still expect to be able + # to pack objects from its alternate. + git clone --shared shared member && + git -C member pack-objects --stdin-packs generated-pack <packfile && + test_cmp shared/.git/objects/pack/pack-*.pack member/generated-pack-*.pack +' + +test_expect_success 'pack-objects --stdin with packfiles from main and alternate object database' ' + test_when_finished "rm -fr shared member" && + + # Set up a shared repository with a single packfile. + git init shared && + test_commit -C shared "shared-commit" && + git -C shared repack -ad && + + # Set up a repository that is connected to the shared repository. This + # repository has a second packfile so that we can verify that it is + # possible to write packs that include packfiles from different object + # databases. + git clone --shared shared member && + test_commit -C member "local-commit" && + git -C member repack -dl && + + { + basename shared/.git/objects/pack/pack-*.pack && + basename member/.git/objects/pack/pack-*.pack + } >packfiles && + + { + packed_objects shared/.git/objects/pack/pack-*.idx && + packed_objects member/.git/objects/pack/pack-*.idx + } | sort >expected-objects && + + git -C member pack-objects --stdin-packs generated-pack <packfiles && + packed_objects member/generated-pack-*.idx >actual-objects && + test_cmp expected-objects actual-objects +' + +test_done diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh index 20d063fb9a..151c76eb09 100755 --- a/t/t5512-ls-remote.sh +++ b/t/t5512-ls-remote.sh @@ -15,6 +15,19 @@ generate_references () { done } +test_expect_success 'set up fake upload-pack' ' + # This can be used to simulate an upload-pack that just shows the + # contents of the "input" file (prepared with the test-tool pkt-line + # helper), and does not do any negotiation (since ls-remote does not + # need it). + write_script cat-input <<-\EOF + # send our initial advertisement/response + cat input + # soak up the flush packet from the client + cat + EOF +' + test_expect_success 'dies when no remote found' ' test_must_fail git ls-remote ' @@ -231,22 +244,25 @@ test_expect_success 'protocol v2 supports hiderefs' ' test_expect_success 'ls-remote --symref' ' git fetch origin && - echo "ref: refs/heads/main HEAD" >expect && + echo "ref: refs/heads/main HEAD" >expect.v2 && generate_references \ HEAD \ - refs/heads/main >>expect && + refs/heads/main >>expect.v2 && + echo "ref: refs/remotes/origin/main refs/remotes/origin/HEAD" >>expect.v2 && oid=$(git rev-parse HEAD) && - echo "$oid refs/remotes/origin/HEAD" >>expect && + echo "$oid refs/remotes/origin/HEAD" >>expect.v2 && generate_references \ refs/remotes/origin/main \ refs/tags/mark \ refs/tags/mark1.1 \ refs/tags/mark1.10 \ - refs/tags/mark1.2 >>expect && - # Protocol v2 supports sending symrefs for refs other than HEAD, so use - # protocol v0 here. - GIT_TEST_PROTOCOL_VERSION=0 git ls-remote --symref >actual && - test_cmp expect actual + refs/tags/mark1.2 >>expect.v2 && + # v0 does not show non-HEAD symrefs + grep -v "ref: refs/remotes" <expect.v2 >expect.v0 && + git -c protocol.version=0 ls-remote --symref >actual.v0 && + test_cmp expect.v0 actual.v0 && + git -c protocol.version=2 ls-remote --symref >actual.v2 && + test_cmp expect.v2 actual.v2 ' test_expect_success 'ls-remote with filtered symref (refname)' ' @@ -255,76 +271,41 @@ test_expect_success 'ls-remote with filtered symref (refname)' ' ref: refs/heads/main HEAD $rev HEAD EOF - # Protocol v2 supports sending symrefs for refs other than HEAD, so use - # protocol v0 here. - GIT_TEST_PROTOCOL_VERSION=0 git ls-remote --symref . HEAD >actual && + git ls-remote --symref . HEAD >actual && test_cmp expect actual ' -test_expect_failure 'ls-remote with filtered symref (--heads)' ' +test_expect_success 'ls-remote with filtered symref (--heads)' ' git symbolic-ref refs/heads/foo refs/tags/mark && - cat >expect <<-EOF && + cat >expect.v2 <<-EOF && ref: refs/tags/mark refs/heads/foo $rev refs/heads/foo $rev refs/heads/main EOF - # Protocol v2 supports sending symrefs for refs other than HEAD, so use - # protocol v0 here. - GIT_TEST_PROTOCOL_VERSION=0 git ls-remote --symref --heads . >actual && - test_cmp expect actual + grep -v "^ref: refs/tags/" <expect.v2 >expect.v0 && + git -c protocol.version=0 ls-remote --symref --heads . >actual.v0 && + test_cmp expect.v0 actual.v0 && + git -c protocol.version=2 ls-remote --symref --heads . >actual.v2 && + test_cmp expect.v2 actual.v2 ' -test_expect_success 'ls-remote --symref omits filtered-out matches' ' - cat >expect <<-EOF && - $rev refs/heads/foo - $rev refs/heads/main +test_expect_success 'indicate no refs in v0 standards-compliant empty remote' ' + # Git does not produce an output like this, but it does match the + # standard and is produced by other implementations like JGit. So + # hard-code the case we care about. + # + # The actual capabilities do not matter; there are none that would + # change how ls-remote behaves. + oid=0000000000000000000000000000000000000000 && + test-tool pkt-line pack >input.q <<-EOF && + $oid capabilities^{}Qcaps-go-here + 0000 EOF - # Protocol v2 supports sending symrefs for refs other than HEAD, so use - # protocol v0 here. - GIT_TEST_PROTOCOL_VERSION=0 git ls-remote --symref --heads . >actual && - test_cmp expect actual && - GIT_TEST_PROTOCOL_VERSION=0 git ls-remote --symref . "refs/heads/*" >actual && - test_cmp expect actual -' - -test_lazy_prereq GIT_DAEMON ' - test_bool_env GIT_TEST_GIT_DAEMON true -' + q_to_nul <input.q >input && -# This test spawns a daemon, so run it only if the user would be OK with -# testing with git-daemon. -test_expect_success PIPE,JGIT,GIT_DAEMON 'indicate no refs in standards-compliant empty remote' ' - test_set_port JGIT_DAEMON_PORT && - JGIT_DAEMON_PID= && - git init --bare empty.git && - >empty.git/git-daemon-export-ok && - mkfifo jgit_daemon_output && - { - jgit daemon --port="$JGIT_DAEMON_PORT" . >jgit_daemon_output & - JGIT_DAEMON_PID=$! - } && - test_when_finished kill "$JGIT_DAEMON_PID" && - { - read line && - case $line in - Exporting*) - ;; - *) - echo "Expected: Exporting" && - false;; - esac && - read line && - case $line in - "Listening on"*) - ;; - *) - echo "Expected: Listening on" && - false;; - esac - } <jgit_daemon_output && # --exit-code asks the command to exit with 2 when no # matching refs are found. - test_expect_code 2 git ls-remote --exit-code git://localhost:$JGIT_DAEMON_PORT/empty.git + test_expect_code 2 git ls-remote --exit-code --upload-pack=./cat-input . ' test_expect_success 'ls-remote works outside repository' ' @@ -345,8 +326,8 @@ test_expect_success 'ls-remote --sort fails gracefully outside repository' ' test_expect_success 'ls-remote patterns work with all protocol versions' ' git for-each-ref --format="%(objectname) %(refname)" \ refs/heads/main refs/remotes/origin/main >expect && - git -c protocol.version=1 ls-remote . main >actual.v1 && - test_cmp expect actual.v1 && + git -c protocol.version=0 ls-remote . main >actual.v0 && + test_cmp expect actual.v0 && git -c protocol.version=2 ls-remote . main >actual.v2 && test_cmp expect actual.v2 ' @@ -354,10 +335,49 @@ test_expect_success 'ls-remote patterns work with all protocol versions' ' test_expect_success 'ls-remote prefixes work with all protocol versions' ' git for-each-ref --format="%(objectname) %(refname)" \ refs/heads/ refs/tags/ >expect && - git -c protocol.version=1 ls-remote --heads --tags . >actual.v1 && - test_cmp expect actual.v1 && + git -c protocol.version=0 ls-remote --heads --tags . >actual.v0 && + test_cmp expect actual.v0 && git -c protocol.version=2 ls-remote --heads --tags . >actual.v2 && test_cmp expect actual.v2 ' +test_expect_success 'v0 clients can handle multiple symrefs' ' + # Modern versions of Git will not return multiple symref capabilities + # for v0, so we have to hard-code the response. Note that we will + # always use both v0 and object-format=sha1 here, as the hard-coded + # response reflects a server that only supports those. + oid=1234567890123456789012345678901234567890 && + symrefs="symref=refs/remotes/origin/HEAD:refs/remotes/origin/main" && + symrefs="$symrefs symref=HEAD:refs/heads/main" && + + # Likewise we want to make sure our parser is not fooled by the string + # "symref" appearing as part of an earlier cap. But there is no way to + # do that via upload-pack, as arbitrary strings can appear only in a + # "symref" value itself (where we skip past the values as a whole) + # and "agent" (which always appears after "symref", so putting our + # parser in a confused state is less interesting). + caps="some other caps including a-fake-symref-cap" && + + test-tool pkt-line pack >input.q <<-EOF && + $oid HEADQ$caps $symrefs + $oid refs/heads/main + $oid refs/remotes/origin/HEAD + $oid refs/remotes/origin/main + 0000 + EOF + q_to_nul <input.q >input && + + cat >expect <<-EOF && + ref: refs/heads/main HEAD + $oid HEAD + $oid refs/heads/main + ref: refs/remotes/origin/main refs/remotes/origin/HEAD + $oid refs/remotes/origin/HEAD + $oid refs/remotes/origin/main + EOF + + git ls-remote --symref --upload-pack=./cat-input . >actual && + test_cmp expect actual +' + test_done diff --git a/t/t5604-clone-reference.sh b/t/t5604-clone-reference.sh index 83e3c97861..9845fc04d5 100755 --- a/t/t5604-clone-reference.sh +++ b/t/t5604-clone-reference.sh @@ -358,7 +358,7 @@ test_expect_success SYMLINKS 'clone repo with symlinked objects directory' ' test_must_fail git clone --local malicious clone 2>err && test_path_is_missing clone && - grep "failed to start iterator over" err + grep "is a symlink, refusing to clone with --local" err ' test_done diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh index 6614469d2d..5c00607608 100755 --- a/t/t6300-for-each-ref.sh +++ b/t/t6300-for-each-ref.sh @@ -1374,6 +1374,14 @@ test_expect_success 'for-each-ref --ignore-case ignores case' ' test_cmp expect actual ' +test_expect_success 'for-each-ref --omit-empty works' ' + git for-each-ref --format="%(refname)" >actual && + test_line_count -gt 1 actual && + git for-each-ref --format="%(if:equals=refs/heads/main)%(refname)%(then)%(refname)%(end)" --omit-empty >actual && + echo refs/heads/main >expect && + test_cmp expect actual +' + test_expect_success 'for-each-ref --ignore-case works on multiple sort keys' ' # name refs numerically to avoid case-insensitive filesystem conflicts nr=0 && diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 32b312fa80..0fe6ba93a2 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -2046,6 +2046,22 @@ test_expect_success '--format should list tags as per format given' ' test_cmp expect actual ' +test_expect_success '--format --omit-empty works' ' + cat >expect <<-\EOF && + refname : refs/tags/v1.0 + + refname : refs/tags/v1.1.3 + EOF + git tag -l --format="%(if:notequals=refs/tags/v1.0.1)%(refname)%(then)refname : %(refname)%(end)" "v1*" >actual && + test_cmp expect actual && + cat >expect <<-\EOF && + refname : refs/tags/v1.0 + refname : refs/tags/v1.1.3 + EOF + git tag -l --omit-empty --format="%(if:notequals=refs/tags/v1.0.1)%(refname)%(then)refname : %(refname)%(end)" "v1*" >actual && + test_cmp expect actual +' + test_expect_success 'git tag -l with --format="%(rest)" must fail' ' test_must_fail git tag -l --format="%(rest)" "v1*" ' diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh index 7b957022f1..22b3a85b3e 100755 --- a/t/t7610-mergetool.sh +++ b/t/t7610-mergetool.sh @@ -860,4 +860,42 @@ test_expect_success 'mergetool hideResolved' ' git commit -m "test resolved with mergetool" ' +test_expect_success 'mergetool with guiDefault' ' + test_config merge.guitool myguitool && + test_config mergetool.myguitool.cmd "(printf \"gui \" && cat \"\$REMOTE\") >\"\$MERGED\"" && + test_config mergetool.myguitool.trustExitCode true && + test_when_finished "git reset --hard" && + git checkout -b test$test_count branch1 && + git submodule update -N && + test_must_fail git merge main && + + test_config mergetool.guiDefault auto && + DISPLAY=SOMETHING && export DISPLAY && + yes "" | git mergetool both && + yes "" | git mergetool file1 file1 && + + DISPLAY= && export DISPLAY && + yes "" | git mergetool file2 "spaced name" && + + test_config mergetool.guiDefault true && + yes "" | git mergetool subdir/file3 && + + yes "d" | git mergetool file11 && + yes "d" | git mergetool file12 && + yes "l" | git mergetool submod && + + echo "gui main updated" >expect && + test_cmp expect file1 && + + echo "main new" >expect && + test_cmp expect file2 && + + echo "gui main new sub" >expect && + test_cmp expect subdir/file3 && + + echo "branch1 submodule" >expect && + test_cmp expect submod/bar && + git commit -m "branch1 resolved with mergetool" +' + test_done diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh index 4aabe98139..faa739eeb9 100755 --- a/t/t7700-repack.sh +++ b/t/t7700-repack.sh @@ -106,6 +106,23 @@ test_expect_success SYMLINKS '--local keeps packs when alternate is objectdir ' test_cmp expect actual ' +test_expect_success '--local disables writing bitmaps when connected to alternate ODB' ' + test_when_finished "rm -rf shared member" && + + git init shared && + git clone --shared shared member && + ( + cd member && + test_commit "object" && + GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adl --write-bitmap-index 2>err && + cat >expect <<-EOF && + warning: disabling bitmap writing, as some objects are not being packed + EOF + test_cmp expect err && + test_path_is_missing .git/objects/pack-*.bitmap + ) +' + test_expect_success 'packed obs in alt ODB are repacked even when local repo is packless' ' mkdir alt_objects/pack && mv .git/objects/pack/* alt_objects/pack && diff --git a/t/t7703-repack-geometric.sh b/t/t7703-repack-geometric.sh index 8821fbd2dd..00f28fb558 100755 --- a/t/t7703-repack-geometric.sh +++ b/t/t7703-repack-geometric.sh @@ -10,6 +10,12 @@ objdir=.git/objects packdir=$objdir/pack midx=$objdir/pack/multi-pack-index +packed_objects () { + git show-index <"$1" >tmp-object-list && + cut -d' ' -f2 tmp-object-list | sort && + rm tmp-object-list + } + test_expect_success '--geometric with no packs' ' git init geometric && test_when_finished "rm -fr geometric" && @@ -281,4 +287,162 @@ test_expect_success '--geometric with pack.packSizeLimit' ' ) ' +test_expect_success '--geometric --write-midx with packfiles in main and alternate ODB' ' + test_when_finished "rm -fr shared member" && + + # Create a shared repository that will serve as the alternate object + # database for the member linked to it. It has got some objects on its + # own that are packed into a single packfile. + git init shared && + test_commit -C shared common-object && + git -C shared repack -ad && + + # We create member so that its alternates file points to the shared + # repository. We then create a commit in it so that git-repack(1) has + # something to repack. + # of the shared object database. + git clone --shared shared member && + test_commit -C member unique-object && + git -C member repack --geometric=2 --write-midx 2>err && + test_must_be_empty err && + + # We should see that a new packfile was generated. + find shared/.git/objects/pack -type f -name "*.pack" >packs && + test_line_count = 1 packs && + + # We should also see a multi-pack-index. This multi-pack-index should + # never refer to any packfiles in the alternate object database. + test_path_is_file member/.git/objects/pack/multi-pack-index && + test-tool read-midx member/.git/objects >packs.midx && + grep "^pack-.*\.idx$" packs.midx | sort >actual && + basename member/.git/objects/pack/pack-*.idx >expect && + test_cmp expect actual +' + +test_expect_success '--geometric --with-midx with no local objects' ' + test_when_finished "rm -fr shared member" && + + # Create a repository with a single packfile that acts as alternate + # object database. + git init shared && + test_commit -C shared "shared-objects" && + git -C shared repack -ad && + + # Create a second repository linked to the first one and perform a + # geometric repack on it. + git clone --shared shared member && + git -C member repack --geometric 2 --write-midx 2>err && + test_must_be_empty err && + + # Assert that we wrote neither a new packfile nor a multi-pack-index. + # We should not have a packfile because the single packfile in the + # alternate object database does not invalidate the geometric sequence. + # And we should not have a multi-pack-index because these only index + # local packfiles, and there are none. + test_dir_is_empty member/$packdir +' + +test_expect_success '--geometric with same pack in main and alternate ODB' ' + test_when_finished "rm -fr shared member" && + + # Create a repository with a single packfile that acts as alternate + # object database. + git init shared && + test_commit -C shared "shared-objects" && + git -C shared repack -ad && + + # We create the member repository as an exact copy so that it has the + # same packfile. + cp -r shared member && + test-tool path-utils real_path shared/.git/objects >member/.git/objects/info/alternates && + find shared/.git/objects -type f >expected-files && + + # Verify that we can repack objects as expected without observing any + # error. Having the same packfile in both ODBs used to cause an error + # in git-pack-objects(1). + git -C member repack --geometric 2 2>err && + test_must_be_empty err && + # Nothing should have changed. + find shared/.git/objects -type f >actual-files && + test_cmp expected-files actual-files +' + +test_expect_success '--geometric -l with non-intact geometric sequence across ODBs' ' + test_when_finished "rm -fr shared member" && + + git init shared && + test_commit_bulk -C shared --start=1 1 && + + git clone --shared shared member && + test_commit_bulk -C member --start=2 1 && + + # Verify that our assumptions actually hold: both generated packfiles + # should have three objects and should be non-equal. + packed_objects shared/.git/objects/pack/pack-*.idx >shared-objects && + packed_objects member/.git/objects/pack/pack-*.idx >member-objects && + test_line_count = 3 shared-objects && + test_line_count = 3 member-objects && + ! test_cmp shared-objects member-objects && + + # Perform the geometric repack. With `-l`, we should only see the local + # packfile and thus arrive at the conclusion that the geometric + # sequence is intact. We thus expect no changes. + # + # Note that we are tweaking mtimes of the packfiles so that we can + # verify they did not change. This is done in order to detect the case + # where we do repack objects, but the resulting packfile is the same. + test-tool chmtime --verbose =0 member/.git/objects/pack/* >expected-member-packs && + git -C member repack --geometric=2 -l -d && + test-tool chmtime --verbose member/.git/objects/pack/* >actual-member-packs && + test_cmp expected-member-packs actual-member-packs && + + { + packed_objects shared/.git/objects/pack/pack-*.idx && + packed_objects member/.git/objects/pack/pack-*.idx + } | sort >expected-objects && + + # On the other hand, when doing a non-local geometric repack we should + # see both packfiles and thus repack them. We expect that the shared + # object database was not changed. + test-tool chmtime --verbose =0 shared/.git/objects/pack/* >expected-shared-packs && + git -C member repack --geometric=2 -d && + test-tool chmtime --verbose shared/.git/objects/pack/* >actual-shared-packs && + test_cmp expected-shared-packs actual-shared-packs && + + # Furthermore, we expect that the member repository now has a single + # packfile that contains the combined shared and non-shared objects. + ls member/.git/objects/pack/pack-*.idx >actual && + test_line_count = 1 actual && + packed_objects member/.git/objects/pack/pack-*.idx >actual-objects && + test_line_count = 6 actual-objects && + test_cmp expected-objects actual-objects +' + +test_expect_success '--geometric -l disables writing bitmaps with non-local packfiles' ' + test_when_finished "rm -fr shared member" && + + git init shared && + test_commit_bulk -C shared --start=1 1 && + + git clone --shared shared member && + test_commit_bulk -C member --start=2 1 && + + # When performing a geometric repack with `-l` while connected to an + # alternate object database that has a packfile we do not have full + # coverage of objects. As a result, we expect that writing the bitmap + # will be disabled. + git -C member repack -l --geometric=2 --write-midx --write-bitmap-index 2>err && + cat >expect <<-EOF && + warning: disabling bitmap writing, as some objects are not being packed + EOF + test_cmp expect err && + test_path_is_missing member/.git/objects/pack/multi-pack-index-*.bitmap && + + # On the other hand, when we repack without `-l`, we should see that + # the bitmap gets created. + git -C member repack --geometric=2 --write-midx --write-bitmap-index 2>err && + test_must_be_empty err && + test_path_is_file member/.git/objects/pack/multi-pack-index-*.bitmap +' + test_done diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh index 24297e26ca..59d3847bf8 100755 --- a/t/t7800-difftool.sh +++ b/t/t7800-difftool.sh @@ -155,6 +155,58 @@ test_expect_success 'difftool honors --gui' ' test_cmp expect actual ' +test_expect_success 'difftool with guiDefault auto selects gui tool when there is DISPLAY' ' + difftool_test_setup && + test_config merge.tool bogus-tool && + test_config diff.tool bogus-tool && + test_config diff.guitool test-tool && + test_config difftool.guiDefault auto && + DISPLAY=SOMETHING && export DISPLAY && + + echo branch >expect && + git difftool --no-prompt branch >actual && + test_cmp expect actual +' +test_expect_success 'difftool with guiDefault auto selects regular tool when no DISPLAY' ' + difftool_test_setup && + test_config diff.guitool bogus-tool && + test_config diff.tool test-tool && + test_config difftool.guiDefault Auto && + DISPLAY= && export DISPLAY && + + echo branch >expect && + git difftool --no-prompt branch >actual && + test_cmp expect actual +' + +test_expect_success 'difftool with guiDefault true selects gui tool' ' + difftool_test_setup && + test_config diff.tool bogus-tool && + test_config diff.guitool test-tool && + test_config difftool.guiDefault true && + + DISPLAY= && export DISPLAY && + echo branch >expect && + git difftool --no-prompt branch >actual && + test_cmp expect actual && + + DISPLAY=Something && export DISPLAY && + echo branch >expect && + git difftool --no-prompt branch >actual && + test_cmp expect actual +' + +test_expect_success 'difftool --no-gui trumps config guiDefault' ' + difftool_test_setup && + test_config diff.guitool bogus-tool && + test_config diff.tool test-tool && + test_config difftool.guiDefault true && + + echo branch >expect && + git difftool --no-prompt --no-gui branch >actual && + test_cmp expect actual +' + test_expect_success 'difftool --gui last setting wins' ' difftool_test_setup && : >expect && diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 0de83b5d2b..6520346246 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -2326,6 +2326,37 @@ test_expect_success $PREREQ 'invoke hook' ' ) ' +expected_file_counter_output () { + total=$1 + count=0 + while test $count -ne $total + do + count=$((count + 1)) && + echo "$count/$total" || return + done +} + +test_expect_success $PREREQ '--validate hook allows counting of messages' ' + test_when_finished "rm -rf my-hooks.log" && + test_config core.hooksPath "my-hooks" && + mkdir -p my-hooks && + + write_script my-hooks/sendemail-validate <<-\EOF && + num=$GIT_SENDEMAIL_FILE_COUNTER && + tot=$GIT_SENDEMAIL_FILE_TOTAL && + echo "$num/$tot" >>my-hooks.log || exit 1 + EOF + + >my-hooks.log && + expected_file_counter_output 4 >expect && + git send-email \ + --from="Example <from@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + --validate -3 --cover-letter --force && + test_cmp expect my-hooks.log +' + test_expect_success $PREREQ 'test that send-email works outside a repo' ' nongit git send-email \ --from="Example <nobody@example.com>" \ @@ -1,6 +1,7 @@ -#include "cache.h" +#include "git-compat-util.h" #include "environment.h" #include "tag.h" +#include "object-name.h" #include "object-store.h" #include "commit.h" #include "tree.h" diff --git a/templates/hooks--sendemail-validate.sample b/templates/hooks--sendemail-validate.sample new file mode 100755 index 0000000000..640bcf874d --- /dev/null +++ b/templates/hooks--sendemail-validate.sample @@ -0,0 +1,77 @@ +#!/bin/sh + +# An example hook script to validate a patch (and/or patch series) before +# sending it via email. +# +# The hook should exit with non-zero status after issuing an appropriate +# message if it wants to prevent the email(s) from being sent. +# +# To enable this hook, rename this file to "sendemail-validate". +# +# By default, it will only check that the patch(es) can be applied on top of +# the default upstream branch without conflicts in a secondary worktree. After +# validation (successful or not) of the last patch of a series, the worktree +# will be deleted. +# +# The following config variables can be set to change the default remote and +# remote ref that are used to apply the patches against: +# +# sendemail.validateRemote (default: origin) +# sendemail.validateRemoteRef (default: HEAD) +# +# Replace the TODO placeholders with appropriate checks according to your +# needs. + +validate_cover_letter () { + file="$1" + # TODO: Replace with appropriate checks (e.g. spell checking). + true +} + +validate_patch () { + file="$1" + # Ensure that the patch applies without conflicts. + git am -3 "$file" || return + # TODO: Replace with appropriate checks for this patch + # (e.g. checkpatch.pl). + true +} + +validate_series () { + # TODO: Replace with appropriate checks for the whole series + # (e.g. quick build, coding style checks, etc.). + true +} + +# main ------------------------------------------------------------------------- + +if test "$GIT_SENDEMAIL_FILE_COUNTER" = 1 +then + remote=$(git config --default origin --get sendemail.validateRemote) && + ref=$(git config --default HEAD --get sendemail.validateRemoteRef) && + worktree=$(mktemp --tmpdir -d sendemail-validate.XXXXXXX) && + git worktree add -fd --checkout "$worktree" "refs/remotes/$remote/$ref" && + git config --replace-all sendemail.validateWorktree "$worktree" +else + worktree=$(git config --get sendemail.validateWorktree) +fi || { + echo "sendemail-validate: error: failed to prepare worktree" >&2 + exit 1 +} + +unset GIT_DIR GIT_WORK_TREE +cd "$worktree" && + +if grep -q "^diff --git " "$1" +then + validate_patch "$1" +else + validate_cover_letter "$1" +fi && + +if test "$GIT_SENDEMAIL_FILE_COUNTER" = "$GIT_SENDEMAIL_FILE_TOTAL" +then + git config --unset-all sendemail.validateWorktree && + trap 'git worktree remove -ff "$worktree"' EXIT && + validate_series +fi diff --git a/tmp-objdir.c b/tmp-objdir.c index 5adad1925d..c33a554f92 100644 --- a/tmp-objdir.c +++ b/tmp-objdir.c @@ -1,9 +1,10 @@ -#include "cache.h" +#include "git-compat-util.h" #include "tmp-objdir.h" #include "abspath.h" #include "chdir-notify.h" #include "dir.h" #include "environment.h" +#include "object-file.h" #include "sigchain.h" #include "string-list.h" #include "strbuf.h" @@ -21,11 +21,12 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "cache.h" +#include "git-compat-util.h" #include "abspath.h" #include "environment.h" #include "quote.h" #include "setup.h" +#include "trace.h" #include "wrapper.h" struct trace_key trace_default_key = { "GIT_TRACE", 0, 0, 0 }; @@ -7,6 +7,7 @@ #include "thread-utils.h" #include "version.h" #include "trace.h" +#include "trace2.h" #include "trace2/tr2_cfg.h" #include "trace2/tr2_cmd_name.h" #include "trace2/tr2_ctr.h" diff --git a/transport-helper.c b/transport-helper.c index 76d146ee88..6b816940dc 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -1,4 +1,4 @@ -#include "cache.h" +#include "git-compat-util.h" #include "transport.h" #include "quote.h" #include "run-command.h" @@ -7,6 +7,7 @@ #include "environment.h" #include "gettext.h" #include "hex.h" +#include "object-name.h" #include "revision.h" #include "remote.h" #include "string-list.h" diff --git a/transport.c b/transport.c index 89a220425e..67afdae57c 100644 --- a/transport.c +++ b/transport.c @@ -1,4 +1,5 @@ -#include "cache.h" +#include "git-compat-util.h" +#include "advice.h" #include "alloc.h" #include "config.h" #include "environment.h" @@ -22,8 +23,10 @@ #include "string-list.h" #include "oid-array.h" #include "sigchain.h" +#include "trace2.h" #include "transport-internal.h" #include "protocol.h" +#include "object-name.h" #include "object-store.h" #include "color.h" #include "bundle-uri.h" @@ -317,7 +320,7 @@ static struct ref *handshake(struct transport *transport, int for_push, struct git_transport_data *data = transport->data; struct ref *refs = NULL; struct packet_reader reader; - int sid_len; + size_t sid_len; const char *server_sid; connect_setup(transport, for_push); diff --git a/tree-walk.c b/tree-walk.c index 38b6556478..2993c48c2f 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -4,7 +4,9 @@ #include "dir.h" #include "gettext.h" #include "hex.h" +#include "object-file.h" #include "object-store.h" +#include "trace2.h" #include "tree.h" #include "pathspec.h" #include "json-writer.h" @@ -2,6 +2,7 @@ #include "cache-tree.h" #include "hex.h" #include "tree.h" +#include "object-name.h" #include "object-store.h" #include "blob.h" #include "commit.h" diff --git a/unpack-trees.c b/unpack-trees.c index 3ded68ecb6..c0732aa0c2 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "advice.h" #include "strvec.h" #include "repository.h" #include "config.h" @@ -17,6 +18,7 @@ #include "sparse-index.h" #include "submodule.h" #include "submodule-config.h" +#include "trace2.h" #include "fsmonitor.h" #include "object-store.h" #include "promisor-remote.h" diff --git a/unpack-trees.h b/unpack-trees.h index 61c06eb7c5..30622aeebf 100644 --- a/unpack-trees.h +++ b/unpack-trees.h @@ -2,6 +2,7 @@ #define UNPACK_TREES_H #include "cache.h" +#include "convert.h" #include "strvec.h" #include "string-list.h" #include "tree-walk.h" diff --git a/upload-pack.c b/upload-pack.c index e23f16dfdd..08633dc121 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -1,4 +1,4 @@ -#include "cache.h" +#include "git-compat-util.h" #include "config.h" #include "environment.h" #include "gettext.h" @@ -8,6 +8,7 @@ #include "sideband.h" #include "repository.h" #include "object-store.h" +#include "oid-array.h" #include "tag.h" #include "object.h" #include "commit.h" @@ -22,6 +23,7 @@ #include "version.h" #include "string-list.h" #include "strvec.h" +#include "trace2.h" #include "prio-queue.h" #include "protocol.h" #include "quote.h" @@ -30,6 +32,7 @@ #include "commit-graph.h" #include "commit-reach.h" #include "shallow.h" +#include "wrapper.h" #include "write-or-die.h" /* Remember to update object flag allocation in object.h */ @@ -1067,7 +1070,7 @@ static void receive_needs(struct upload_pack_data *data, const char *features; struct object_id oid_buf; const char *arg; - int feature_len; + size_t feature_len; reset_timeout(data->timeout); if (packet_reader_read(reader) != PACKET_READ_NORMAL) diff --git a/userdiff.c b/userdiff.c index 09203fbc35..eaec6ebb5e 100644 --- a/userdiff.c +++ b/userdiff.c @@ -17,6 +17,7 @@ static int drivers_alloc; .cflags = REG_EXTENDED, \ }, \ .word_regex = wrx "|[^[:space:]]|[\xc0-\xff][\x80-\xbf]+", \ + .word_regex_multi_byte = wrx "|[^[:space:]]", \ } #define IPATTERN(lang, rx, wrx) { \ .name = lang, \ @@ -26,6 +27,7 @@ static int drivers_alloc; .cflags = REG_EXTENDED | REG_ICASE, \ }, \ .word_regex = wrx "|[^[:space:]]|[\xc0-\xff][\x80-\xbf]+", \ + .word_regex_multi_byte = wrx "|[^[:space:]]", \ } /* @@ -294,7 +296,7 @@ PATTERNS("scheme", /* All other words should be delimited by spaces or parentheses */ "|([^][)(}{[ \t])+"), PATTERNS("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$", - "\\\\[a-zA-Z@]+|\\\\.|[a-zA-Z0-9\x80-\xff]+"), + "\\\\[a-zA-Z@]+|\\\\.|([a-zA-Z0-9]|[^\x01-\x7f])+"), { "default", NULL, NULL, -1, { NULL, 0 } }, }; #undef PATTERNS @@ -330,6 +332,25 @@ static int userdiff_find_by_namelen_cb(struct userdiff_driver *driver, return 0; } +static int regexec_supports_multi_byte_chars(void) +{ + static const char not_space[] = "[^[:space:]]"; + static const char utf8_multi_byte_char[] = "\xc2\xa3"; + regex_t re; + regmatch_t match; + static int result = -1; + + if (result != -1) + return result; + if (regcomp(&re, not_space, REG_EXTENDED)) + BUG("invalid regular expression: %s", not_space); + result = !regexec(&re, utf8_multi_byte_char, 1, &match, 0) && + match.rm_so == 0 && + match.rm_eo == strlen(utf8_multi_byte_char); + regfree(&re); + return result; +} + static struct userdiff_driver *userdiff_find_by_namelen(const char *name, size_t len) { struct find_by_namelen_data udcbdata = { @@ -405,7 +426,13 @@ int userdiff_config(const char *k, const char *v) struct userdiff_driver *userdiff_find_by_name(const char *name) { int len = strlen(name); - return userdiff_find_by_namelen(name, len); + struct userdiff_driver *driver = userdiff_find_by_namelen(name, len); + if (driver && driver->word_regex_multi_byte) { + if (regexec_supports_multi_byte_chars()) + driver->word_regex = driver->word_regex_multi_byte; + driver->word_regex_multi_byte = NULL; + } + return driver; } struct userdiff_driver *userdiff_find_by_path(struct index_state *istate, diff --git a/userdiff.h b/userdiff.h index 24419db697..d726804c3e 100644 --- a/userdiff.h +++ b/userdiff.h @@ -18,6 +18,7 @@ struct userdiff_driver { int binary; struct userdiff_funcname funcname; const char *word_regex; + const char *word_regex_multi_byte; const char *textconv; struct notes_cache *textconv_cache; int textconv_want_cache; @@ -1,4 +1,4 @@ -#include "cache.h" +#include "git-compat-util.h" #include "gettext.h" #include "hex.h" #include "walker.h" @@ -5,6 +5,7 @@ #include "abspath.h" #include "config.h" #include "gettext.h" +#include "trace2.h" #include "wrapper.h" static intmax_t count_fsync_writeout_only; diff --git a/wt-status.c b/wt-status.c index 4bef09de1c..97b9c1c035 100644 --- a/wt-status.c +++ b/wt-status.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "advice.h" #include "wt-status.h" #include "object.h" #include "dir.h" @@ -7,6 +8,7 @@ #include "environment.h" #include "gettext.h" #include "hex.h" +#include "object-name.h" #include "revision.h" #include "diffcore.h" #include "quote.h" @@ -18,6 +20,8 @@ #include "column.h" #include "setup.h" #include "strbuf.h" +#include "trace.h" +#include "trace2.h" #include "utf8.h" #include "worktree.h" #include "lockfile.h" |
