diff options
-rw-r--r-- | .github/workflows/check-whitespace.yml | 63 | ||||
-rw-r--r-- | .github/workflows/l10n.yml | 6 | ||||
-rw-r--r-- | .github/workflows/main.yml | 48 | ||||
-rw-r--r-- | Documentation/RelNotes/2.40.0.txt | 14 | ||||
-rw-r--r-- | Documentation/config/feature.txt | 5 | ||||
-rw-r--r-- | Documentation/config/index.txt | 11 | ||||
-rw-r--r-- | Documentation/git-am.txt | 8 | ||||
-rw-r--r-- | builtin/am.c | 11 | ||||
-rw-r--r-- | csum-file.c | 14 | ||||
-rw-r--r-- | csum-file.h | 7 | ||||
-rw-r--r-- | diff.c | 30 | ||||
-rw-r--r-- | dir.c | 7 | ||||
-rw-r--r-- | read-cache.c | 14 | ||||
-rw-r--r-- | repo-settings.c | 2 | ||||
-rw-r--r-- | repository.h | 1 | ||||
-rw-r--r-- | scalar.c | 1 | ||||
-rw-r--r-- | t/helper/test-bundle-uri.c | 7 | ||||
-rwxr-xr-x | t/t1091-sparse-checkout-builtin.sh | 11 | ||||
-rwxr-xr-x | t/t1509-root-work-tree.sh | 10 | ||||
-rwxr-xr-x | t/t1600-index.sh | 30 | ||||
-rwxr-xr-x | t/t4045-diff-relative.sh | 29 | ||||
-rwxr-xr-x | t/t4150-am.sh | 32 | ||||
-rw-r--r-- | t/test-lib-functions.sh | 74 | ||||
-rw-r--r-- | t/test-lib.sh | 2 |
24 files changed, 319 insertions, 118 deletions
diff --git a/.github/workflows/check-whitespace.yml b/.github/workflows/check-whitespace.yml index ad3466a..a58e2dc 100644 --- a/.github/workflows/check-whitespace.yml +++ b/.github/workflows/check-whitespace.yml @@ -9,42 +9,83 @@ on: pull_request: types: [opened, synchronize] +# Avoid unnecessary builds. Unlike the main CI jobs, these are not +# ci-configurable (but could be). +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: check-whitespace: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 - name: git log --check id: check_out run: | - log= + baseSha=${{github.event.pull_request.base.sha}} + problems=() commit= - while read dash etc + commitText= + commitTextmd= + goodparent= + while read dash sha etc do case "${dash}" in "---") - commit="${etc}" + if test -z "${commit}" + then + goodparent=${sha} + fi + commit="${sha}" + commitText="${sha} ${etc}" + commitTextmd="[${sha}](https://github.com/${{ github.repository }}/commit/${sha}) ${etc}" ;; "") ;; *) if test -n "${commit}" then - log="${log}\n${commit}" + problems+=("1) --- ${commitTextmd}") echo "" - echo "--- ${commit}" + echo "--- ${commitText}" + commit= fi - commit= - log="${log}\n${dash} ${etc}" - echo "${dash} ${etc}" + case "${dash}" in + *:[1-9]*:) # contains file and line number information + dashend=${dash#*:} + problems+=("[${dash}](https://github.com/${{ github.repository }}/blob/${{github.event.pull_request.head.ref}}/${dash%%:*}#L${dashend%:}) ${sha} ${etc}") + ;; + *) + problems+=("\`${dash} ${sha} ${etc}\`") + ;; + esac + echo "${dash} ${sha} ${etc}" ;; esac - done <<< $(git log --check --pretty=format:"---% h% s" ${{github.event.pull_request.base.sha}}..) + done <<< $(git log --check --pretty=format:"---% h% s" ${baseSha}..) - if test -n "${log}" + if test ${#problems[*]} -gt 0 then + if test -z "${commit}" + then + goodparent=${baseSha: 0:7} + fi + echo "🛑 Please review the Summary output for further information." + echo "### :x: A whitespace issue was found in one or more of the commits." >$GITHUB_STEP_SUMMARY + echo "" >>$GITHUB_STEP_SUMMARY + echo "Run these commands to correct the problem:" >>$GITHUB_STEP_SUMMARY + echo "1. \`git rebase --whitespace=fix ${goodparent}\`" >>$GITHUB_STEP_SUMMARY + echo "1. \`git push --force\`" >>$GITHUB_STEP_SUMMARY + echo " " >>$GITHUB_STEP_SUMMARY + echo "Errors:" >>$GITHUB_STEP_SUMMARY + for i in "${problems[@]}" + do + echo "${i}" >>$GITHUB_STEP_SUMMARY + done + exit 2 fi diff --git a/.github/workflows/l10n.yml b/.github/workflows/l10n.yml index f7ea0f0..6c38496 100644 --- a/.github/workflows/l10n.yml +++ b/.github/workflows/l10n.yml @@ -2,6 +2,12 @@ name: git-l10n on: [push, pull_request_target] +# Avoid unnecessary builds. Unlike the main CI jobs, these are not +# ci-configurable (but could be). +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: git-po-helper: if: >- diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e67847a..30492ea 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,6 +11,7 @@ jobs: runs-on: ubuntu-latest outputs: enabled: ${{ steps.check-ref.outputs.enabled }}${{ steps.skip-if-redundant.outputs.enabled }} + skip_concurrent: ${{ steps.check-ref.outputs.skip_concurrent }} steps: - name: try to clone ci-config branch run: | @@ -34,7 +35,15 @@ jobs: then enabled=no fi + + skip_concurrent=yes + if test -x config-repo/ci/config/skip-concurrent && + ! config-repo/ci/config/skip-concurrent '${{ github.ref }}' + then + skip_concurrent=no + fi echo "enabled=$enabled" >>$GITHUB_OUTPUT + echo "skip_concurrent=$skip_concurrent" >>$GITHUB_OUTPUT - name: skip if the commit or tree was already tested id: skip-if-redundant uses: actions/github-script@v6 @@ -82,6 +91,9 @@ jobs: needs: ci-config if: needs.ci-config.outputs.enabled == 'yes' runs-on: windows-latest + concurrency: + group: windows-build-${{ github.ref }} + cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - uses: actions/checkout@v3 - uses: git-for-windows/setup-git-for-windows-sdk@v1 @@ -101,11 +113,14 @@ jobs: windows-test: name: win test runs-on: windows-latest - needs: [windows-build] + needs: [ci-config, windows-build] strategy: fail-fast: false matrix: nr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + concurrency: + group: windows-test-${{ matrix.nr }}-${{ github.ref }} + cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - name: download tracked files and build artifacts uses: actions/download-artifact@v3 @@ -132,11 +147,14 @@ jobs: vs-build: name: win+VS build needs: ci-config - if: needs.ci-config.outputs.enabled == 'yes' + if: github.event.repository.owner.login == 'git-for-windows' && needs.ci-config.outputs.enabled == 'yes' env: NO_PERL: 1 GIT_CONFIG_PARAMETERS: "'user.name=CI' 'user.email=ci@git'" runs-on: windows-latest + concurrency: + group: vs-build-${{ github.ref }} + cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - uses: actions/checkout@v3 - uses: git-for-windows/setup-git-for-windows-sdk@v1 @@ -184,11 +202,14 @@ jobs: vs-test: name: win+VS test runs-on: windows-latest - needs: vs-build + needs: [ci-config, vs-build] strategy: fail-fast: false matrix: nr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + concurrency: + group: vs-test-${{ matrix.nr }}-${{ github.ref }} + cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - uses: git-for-windows/setup-git-for-windows-sdk@v1 - name: download tracked files and build artifacts @@ -218,6 +239,9 @@ jobs: name: ${{matrix.vector.jobname}} (${{matrix.vector.pool}}) needs: ci-config if: needs.ci-config.outputs.enabled == 'yes' + concurrency: + group: ${{ matrix.vector.jobname }}-${{ matrix.vector.pool }}-${{ github.ref }} + cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} strategy: fail-fast: false matrix: @@ -265,8 +289,9 @@ jobs: - uses: actions/checkout@v3 - run: ci/install-dependencies.sh - run: ci/run-build-and-tests.sh - - run: ci/print-test-failures.sh + - name: print test failures if: failure() && env.FAILED_TEST_ARTIFACTS != '' + run: ci/print-test-failures.sh - name: Upload failed tests' directories if: failure() && env.FAILED_TEST_ARTIFACTS != '' uses: actions/upload-artifact@v3 @@ -277,6 +302,9 @@ jobs: name: ${{matrix.vector.jobname}} (${{matrix.vector.image}}) needs: ci-config if: needs.ci-config.outputs.enabled == 'yes' + concurrency: + group: dockerized-${{ matrix.vector.jobname }}-${{ matrix.vector.image }}-${{ github.ref }} + cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} strategy: fail-fast: false matrix: @@ -298,8 +326,9 @@ jobs: if: matrix.vector.jobname == 'linux32' - run: ci/install-docker-dependencies.sh - run: ci/run-build-and-tests.sh - - run: ci/print-test-failures.sh + - name: print test failures if: failure() && env.FAILED_TEST_ARTIFACTS != '' + run: ci/print-test-failures.sh - name: Upload failed tests' directories if: failure() && env.FAILED_TEST_ARTIFACTS != '' && matrix.vector.jobname != 'linux32' uses: actions/upload-artifact@v3 @@ -318,6 +347,9 @@ jobs: env: jobname: StaticAnalysis runs-on: ubuntu-22.04 + concurrency: + group: static-analysis-${{ github.ref }} + cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - uses: actions/checkout@v3 - run: ci/install-dependencies.sh @@ -329,6 +361,9 @@ jobs: env: jobname: sparse runs-on: ubuntu-20.04 + concurrency: + group: sparse-${{ github.ref }} + cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - name: Download a current `sparse` package # Ubuntu's `sparse` version is too old for us @@ -347,6 +382,9 @@ jobs: name: documentation needs: ci-config if: needs.ci-config.outputs.enabled == 'yes' + concurrency: + group: documentation-${{ github.ref }} + cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} env: jobname: Documentation runs-on: ubuntu-latest diff --git a/Documentation/RelNotes/2.40.0.txt b/Documentation/RelNotes/2.40.0.txt index 5193a99..d7685b8 100644 --- a/Documentation/RelNotes/2.40.0.txt +++ b/Documentation/RelNotes/2.40.0.txt @@ -48,6 +48,20 @@ Performance, Internal Implementation, Development Support etc. * Stop using "git --super-prefix" and narrow the scope of its use to the submodule--helper. + * Stop running win+VS build by default. + (merge a0da6deeec js/ci-disable-cmake-by-default later to maint). + + * CI updates. We probably want a clean-up to move the long shell + script embedded in yaml file into a separate file, but that can + come later. + (merge 4542582e59 cw/ci-whitespace later to maint). + + * Use `git diff --no-index` as a test_cmp on Windows. + + We'd probably need to revisit "do we really want to, and have to, + lose CRLF vs LF?" later, at which time we may be able to further + clean this up by replacing "git diff --no-index" with "diff -u". + Fixes since v2.39 ----------------- diff --git a/Documentation/config/feature.txt b/Documentation/config/feature.txt index 95975e5..e52bc6b 100644 --- a/Documentation/config/feature.txt +++ b/Documentation/config/feature.txt @@ -23,6 +23,11 @@ feature.manyFiles:: working directory. With many files, commands such as `git status` and `git checkout` may be slow and these new defaults improve performance: + +* `index.skipHash=true` speeds up index writes by not computing a trailing + checksum. Note that this will cause Git versions earlier than 2.13.0 to + refuse to parse the index and Git versions earlier than 2.40.0 will report + a corrupted index during `git fsck`. ++ * `index.version=4` enables path-prefix compression in the index. + * `core.untrackedCache=true` enables the untracked cache. This setting assumes diff --git a/Documentation/config/index.txt b/Documentation/config/index.txt index 75f3a2d..23c7985 100644 --- a/Documentation/config/index.txt +++ b/Documentation/config/index.txt @@ -30,3 +30,14 @@ index.version:: Specify the version with which new index files should be initialized. This does not affect existing repositories. If `feature.manyFiles` is enabled, then the default is 4. + +index.skipHash:: + When enabled, do not compute the trailing hash for the index file. + This accelerates Git commands that manipulate the index, such as + `git add`, `git commit`, or `git status`. Instead of storing the + checksum, write a trailing set of bytes with value zero, indicating + that the computation was skipped. ++ +If you enable `index.skipHash`, then Git clients older than 2.13.0 will +refuse to parse the index and Git clients older than 2.40.0 will report an +error during `git fsck`. diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt index 326276e..0c1dfb3 100644 --- a/Documentation/git-am.txt +++ b/Documentation/git-am.txt @@ -9,7 +9,7 @@ git-am - Apply a series of patches from a mailbox SYNOPSIS -------- [verse] -'git am' [--signoff] [--keep] [--[no-]keep-cr] [--[no-]utf8] +'git am' [--signoff] [--keep] [--[no-]keep-cr] [--[no-]utf8] [--no-verify] [--[no-]3way] [--interactive] [--committer-date-is-author-date] [--ignore-date] [--ignore-space-change | --ignore-whitespace] [--whitespace=<option>] [-C<n>] [-p<n>] [--directory=<dir>] @@ -138,6 +138,12 @@ include::rerere-options.txt[] --interactive:: Run interactively. +-n:: +--no-verify:: + By default, the pre-applypatch and applypatch-msg hooks are run. + When any of `--no-verify` or `-n` is given, these are bypassed. + See also linkgit:githooks[5]. + --committer-date-is-author-date:: By default the command records the date from the e-mail message as the commit author date, and uses the time of diff --git a/builtin/am.c b/builtin/am.c index dddf1b9..7e88d24 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -117,6 +117,7 @@ struct am_state { /* various operating modes and command line options */ int interactive; + int no_verify; int threeway; int quiet; int signoff; /* enum signoff_type */ @@ -472,10 +473,12 @@ static void am_destroy(const struct am_state *state) */ static int run_applypatch_msg_hook(struct am_state *state) { - int ret; + int ret = 0; assert(state->msg); - ret = run_hooks_l("applypatch-msg", am_path(state, "final-commit"), NULL); + + if (!state->no_verify) + ret = run_hooks_l("applypatch-msg", am_path(state, "final-commit"), NULL); if (!ret) { FREE_AND_NULL(state->msg); @@ -1650,7 +1653,7 @@ static void do_commit(const struct am_state *state) const char *reflog_msg, *author, *committer = NULL; struct strbuf sb = STRBUF_INIT; - if (run_hooks("pre-applypatch")) + if (!state->no_verify && run_hooks("pre-applypatch")) exit(1); if (write_cache_as_tree(&tree, 0, NULL)) @@ -2340,6 +2343,8 @@ int cmd_am(int argc, const char **argv, const char *prefix) struct option options[] = { OPT_BOOL('i', "interactive", &state.interactive, N_("run interactively")), + OPT_BOOL('n', "no-verify", &state.no_verify, + N_("bypass pre-applypatch and applypatch-msg hooks")), OPT_HIDDEN_BOOL('b', "binary", &binary, N_("historical option -- no-op")), OPT_BOOL('3', "3way", &state.threeway, diff --git a/csum-file.c b/csum-file.c index 59ef339..cce13c0 100644 --- a/csum-file.c +++ b/csum-file.c @@ -45,7 +45,8 @@ void hashflush(struct hashfile *f) unsigned offset = f->offset; if (offset) { - the_hash_algo->update_fn(&f->ctx, f->buffer, offset); + if (!f->skip_hash) + the_hash_algo->update_fn(&f->ctx, f->buffer, offset); flush(f, f->buffer, offset); f->offset = 0; } @@ -64,7 +65,12 @@ int finalize_hashfile(struct hashfile *f, unsigned char *result, int fd; hashflush(f); - the_hash_algo->final_fn(f->buffer, &f->ctx); + + if (f->skip_hash) + hashclr(f->buffer); + else + the_hash_algo->final_fn(f->buffer, &f->ctx); + if (result) hashcpy(result, f->buffer); if (flags & CSUM_HASH_IN_STREAM) @@ -108,7 +114,8 @@ void hashwrite(struct hashfile *f, const void *buf, unsigned int count) * the hashfile's buffer. In this block, * f->offset is necessarily zero. */ - the_hash_algo->update_fn(&f->ctx, buf, nr); + if (!f->skip_hash) + the_hash_algo->update_fn(&f->ctx, buf, nr); flush(f, buf, nr); } else { /* @@ -153,6 +160,7 @@ static struct hashfile *hashfd_internal(int fd, const char *name, f->tp = tp; f->name = name; f->do_crc = 0; + f->skip_hash = 0; the_hash_algo->init_fn(&f->ctx); f->buffer_len = buffer_len; diff --git a/csum-file.h b/csum-file.h index 0d29f52..793a59d 100644 --- a/csum-file.h +++ b/csum-file.h @@ -20,6 +20,13 @@ struct hashfile { size_t buffer_len; unsigned char *buffer; unsigned char *check_buffer; + + /** + * If non-zero, skip_hash indicates that we should + * not actually compute the hash for this hashfile and + * instead only use it as a buffered write. + */ + int skip_hash; }; /* Checkpoint */ @@ -4213,7 +4213,6 @@ static void prep_temp_blob(struct index_state *istate, } static struct diff_tempfile *prepare_temp_file(struct repository *r, - const char *name, struct diff_filespec *one) { struct diff_tempfile *temp = claim_diff_tempfile(); @@ -4231,18 +4230,18 @@ static struct diff_tempfile *prepare_temp_file(struct repository *r, if (!S_ISGITLINK(one->mode) && (!one->oid_valid || - reuse_worktree_file(r->index, name, &one->oid, 1))) { + reuse_worktree_file(r->index, one->path, &one->oid, 1))) { struct stat st; - if (lstat(name, &st) < 0) { + if (lstat(one->path, &st) < 0) { if (errno == ENOENT) goto not_a_valid_file; - die_errno("stat(%s)", name); + die_errno("stat(%s)", one->path); } if (S_ISLNK(st.st_mode)) { struct strbuf sb = STRBUF_INIT; - if (strbuf_readlink(&sb, name, st.st_size) < 0) - die_errno("readlink(%s)", name); - prep_temp_blob(r->index, name, temp, sb.buf, sb.len, + if (strbuf_readlink(&sb, one->path, st.st_size) < 0) + die_errno("readlink(%s)", one->path); + prep_temp_blob(r->index, one->path, temp, sb.buf, sb.len, (one->oid_valid ? &one->oid : null_oid()), (one->oid_valid ? @@ -4251,7 +4250,7 @@ static struct diff_tempfile *prepare_temp_file(struct repository *r, } else { /* we can borrow from the file in the work tree */ - temp->name = name; + temp->name = one->path; if (!one->oid_valid) oid_to_hex_r(temp->hex, null_oid()); else @@ -4269,7 +4268,7 @@ static struct diff_tempfile *prepare_temp_file(struct repository *r, else { if (diff_populate_filespec(r, one, NULL)) die("cannot read data blob for %s", one->path); - prep_temp_blob(r->index, name, temp, + prep_temp_blob(r->index, one->path, temp, one->data, one->size, &one->oid, one->mode); } @@ -4278,10 +4277,9 @@ static struct diff_tempfile *prepare_temp_file(struct repository *r, static void add_external_diff_name(struct repository *r, struct strvec *argv, - const char *name, struct diff_filespec *df) { - struct diff_tempfile *temp = prepare_temp_file(r, name, df); + struct diff_tempfile *temp = prepare_temp_file(r, df); strvec_push(argv, temp->name); strvec_push(argv, temp->hex); strvec_push(argv, temp->mode); @@ -4308,11 +4306,9 @@ static void run_external_diff(const char *pgm, strvec_push(&cmd.args, name); if (one && two) { - add_external_diff_name(o->repo, &cmd.args, name, one); - if (!other) - add_external_diff_name(o->repo, &cmd.args, name, two); - else { - add_external_diff_name(o->repo, &cmd.args, other, two); + add_external_diff_name(o->repo, &cmd.args, one); + add_external_diff_name(o->repo, &cmd.args, two); + if (other) { strvec_push(&cmd.args, other); strvec_push(&cmd.args, xfrm_msg); } @@ -7034,7 +7030,7 @@ static char *run_textconv(struct repository *r, struct strbuf buf = STRBUF_INIT; int err = 0; - temp = prepare_temp_file(r, spec->path, spec); + temp = prepare_temp_file(r, spec); strvec_push(&child.args, pgm); strvec_push(&child.args, temp->name); @@ -732,6 +732,13 @@ static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_pattern goto clear_hashmaps; } + if (!(given->flags & PATTERN_FLAG_MUSTBEDIR) && + strcmp(given->pattern, "/*")) { + /* Not a cone pattern. */ + warning(_("unrecognized pattern: '%s'"), given->pattern); + goto clear_hashmaps; + } + prev = given->pattern; cur = given->pattern + 1; next = given->pattern + 2; diff --git a/read-cache.c b/read-cache.c index 1ff518b..cf87ad7 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1817,6 +1817,8 @@ static int verify_hdr(const struct cache_header *hdr, unsigned long size) git_hash_ctx c; unsigned char hash[GIT_MAX_RAWSZ]; int hdr_version; + unsigned char *start, *end; + struct object_id oid; if (hdr->hdr_signature != htonl(CACHE_SIGNATURE)) return error(_("bad signature 0x%08x"), hdr->hdr_signature); @@ -1827,10 +1829,16 @@ static int verify_hdr(const struct cache_header *hdr, unsigned long size) if (!verify_index_checksum) return 0; + end = (unsigned char *)hdr + size; + start = end - the_hash_algo->rawsz; + oidread(&oid, start); + if (oideq(&oid, null_oid())) + return 0; + the_hash_algo->init_fn(&c); the_hash_algo->update_fn(&c, hdr, size - the_hash_algo->rawsz); the_hash_algo->final_fn(hash, &c); - if (!hasheq(hash, (unsigned char *)hdr + size - the_hash_algo->rawsz)) + if (!hasheq(hash, start)) return error(_("bad index file sha1 signature")); return 0; } @@ -2920,9 +2928,13 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, int ieot_entries = 1; struct index_entry_offset_table *ieot = NULL; int nr, nr_threads; + struct repository *r = istate->repo ? istate->repo : the_repository; f = hashfd(tempfile->fd, tempfile->filename.buf); + prepare_repo_settings(r); + f->skip_hash = r->settings.index_skip_hash; + for (i = removed = extended = 0; i < entries; i++) { if (cache[i]->ce_flags & CE_REMOVE) removed++; diff --git a/repo-settings.c b/repo-settings.c index 3021921..3dbd3f0 100644 --- a/repo-settings.c +++ b/repo-settings.c @@ -47,6 +47,7 @@ void prepare_repo_settings(struct repository *r) } if (manyfiles) { r->settings.index_version = 4; + r->settings.index_skip_hash = 1; r->settings.core_untracked_cache = UNTRACKED_CACHE_WRITE; } @@ -61,6 +62,7 @@ void prepare_repo_settings(struct repository *r) repo_cfg_bool(r, "pack.usesparse", &r->settings.pack_use_sparse, 1); 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); /* * The GIT_TEST_MULTI_PACK_INDEX variable is special in that diff --git a/repository.h b/repository.h index 6c461c5..e8c67ff 100644 --- a/repository.h +++ b/repository.h @@ -42,6 +42,7 @@ struct repo_settings { struct fsmonitor_settings *fsmonitor; /* lazily loaded */ int index_version; + int index_skip_hash; enum untracked_cache_setting core_untracked_cache; int pack_use_sparse; @@ -143,6 +143,7 @@ static int set_recommended_config(int reconfigure) { "credential.validate", "false", 1 }, /* GCM4W-only */ { "gc.auto", "0", 1 }, { "gui.GCWarning", "false", 1 }, + { "index.skipHash", "false", 1 }, { "index.threads", "true", 1 }, { "index.version", "4", 1 }, { "merge.stat", "false", 1 }, diff --git a/t/helper/test-bundle-uri.c b/t/helper/test-bundle-uri.c index 5df5bc3..b18e760 100644 --- a/t/helper/test-bundle-uri.c +++ b/t/helper/test-bundle-uri.c @@ -76,8 +76,6 @@ usage: static int cmd_ls_remote(int argc, const char **argv) { - const char *uploadpack = NULL; - struct string_list server_options = STRING_LIST_INIT_DUP; const char *dest; struct remote *remote; struct transport *transport; @@ -95,11 +93,6 @@ static int cmd_ls_remote(int argc, const char **argv) die(_("remote '%s' has no configured URL"), dest); transport = transport_get(remote, NULL); - if (uploadpack) - transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack); - if (server_options.nr) - transport->server_options = &server_options; - if (transport_get_remote_bundle_uri(transport) < 0) { error(_("could not get the bundle-uri list")); status = 1; diff --git a/t/t1091-sparse-checkout-builtin.sh b/t/t1091-sparse-checkout-builtin.sh index b563d6c..627267b 100755 --- a/t/t1091-sparse-checkout-builtin.sh +++ b/t/t1091-sparse-checkout-builtin.sh @@ -238,7 +238,7 @@ test_expect_success 'cone mode: match patterns' ' test_expect_success 'cone mode: warn on bad pattern' ' test_when_finished mv sparse-checkout repo/.git/info/ && cp repo/.git/info/sparse-checkout . && - echo "!/deep/deeper/*" >>repo/.git/info/sparse-checkout && + echo "!/deep/deeper/*/" >>repo/.git/info/sparse-checkout && git -C repo read-tree -mu HEAD 2>err && test_i18ngrep "unrecognized negative pattern" err ' @@ -667,6 +667,15 @@ test_expect_success 'pattern-checks: starting "*"' ' check_read_tree_errors repo "a deep" "disabling cone pattern matching" ' +test_expect_success 'pattern-checks: non directory pattern' ' + cat >repo/.git/info/sparse-checkout <<-\EOF && + /deep/deeper1/a + EOF + check_read_tree_errors repo deep "disabling cone pattern matching" && + check_files repo/deep deeper1 && + check_files repo/deep/deeper1 a +' + test_expect_success 'pattern-checks: contained glob characters' ' for c in "[a]" "\\" "?" "*" do diff --git a/t/t1509-root-work-tree.sh b/t/t1509-root-work-tree.sh index 553a3f6..c799f5b 100755 --- a/t/t1509-root-work-tree.sh +++ b/t/t1509-root-work-tree.sh @@ -221,7 +221,8 @@ test_expect_success 'setup' ' rm -rf /.git && echo "Initialized empty Git repository in /.git/" > expected && git init > result && - test_cmp expected result + test_cmp expected result && + git config --global --add safe.directory / ' test_vars 'auto gitdir, root' ".git" "/" "" @@ -242,7 +243,7 @@ say "auto bare gitdir" # DESTROYYYYY!!!!! test_expect_success 'setup' ' rm -rf /refs /objects /info /hooks && - rm -f /expected /ls.expected /me /result && + rm -f /HEAD /expected /ls.expected /me /result && cd / && echo "Initialized empty Git repository in /" > expected && git init --bare > result && @@ -255,4 +256,9 @@ test_expect_success 'go to /foo' 'cd /foo' test_vars 'auto gitdir, root' "/" "" "" +test_expect_success 'cleanup root' ' + rm -rf /.git /refs /objects /info /hooks /branches /foo && + rm -f /HEAD /config /description /expected /ls.expected /me /result +' + test_done diff --git a/t/t1600-index.sh b/t/t1600-index.sh index 010989f..0ebbae1 100755 --- a/t/t1600-index.sh +++ b/t/t1600-index.sh @@ -65,6 +65,36 @@ test_expect_success 'out of bounds index.version issues warning' ' ) ' +test_expect_success 'index.skipHash config option' ' + rm -f .git/index && + git -c index.skipHash=true add a && + test_trailing_hash .git/index >hash && + echo $(test_oid zero) >expect && + test_cmp expect hash && + git fsck && + + rm -f .git/index && + git -c feature.manyFiles=true add a && + test_trailing_hash .git/index >hash && + cmp expect hash && + + rm -f .git/index && + git -c feature.manyFiles=true \ + -c index.skipHash=false add a && + test_trailing_hash .git/index >hash && + ! cmp expect hash && + + test_commit start && + git -c protocol.file.allow=always submodule add ./ sub && + git config index.skipHash false && + git -C sub config index.skipHash true && + >sub/file && + git -C sub add a && + test_trailing_hash .git/modules/sub/index >hash && + test_cmp expect hash && + git -C sub fsck +' + test_index_version () { INDEX_VERSION_CONFIG=$1 && FEATURE_MANY_FILES=$2 && diff --git a/t/t4045-diff-relative.sh b/t/t4045-diff-relative.sh index 198dfc9..9b46c4c 100755 --- a/t/t4045-diff-relative.sh +++ b/t/t4045-diff-relative.sh @@ -164,6 +164,35 @@ check_diff_relative_option subdir file2 true --no-relative --relative check_diff_relative_option . file2 false --no-relative --relative=subdir check_diff_relative_option . file2 true --no-relative --relative=subdir +test_expect_success 'external diff with --relative' ' + test_when_finished "git reset --hard" && + echo changed >file1 && + echo changed >subdir/file2 && + + write_script mydiff <<-\EOF && + # hacky pretend diff; the goal here is just to make sure we got + # passed sensible input that we _could_ diff, without relying on + # the specific output of a system diff tool. + echo "diff a/$1 b/$1" && + echo "--- a/$1" && + echo "+++ b/$1" && + echo "@@ -1 +0,0 @@" && + sed "s/^/-/" "$2" && + sed "s/^/+/" "$5" + EOF + + cat >expect <<-\EOF && + diff a/file2 b/file2 + --- a/file2 + +++ b/file2 + @@ -1 +0,0 @@ + -other content + +changed + EOF + GIT_EXTERNAL_DIFF=./mydiff git diff --relative=subdir >actual && + test_cmp expect actual +' + test_expect_success 'setup diff --relative unmerged' ' test_commit zero file0 && test_commit base subdir/file0 && diff --git a/t/t4150-am.sh b/t/t4150-am.sh index 7646e85..78cf1c8 100755 --- a/t/t4150-am.sh +++ b/t/t4150-am.sh @@ -345,6 +345,21 @@ test_expect_success 'am with failing applypatch-msg hook' ' test_cmp_rev first HEAD ' +test_expect_success 'am with failing applypatch-msg hook (no verify)' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + test_hook applypatch-msg <<-\EOF && + echo hook-message >"$1" + exit 1 + EOF + git am --no-verify patch1 && + test_path_is_missing .git/rebase-apply && + git diff --exit-code second && + git log -1 --format=format:%B >actual && + test_cmp msg actual +' + test_expect_success 'am with pre-applypatch hook' ' rm -fr .git/rebase-apply && git reset --hard && @@ -374,6 +389,23 @@ test_expect_success 'am with failing pre-applypatch hook' ' test_cmp_rev first HEAD ' +test_expect_success 'am with failing pre-applypatch hook (no verify)' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + touch empty-file && + test_hook pre-applypatch <<-\EOF && + rm empty-file + exit 1 + EOF + git am --no-verify patch1 && + test_path_is_missing .git/rebase-apply && + test_path_is_file empty-file && + git diff --exit-code second && + git log -1 --format=format:%B >actual && + test_cmp msg actual +' + test_expect_success 'am with post-applypatch hook' ' rm -fr .git/rebase-apply && git reset --hard && diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index f036c4d..1b8d434 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -1450,72 +1450,6 @@ test_skip_or_die () { error "$2" } -# The following mingw_* functions obey POSIX shell syntax, but are actually -# bash scripts, and are meant to be used only with bash on Windows. - -# A test_cmp function that treats LF and CRLF equal and avoids to fork -# diff when possible. -mingw_test_cmp () { - # Read text into shell variables and compare them. If the results - # are different, use regular diff to report the difference. - local test_cmp_a= test_cmp_b= - - # When text came from stdin (one argument is '-') we must feed it - # to diff. - local stdin_for_diff= - - # Since it is difficult to detect the difference between an - # empty input file and a failure to read the files, we go straight - # to diff if one of the inputs is empty. - if test -s "$1" && test -s "$2" - then - # regular case: both files non-empty - mingw_read_file_strip_cr_ test_cmp_a <"$1" - mingw_read_file_strip_cr_ test_cmp_b <"$2" - elif test -s "$1" && test "$2" = - - then - # read 2nd file from stdin - mingw_read_file_strip_cr_ test_cmp_a <"$1" - mingw_read_file_strip_cr_ test_cmp_b - stdin_for_diff='<<<"$test_cmp_b"' - elif test "$1" = - && test -s "$2" - then - # read 1st file from stdin - mingw_read_file_strip_cr_ test_cmp_a - mingw_read_file_strip_cr_ test_cmp_b <"$2" - stdin_for_diff='<<<"$test_cmp_a"' - fi - test -n "$test_cmp_a" && - test -n "$test_cmp_b" && - test "$test_cmp_a" = "$test_cmp_b" || - eval "diff -u \"\$@\" $stdin_for_diff" -} - -# $1 is the name of the shell variable to fill in -mingw_read_file_strip_cr_ () { - # Read line-wise using LF as the line separator - # and use IFS to strip CR. - local line - while : - do - if IFS=$'\r' read -r -d $'\n' line - then - # good - line=$line$'\n' - else - # we get here at EOF, but also if the last line - # was not terminated by LF; in the latter case, - # some text was read - if test -z "$line" - then - # EOF, really - break - fi - fi - eval "$1=\$$1\$line" - done -} - # Like "env FOO=BAR some-program", but run inside a subshell, which means # it also works for shell functions (though those functions cannot impact # the environment outside of the test_env invocation). @@ -1882,3 +1816,11 @@ test_cmp_config_output () { sort config-actual >sorted-actual && test_cmp sorted-expect sorted-actual } + +# Given a filename, extract its trailing hash as a hex string +test_trailing_hash () { + local file="$1" && + tail -c $(test_oid rawsz) "$file" | + test-tool hexdump | + sed "s/ //g" +} diff --git a/t/test-lib.sh b/t/test-lib.sh index 6db377f..4fab1c1 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -1721,7 +1721,7 @@ case $uname_s in test_set_prereq SED_STRIPS_CR test_set_prereq GREP_STRIPS_CR test_set_prereq WINDOWS - GIT_TEST_CMP=mingw_test_cmp + GIT_TEST_CMP="GIT_DIR=/dev/null git diff --no-index --ignore-cr-at-eol --" ;; *CYGWIN*) test_set_prereq POSIXPERM |