summaryrefslogtreecommitdiff
path: root/t
diff options
context:
space:
mode:
Diffstat (limited to 't')
-rw-r--r--t/README2
-rw-r--r--t/helper/test-drop-caches.c4
-rw-r--r--t/helper/test-read-cache.c64
-rw-r--r--t/helper/test-ref-store.c9
-rwxr-xr-xt/perf/p4002-diff-color-moved.sh57
-rw-r--r--t/perf/perf-lib.sh2
-rwxr-xr-xt/t0001-init.sh2
-rwxr-xr-xt/t1006-cat-file.sh92
-rwxr-xr-xt/t1091-sparse-checkout-builtin.sh62
-rwxr-xr-xt/t1092-sparse-checkout-compatibility.sh132
-rwxr-xr-xt/t1450-fsck.sh4
-rwxr-xr-xt/t2017-checkout-orphan.sh11
-rwxr-xr-xt/t2018-checkout-branch.sh13
-rwxr-xr-xt/t2025-checkout-no-overlay.sh2
-rwxr-xr-xt/t2026-checkout-pathspec-file.sh8
-rwxr-xr-xt/t2027-checkout-track.sh23
-rwxr-xr-xt/t2060-switch.sh28
-rwxr-xr-xt/t2072-restore-pathspec-file.sh6
-rwxr-xr-xt/t2501-cwd-empty.sh277
-rwxr-xr-xt/t3200-branch.sh39
-rwxr-xr-xt/t3400-rebase.sh21
-rwxr-xr-xt/t3431-rebase-fork-point.sh2
-rwxr-xr-xt/t3601-rm-pathspec-file.sh4
-rwxr-xr-xt/t3704-add-pathspec-file.sh10
-rwxr-xr-xt/t3705-add-sparse-checkout.sh8
-rwxr-xr-xt/t3903-stash.sh43
-rwxr-xr-xt/t3909-stash-pathspec-file.sh6
-rwxr-xr-xt/t4015-diff-whitespace.sh205
-rwxr-xr-xt/t4108-apply-threeway.sh18
-rwxr-xr-xt/t4150-am.sh107
-rwxr-xr-xt/t4202-log.sh21
-rwxr-xr-xt/t4204-patch-id.sh29
-rwxr-xr-xt/t4209-log-pickaxe.sh10
-rwxr-xr-xt/t5520-pull.sh13
-rwxr-xr-xt/t5540-http-push-webdav.sh6
-rwxr-xr-xt/t5550-http-fetch-dumb.sh7
-rwxr-xr-xt/t5606-clone-options.sh4
-rwxr-xr-xt/t6200-fmt-merge-msg.sh50
-rwxr-xr-xt/t6418-merge-text-auto.sh26
-rwxr-xr-xt/t7004-tag.sh22
-rwxr-xr-xt/t7107-reset-pathspec-file.sh6
-rwxr-xr-xt/t7201-co.sh17
-rwxr-xr-xt/t7500-commit-template-squash-signoff.sh11
-rwxr-xr-xt/t7510-signed-commit.sh22
-rwxr-xr-xt/t7512-status-help.sh1
-rwxr-xr-xt/t7526-commit-pathspec-file.sh10
-rwxr-xr-xt/t7700-repack.sh13
-rwxr-xr-xt/t7812-grep-icase-non-ascii.sh6
-rwxr-xr-xt/t8007-cat-file-textconv.sh42
-rwxr-xr-xt/t9350-fast-export.sh32
-rwxr-xr-xt/t9810-git-p4-rcs.sh15
-rw-r--r--t/test-lib-functions.sh34
52 files changed, 1468 insertions, 190 deletions
diff --git a/t/README b/t/README
index 2353a4c5e1..f48e0542cd 100644
--- a/t/README
+++ b/t/README
@@ -466,7 +466,7 @@ explicitly providing repositories when accessing submodule objects is
complete or needs to be abandoned for whatever reason (in which case the
migrated codepaths still retain their performance benefits).
-GIT_TEST_REQUIRE_PREREQ=<list> allows specifying a space speparated list of
+GIT_TEST_REQUIRE_PREREQ=<list> allows specifying a space separated list of
prereqs that are required to succeed. If a prereq in this list is triggered by
a test and then fails then the whole test run will abort. This can help to make
sure the expected tests are executed and not silently skipped when their
diff --git a/t/helper/test-drop-caches.c b/t/helper/test-drop-caches.c
index 7b4278462b..e37396dd9c 100644
--- a/t/helper/test-drop-caches.c
+++ b/t/helper/test-drop-caches.c
@@ -3,6 +3,7 @@
#if defined(GIT_WINDOWS_NATIVE)
#include "lazyload.h"
+#include <winnt.h>
static int cmd_sync(void)
{
@@ -86,7 +87,8 @@ static int cmd_dropcaches(void)
{
HANDLE hProcess = GetCurrentProcess();
HANDLE hToken;
- DECLARE_PROC_ADDR(ntdll.dll, DWORD, NtSetSystemInformation, INT, PVOID, ULONG);
+ DECLARE_PROC_ADDR(ntdll.dll, DWORD, NTAPI, NtSetSystemInformation, INT, PVOID,
+ ULONG);
SYSTEM_MEMORY_LIST_COMMAND command;
int status;
diff --git a/t/helper/test-read-cache.c b/t/helper/test-read-cache.c
index 0d9f08931a..b736ef1642 100644
--- a/t/helper/test-read-cache.c
+++ b/t/helper/test-read-cache.c
@@ -1,83 +1,39 @@
#include "test-tool.h"
#include "cache.h"
#include "config.h"
-#include "blob.h"
-#include "commit.h"
-#include "tree.h"
-#include "sparse-index.h"
-
-static void print_cache_entry(struct cache_entry *ce)
-{
- const char *type;
- printf("%06o ", ce->ce_mode & 0177777);
-
- if (S_ISSPARSEDIR(ce->ce_mode))
- type = tree_type;
- else if (S_ISGITLINK(ce->ce_mode))
- type = commit_type;
- else
- type = blob_type;
-
- printf("%s %s\t%s\n",
- type,
- oid_to_hex(&ce->oid),
- ce->name);
-}
-
-static void print_cache(struct index_state *istate)
-{
- int i;
- for (i = 0; i < istate->cache_nr; i++)
- print_cache_entry(istate->cache[i]);
-}
int cmd__read_cache(int argc, const char **argv)
{
- struct repository *r = the_repository;
int i, cnt = 1;
const char *name = NULL;
- int table = 0, expand = 0;
initialize_the_repository();
- for (++argv, --argc; *argv && starts_with(*argv, "--"); ++argv, --argc) {
- if (skip_prefix(*argv, "--print-and-refresh=", &name))
- continue;
- if (!strcmp(*argv, "--table"))
- table = 1;
- else if (!strcmp(*argv, "--expand"))
- expand = 1;
+ if (argc > 1 && skip_prefix(argv[1], "--print-and-refresh=", &name)) {
+ argc--;
+ argv++;
}
- if (argc == 1)
- cnt = strtol(argv[0], NULL, 0);
+ if (argc == 2)
+ cnt = strtol(argv[1], NULL, 0);
setup_git_directory();
git_config(git_default_config, NULL);
- prepare_repo_settings(r);
- r->settings.command_requires_full_index = 0;
-
for (i = 0; i < cnt; i++) {
- repo_read_index(r);
-
- if (expand)
- ensure_full_index(r->index);
-
+ read_cache();
if (name) {
int pos;
- refresh_index(r->index, REFRESH_QUIET,
+ refresh_index(&the_index, REFRESH_QUIET,
NULL, NULL, NULL);
- pos = index_name_pos(r->index, name, strlen(name));
+ pos = index_name_pos(&the_index, name, strlen(name));
if (pos < 0)
die("%s not in index", name);
printf("%s is%s up to date\n", name,
- ce_uptodate(r->index->cache[pos]) ? "" : " not");
+ ce_uptodate(the_index.cache[pos]) ? "" : " not");
write_file(name, "%d\n", i);
}
- if (table)
- print_cache(r->index);
- discard_index(r->index);
+ discard_cache();
}
return 0;
}
diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c
index 24dd4bec08..3e4ddaee70 100644
--- a/t/helper/test-ref-store.c
+++ b/t/helper/test-ref-store.c
@@ -269,7 +269,7 @@ static int cmd_delete_ref(struct ref_store *refs, const char **argv)
struct object_id old_oid;
if (get_oid_hex(sha1_buf, &old_oid))
- die("not sha-1");
+ die("cannot parse %s as %s", sha1_buf, the_hash_algo->name);
return refs_delete_ref(refs, msg, refname, &old_oid, flags);
}
@@ -284,9 +284,10 @@ static int cmd_update_ref(struct ref_store *refs, const char **argv)
struct object_id old_oid;
struct object_id new_oid;
- if (get_oid_hex(old_sha1_buf, &old_oid) ||
- get_oid_hex(new_sha1_buf, &new_oid))
- die("not sha-1");
+ if (get_oid_hex(old_sha1_buf, &old_oid))
+ die("cannot parse %s as %s", old_sha1_buf, the_hash_algo->name);
+ if (get_oid_hex(new_sha1_buf, &new_oid))
+ die("cannot parse %s as %s", new_sha1_buf, the_hash_algo->name);
return refs_update_ref(refs, msg, refname,
&new_oid, &old_oid,
diff --git a/t/perf/p4002-diff-color-moved.sh b/t/perf/p4002-diff-color-moved.sh
new file mode 100755
index 0000000000..ab2af931c0
--- /dev/null
+++ b/t/perf/p4002-diff-color-moved.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+test_description='Tests diff --color-moved performance'
+. ./perf-lib.sh
+
+test_perf_default_repo
+
+# The endpoints of the diff can be customized by setting TEST_REV_A
+# and TEST_REV_B in the environment when running this test.
+
+rev="${TEST_REV_A:-v2.28.0}"
+if ! rev_a="$(git rev-parse --quiet --verify "$rev")"
+then
+ skip_all="skipping because '$rev' was not found. \
+ Use TEST_REV_A and TEST_REV_B to set the revs to use"
+ test_done
+fi
+rev="${TEST_REV_B:-v2.29.0}"
+if ! rev_b="$(git rev-parse --quiet --verify "$rev")"
+then
+ skip_all="skipping because '$rev' was not found. \
+ Use TEST_REV_A and TEST_REV_B to set the revs to use"
+ test_done
+fi
+
+GIT_PAGER_IN_USE=1
+test_export GIT_PAGER_IN_USE rev_a rev_b
+
+test_perf 'diff --no-color-moved --no-color-moved-ws large change' '
+ git diff --no-color-moved --no-color-moved-ws $rev_a $rev_b
+'
+
+test_perf 'diff --color-moved --no-color-moved-ws large change' '
+ git diff --color-moved=zebra --no-color-moved-ws $rev_a $rev_b
+'
+
+test_perf 'diff --color-moved-ws=allow-indentation-change large change' '
+ git diff --color-moved=zebra --color-moved-ws=allow-indentation-change \
+ $rev_a $rev_b
+'
+
+test_perf 'log --no-color-moved --no-color-moved-ws' '
+ git log --no-color-moved --no-color-moved-ws --no-merges --patch \
+ -n1000 $rev_b
+'
+
+test_perf 'log --color-moved --no-color-moved-ws' '
+ git log --color-moved=zebra --no-color-moved-ws --no-merges --patch \
+ -n1000 $rev_b
+'
+
+test_perf 'log --color-moved-ws=allow-indentation-change' '
+ git log --color-moved=zebra --color-moved-ws=allow-indentation-change \
+ --no-merges --patch -n1000 $rev_b
+'
+
+test_done
diff --git a/t/perf/perf-lib.sh b/t/perf/perf-lib.sh
index 780a7402d5..407252bac7 100644
--- a/t/perf/perf-lib.sh
+++ b/t/perf/perf-lib.sh
@@ -161,7 +161,7 @@ test_run_perf_ () {
test_cleanup=:
test_export_="test_cleanup"
export test_cleanup test_export_
- "$GTIME" -f "%E %U %S" -o test_time.$i "$SHELL" -c '
+ "$GTIME" -f "%E %U %S" -o test_time.$i "$TEST_SHELL_PATH" -c '
. '"$TEST_DIRECTORY"/test-lib-functions.sh'
test_export () {
test_export_="$test_export_ $*"
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index 7603ad2f82..3235ab4d53 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -331,7 +331,7 @@ test_expect_success 'init with separate gitdir' '
test_expect_success 'explicit bare & --separate-git-dir incompatible' '
test_must_fail git init --bare --separate-git-dir goop.git bare.git 2>err &&
- test_i18ngrep "mutually exclusive" err
+ test_i18ngrep "cannot be used together" err
'
test_expect_success 'implicit bare & --separate-git-dir incompatible' '
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index 39382fa195..145eee11df 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -4,6 +4,98 @@ test_description='git cat-file'
. ./test-lib.sh
+test_cmdmode_usage () {
+ test_expect_code 129 "$@" 2>err &&
+ grep "^error:.*is incompatible with" err
+}
+
+for switches in \
+ '-e -p' \
+ '-p -t' \
+ '-t -s' \
+ '-s --textconv' \
+ '--textconv --filters' \
+ '--batch-all-objects -e'
+do
+ test_expect_success "usage: cmdmode $switches" '
+ test_cmdmode_usage git cat-file $switches
+ '
+done
+
+test_incompatible_usage () {
+ test_expect_code 129 "$@" 2>err &&
+ grep -E "^(fatal|error):.*(requires|incompatible with|needs)" err
+}
+
+for opt in --batch --batch-check
+do
+ test_expect_success "usage: incompatible options: --path with $opt" '
+ test_incompatible_usage git cat-file --path=foo $opt
+ '
+done
+
+test_missing_usage () {
+ test_expect_code 129 "$@" 2>err &&
+ grep -E "^fatal:.*required" err
+}
+
+short_modes="-e -p -t -s"
+cw_modes="--textconv --filters"
+
+for opt in $cw_modes
+do
+ test_expect_success "usage: $opt requires another option" '
+ test_missing_usage git cat-file $opt
+ '
+done
+
+for opt in $short_modes
+do
+ test_expect_success "usage: $opt requires another option" '
+ test_missing_usage git cat-file $opt
+ '
+
+ for opt2 in --batch \
+ --batch-check \
+ --follow-symlinks \
+ "--path=foo HEAD:some-path.txt"
+ do
+ test_expect_success "usage: incompatible options: $opt and $opt2" '
+ test_incompatible_usage git cat-file $opt $opt2
+ '
+ done
+done
+
+test_too_many_arguments () {
+ test_expect_code 129 "$@" 2>err &&
+ grep -E "^fatal: too many arguments$" err
+}
+
+for opt in $short_modes $cw_modes
+do
+ args="one two three"
+ test_expect_success "usage: too many arguments: $opt $args" '
+ test_too_many_arguments git cat-file $opt $args
+ '
+
+ for opt2 in --buffer --follow-symlinks
+ do
+ test_expect_success "usage: incompatible arguments: $opt with batch option $opt2" '
+ test_incompatible_usage git cat-file $opt $opt2
+ '
+ done
+done
+
+for opt in --buffer \
+ --follow-symlinks \
+ --batch-all-objects
+do
+ test_expect_success "usage: bad option combination: $opt without batch mode" '
+ test_incompatible_usage git cat-file $opt &&
+ test_incompatible_usage git cat-file $opt commit HEAD
+ '
+done
+
echo_without_newline () {
printf '%s' "$*"
}
diff --git a/t/t1091-sparse-checkout-builtin.sh b/t/t1091-sparse-checkout-builtin.sh
index 833fcadd5c..42776984fe 100755
--- a/t/t1091-sparse-checkout-builtin.sh
+++ b/t/t1091-sparse-checkout-builtin.sh
@@ -111,6 +111,18 @@ test_expect_success 'clone --sparse' '
check_files clone a
'
+test_expect_success 'switching to cone mode with non-cone mode patterns' '
+ git init bad-patterns &&
+ (
+ cd bad-patterns &&
+ git sparse-checkout init &&
+ git sparse-checkout add dir &&
+ git config core.sparseCheckoutCone true &&
+ test_must_fail git sparse-checkout add dir 2>err &&
+ grep "existing sparse-checkout patterns do not use cone mode" err
+ )
+'
+
test_expect_success 'interaction with clone --no-checkout (unborn index)' '
git clone --no-checkout "file://$(pwd)/repo" clone_no_checkout &&
git -C clone_no_checkout sparse-checkout init --cone &&
@@ -173,12 +185,14 @@ test_expect_success 'set sparse-checkout using --stdin' '
'
test_expect_success 'add to sparse-checkout' '
- cat repo/.git/info/sparse-checkout >expect &&
+ cat repo/.git/info/sparse-checkout >old &&
+ test_when_finished cp old repo/.git/info/sparse-checkout &&
cat >add <<-\EOF &&
pattern1
/folder1/
pattern2
EOF
+ cat old >expect &&
cat add >>expect &&
git -C repo sparse-checkout add --stdin <add &&
git -C repo sparse-checkout list >actual &&
@@ -220,12 +234,27 @@ test_expect_success 'sparse-index enabled and disabled' '
git -C repo sparse-checkout init --cone --sparse-index &&
test_cmp_config -C repo true index.sparse &&
- test-tool -C repo read-cache --table >cache &&
- grep " tree " cache &&
-
+ git -C repo ls-files --sparse >sparse &&
git -C repo sparse-checkout disable &&
- test-tool -C repo read-cache --table >cache &&
- ! grep " tree " cache &&
+ git -C repo ls-files --sparse >full &&
+
+ cat >expect <<-\EOF &&
+ @@ -1,4 +1,7 @@
+ a
+ -deep/
+ -folder1/
+ -folder2/
+ +deep/a
+ +deep/deeper1/a
+ +deep/deeper1/deepest/a
+ +deep/deeper2/a
+ +folder1/a
+ +folder2/a
+ EOF
+
+ diff -u sparse full | tail -n +3 >actual &&
+ test_cmp expect actual &&
+
git -C repo config --list >config &&
! grep index.sparse config
)
@@ -716,4 +745,25 @@ test_expect_success 'cone mode clears ignored subdirectories' '
test_cmp expect out
'
+test_expect_success 'malformed cone-mode patterns' '
+ git -C repo sparse-checkout init --cone &&
+ mkdir -p repo/foo/bar &&
+ touch repo/foo/bar/x repo/foo/y &&
+ cat >repo/.git/info/sparse-checkout <<-\EOF &&
+ /*
+ !/*/
+ /foo/
+ !/foo/*/
+ /foo/\*/
+ EOF
+
+ # Listing the patterns will notice the duplicate pattern and
+ # emit a warning. It will list the patterns directly instead
+ # of using the cone-mode translation to a set of directories.
+ git -C repo sparse-checkout list >actual 2>err &&
+ test_cmp repo/.git/info/sparse-checkout actual &&
+ grep "warning: your sparse-checkout file may have issues: pattern .* is repeated" err &&
+ grep "warning: disabling cone pattern matching" err
+'
+
test_done
diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh
index 49f70a6569..4ba1617752 100755
--- a/t/t1092-sparse-checkout-compatibility.sh
+++ b/t/t1092-sparse-checkout-compatibility.sh
@@ -206,45 +206,42 @@ test_sparse_unstaged () {
test_expect_success 'sparse-index contents' '
init_repos &&
- test-tool -C sparse-index read-cache --table >cache &&
+ git -C sparse-index ls-files --sparse --stage >cache &&
for dir in folder1 folder2 x
do
TREE=$(git -C sparse-index rev-parse HEAD:$dir) &&
- grep "040000 tree $TREE $dir/" cache \
+ grep "040000 $TREE 0 $dir/" cache \
|| return 1
done &&
git -C sparse-index sparse-checkout set folder1 &&
- test-tool -C sparse-index read-cache --table >cache &&
+ git -C sparse-index ls-files --sparse --stage >cache &&
for dir in deep folder2 x
do
TREE=$(git -C sparse-index rev-parse HEAD:$dir) &&
- grep "040000 tree $TREE $dir/" cache \
+ grep "040000 $TREE 0 $dir/" cache \
|| return 1
done &&
git -C sparse-index sparse-checkout set deep/deeper1 &&
- test-tool -C sparse-index read-cache --table >cache &&
+ git -C sparse-index ls-files --sparse --stage >cache &&
for dir in deep/deeper2 folder1 folder2 x
do
TREE=$(git -C sparse-index rev-parse HEAD:$dir) &&
- grep "040000 tree $TREE $dir/" cache \
+ grep "040000 $TREE 0 $dir/" cache \
|| return 1
done &&
- # Disabling the sparse-index removes tree entries with full ones
+ # Disabling the sparse-index replaces tree entries with full ones
git -C sparse-index sparse-checkout init --no-sparse-index &&
-
- test-tool -C sparse-index read-cache --table >cache &&
- ! grep "040000 tree" cache &&
- test_sparse_match test-tool read-cache --table
+ test_sparse_match git ls-files --stage --sparse
'
test_expect_success 'expanded in-memory index matches full index' '
init_repos &&
- test_sparse_match test-tool read-cache --expand --table
+ test_sparse_match git ls-files --stage
'
test_expect_success 'status with options' '
@@ -801,9 +798,9 @@ test_expect_success 'submodule handling' '
# having a submodule prevents "modules" from collapse
test_sparse_match git sparse-checkout set deep/deeper1 &&
- test-tool -C sparse-index read-cache --table >cache &&
- grep "100644 blob .* modules/a" cache &&
- grep "160000 commit $(git -C initial-repo rev-parse HEAD) modules/sub" cache
+ git -C sparse-index ls-files --sparse --stage >cache &&
+ grep "100644 .* modules/a" cache &&
+ grep "160000 $(git -C initial-repo rev-parse HEAD) 0 modules/sub" cache
'
# When working with a sparse index, some commands will need to expand the
@@ -816,6 +813,12 @@ test_expect_success 'sparse-index is expanded and converted back' '
GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
git -C sparse-index reset -- folder1/a &&
test_region index convert_to_sparse trace2.txt &&
+ test_region index ensure_full_index trace2.txt &&
+
+ # ls-files expands on read, but does not write.
+ rm trace2.txt &&
+ GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \
+ git -C sparse-index ls-files &&
test_region index ensure_full_index trace2.txt
'
@@ -871,6 +874,7 @@ test_expect_success 'sparse-index is not expanded' '
init_repos &&
ensure_not_expanded status &&
+ ensure_not_expanded ls-files --sparse &&
ensure_not_expanded commit --allow-empty -m empty &&
echo >>sparse-index/a &&
ensure_not_expanded commit -a -m a &&
@@ -1009,6 +1013,100 @@ test_expect_success 'sparse index is not expanded: blame' '
done
'
+test_expect_success 'sparse index is not expanded: fetch/pull' '
+ init_repos &&
+
+ git -C sparse-index remote add full "file://$(pwd)/full-checkout" &&
+ ensure_not_expanded fetch full &&
+ git -C full-checkout commit --allow-empty -m "for pull merge" &&
+ git -C sparse-index commit --allow-empty -m "for pull merge" &&
+ ensure_not_expanded pull full base
+'
+
+test_expect_success 'ls-files' '
+ init_repos &&
+
+ # Use a smaller sparse-checkout for reduced output
+ test_sparse_match git sparse-checkout set &&
+
+ # Behavior agrees by default. Sparse index is expanded.
+ test_all_match git ls-files &&
+
+ # With --sparse, the sparse index data changes behavior.
+ git -C sparse-index ls-files --sparse >actual &&
+
+ cat >expect <<-\EOF &&
+ a
+ deep/
+ e
+ folder1-
+ folder1.x
+ folder1/
+ folder10
+ folder2/
+ g
+ x/
+ z
+ EOF
+
+ test_cmp expect actual &&
+
+ # With --sparse and no sparse index, nothing changes.
+ git -C sparse-checkout ls-files >dense &&
+ git -C sparse-checkout ls-files --sparse >sparse &&
+ test_cmp dense sparse &&
+
+ # Set up a strange condition of having a file edit
+ # outside of the sparse-checkout cone. This is just
+ # to verify that sparse-checkout and sparse-index
+ # behave the same in this case.
+ write_script edit-content <<-\EOF &&
+ mkdir folder1 &&
+ echo content >>folder1/a
+ EOF
+ run_on_sparse ../edit-content &&
+
+ # ls-files does not currently notice modified files whose
+ # cache entries are marked SKIP_WORKTREE. This may change
+ # in the future, but here we test that sparse index does
+ # not accidentally create a change of behavior.
+ test_sparse_match git ls-files --modified &&
+ test_must_be_empty sparse-checkout-out &&
+ test_must_be_empty sparse-index-out &&
+
+ git -C sparse-index ls-files --sparse --modified >sparse-index-out &&
+ test_must_be_empty sparse-index-out &&
+
+ # Add folder1 to the sparse-checkout cone and
+ # check that ls-files shows the expanded files.
+ test_sparse_match git sparse-checkout add folder1 &&
+ test_sparse_match git ls-files --modified &&
+
+ test_all_match git ls-files &&
+ git -C sparse-index ls-files --sparse >actual &&
+
+ cat >expect <<-\EOF &&
+ a
+ deep/
+ e
+ folder1-
+ folder1.x
+ folder1/0/0/0
+ folder1/0/1
+ folder1/a
+ folder10
+ folder2/
+ g
+ x/
+ z
+ EOF
+
+ test_cmp expect actual &&
+
+ # Double-check index expansion is avoided
+ ensure_not_expanded ls-files --sparse
+'
+
# NEEDSWORK: a sparse-checkout behaves differently from a full checkout
# in this scenario, but it shouldn't.
test_expect_success 'reset mixed and checkout orphan' '
@@ -1024,13 +1122,13 @@ test_expect_success 'reset mixed and checkout orphan' '
# the sparse checkouts skip "adding" the other side of
# the conflict.
test_sparse_match git reset --mixed HEAD~1 &&
- test_sparse_match test-tool read-cache --table --expand &&
+ test_sparse_match git ls-files --stage &&
test_sparse_match git status --porcelain=v2 &&
# At this point, sparse-checkouts behave differently
# from the full-checkout.
test_sparse_match git checkout --orphan new-branch &&
- test_sparse_match test-tool read-cache --table --expand &&
+ test_sparse_match git ls-files --stage &&
test_sparse_match git status --porcelain=v2
'
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 6337236fd8..de50c0ea01 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -94,13 +94,13 @@ test_expect_success 'object with hash and type mismatch' '
)
'
-test_expect_success POSIXPERM 'zlib corrupt loose object output ' '
+test_expect_success 'zlib corrupt loose object output ' '
git init --bare corrupt-loose-output &&
(
cd corrupt-loose-output &&
oid=$(git hash-object -w --stdin --literally </dev/null) &&
oidf=objects/$(test_oid_to_path "$oid") &&
- chmod 755 $oidf &&
+ chmod +w $oidf &&
echo extra garbage >>$oidf &&
cat >expect.error <<-EOF &&
diff --git a/t/t2017-checkout-orphan.sh b/t/t2017-checkout-orphan.sh
index f3371e2646..947d1587ac 100755
--- a/t/t2017-checkout-orphan.sh
+++ b/t/t2017-checkout-orphan.sh
@@ -63,8 +63,17 @@ test_expect_success '--orphan ignores branch.autosetupmerge' '
git checkout main &&
git config branch.autosetupmerge always &&
git checkout --orphan gamma &&
- test -z "$(git config branch.gamma.merge)" &&
+ test_cmp_config "" --default "" branch.gamma.merge &&
test refs/heads/gamma = "$(git symbolic-ref HEAD)" &&
+ test_must_fail git rev-parse --verify HEAD^ &&
+ git checkout main &&
+ git config branch.autosetupmerge inherit &&
+ git checkout --orphan eta &&
+ test_cmp_config "" --default "" branch.eta.merge &&
+ test_cmp_config "" --default "" branch.eta.remote &&
+ echo refs/heads/eta >expected &&
+ git symbolic-ref HEAD >actual &&
+ test_cmp expected actual &&
test_must_fail git rev-parse --verify HEAD^
'
diff --git a/t/t2018-checkout-branch.sh b/t/t2018-checkout-branch.sh
index 3e93506c04..52e51b0726 100755
--- a/t/t2018-checkout-branch.sh
+++ b/t/t2018-checkout-branch.sh
@@ -85,6 +85,19 @@ test_expect_success 'setup' '
git branch -m branch1
'
+test_expect_success 'checkout a branch without refs/heads/* prefix' '
+ git clone --no-tags . repo-odd-prefix &&
+ (
+ cd repo-odd-prefix &&
+
+ origin=$(git symbolic-ref refs/remotes/origin/HEAD) &&
+ git symbolic-ref refs/heads/a-branch "$origin" &&
+
+ git checkout -f a-branch &&
+ git checkout -f a-branch
+ )
+'
+
test_expect_success 'checkout -b to a new branch, set to HEAD' '
test_when_finished "
git checkout branch1 &&
diff --git a/t/t2025-checkout-no-overlay.sh b/t/t2025-checkout-no-overlay.sh
index fa9e098706..8f13341cf8 100755
--- a/t/t2025-checkout-no-overlay.sh
+++ b/t/t2025-checkout-no-overlay.sh
@@ -25,7 +25,7 @@ test_expect_success 'checkout --no-overlay removing last file from directory' '
test_expect_success 'checkout -p --overlay is disallowed' '
test_must_fail git checkout -p --overlay HEAD 2>actual &&
- test_i18ngrep "fatal: -p and --overlay are mutually exclusive" actual
+ test_i18ngrep "fatal: options .-p. and .--overlay. cannot be used together" actual
'
test_expect_success '--no-overlay --theirs with D/F conflict deletes file' '
diff --git a/t/t2026-checkout-pathspec-file.sh b/t/t2026-checkout-pathspec-file.sh
index 9db11f86dd..9c651aefbc 100755
--- a/t/t2026-checkout-pathspec-file.sh
+++ b/t/t2026-checkout-pathspec-file.sh
@@ -149,16 +149,16 @@ test_expect_success 'error conditions' '
echo fileA.t >list &&
test_must_fail git checkout --pathspec-from-file=list --detach 2>err &&
- test_i18ngrep -e "--pathspec-from-file is incompatible with --detach" err &&
+ test_i18ngrep -e "options .--pathspec-from-file. and .--detach. cannot be used together" err &&
test_must_fail git checkout --pathspec-from-file=list --patch 2>err &&
- test_i18ngrep -e "--pathspec-from-file is incompatible with --patch" err &&
+ test_i18ngrep -e "options .--pathspec-from-file. and .--patch. cannot be used together" err &&
test_must_fail git checkout --pathspec-from-file=list -- fileA.t 2>err &&
- test_i18ngrep -e "--pathspec-from-file is incompatible with pathspec arguments" err &&
+ test_i18ngrep -e ".--pathspec-from-file. and pathspec arguments cannot be used together" err &&
test_must_fail git checkout --pathspec-file-nul 2>err &&
- test_i18ngrep -e "--pathspec-file-nul requires --pathspec-from-file" err
+ test_i18ngrep -e "the option .--pathspec-file-nul. requires .--pathspec-from-file." err
'
test_done
diff --git a/t/t2027-checkout-track.sh b/t/t2027-checkout-track.sh
index 4453741b96..dca35aa3e3 100755
--- a/t/t2027-checkout-track.sh
+++ b/t/t2027-checkout-track.sh
@@ -24,4 +24,27 @@ test_expect_success 'checkout --track -b rejects an extra path argument' '
test_i18ngrep "cannot be used with updating paths" err
'
+test_expect_success 'checkout --track -b overrides autoSetupMerge=inherit' '
+ # Set up tracking config on main
+ test_config branch.main.remote origin &&
+ test_config branch.main.merge refs/heads/some-branch &&
+ test_config branch.autoSetupMerge inherit &&
+ # With --track=inherit, we copy the tracking config from main
+ git checkout --track=inherit -b b1 main &&
+ test_cmp_config origin branch.b1.remote &&
+ test_cmp_config refs/heads/some-branch branch.b1.merge &&
+ # With branch.autoSetupMerge=inherit, we do the same
+ git checkout -b b2 main &&
+ test_cmp_config origin branch.b2.remote &&
+ test_cmp_config refs/heads/some-branch branch.b2.merge &&
+ # But --track overrides this
+ git checkout --track -b b3 main &&
+ test_cmp_config . branch.b3.remote &&
+ test_cmp_config refs/heads/main branch.b3.merge &&
+ # And --track=direct does as well
+ git checkout --track=direct -b b4 main &&
+ test_cmp_config . branch.b4.remote &&
+ test_cmp_config refs/heads/main branch.b4.merge
+'
+
test_done
diff --git a/t/t2060-switch.sh b/t/t2060-switch.sh
index 9bc6a3aa5c..ebb961be29 100755
--- a/t/t2060-switch.sh
+++ b/t/t2060-switch.sh
@@ -107,4 +107,32 @@ test_expect_success 'not switching when something is in progress' '
test_must_fail git switch -d @^
'
+test_expect_success 'tracking info copied with autoSetupMerge=inherit' '
+ # default config does not copy tracking info
+ git switch -c foo-no-inherit foo &&
+ test_cmp_config "" --default "" branch.foo-no-inherit.remote &&
+ test_cmp_config "" --default "" branch.foo-no-inherit.merge &&
+ # with --track=inherit, we copy tracking info from foo
+ git switch --track=inherit -c foo2 foo &&
+ test_cmp_config origin branch.foo2.remote &&
+ test_cmp_config refs/heads/foo branch.foo2.merge &&
+ # with autoSetupMerge=inherit, we do the same
+ test_config branch.autoSetupMerge inherit &&
+ git switch -c foo3 foo &&
+ test_cmp_config origin branch.foo3.remote &&
+ test_cmp_config refs/heads/foo branch.foo3.merge &&
+ # with --track, we override autoSetupMerge
+ git switch --track -c foo4 foo &&
+ test_cmp_config . branch.foo4.remote &&
+ test_cmp_config refs/heads/foo branch.foo4.merge &&
+ # and --track=direct does as well
+ git switch --track=direct -c foo5 foo &&
+ test_cmp_config . branch.foo5.remote &&
+ test_cmp_config refs/heads/foo branch.foo5.merge &&
+ # no tracking info to inherit from main
+ git switch -c main2 main &&
+ test_cmp_config "" --default "" branch.main2.remote &&
+ test_cmp_config "" --default "" branch.main2.merge
+'
+
test_done
diff --git a/t/t2072-restore-pathspec-file.sh b/t/t2072-restore-pathspec-file.sh
index b48345bf95..c22669b39f 100755
--- a/t/t2072-restore-pathspec-file.sh
+++ b/t/t2072-restore-pathspec-file.sh
@@ -152,13 +152,13 @@ test_expect_success 'error conditions' '
>empty_list &&
test_must_fail git restore --pathspec-from-file=list --patch --source=HEAD^1 2>err &&
- test_i18ngrep -e "--pathspec-from-file is incompatible with --patch" err &&
+ test_i18ngrep -e "options .--pathspec-from-file. and .--patch. cannot be used together" err &&
test_must_fail git restore --pathspec-from-file=list --source=HEAD^1 -- fileA.t 2>err &&
- test_i18ngrep -e "--pathspec-from-file is incompatible with pathspec arguments" err &&
+ test_i18ngrep -e ".--pathspec-from-file. and pathspec arguments cannot be used together" err &&
test_must_fail git restore --pathspec-file-nul --source=HEAD^1 2>err &&
- test_i18ngrep -e "--pathspec-file-nul requires --pathspec-from-file" err &&
+ test_i18ngrep -e "the option .--pathspec-file-nul. requires .--pathspec-from-file." err &&
test_must_fail git restore --pathspec-from-file=empty_list --source=HEAD^1 2>err &&
test_i18ngrep -e "you must specify path(s) to restore" err
diff --git a/t/t2501-cwd-empty.sh b/t/t2501-cwd-empty.sh
new file mode 100755
index 0000000000..f6d8d7d03d
--- /dev/null
+++ b/t/t2501-cwd-empty.sh
@@ -0,0 +1,277 @@
+#!/bin/sh
+
+test_description='Test handling of the current working directory becoming empty'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+ test_commit init &&
+
+ git branch fd_conflict &&
+
+ mkdir -p foo/bar &&
+ test_commit foo/bar/baz &&
+
+ git revert HEAD &&
+ git tag reverted &&
+
+ git checkout fd_conflict &&
+ mkdir dirORfile &&
+ test_commit dirORfile/foo &&
+
+ git rm -r dirORfile &&
+ echo not-a-directory >dirORfile &&
+ git add dirORfile &&
+ git commit -m dirORfile &&
+
+ git switch -c df_conflict HEAD~1 &&
+ test_commit random_file &&
+
+ git switch -c undo_fd_conflict fd_conflict &&
+ git revert HEAD
+'
+
+test_incidental_dir_removal () {
+ test_when_finished "git reset --hard" &&
+
+ git checkout foo/bar/baz^{commit} &&
+ test_path_is_dir foo/bar &&
+
+ (
+ cd foo &&
+ "$@" &&
+
+ # Make sure foo still exists, and commands needing it work
+ test-tool getcwd &&
+ git status --porcelain
+ ) &&
+ test_path_is_missing foo/bar/baz &&
+ test_path_is_missing foo/bar &&
+
+ test_path_is_dir foo
+}
+
+test_required_dir_removal () {
+ git checkout df_conflict^{commit} &&
+ test_when_finished "git clean -fdx" &&
+
+ (
+ cd dirORfile &&
+
+ # Ensure command refuses to run
+ test_must_fail "$@" 2>../error &&
+ grep "Refusing to remove.*current working directory" ../error &&
+
+ # ...and that the index and working tree are left clean
+ git diff --exit-code HEAD &&
+
+ # Ensure that getcwd and git status do not error out (which
+ # they might if the current working directory had been removed)
+ test-tool getcwd &&
+ git status --porcelain
+ ) &&
+
+ test_path_is_dir dirORfile
+}
+
+test_expect_success 'checkout does not clean cwd incidentally' '
+ test_incidental_dir_removal git checkout init
+'
+
+test_expect_success 'checkout fails if cwd needs to be removed' '
+ test_required_dir_removal git checkout fd_conflict
+'
+
+test_expect_success 'reset --hard does not clean cwd incidentally' '
+ test_incidental_dir_removal git reset --hard init
+'
+
+test_expect_success 'reset --hard fails if cwd needs to be removed' '
+ test_required_dir_removal git reset --hard fd_conflict
+'
+
+test_expect_success 'merge does not clean cwd incidentally' '
+ test_incidental_dir_removal git merge reverted
+'
+
+# This file uses some simple merges where
+# Base: 'dirORfile/' exists
+# Side1: random other file changed
+# Side2: 'dirORfile/' removed, 'dirORfile' added
+# this should resolve cleanly, but merge-recursive throws merge conflicts
+# because it's dumb. Add a special test for checking merge-recursive (and
+# merge-ort), then after this just hard require ort for all remaining tests.
+#
+test_expect_success 'merge fails if cwd needs to be removed; recursive friendly' '
+ git checkout foo/bar/baz &&
+ test_when_finished "git clean -fdx" &&
+
+ mkdir dirORfile &&
+ (
+ cd dirORfile &&
+
+ test_must_fail git merge fd_conflict 2>../error
+ ) &&
+
+ test_path_is_dir dirORfile &&
+ grep "Refusing to remove the current working directory" error
+'
+
+GIT_TEST_MERGE_ALGORITHM=ort
+
+test_expect_success 'merge fails if cwd needs to be removed' '
+ test_required_dir_removal git merge fd_conflict
+'
+
+test_expect_success 'cherry-pick does not clean cwd incidentally' '
+ test_incidental_dir_removal git cherry-pick reverted
+'
+
+test_expect_success 'cherry-pick fails if cwd needs to be removed' '
+ test_required_dir_removal git cherry-pick fd_conflict
+'
+
+test_expect_success 'rebase does not clean cwd incidentally' '
+ test_incidental_dir_removal git rebase reverted
+'
+
+test_expect_success 'rebase fails if cwd needs to be removed' '
+ test_required_dir_removal git rebase fd_conflict
+'
+
+test_expect_success 'revert does not clean cwd incidentally' '
+ test_incidental_dir_removal git revert HEAD
+'
+
+test_expect_success 'revert fails if cwd needs to be removed' '
+ test_required_dir_removal git revert undo_fd_conflict
+'
+
+test_expect_success 'rm does not clean cwd incidentally' '
+ test_incidental_dir_removal git rm bar/baz.t
+'
+
+test_expect_success 'apply does not remove cwd incidentally' '
+ git diff HEAD HEAD~1 >patch &&
+ test_incidental_dir_removal git apply ../patch
+'
+
+test_incidental_untracked_dir_removal () {
+ test_when_finished "git reset --hard" &&
+
+ git checkout foo/bar/baz^{commit} &&
+ mkdir -p untracked &&
+ mkdir empty
+ >untracked/random &&
+
+ (
+ cd untracked &&
+ "$@" &&
+
+ # Make sure untracked still exists, and commands needing it work
+ test-tool getcwd &&
+ git status --porcelain
+ ) &&
+ test_path_is_missing empty &&
+ test_path_is_missing untracked/random &&
+
+ test_path_is_dir untracked
+}
+
+test_expect_success 'clean does not remove cwd incidentally' '
+ test_incidental_untracked_dir_removal \
+ git -C .. clean -fd -e warnings . >warnings &&
+ grep "Refusing to remove current working directory" warnings
+'
+
+test_expect_success 'stash does not remove cwd incidentally' '
+ test_incidental_untracked_dir_removal \
+ git stash --include-untracked
+'
+
+test_expect_success '`rm -rf dir` only removes a subset of dir' '
+ test_when_finished "rm -rf a/" &&
+
+ mkdir -p a/b/c &&
+ >a/b/c/untracked &&
+ >a/b/c/tracked &&
+ git add a/b/c/tracked &&
+
+ (
+ cd a/b &&
+ git rm -rf ../b
+ ) &&
+
+ test_path_is_dir a/b &&
+ test_path_is_missing a/b/c/tracked &&
+ test_path_is_file a/b/c/untracked
+'
+
+test_expect_success '`rm -rf dir` even with only tracked files will remove something else' '
+ test_when_finished "rm -rf a/" &&
+
+ mkdir -p a/b/c &&
+ >a/b/c/tracked &&
+ git add a/b/c/tracked &&
+
+ (
+ cd a/b &&
+ git rm -rf ../b
+ ) &&
+
+ test_path_is_missing a/b/c/tracked &&
+ test_path_is_missing a/b/c &&
+ test_path_is_dir a/b
+'
+
+test_expect_success 'git version continues working from a deleted dir' '
+ mkdir tmp &&
+ (
+ cd tmp &&
+ rm -rf ../tmp &&
+ git version
+ )
+'
+
+test_submodule_removal () {
+ path_status=$1 &&
+ shift &&
+
+ test_status=
+ test "$path_status" = dir && test_status=test_must_fail
+
+ test_when_finished "git reset --hard HEAD~1" &&
+ test_when_finished "rm -rf .git/modules/my_submodule" &&
+
+ git checkout foo/bar/baz &&
+
+ git init my_submodule &&
+ touch my_submodule/file &&
+ git -C my_submodule add file &&
+ git -C my_submodule commit -m "initial commit" &&
+ git submodule add ./my_submodule &&
+ git commit -m "Add the submodule" &&
+
+ (
+ cd my_submodule &&
+ $test_status "$@"
+ ) &&
+
+ test_path_is_${path_status} my_submodule
+}
+
+test_expect_success 'rm -r with -C leaves submodule if cwd inside' '
+ test_submodule_removal dir git -C .. rm -r my_submodule/
+'
+
+test_expect_success 'rm -r leaves submodule if cwd inside' '
+ test_submodule_removal dir \
+ git --git-dir=../.git --work-tree=.. rm -r ../my_submodule/
+'
+
+test_expect_success 'rm -rf removes submodule even if cwd inside' '
+ test_submodule_removal missing \
+ git --git-dir=../.git --work-tree=.. rm -rf ../my_submodule/
+'
+
+test_done
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 8a619d785e..1bc3795847 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -979,15 +979,15 @@ test_expect_success 'disabled option --set-upstream fails' '
test_must_fail git branch --set-upstream origin/main
'
-test_expect_success '--set-upstream-to notices an error to set branch as own upstream' '
+test_expect_success '--set-upstream-to notices an error to set branch as own upstream' "
git branch --set-upstream-to refs/heads/my13 my13 2>actual &&
cat >expect <<-\EOF &&
- warning: not setting branch my13 as its own upstream
+ warning: not setting branch 'my13' as its own upstream
EOF
test_expect_code 1 git config branch.my13.remote &&
test_expect_code 1 git config branch.my13.merge &&
test_cmp expect actual
-'
+"
# Keep this test last, as it changes the current branch
cat >expect <<EOF
@@ -1461,4 +1461,37 @@ test_expect_success 'invalid sort parameter in configuration' '
)
'
+test_expect_success 'tracking info copied with --track=inherit' '
+ git branch --track=inherit foo2 my1 &&
+ test_cmp_config local branch.foo2.remote &&
+ test_cmp_config refs/heads/main branch.foo2.merge
+'
+
+test_expect_success 'tracking info copied with autoSetupMerge=inherit' '
+ test_unconfig branch.autoSetupMerge &&
+ # default config does not copy tracking info
+ git branch foo-no-inherit my1 &&
+ test_cmp_config "" --default "" branch.foo-no-inherit.remote &&
+ test_cmp_config "" --default "" branch.foo-no-inherit.merge &&
+ # with autoSetupMerge=inherit, we copy tracking info from my1
+ test_config branch.autoSetupMerge inherit &&
+ git branch foo3 my1 &&
+ test_cmp_config local branch.foo3.remote &&
+ test_cmp_config refs/heads/main branch.foo3.merge &&
+ # no tracking info to inherit from main
+ git branch main2 main &&
+ test_cmp_config "" --default "" branch.main2.remote &&
+ test_cmp_config "" --default "" branch.main2.merge
+'
+
+test_expect_success '--track overrides branch.autoSetupMerge' '
+ test_config branch.autoSetupMerge inherit &&
+ git branch --track=direct foo4 my1 &&
+ test_cmp_config . branch.foo4.remote &&
+ test_cmp_config refs/heads/my1 branch.foo4.merge &&
+ git branch --no-track foo5 my1 &&
+ test_cmp_config "" --default "" branch.foo5.remote &&
+ test_cmp_config "" --default "" branch.foo5.merge
+'
+
test_done
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 23dbd3c82e..71b1735e1d 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -416,4 +416,25 @@ test_expect_success MINGW,SYMLINKS_WINDOWS 'rebase when .git/logs is a symlink'
mv actual_logs .git/logs
'
+test_expect_success 'rebase when inside worktree subdirectory' '
+ git init main-wt &&
+ (
+ cd main-wt &&
+ git commit --allow-empty -m "initial" &&
+ mkdir -p foo/bar &&
+ test_commit foo/bar/baz &&
+ mkdir -p a/b &&
+ test_commit a/b/c &&
+ # create another branch for our other worktree
+ git branch other &&
+ git worktree add ../other-wt other &&
+ cd ../other-wt &&
+ # create and cd into a subdirectory
+ mkdir -p random/dir &&
+ cd random/dir &&
+ # now do the rebase
+ git rebase --onto HEAD^^ HEAD^ # drops the HEAD^ commit
+ )
+'
+
test_done
diff --git a/t/t3431-rebase-fork-point.sh b/t/t3431-rebase-fork-point.sh
index 4c98d99e7e..1d0b15380e 100755
--- a/t/t3431-rebase-fork-point.sh
+++ b/t/t3431-rebase-fork-point.sh
@@ -83,7 +83,7 @@ test_expect_success 'git rebase --fork-point with ambigous refname' '
test_expect_success '--fork-point and --root both given' '
test_must_fail git rebase --fork-point --root 2>err &&
- test_i18ngrep "cannot combine" err
+ test_i18ngrep "cannot be used together" err
'
test_expect_success 'rebase.forkPoint set to false' '
diff --git a/t/t3601-rm-pathspec-file.sh b/t/t3601-rm-pathspec-file.sh
index b2a8db69af..a2a0c820fe 100755
--- a/t/t3601-rm-pathspec-file.sh
+++ b/t/t3601-rm-pathspec-file.sh
@@ -67,10 +67,10 @@ test_expect_success 'error conditions' '
echo fileA.t >list &&
test_must_fail git rm --pathspec-from-file=list -- fileA.t 2>err &&
- test_i18ngrep -e "--pathspec-from-file is incompatible with pathspec arguments" err &&
+ test_i18ngrep -e ".--pathspec-from-file. and pathspec arguments cannot be used together" err &&
test_must_fail git rm --pathspec-file-nul 2>err &&
- test_i18ngrep -e "--pathspec-file-nul requires --pathspec-from-file" err &&
+ test_i18ngrep -e "the option .--pathspec-file-nul. requires .--pathspec-from-file." err &&
>empty_list &&
test_must_fail git rm --pathspec-from-file=empty_list 2>err &&
diff --git a/t/t3704-add-pathspec-file.sh b/t/t3704-add-pathspec-file.sh
index 5d5164d1fc..4e6b5177c9 100755
--- a/t/t3704-add-pathspec-file.sh
+++ b/t/t3704-add-pathspec-file.sh
@@ -138,19 +138,19 @@ test_expect_success 'error conditions' '
>empty_list &&
test_must_fail git add --pathspec-from-file=list --interactive 2>err &&
- test_i18ngrep -e "--pathspec-from-file is incompatible with --interactive/--patch" err &&
+ test_i18ngrep -e "options .--pathspec-from-file. and .--interactive/--patch. cannot be used together" err &&
test_must_fail git add --pathspec-from-file=list --patch 2>err &&
- test_i18ngrep -e "--pathspec-from-file is incompatible with --interactive/--patch" err &&
+ test_i18ngrep -e "options .--pathspec-from-file. and .--interactive/--patch. cannot be used together" err &&
test_must_fail git add --pathspec-from-file=list --edit 2>err &&
- test_i18ngrep -e "--pathspec-from-file is incompatible with --edit" err &&
+ test_i18ngrep -e "options .--pathspec-from-file. and .--edit. cannot be used together" err &&
test_must_fail git add --pathspec-from-file=list -- fileA.t 2>err &&
- test_i18ngrep -e "--pathspec-from-file is incompatible with pathspec arguments" err &&
+ test_i18ngrep -e ".--pathspec-from-file. and pathspec arguments cannot be used together" err &&
test_must_fail git add --pathspec-file-nul 2>err &&
- test_i18ngrep -e "--pathspec-file-nul requires --pathspec-from-file" err &&
+ test_i18ngrep -e "the option .--pathspec-file-nul. requires .--pathspec-from-file." err &&
# This case succeeds, but still prints to stderr
git add --pathspec-from-file=empty_list 2>err &&
diff --git a/t/t3705-add-sparse-checkout.sh b/t/t3705-add-sparse-checkout.sh
index f3143c9290..81f3384eee 100755
--- a/t/t3705-add-sparse-checkout.sh
+++ b/t/t3705-add-sparse-checkout.sh
@@ -181,13 +181,13 @@ test_expect_success 'git add fails outside of sparse-checkout definition' '
# Avoid munging CRLFs to avoid an error message
git -c core.autocrlf=input add --sparse sparse_entry 2>stderr &&
test_must_be_empty stderr &&
- test-tool read-cache --table >actual &&
- grep "^100644 blob.*sparse_entry\$" actual &&
+ git ls-files --stage >actual &&
+ grep "^100644 .*sparse_entry\$" actual &&
git add --sparse --chmod=+x sparse_entry 2>stderr &&
test_must_be_empty stderr &&
- test-tool read-cache --table >actual &&
- grep "^100755 blob.*sparse_entry\$" actual &&
+ git ls-files --stage >actual &&
+ grep "^100755 .*sparse_entry\$" actual &&
git reset &&
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 2c66cfbc3b..686747e55a 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -10,6 +10,25 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
+test_expect_success 'usage on cmd and subcommand invalid option' '
+ test_expect_code 129 git stash --invalid-option 2>usage &&
+ grep "or: git stash" usage &&
+
+ test_expect_code 129 git stash push --invalid-option 2>usage &&
+ ! grep "or: git stash" usage
+'
+
+test_expect_success 'usage on main command -h emits a summary of subcommands' '
+ test_expect_code 129 git stash -h >usage &&
+ grep -F "usage: git stash list" usage &&
+ grep -F "or: git stash show" usage
+'
+
+test_expect_failure 'usage for subcommands should emit subcommand usage' '
+ test_expect_code 129 git stash push -h >usage &&
+ grep -F "usage: git stash [push" usage
+'
+
diff_cmp () {
for i in "$1" "$2"
do
@@ -1376,4 +1395,28 @@ test_expect_success 'git stash can pop directory -> file saved changes' '
)
'
+test_expect_success 'restore untracked files even when we hit conflicts' '
+ git init restore_untracked_after_conflict &&
+ (
+ cd restore_untracked_after_conflict &&
+
+ echo hi >a &&
+ echo there >b &&
+ git add . &&
+ git commit -m first &&
+ echo hello >a &&
+ echo something >c &&
+
+ git stash push --include-untracked &&
+
+ echo conflict >a &&
+ git add a &&
+ git commit -m second &&
+
+ test_must_fail git stash pop &&
+
+ test_path_is_file c
+ )
+'
+
test_done
diff --git a/t/t3909-stash-pathspec-file.sh b/t/t3909-stash-pathspec-file.sh
index 55e050cfd4..dead9f18d9 100755
--- a/t/t3909-stash-pathspec-file.sh
+++ b/t/t3909-stash-pathspec-file.sh
@@ -88,13 +88,13 @@ test_expect_success 'error conditions' '
echo fileA.t >list &&
test_must_fail git stash push --pathspec-from-file=list --patch 2>err &&
- test_i18ngrep -e "--pathspec-from-file is incompatible with --patch" err &&
+ test_i18ngrep -e "options .--pathspec-from-file. and .--patch. cannot be used together" err &&
test_must_fail git stash push --pathspec-from-file=list -- fileA.t 2>err &&
- test_i18ngrep -e "--pathspec-from-file is incompatible with pathspec arguments" err &&
+ test_i18ngrep -e ".--pathspec-from-file. and pathspec arguments cannot be used together" err &&
test_must_fail git stash push --pathspec-file-nul 2>err &&
- test_i18ngrep -e "--pathspec-file-nul requires --pathspec-from-file" err
+ test_i18ngrep -e "the option .--pathspec-file-nul. requires .--pathspec-from-file." err
'
test_done
diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh
index ca5adabe14..9babf13bc9 100755
--- a/t/t4015-diff-whitespace.sh
+++ b/t/t4015-diff-whitespace.sh
@@ -1442,6 +1442,143 @@ test_expect_success 'detect permutations inside moved code -- dimmed-zebra' '
test_cmp expected actual
'
+test_expect_success 'zebra alternate color is only used when necessary' '
+ cat >old.txt <<-\EOF &&
+ line 1A should be marked as oldMoved newMovedAlternate
+ line 1B should be marked as oldMoved newMovedAlternate
+ unchanged
+ line 2A should be marked as oldMoved newMovedAlternate
+ line 2B should be marked as oldMoved newMovedAlternate
+ line 3A should be marked as oldMovedAlternate newMoved
+ line 3B should be marked as oldMovedAlternate newMoved
+ unchanged
+ line 4A should be marked as oldMoved newMovedAlternate
+ line 4B should be marked as oldMoved newMovedAlternate
+ line 5A should be marked as oldMovedAlternate newMoved
+ line 5B should be marked as oldMovedAlternate newMoved
+ line 6A should be marked as oldMoved newMoved
+ line 6B should be marked as oldMoved newMoved
+ EOF
+ cat >new.txt <<-\EOF &&
+ line 1A should be marked as oldMoved newMovedAlternate
+ line 1B should be marked as oldMoved newMovedAlternate
+ unchanged
+ line 3A should be marked as oldMovedAlternate newMoved
+ line 3B should be marked as oldMovedAlternate newMoved
+ line 2A should be marked as oldMoved newMovedAlternate
+ line 2B should be marked as oldMoved newMovedAlternate
+ unchanged
+ line 6A should be marked as oldMoved newMoved
+ line 6B should be marked as oldMoved newMoved
+ line 4A should be marked as oldMoved newMovedAlternate
+ line 4B should be marked as oldMoved newMovedAlternate
+ line 5A should be marked as oldMovedAlternate newMoved
+ line 5B should be marked as oldMovedAlternate newMoved
+ EOF
+ test_expect_code 1 git diff --no-index --color --color-moved=zebra \
+ --color-moved-ws=allow-indentation-change \
+ old.txt new.txt >output &&
+ grep -v index output | test_decode_color >actual &&
+ cat >expected <<-\EOF &&
+ <BOLD>diff --git a/old.txt b/new.txt<RESET>
+ <BOLD>--- a/old.txt<RESET>
+ <BOLD>+++ b/new.txt<RESET>
+ <CYAN>@@ -1,14 +1,14 @@<RESET>
+ <BOLD;MAGENTA>-line 1A should be marked as oldMoved newMovedAlternate<RESET>
+ <BOLD;MAGENTA>-line 1B should be marked as oldMoved newMovedAlternate<RESET>
+ <BOLD;CYAN>+<RESET><BOLD;CYAN> line 1A should be marked as oldMoved newMovedAlternate<RESET>
+ <BOLD;CYAN>+<RESET><BOLD;CYAN> line 1B should be marked as oldMoved newMovedAlternate<RESET>
+ unchanged<RESET>
+ <BOLD;MAGENTA>-line 2A should be marked as oldMoved newMovedAlternate<RESET>
+ <BOLD;MAGENTA>-line 2B should be marked as oldMoved newMovedAlternate<RESET>
+ <BOLD;BLUE>-line 3A should be marked as oldMovedAlternate newMoved<RESET>
+ <BOLD;BLUE>-line 3B should be marked as oldMovedAlternate newMoved<RESET>
+ <BOLD;CYAN>+<RESET><BOLD;CYAN> line 3A should be marked as oldMovedAlternate newMoved<RESET>
+ <BOLD;CYAN>+<RESET><BOLD;CYAN> line 3B should be marked as oldMovedAlternate newMoved<RESET>
+ <BOLD;YELLOW>+<RESET><BOLD;YELLOW> line 2A should be marked as oldMoved newMovedAlternate<RESET>
+ <BOLD;YELLOW>+<RESET><BOLD;YELLOW> line 2B should be marked as oldMoved newMovedAlternate<RESET>
+ unchanged<RESET>
+ <BOLD;MAGENTA>-line 4A should be marked as oldMoved newMovedAlternate<RESET>
+ <BOLD;MAGENTA>-line 4B should be marked as oldMoved newMovedAlternate<RESET>
+ <BOLD;BLUE>-line 5A should be marked as oldMovedAlternate newMoved<RESET>
+ <BOLD;BLUE>-line 5B should be marked as oldMovedAlternate newMoved<RESET>
+ <BOLD;MAGENTA>-line 6A should be marked as oldMoved newMoved<RESET>
+ <BOLD;MAGENTA>-line 6B should be marked as oldMoved newMoved<RESET>
+ <BOLD;CYAN>+<RESET><BOLD;CYAN> line 6A should be marked as oldMoved newMoved<RESET>
+ <BOLD;CYAN>+<RESET><BOLD;CYAN> line 6B should be marked as oldMoved newMoved<RESET>
+ <BOLD;YELLOW>+<RESET><BOLD;YELLOW> line 4A should be marked as oldMoved newMovedAlternate<RESET>
+ <BOLD;YELLOW>+<RESET><BOLD;YELLOW> line 4B should be marked as oldMoved newMovedAlternate<RESET>
+ <BOLD;CYAN>+<RESET><BOLD;CYAN> line 5A should be marked as oldMovedAlternate newMoved<RESET>
+ <BOLD;CYAN>+<RESET><BOLD;CYAN> line 5B should be marked as oldMovedAlternate newMoved<RESET>
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'short lines of opposite sign do not get marked as moved' '
+ cat >old.txt <<-\EOF &&
+ this line should be marked as moved
+ unchanged
+ unchanged
+ unchanged
+ unchanged
+ too short
+ this line should be marked as oldMoved newMoved
+ this line should be marked as oldMovedAlternate newMoved
+ unchanged 1
+ unchanged 2
+ unchanged 3
+ unchanged 4
+ this line should be marked as oldMoved newMoved/newMovedAlternate
+ EOF
+ cat >new.txt <<-\EOF &&
+ too short
+ unchanged
+ unchanged
+ this line should be marked as moved
+ too short
+ unchanged
+ unchanged
+ this line should be marked as oldMoved newMoved/newMovedAlternate
+ unchanged 1
+ unchanged 2
+ this line should be marked as oldMovedAlternate newMoved
+ this line should be marked as oldMoved newMoved/newMovedAlternate
+ unchanged 3
+ this line should be marked as oldMoved newMoved
+ unchanged 4
+ EOF
+ test_expect_code 1 git diff --no-index --color --color-moved=zebra \
+ old.txt new.txt >output && cat output &&
+ grep -v index output | test_decode_color >actual &&
+ cat >expect <<-\EOF &&
+ <BOLD>diff --git a/old.txt b/new.txt<RESET>
+ <BOLD>--- a/old.txt<RESET>
+ <BOLD>+++ b/new.txt<RESET>
+ <CYAN>@@ -1,13 +1,15 @@<RESET>
+ <BOLD;MAGENTA>-this line should be marked as moved<RESET>
+ <GREEN>+<RESET><GREEN>too short<RESET>
+ unchanged<RESET>
+ unchanged<RESET>
+ <BOLD;CYAN>+<RESET><BOLD;CYAN>this line should be marked as moved<RESET>
+ <GREEN>+<RESET><GREEN>too short<RESET>
+ unchanged<RESET>
+ unchanged<RESET>
+ <RED>-too short<RESET>
+ <BOLD;MAGENTA>-this line should be marked as oldMoved newMoved<RESET>
+ <BOLD;BLUE>-this line should be marked as oldMovedAlternate newMoved<RESET>
+ <BOLD;CYAN>+<RESET><BOLD;CYAN>this line should be marked as oldMoved newMoved/newMovedAlternate<RESET>
+ unchanged 1<RESET>
+ unchanged 2<RESET>
+ <BOLD;CYAN>+<RESET><BOLD;CYAN>this line should be marked as oldMovedAlternate newMoved<RESET>
+ <BOLD;YELLOW>+<RESET><BOLD;YELLOW>this line should be marked as oldMoved newMoved/newMovedAlternate<RESET>
+ unchanged 3<RESET>
+ <BOLD;CYAN>+<RESET><BOLD;CYAN>this line should be marked as oldMoved newMoved<RESET>
+ unchanged 4<RESET>
+ <BOLD;MAGENTA>-this line should be marked as oldMoved newMoved/newMovedAlternate<RESET>
+ EOF
+ test_cmp expect actual
+'
+
test_expect_success 'cmd option assumes configured colored-moved' '
test_config color.diff.oldMoved "magenta" &&
test_config color.diff.newMoved "cyan" &&
@@ -1833,6 +1970,52 @@ test_expect_success '--color-moved treats adjacent blocks as separate for MIN_AL
test_cmp expected actual
'
+test_expect_success '--color-moved rewinds for MIN_ALNUM_COUNT' '
+ git reset --hard &&
+ test_write_lines >file \
+ A B C one two three four five six seven D E F G H I J &&
+ git add file &&
+ test_write_lines >file \
+ one two A B C D E F G H I J two three four five six seven &&
+ git diff --color-moved=zebra -- file &&
+
+ git diff --color-moved=zebra --color -- file >actual.raw &&
+ grep -v "index" actual.raw | test_decode_color >actual &&
+ cat >expected <<-\EOF &&
+ <BOLD>diff --git a/file b/file<RESET>
+ <BOLD>--- a/file<RESET>
+ <BOLD>+++ b/file<RESET>
+ <CYAN>@@ -1,13 +1,8 @@<RESET>
+ <GREEN>+<RESET><GREEN>one<RESET>
+ <GREEN>+<RESET><GREEN>two<RESET>
+ A<RESET>
+ B<RESET>
+ C<RESET>
+ <RED>-one<RESET>
+ <BOLD;MAGENTA>-two<RESET>
+ <BOLD;MAGENTA>-three<RESET>
+ <BOLD;MAGENTA>-four<RESET>
+ <BOLD;MAGENTA>-five<RESET>
+ <BOLD;MAGENTA>-six<RESET>
+ <BOLD;MAGENTA>-seven<RESET>
+ D<RESET>
+ E<RESET>
+ F<RESET>
+ <CYAN>@@ -15,3 +10,9 @@<RESET> <RESET>G<RESET>
+ H<RESET>
+ I<RESET>
+ J<RESET>
+ <BOLD;CYAN>+<RESET><BOLD;CYAN>two<RESET>
+ <BOLD;CYAN>+<RESET><BOLD;CYAN>three<RESET>
+ <BOLD;CYAN>+<RESET><BOLD;CYAN>four<RESET>
+ <BOLD;CYAN>+<RESET><BOLD;CYAN>five<RESET>
+ <BOLD;CYAN>+<RESET><BOLD;CYAN>six<RESET>
+ <BOLD;CYAN>+<RESET><BOLD;CYAN>seven<RESET>
+ EOF
+
+ test_cmp expected actual
+'
+
test_expect_success 'move detection with submodules' '
test_create_repo bananas &&
echo ripe >bananas/recipe &&
@@ -2023,10 +2206,10 @@ EMPTY=''
test_expect_success 'compare mixed whitespace delta across moved blocks' '
git reset --hard &&
- tr Q_ "\t " <<-EOF >text.txt &&
- ${EMPTY}
- ____too short without
- ${EMPTY}
+ tr "^|Q_" "\f\v\t " <<-EOF >text.txt &&
+ ^__
+ |____too short without
+ ^
___being grouped across blank line
${EMPTY}
context
@@ -2045,7 +2228,7 @@ test_expect_success 'compare mixed whitespace delta across moved blocks' '
git add text.txt &&
git commit -m "add text.txt" &&
- tr Q_ "\t " <<-EOF >text.txt &&
+ tr "^|Q_" "\f\v\t " <<-EOF >text.txt &&
context
lines
to
@@ -2056,7 +2239,7 @@ test_expect_success 'compare mixed whitespace delta across moved blocks' '
${EMPTY}
QQtoo short without
${EMPTY}
- Q_______being grouped across blank line
+ ^Q_______being grouped across blank line
${EMPTY}
Q_QThese two lines have had their
indentation reduced by four spaces
@@ -2068,16 +2251,16 @@ test_expect_success 'compare mixed whitespace delta across moved blocks' '
-c core.whitespace=space-before-tab \
diff --color --color-moved --ws-error-highlight=all \
--color-moved-ws=allow-indentation-change >actual.raw &&
- grep -v "index" actual.raw | test_decode_color >actual &&
+ grep -v "index" actual.raw | tr "\f\v" "^|" | test_decode_color >actual &&
cat <<-\EOF >expected &&
<BOLD>diff --git a/text.txt b/text.txt<RESET>
<BOLD>--- a/text.txt<RESET>
<BOLD>+++ b/text.txt<RESET>
<CYAN>@@ -1,16 +1,16 @@<RESET>
- <BOLD;MAGENTA>-<RESET>
- <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA> too short without<RESET>
- <BOLD;MAGENTA>-<RESET>
+ <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA>^<RESET><BRED> <RESET>
+ <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA>| too short without<RESET>
+ <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA>^<RESET>
<BOLD;MAGENTA>-<RESET><BOLD;MAGENTA> being grouped across blank line<RESET>
<BOLD;MAGENTA>-<RESET>
<RESET>context<RESET>
@@ -2097,7 +2280,7 @@ test_expect_success 'compare mixed whitespace delta across moved blocks' '
<BOLD;YELLOW>+<RESET>
<BOLD;YELLOW>+<RESET> <BOLD;YELLOW>too short without<RESET>
<BOLD;YELLOW>+<RESET>
- <BOLD;YELLOW>+<RESET> <BOLD;YELLOW> being grouped across blank line<RESET>
+ <BOLD;YELLOW>+<RESET><BOLD;YELLOW>^ being grouped across blank line<RESET>
<BOLD;YELLOW>+<RESET>
<BOLD;CYAN>+<RESET> <BRED> <RESET> <BOLD;CYAN>These two lines have had their<RESET>
<BOLD;CYAN>+<RESET><BOLD;CYAN>indentation reduced by four spaces<RESET>
diff --git a/t/t4108-apply-threeway.sh b/t/t4108-apply-threeway.sh
index cc3aa3314a..c558282bc0 100755
--- a/t/t4108-apply-threeway.sh
+++ b/t/t4108-apply-threeway.sh
@@ -275,4 +275,22 @@ test_expect_success 'apply full-index patch with 3way' '
git apply --3way --index bin.diff
'
+test_expect_success 'apply delete then new patch with 3way' '
+ git reset --hard main &&
+ test_write_lines 2 > delnew &&
+ git add delnew &&
+ git diff --cached >> new.patch &&
+ git reset --hard &&
+ test_write_lines 1 > delnew &&
+ git add delnew &&
+ git commit -m "delnew" &&
+ rm delnew &&
+ git diff >> delete-then-new.patch &&
+ cat new.patch >> delete-then-new.patch &&
+
+ git checkout -- . &&
+ # Apply must succeed.
+ git apply --3way delete-then-new.patch
+'
+
test_done
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 103cd39148..6caff0ca39 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -196,6 +196,12 @@ test_expect_success setup '
git format-patch -M --stdout lorem^ >rename-add.patch &&
+ git checkout -b empty-commit &&
+ git commit -m "empty commit" --allow-empty &&
+
+ : >empty.patch &&
+ git format-patch --always --stdout empty-commit^ >empty-commit.patch &&
+
# reset time
sane_unset test_tick &&
test_tick
@@ -1152,4 +1158,105 @@ test_expect_success 'apply binary blob in partial clone' '
git -C client am ../patch
'
+test_expect_success 'an empty input file is error regardless of --empty option' '
+ test_when_finished "git am --abort || :" &&
+ test_must_fail git am --empty=drop empty.patch 2>actual &&
+ echo "Patch format detection failed." >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'invalid when passing the --empty option alone' '
+ test_when_finished "git am --abort || :" &&
+ git checkout empty-commit^ &&
+ test_must_fail git am --empty empty-commit.patch 2>err &&
+ echo "error: Invalid value for --empty: empty-commit.patch" >expected &&
+ test_cmp expected err
+'
+
+test_expect_success 'a message without a patch is an error (default)' '
+ test_when_finished "git am --abort || :" &&
+ test_must_fail git am empty-commit.patch >err &&
+ grep "Patch is empty" err
+'
+
+test_expect_success 'a message without a patch is an error where an explicit "--empty=stop" is given' '
+ test_when_finished "git am --abort || :" &&
+ test_must_fail git am --empty=stop empty-commit.patch >err &&
+ grep "Patch is empty." err
+'
+
+test_expect_success 'a message without a patch will be skipped when "--empty=drop" is given' '
+ git am --empty=drop empty-commit.patch >output &&
+ git rev-parse empty-commit^ >expected &&
+ git rev-parse HEAD >actual &&
+ test_cmp expected actual &&
+ grep "Skipping: empty commit" output
+'
+
+test_expect_success 'record as an empty commit when meeting e-mail message that lacks a patch' '
+ git am --empty=keep empty-commit.patch >output &&
+ test_path_is_missing .git/rebase-apply &&
+ git show empty-commit --format="%B" >expected &&
+ git show HEAD --format="%B" >actual &&
+ grep -f actual expected &&
+ grep "Creating an empty commit: empty commit" output
+'
+
+test_expect_success 'skip an empty patch in the middle of an am session' '
+ git checkout empty-commit^ &&
+ test_must_fail git am empty-commit.patch >err &&
+ grep "Patch is empty." err &&
+ grep "To record the empty patch as an empty commit, run \"git am --allow-empty\"." err &&
+ git am --skip &&
+ test_path_is_missing .git/rebase-apply &&
+ git rev-parse empty-commit^ >expected &&
+ git rev-parse HEAD >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'record an empty patch as an empty commit in the middle of an am session' '
+ git checkout empty-commit^ &&
+ test_must_fail git am empty-commit.patch >err &&
+ grep "Patch is empty." err &&
+ grep "To record the empty patch as an empty commit, run \"git am --allow-empty\"." err &&
+ git am --allow-empty >output &&
+ grep "No changes - recorded it as an empty commit." output &&
+ test_path_is_missing .git/rebase-apply &&
+ git show empty-commit --format="%B" >expected &&
+ git show HEAD --format="%B" >actual &&
+ grep -f actual expected
+'
+
+test_expect_success 'create an non-empty commit when the index IS changed though "--allow-empty" is given' '
+ git checkout empty-commit^ &&
+ test_must_fail git am empty-commit.patch >err &&
+ : >empty-file &&
+ git add empty-file &&
+ git am --allow-empty &&
+ git show empty-commit --format="%B" >expected &&
+ git show HEAD --format="%B" >actual &&
+ grep -f actual expected &&
+ git diff HEAD^..HEAD --name-only
+'
+
+test_expect_success 'cannot create empty commits when there is a clean index due to merge conflicts' '
+ test_when_finished "git am --abort || :" &&
+ git rev-parse HEAD >expected &&
+ test_must_fail git am seq.patch &&
+ test_must_fail git am --allow-empty >err &&
+ ! grep "To record the empty patch as an empty commit, run \"git am --allow-empty\"." err &&
+ git rev-parse HEAD >actual &&
+ test_cmp actual expected
+'
+
+test_expect_success 'cannot create empty commits when there is unmerged index due to merge conflicts' '
+ test_when_finished "git am --abort || :" &&
+ git rev-parse HEAD >expected &&
+ test_must_fail git am -3 seq.patch &&
+ test_must_fail git am --allow-empty >err &&
+ ! grep "To record the empty patch as an empty commit, run \"git am --allow-empty\"." err &&
+ git rev-parse HEAD >actual &&
+ test_cmp actual expected
+'
+
test_done
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index cadb25b8f5..5049559861 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -250,7 +250,7 @@ test_expect_success 'log --invert-grep --grep' '
test_cmp expect actual &&
# POSIX extended
- git -c grep.patternType=basic log --pretty="tformat:%s" --invert-grep --grep=t[h] --grep=S[e]c >actual &&
+ git -c grep.patternType=extended log --pretty="tformat:%s" --invert-grep --grep=t[h] --grep=S[e]c >actual &&
test_cmp expect actual &&
# PCRE
@@ -2090,4 +2090,23 @@ test_expect_success 'log --end-of-options' '
test_cmp expect actual
'
+test_expect_success 'set up commits with different authors' '
+ git checkout --orphan authors &&
+ test_commit --author "Jim <jim@example.com>" jim_1 &&
+ test_commit --author "Val <val@example.com>" val_1 &&
+ test_commit --author "Val <val@example.com>" val_2 &&
+ test_commit --author "Jim <jim@example.com>" jim_2 &&
+ test_commit --author "Val <val@example.com>" val_3 &&
+ test_commit --author "Jim <jim@example.com>" jim_3
+'
+
+test_expect_success 'log --invert-grep --grep --author' '
+ cat >expect <<-\EOF &&
+ val_3
+ val_1
+ EOF
+ git log --format=%s --author=Val --grep 2 --invert-grep >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t4204-patch-id.sh b/t/t4204-patch-id.sh
index e78d8097f3..80f4a65b28 100755
--- a/t/t4204-patch-id.sh
+++ b/t/t4204-patch-id.sh
@@ -5,7 +5,6 @@ test_description='git patch-id'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
-TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -28,7 +27,8 @@ test_expect_success 'setup' '
'
test_expect_success 'patch-id output is well-formed' '
- git log -p -1 | git patch-id >output &&
+ git log -p -1 >log.output &&
+ git patch-id <log.output >output &&
grep "^$OID_REGEX $(git rev-parse HEAD)$" output
'
@@ -36,8 +36,8 @@ test_expect_success 'patch-id output is well-formed' '
calc_patch_id () {
patch_name="$1"
shift
- git patch-id "$@" |
- sed "s/ .*//" >patch-id_"$patch_name" &&
+ git patch-id "$@" >patch-id.output &&
+ sed "s/ .*//" patch-id.output >patch-id_"$patch_name" &&
test_line_count -gt 0 patch-id_"$patch_name"
}
@@ -46,7 +46,8 @@ get_top_diff () {
}
get_patch_id () {
- get_top_diff "$1" | calc_patch_id "$@"
+ get_top_diff "$1" >top-diff.output &&
+ calc_patch_id <top-diff.output "$@"
}
test_expect_success 'patch-id detects equality' '
@@ -64,16 +65,18 @@ test_expect_success 'patch-id detects inequality' '
test_expect_success 'patch-id supports git-format-patch output' '
get_patch_id main &&
git checkout same &&
- git format-patch -1 --stdout | calc_patch_id same &&
+ git format-patch -1 --stdout >format-patch.output &&
+ calc_patch_id same <format-patch.output &&
test_cmp patch-id_main patch-id_same &&
- set $(git format-patch -1 --stdout | git patch-id) &&
+ set $(git patch-id <format-patch.output) &&
test "$2" = $(git rev-parse HEAD)
'
test_expect_success 'whitespace is irrelevant in footer' '
get_patch_id main &&
git checkout same &&
- git format-patch -1 --stdout | sed "s/ \$//" | calc_patch_id same &&
+ git format-patch -1 --stdout >format-patch.output &&
+ sed "s/ \$//" format-patch.output | calc_patch_id same &&
test_cmp patch-id_main patch-id_same
'
@@ -92,10 +95,11 @@ test_patch_id_file_order () {
shift
name="order-${1}-$relevant"
shift
- get_top_diff "main" | calc_patch_id "$name" "$@" &&
+ get_top_diff "main" >top-diff.output &&
+ calc_patch_id <top-diff.output "$name" "$@" &&
git checkout same &&
- git format-patch -1 --stdout -O foo-then-bar |
- calc_patch_id "ordered-$name" "$@" &&
+ git format-patch -1 --stdout -O foo-then-bar >format-patch.output &&
+ calc_patch_id <format-patch.output "ordered-$name" "$@" &&
cmp_patch_id $relevant "$name" "ordered-$name"
}
@@ -143,7 +147,8 @@ test_expect_success '--stable overrides patchid.stable = false' '
test_expect_success 'patch-id supports git-format-patch MIME output' '
get_patch_id main &&
git checkout same &&
- git format-patch -1 --attach --stdout | calc_patch_id same &&
+ git format-patch -1 --attach --stdout >format-patch.output &&
+ calc_patch_id <format-patch.output same &&
test_cmp patch-id_main patch-id_same
'
diff --git a/t/t4209-log-pickaxe.sh b/t/t4209-log-pickaxe.sh
index 75795d0b49..7f6bb27f14 100755
--- a/t/t4209-log-pickaxe.sh
+++ b/t/t4209-log-pickaxe.sh
@@ -63,21 +63,21 @@ test_expect_success 'usage' '
test_i18ngrep "switch.*requires a value" err &&
test_expect_code 128 git log -Gregex -Sstring 2>err &&
- grep "mutually exclusive" err &&
+ grep "cannot be used together" err &&
test_expect_code 128 git log -Gregex --find-object=HEAD 2>err &&
- grep "mutually exclusive" err &&
+ grep "cannot be used together" err &&
test_expect_code 128 git log -Sstring --find-object=HEAD 2>err &&
- grep "mutually exclusive" err &&
+ grep "cannot be used together" err &&
test_expect_code 128 git log --pickaxe-all --find-object=HEAD 2>err &&
- grep "mutually exclusive" err
+ grep "cannot be used together" err
'
test_expect_success 'usage: --pickaxe-regex' '
test_expect_code 128 git log -Gregex --pickaxe-regex 2>err &&
- grep "mutually exclusive" err
+ grep "cannot be used together" err
'
test_expect_success 'usage: --no-pickaxe-regex' '
diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh
index 93ecfcdd24..081808009b 100755
--- a/t/t5520-pull.sh
+++ b/t/t5520-pull.sh
@@ -330,6 +330,19 @@ test_expect_success '--rebase --autostash fast forward' '
test_cmp_rev HEAD to-rebase-ff
'
+test_expect_success '--rebase with rebase.autostash succeeds on ff' '
+ test_when_finished "rm -fr src dst actual" &&
+ git init src &&
+ test_commit -C src "initial" file "content" &&
+ git clone src dst &&
+ test_commit -C src --printf "more_content" file "more content\ncontent\n" &&
+ echo "dirty" >>dst/file &&
+ test_config -C dst rebase.autostash true &&
+ git -C dst pull --rebase >actual 2>&1 &&
+ grep -q "Fast-forward" actual &&
+ grep -q "Applied autostash." actual
+'
+
test_expect_success '--rebase with conflicts shows advice' '
test_when_finished "git rebase --abort; git checkout -f to-rebase" &&
git checkout -b seq &&
diff --git a/t/t5540-http-push-webdav.sh b/t/t5540-http-push-webdav.sh
index 8b68bb38a4..b0dbacf0b9 100755
--- a/t/t5540-http-push-webdav.sh
+++ b/t/t5540-http-push-webdav.sh
@@ -18,6 +18,12 @@ then
test_done
fi
+if test_have_prereq !REFFILES
+then
+ skip_all='skipping test; dumb HTTP protocol not supported with reftable.'
+ test_done
+fi
+
LIB_HTTPD_DAV=t
. "$TEST_DIRECTORY"/lib-httpd.sh
ROOT_PATH="$PWD"
diff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh
index 6d9142afc3..259203926a 100755
--- a/t/t5550-http-fetch-dumb.sh
+++ b/t/t5550-http-fetch-dumb.sh
@@ -5,6 +5,13 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
+
+if test_have_prereq !REFFILES
+then
+ skip_all='skipping test; dumb HTTP protocol not supported with reftable.'
+ test_done
+fi
+
. "$TEST_DIRECTORY"/lib-httpd.sh
start_httpd
diff --git a/t/t5606-clone-options.sh b/t/t5606-clone-options.sh
index d822153e4d..8f676d6b0c 100755
--- a/t/t5606-clone-options.sh
+++ b/t/t5606-clone-options.sh
@@ -46,7 +46,7 @@ test_expect_success 'disallows --bare with --origin' '
test_must_fail git clone -o foo --bare parent clone-bare-o 2>err &&
test_debug "cat err" &&
- test_i18ngrep -e "--bare and --origin foo options are incompatible" err
+ test_i18ngrep -e "options .--bare. and .--origin foo. cannot be used together" err
'
@@ -54,7 +54,7 @@ test_expect_success 'disallows --bare with --separate-git-dir' '
test_must_fail git clone --bare --separate-git-dir dot-git-destiation parent clone-bare-sgd 2>err &&
test_debug "cat err" &&
- test_i18ngrep -e "--bare and --separate-git-dir are incompatible" err
+ test_i18ngrep -e "options .--bare. and .--separate-git-dir. cannot be used together" err
'
diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh
index a4c02d7b88..5a221f8ef1 100755
--- a/t/t6200-fmt-merge-msg.sh
+++ b/t/t6200-fmt-merge-msg.sh
@@ -126,6 +126,7 @@ test_expect_success GPG 'message for merging local tag signed by good key' '
git fetch . signed-good-tag &&
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
grep "^Merge tag ${apos}signed-good-tag${apos}" actual &&
+ grep "^signed-tag-msg" actual &&
grep "^# gpg: Signature made" actual &&
grep "^# gpg: Good signature from" actual
'
@@ -135,6 +136,7 @@ test_expect_success GPG 'message for merging local tag signed by unknown key' '
git fetch . signed-good-tag &&
GNUPGHOME=. git fmt-merge-msg <.git/FETCH_HEAD >actual &&
grep "^Merge tag ${apos}signed-good-tag${apos}" actual &&
+ grep "^signed-tag-msg" actual &&
grep "^# gpg: Signature made" actual &&
grep -E "^# gpg: Can${apos}t check signature: (public key not found|No public key)" actual
'
@@ -145,6 +147,7 @@ test_expect_success GPGSSH 'message for merging local tag signed by good ssh key
git fetch . signed-good-ssh-tag &&
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
grep "^Merge tag ${apos}signed-good-ssh-tag${apos}" actual &&
+ grep "^signed-ssh-tag-msg" actual &&
grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual &&
! grep "${GPGSSH_BAD_SIGNATURE}" actual
'
@@ -155,6 +158,7 @@ test_expect_success GPGSSH 'message for merging local tag signed by unknown ssh
git fetch . signed-untrusted-ssh-tag &&
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
grep "^Merge tag ${apos}signed-untrusted-ssh-tag${apos}" actual &&
+ grep "^signed-ssh-tag-msg-untrusted" actual &&
grep "${GPGSSH_GOOD_SIGNATURE_UNTRUSTED}" actual &&
! grep "${GPGSSH_BAD_SIGNATURE}" actual &&
grep "${GPGSSH_KEY_NOT_TRUSTED}" actual
@@ -166,6 +170,7 @@ test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'message for merging local tag sign
git fetch . expired-signed &&
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
grep "^Merge tag ${apos}expired-signed${apos}" actual &&
+ grep "^expired-signed" actual &&
! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual
'
@@ -175,6 +180,7 @@ test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'message for merging local tag sign
git fetch . notyetvalid-signed &&
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
grep "^Merge tag ${apos}notyetvalid-signed${apos}" actual &&
+ grep "^notyetvalid-signed" actual &&
! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual
'
@@ -184,6 +190,7 @@ test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'message for merging local tag sign
git fetch . timeboxedvalid-signed &&
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
grep "^Merge tag ${apos}timeboxedvalid-signed${apos}" actual &&
+ grep "^timeboxedvalid-signed" actual &&
grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual &&
! grep "${GPGSSH_BAD_SIGNATURE}" actual
'
@@ -194,6 +201,7 @@ test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'message for merging local tag sign
git fetch . timeboxedinvalid-signed &&
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
grep "^Merge tag ${apos}timeboxedinvalid-signed${apos}" actual &&
+ grep "^timeboxedinvalid-signed" actual &&
! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual
'
@@ -633,7 +641,35 @@ test_expect_success 'merge-msg with "merging" an annotated tag' '
test_cmp expected .git/MERGE_MSG
'
+test_expect_success 'merge --into-name=<name>' '
+ test_when_finished "git checkout main" &&
+ git checkout -B side main &&
+ git commit --allow-empty -m "One step ahead" &&
+
+ git checkout --detach main &&
+ git merge --no-ff side &&
+ git show -s --format="%s" >full.0 &&
+ head -n1 full.0 >actual &&
+ # expect that HEAD is shown as-is
+ grep -e "Merge branch .side. into HEAD$" actual &&
+
+ git reset --hard main &&
+ git merge --no-ff --into-name=main side &&
+ git show -s --format="%s" >full.1 &&
+ head -n1 full.1 >actual &&
+ # expect that we pretend to be merging to main, that is suppressed
+ grep -e "Merge branch .side.$" actual &&
+
+ git checkout -b throwaway main &&
+ git merge --no-ff --into-name=main side &&
+ git show -s --format="%s" >full.2 &&
+ head -n1 full.2 >actual &&
+ # expect that we pretend to be merging to main, that is suppressed
+ grep -e "Merge branch .side.$" actual
+'
+
test_expect_success 'merge.suppressDest configuration' '
+ test_when_finished "git checkout main" &&
git checkout -B side main &&
git commit --allow-empty -m "One step ahead" &&
git checkout main &&
@@ -650,7 +686,19 @@ test_expect_success 'merge.suppressDest configuration' '
git -c merge.suppressDest="ma?*[rn]" fmt-merge-msg <.git/FETCH_HEAD >full.3 &&
head -n1 full.3 >actual &&
grep -e "Merge branch .side." actual &&
- ! grep -e " into main$" actual
+ ! grep -e " into main$" actual &&
+
+ git checkout --detach HEAD &&
+ git -c merge.suppressDest="main" fmt-merge-msg <.git/FETCH_HEAD >full.4 &&
+ head -n1 full.4 >actual &&
+ grep -e "Merge branch .side. into HEAD$" actual &&
+
+ git -c merge.suppressDest="main" fmt-merge-msg \
+ --into-name=main <.git/FETCH_HEAD >full.5 &&
+ head -n1 full.5 >actual &&
+ grep -e "Merge branch .side." actual &&
+ ! grep -e " into main$" actual &&
+ ! grep -e " into HEAD$" actual
'
test_done
diff --git a/t/t6418-merge-text-auto.sh b/t/t6418-merge-text-auto.sh
index 1e0296dd17..41288a60ce 100755
--- a/t/t6418-merge-text-auto.sh
+++ b/t/t6418-merge-text-auto.sh
@@ -204,4 +204,30 @@ test_expect_success 'Test delete/normalize conflict' '
test_path_is_missing file
'
+test_expect_success 'rename/delete vs. renormalization' '
+ git init subrepo &&
+ (
+ cd subrepo &&
+ echo foo >oldfile &&
+ git add oldfile &&
+ git commit -m original &&
+
+ git branch rename &&
+ git branch nuke &&
+
+ git checkout rename &&
+ git mv oldfile newfile &&
+ git commit -m renamed &&
+
+ git checkout nuke &&
+ git rm oldfile &&
+ git commit -m deleted &&
+
+ git checkout rename^0 &&
+ test_must_fail git -c merge.renormalize=true merge nuke >out &&
+
+ grep "rename/delete" out
+ )
+'
+
test_done
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index 25a26563dd..9aa1660651 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -94,10 +94,10 @@ test_expect_success 'creating a tag with --create-reflog should create reflog' '
git log -1 \
--format="format:tag: tagging %h (%s, %cd)%n" \
--date=format:%Y-%m-%d >expected &&
- test_when_finished "git tag -d tag_with_reflog" &&
- git tag --create-reflog tag_with_reflog &&
- git reflog exists refs/tags/tag_with_reflog &&
- sed -e "s/^.* //" .git/logs/refs/tags/tag_with_reflog >actual &&
+ test_when_finished "git tag -d tag_with_reflog1" &&
+ git tag --create-reflog tag_with_reflog1 &&
+ git reflog exists refs/tags/tag_with_reflog1 &&
+ test-tool ref-store main for-each-reflog-ent refs/tags/tag_with_reflog1 | sed -e "s/^.* //" >actual &&
test_cmp expected actual
'
@@ -105,10 +105,10 @@ test_expect_success 'annotated tag with --create-reflog has correct message' '
git log -1 \
--format="format:tag: tagging %h (%s, %cd)%n" \
--date=format:%Y-%m-%d >expected &&
- test_when_finished "git tag -d tag_with_reflog" &&
- git tag -m "annotated tag" --create-reflog tag_with_reflog &&
- git reflog exists refs/tags/tag_with_reflog &&
- sed -e "s/^.* //" .git/logs/refs/tags/tag_with_reflog >actual &&
+ test_when_finished "git tag -d tag_with_reflog2" &&
+ git tag -m "annotated tag" --create-reflog tag_with_reflog2 &&
+ git reflog exists refs/tags/tag_with_reflog2 &&
+ test-tool ref-store main for-each-reflog-ent refs/tags/tag_with_reflog2 | sed -e "s/^.* //" >actual &&
test_cmp expected actual
'
@@ -118,10 +118,10 @@ test_expect_success '--create-reflog does not create reflog on failure' '
'
test_expect_success 'option core.logAllRefUpdates=always creates reflog' '
- test_when_finished "git tag -d tag_with_reflog" &&
+ test_when_finished "git tag -d tag_with_reflog3" &&
test_config core.logAllRefUpdates always &&
- git tag tag_with_reflog &&
- git reflog exists refs/tags/tag_with_reflog
+ git tag tag_with_reflog3 &&
+ git reflog exists refs/tags/tag_with_reflog3
'
test_expect_success 'listing all tags if one exists should succeed' '
diff --git a/t/t7107-reset-pathspec-file.sh b/t/t7107-reset-pathspec-file.sh
index 15ccb14f7e..523efbecde 100755
--- a/t/t7107-reset-pathspec-file.sh
+++ b/t/t7107-reset-pathspec-file.sh
@@ -160,13 +160,13 @@ test_expect_success 'error conditions' '
git rm fileA.t &&
test_must_fail git reset --pathspec-from-file=list --patch 2>err &&
- test_i18ngrep -e "--pathspec-from-file is incompatible with --patch" err &&
+ test_i18ngrep -e "options .--pathspec-from-file. and .--patch. cannot be used together" err &&
test_must_fail git reset --pathspec-from-file=list -- fileA.t 2>err &&
- test_i18ngrep -e "--pathspec-from-file is incompatible with pathspec arguments" err &&
+ test_i18ngrep -e ".--pathspec-from-file. and pathspec arguments cannot be used together" err &&
test_must_fail git reset --pathspec-file-nul 2>err &&
- test_i18ngrep -e "--pathspec-file-nul requires --pathspec-from-file" err &&
+ test_i18ngrep -e "the option .--pathspec-file-nul. requires .--pathspec-from-file." err &&
test_must_fail git reset --soft --pathspec-from-file=list 2>err &&
test_i18ngrep -e "fatal: Cannot do soft reset with paths" err &&
diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index b7ba1c3268..61ad47b0c1 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh
@@ -658,4 +658,21 @@ test_expect_success 'custom merge driver with checkout -m' '
test_cmp expect arm
'
+test_expect_success 'tracking info copied with autoSetupMerge=inherit' '
+ git reset --hard main &&
+ # default config does not copy tracking info
+ git checkout -b foo-no-inherit koala/bear &&
+ test_cmp_config "" --default "" branch.foo-no-inherit.remote &&
+ test_cmp_config "" --default "" branch.foo-no-inherit.merge &&
+ # with autoSetupMerge=inherit, we copy tracking info from koala/bear
+ test_config branch.autoSetupMerge inherit &&
+ git checkout -b foo koala/bear &&
+ test_cmp_config origin branch.foo.remote &&
+ test_cmp_config refs/heads/koala/bear branch.foo.merge &&
+ # no tracking info to inherit from main
+ git checkout -b main2 main &&
+ test_cmp_config "" --default "" branch.main2.remote &&
+ test_cmp_config "" --default "" branch.main2.merge
+'
+
test_done
diff --git a/t/t7500-commit-template-squash-signoff.sh b/t/t7500-commit-template-squash-signoff.sh
index 8dd0f98812..91964653a0 100755
--- a/t/t7500-commit-template-squash-signoff.sh
+++ b/t/t7500-commit-template-squash-signoff.sh
@@ -359,14 +359,14 @@ test_expect_success '--fixup=reword: ignores staged changes' '
test_expect_success '--fixup=reword: error out with -m option' '
commit_for_rebase_autosquash_setup &&
- echo "fatal: cannot combine -m with --fixup:reword" >expect &&
+ echo "fatal: options '\''-m'\'' and '\''--fixup:reword'\'' cannot be used together" >expect &&
test_must_fail git commit --fixup=reword:HEAD~ -m "reword commit message" 2>actual &&
test_cmp expect actual
'
test_expect_success '--fixup=amend: error out with -m option' '
commit_for_rebase_autosquash_setup &&
- echo "fatal: cannot combine -m with --fixup:amend" >expect &&
+ echo "fatal: options '\''-m'\'' and '\''--fixup:amend'\'' cannot be used together" >expect &&
test_must_fail git commit --fixup=amend:HEAD~ -m "amend commit message" 2>actual &&
test_cmp expect actual
'
@@ -421,8 +421,9 @@ test_expect_success 'amend! commit allows empty commit msg body with --allow-emp
test_fixup_reword_opt () {
test_expect_success "--fixup=reword: incompatible with $1" "
- echo 'fatal: reword option of --fixup is mutually exclusive with'\
- '--patch/--interactive/--all/--include/--only' >expect &&
+ echo 'fatal: reword option of '\''--fixup'\'' and' \
+ ''\''--patch/--interactive/--all/--include/--only'\' \
+ 'cannot be used together' >expect &&
test_must_fail git commit --fixup=reword:HEAD~ $1 2>actual &&
test_cmp expect actual
"
@@ -435,7 +436,7 @@ done
test_expect_success '--fixup=reword: give error with pathsec' '
commit_for_rebase_autosquash_setup &&
- echo "fatal: cannot combine reword option of --fixup with path '\''foo'\''" >expect &&
+ echo "fatal: reword option of '\''--fixup'\'' and path '\''foo'\'' cannot be used together" >expect &&
test_must_fail git commit --fixup=reword:HEAD~ -- foo 2>actual &&
test_cmp expect actual
'
diff --git a/t/t7510-signed-commit.sh b/t/t7510-signed-commit.sh
index 9882b69ae2..8593b7e3cb 100755
--- a/t/t7510-signed-commit.sh
+++ b/t/t7510-signed-commit.sh
@@ -71,25 +71,7 @@ test_expect_success GPG 'create signed commits' '
git tag eleventh-signed $(cat oid) &&
echo 12 | git commit-tree --gpg-sign=B7227189 HEAD^{tree} >oid &&
test_line_count = 1 oid &&
- git tag twelfth-signed-alt $(cat oid) &&
-
- cat >keydetails <<-\EOF &&
- Key-Type: RSA
- Key-Length: 2048
- Subkey-Type: RSA
- Subkey-Length: 2048
- Name-Real: Unknown User
- Name-Email: unknown@git.com
- Expire-Date: 0
- %no-ask-passphrase
- %no-protection
- EOF
- gpg --batch --gen-key keydetails &&
- echo 13 >file && git commit -a -S"unknown@git.com" -m thirteenth &&
- git tag thirteenth-signed &&
- DELETE_FINGERPRINT=$(gpg -K --with-colons --fingerprint --batch unknown@git.com | grep "^fpr" | head -n 1 | awk -F ":" "{print \$10;}") &&
- gpg --batch --yes --delete-secret-keys $DELETE_FINGERPRINT &&
- gpg --batch --yes --delete-keys unknown@git.com
+ git tag twelfth-signed-alt $(cat oid)
'
test_expect_success GPG 'verify and show signatures' '
@@ -129,7 +111,7 @@ test_expect_success GPG 'verify and show signatures' '
'
test_expect_success GPG 'verify-commit exits failure on unknown signature' '
- test_must_fail git verify-commit thirteenth-signed 2>actual &&
+ test_must_fail env GNUPGHOME="$GNUPGHOME_NOT_USED" git verify-commit initial 2>actual &&
! grep "Good signature from" actual &&
! grep "BAD signature from" actual &&
grep -q -F -e "No public key" -e "public key not found" actual
diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh
index 7f2956d77a..2f16d5787e 100755
--- a/t/t7512-status-help.sh
+++ b/t/t7512-status-help.sh
@@ -659,6 +659,7 @@ On branch am_empty
You are in the middle of an am session.
The current patch is empty.
(use "git am --skip" to skip this patch)
+ (use "git am --allow-empty" to record this patch as an empty commit)
(use "git am --abort" to restore the original branch)
nothing to commit (use -u to show untracked files)
diff --git a/t/t7526-commit-pathspec-file.sh b/t/t7526-commit-pathspec-file.sh
index dca62fc48e..ad011bb9f1 100755
--- a/t/t7526-commit-pathspec-file.sh
+++ b/t/t7526-commit-pathspec-file.sh
@@ -141,19 +141,19 @@ test_expect_success 'error conditions' '
>empty_list &&
test_must_fail git commit --pathspec-from-file=list --interactive -m "Commit" 2>err &&
- test_i18ngrep -e "--pathspec-from-file is incompatible with --interactive/--patch" err &&
+ test_i18ngrep -e "options .--pathspec-from-file. and .--interactive/--patch. cannot be used together" err &&
test_must_fail git commit --pathspec-from-file=list --patch -m "Commit" 2>err &&
- test_i18ngrep -e "--pathspec-from-file is incompatible with --interactive/--patch" err &&
+ test_i18ngrep -e "options .--pathspec-from-file. and .--interactive/--patch. cannot be used together" err &&
test_must_fail git commit --pathspec-from-file=list --all -m "Commit" 2>err &&
- test_i18ngrep -e "--pathspec-from-file with -a does not make sense" err &&
+ test_i18ngrep -e "options .--pathspec-from-file. and .-a. cannot be used together" err &&
test_must_fail git commit --pathspec-from-file=list -m "Commit" -- fileA.t 2>err &&
- test_i18ngrep -e "--pathspec-from-file is incompatible with pathspec arguments" err &&
+ test_i18ngrep -e ".--pathspec-from-file. and pathspec arguments cannot be used together" err &&
test_must_fail git commit --pathspec-file-nul -m "Commit" 2>err &&
- test_i18ngrep -e "--pathspec-file-nul requires --pathspec-from-file" err &&
+ test_i18ngrep -e "the option .--pathspec-file-nul. requires .--pathspec-from-file." err &&
test_must_fail git commit --pathspec-from-file=empty_list --include -m "Commit" 2>err &&
test_i18ngrep -e "No paths with --include/--only does not make sense." err &&
diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh
index 4693f8dc2b..e489869dd9 100755
--- a/t/t7700-repack.sh
+++ b/t/t7700-repack.sh
@@ -5,6 +5,7 @@ test_description='git repack works correctly'
. ./test-lib.sh
. "${TEST_DIRECTORY}/lib-bitmap.sh"
. "${TEST_DIRECTORY}/lib-midx.sh"
+. "${TEST_DIRECTORY}/lib-terminal.sh"
commit_and_pack () {
test_commit "$@" 1>&2 &&
@@ -372,4 +373,16 @@ test_expect_success '--write-midx with preferred bitmap tips' '
)
'
+test_expect_success '--write-midx -b packs non-kept objects' '
+ GIT_TRACE2_EVENT="$(pwd)/trace.txt" \
+ git repack --write-midx -a -b &&
+ test_subcommand_inexact git pack-objects --honor-pack-keep <trace.txt
+'
+
+test_expect_success TTY '--quiet disables progress' '
+ test_terminal env GIT_PROGRESS_DELAY=0 \
+ git -C midx repack -ad --quiet --write-midx 2>stderr &&
+ test_must_be_empty stderr
+'
+
test_done
diff --git a/t/t7812-grep-icase-non-ascii.sh b/t/t7812-grep-icase-non-ascii.sh
index e5d1e4ea68..ca3f24f807 100755
--- a/t/t7812-grep-icase-non-ascii.sh
+++ b/t/t7812-grep-icase-non-ascii.sh
@@ -123,4 +123,10 @@ test_expect_success GETTEXT_LOCALE,LIBPCRE2,PCRE2_MATCH_INVALID_UTF 'PCRE v2: gr
test_cmp invalid-0xe5 actual
'
+test_expect_success GETTEXT_LOCALE,LIBPCRE2 'PCRE v2: grep non-literal ASCII from UTF-8' '
+ git grep --perl-regexp -h -o -e ll. file >actual &&
+ echo "lló" >expected &&
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t8007-cat-file-textconv.sh b/t/t8007-cat-file-textconv.sh
index eacd49ade6..b067983ba1 100755
--- a/t/t8007-cat-file-textconv.sh
+++ b/t/t8007-cat-file-textconv.sh
@@ -19,6 +19,48 @@ test_expect_success 'setup ' '
GIT_AUTHOR_NAME=Number2 git commit -a -m Second --date="2010-01-01 20:00:00"
'
+test_expect_success 'usage: <bad rev>' '
+ cat >expect <<-\EOF &&
+ fatal: Not a valid object name HEAD2
+ EOF
+ test_must_fail git cat-file --textconv HEAD2 2>actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'usage: <bad rev>:<bad path>' '
+ cat >expect <<-\EOF &&
+ fatal: invalid object name '\''HEAD2'\''.
+ EOF
+ test_must_fail git cat-file --textconv HEAD2:two.bin 2>actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'usage: <rev>:<bad path>' '
+ cat >expect <<-\EOF &&
+ fatal: path '\''two.bin'\'' does not exist in '\''HEAD'\''
+ EOF
+ test_must_fail git cat-file --textconv HEAD:two.bin 2>actual &&
+ test_cmp expect actual
+'
+
+
+test_expect_success 'usage: <rev> with no <path>' '
+ cat >expect <<-\EOF &&
+ fatal: <object>:<path> required, only <object> '\''HEAD'\'' given
+ EOF
+ test_must_fail git cat-file --textconv HEAD 2>actual &&
+ test_cmp expect actual
+'
+
+
+test_expect_success 'usage: <bad rev>:<good (in HEAD) path>' '
+ cat >expect <<-\EOF &&
+ fatal: invalid object name '\''HEAD2'\''.
+ EOF
+ test_must_fail git cat-file --textconv HEAD2:one.bin 2>actual &&
+ test_cmp expect actual
+'
+
cat >expected <<EOF
bin: test version 2
EOF
diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index 409b48e244..7b7a18dd2c 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -750,4 +750,36 @@ test_expect_success 'merge commit gets exported with --import-marks' '
)
'
+
+test_expect_success 'fast-export --first-parent outputs all revisions output by revision walk' '
+ git init first-parent &&
+ (
+ cd first-parent &&
+ test_commit A &&
+ git checkout -b topic1 &&
+ test_commit B &&
+ git checkout main &&
+ git merge --no-ff topic1 &&
+
+ git checkout -b topic2 &&
+ test_commit C &&
+ git checkout main &&
+ git merge --no-ff topic2 &&
+
+ test_commit D &&
+
+ git fast-export main -- --first-parent >first-parent-export &&
+ git fast-export main -- --first-parent --reverse >first-parent-reverse-export &&
+ test_cmp first-parent-export first-parent-reverse-export &&
+
+ git init import &&
+ git -C import fast-import <first-parent-export &&
+
+ git log --format="%ad %s" --first-parent main >expected &&
+ git -C import log --format="%ad %s" --all >actual &&
+ test_cmp expected actual &&
+ test_line_count = 4 actual
+ )
+'
+
test_done
diff --git a/t/t9810-git-p4-rcs.sh b/t/t9810-git-p4-rcs.sh
index e3836888ec..5fe83315ec 100755
--- a/t/t9810-git-p4-rcs.sh
+++ b/t/t9810-git-p4-rcs.sh
@@ -4,6 +4,8 @@ test_description='git p4 rcs keywords'
. ./lib-git-p4.sh
+CP1252="\223\224"
+
test_expect_success 'start p4d' '
start_p4d
'
@@ -32,6 +34,9 @@ test_expect_success 'init depot' '
p4 submit -d "filek" &&
p4 add -t text+ko fileko &&
p4 submit -d "fileko" &&
+ printf "$CP1252" >fileko_cp1252 &&
+ p4 add -t text+ko fileko_cp1252 &&
+ p4 submit -d "fileko_cp1252" &&
p4 add -t text file_text &&
p4 submit -d "file_text"
)
@@ -359,4 +364,14 @@ test_expect_failure 'Add keywords in git which do not match the default p4 value
)
'
+test_expect_success 'check cp1252 smart quote are preserved through RCS keyword processing' '
+ test_when_finished cleanup_git &&
+ git p4 clone --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ printf "$CP1252" >expect &&
+ test_cmp_bin expect fileko_cp1252
+ )
+'
+
test_done
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 389153e591..c3d38aaccb 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -1760,6 +1760,40 @@ test_subcommand () {
}
# Check that the given command was invoked as part of the
+# trace2-format trace on stdin, but without an exact set of
+# arguments.
+#
+# test_subcommand [!] <command> <args>... < <trace>
+#
+# For example, to look for an invocation of "git pack-objects"
+# with the "--honor-pack-keep" argument, use
+#
+# GIT_TRACE2_EVENT=event.log git repack ... &&
+# test_subcommand git pack-objects --honor-pack-keep <event.log
+#
+# If the first parameter passed is !, this instead checks that
+# the given command was not called.
+#
+test_subcommand_inexact () {
+ local negate=
+ if test "$1" = "!"
+ then
+ negate=t
+ shift
+ fi
+
+ local expr=$(printf '"%s".*' "$@")
+ expr="${expr%,}"
+
+ if test -n "$negate"
+ then
+ ! grep "\"event\":\"child_start\".*\[$expr\]"
+ else
+ grep "\"event\":\"child_start\".*\[$expr\]"
+ fi
+}
+
+# Check that the given command was invoked as part of the
# trace2-format trace on stdin.
#
# test_region [!] <category> <label> git <command> <args>...