summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/check-whitespace.yml63
-rw-r--r--.github/workflows/l10n.yml6
-rw-r--r--.github/workflows/main.yml48
-rw-r--r--Documentation/RelNotes/2.40.0.txt14
-rw-r--r--Documentation/config/feature.txt5
-rw-r--r--Documentation/config/index.txt11
-rw-r--r--Documentation/git-am.txt8
-rw-r--r--builtin/am.c11
-rw-r--r--csum-file.c14
-rw-r--r--csum-file.h7
-rw-r--r--diff.c30
-rw-r--r--dir.c7
-rw-r--r--read-cache.c14
-rw-r--r--repo-settings.c2
-rw-r--r--repository.h1
-rw-r--r--scalar.c1
-rw-r--r--t/helper/test-bundle-uri.c7
-rwxr-xr-xt/t1091-sparse-checkout-builtin.sh11
-rwxr-xr-xt/t1509-root-work-tree.sh10
-rwxr-xr-xt/t1600-index.sh30
-rwxr-xr-xt/t4045-diff-relative.sh29
-rwxr-xr-xt/t4150-am.sh32
-rw-r--r--t/test-lib-functions.sh74
-rw-r--r--t/test-lib.sh2
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 */
diff --git a/diff.c b/diff.c
index 9b14543..329eebf 100644
--- a/diff.c
+++ b/diff.c
@@ -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);
diff --git a/dir.c b/dir.c
index fbdb24f..4e99f0c 100644
--- a/dir.c
+++ b/dir.c
@@ -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;
diff --git a/scalar.c b/scalar.c
index 6c52243..b49bb8c 100644
--- a/scalar.c
+++ b/scalar.c
@@ -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