summaryrefslogtreecommitdiff
path: root/t
diff options
context:
space:
mode:
Diffstat (limited to 't')
-rw-r--r--t/README12
-rw-r--r--t/helper/.gitignore1
-rw-r--r--t/helper/test-lazy-init-name-hash.c264
-rwxr-xr-xt/lib-submodule-update.sh596
-rw-r--r--t/perf/p0004-lazy-init-name-hash.sh19
-rwxr-xr-xt/t0001-init.sh14
-rwxr-xr-xt/t1007-hash-object.sh10
-rwxr-xr-xt/t1013-read-tree-submodule.sh8
-rwxr-xr-xt/t1060-object-corruption.sh24
-rwxr-xr-xt/t1400-update-ref.sh154
-rwxr-xr-xt/t1507-rev-parse-upstream.sh15
-rwxr-xr-xt/t1514-rev-parse-push.sh8
-rwxr-xr-xt/t2013-checkout-submodule.sh6
-rwxr-xr-xt/t3007-ls-files-recurse-submodules.sh39
-rwxr-xr-xt/t3200-branch.sh4
-rwxr-xr-xt/t3201-branch-contains.sh61
-rwxr-xr-xt/t3600-rm.sh20
-rwxr-xr-xt/t3903-stash.sh16
-rwxr-xr-xt/t3904-stash-patch.sh8
-rwxr-xr-xt/t4060-diff-submodule-option-diff-format.sh29
-rwxr-xr-xt/t4202-log.sh10
-rwxr-xr-xt/t5545-push-options.sh33
-rwxr-xr-xt/t5615-alternate-env.sh1
-rwxr-xr-xt/t6120-describe.sh20
-rwxr-xr-xt/t6302-for-each-ref-filter.sh20
-rwxr-xr-xt/t7004-tag.sh257
-rwxr-xr-xt/t7030-verify-tag.sh12
-rwxr-xr-xt/t7400-submodule-basic.sh136
-rwxr-xr-xt/t7406-submodule-update.sh6
-rwxr-xr-xt/t7413-submodule-is-active.sh107
-rwxr-xr-xt/t7504-commit-msg-hook.sh17
-rwxr-xr-xt/t7506-status-submodule.sh135
-rwxr-xr-xt/t7800-difftool.sh19
-rwxr-xr-xt/t7814-grep-recurse-submodules.sh75
-rwxr-xr-xt/t9902-completion.sh387
-rw-r--r--t/test-lib.sh6
36 files changed, 2393 insertions, 156 deletions
diff --git a/t/README b/t/README
index 4982d1c..ab386c3 100644
--- a/t/README
+++ b/t/README
@@ -471,13 +471,13 @@ Don't:
their output.
You can glean some further possible issues from the TAP grammar
- (see http://search.cpan.org/perldoc?TAP::Parser::Grammar#TAP_Grammar)
+ (see https://metacpan.org/pod/TAP::Parser::Grammar#TAP-GRAMMAR)
but the best indication is to just run the tests with prove(1),
it'll complain if anything is amiss.
Keep in mind:
- - Inside <script> part, the standard output and standard error
+ - Inside the <script> part, the standard output and standard error
streams are discarded, and the test harness only reports "ok" or
"not ok" to the end user running the tests. Under --verbose, they
are shown to help debugging the tests.
@@ -611,9 +611,11 @@ library for your script to use.
- test_have_prereq <prereq>
- Check if we have a prerequisite previously set with
- test_set_prereq. The most common use of this directly is to skip
- all the tests if we don't have some essential prerequisite:
+ Check if we have a prerequisite previously set with test_set_prereq.
+ The most common way to use this explicitly (as opposed to the
+ implicit use when an argument is passed to test_expect_*) is to skip
+ all the tests at the start of the test script if we don't have some
+ essential prerequisite:
if ! test_have_prereq PERL
then
diff --git a/t/helper/.gitignore b/t/helper/.gitignore
index d6e8b36..758ed2e 100644
--- a/t/helper/.gitignore
+++ b/t/helper/.gitignore
@@ -11,6 +11,7 @@
/test-genrandom
/test-hashmap
/test-index-version
+/test-lazy-init-name-hash
/test-line-buffer
/test-match-trees
/test-mergesort
diff --git a/t/helper/test-lazy-init-name-hash.c b/t/helper/test-lazy-init-name-hash.c
new file mode 100644
index 0000000..6368a89
--- /dev/null
+++ b/t/helper/test-lazy-init-name-hash.c
@@ -0,0 +1,264 @@
+#include "cache.h"
+#include "parse-options.h"
+
+static int single;
+static int multi;
+static int count = 1;
+static int dump;
+static int perf;
+static int analyze;
+static int analyze_step;
+
+/*
+ * Dump the contents of the "dir" and "name" hash tables to stdout.
+ * If you sort the result, you can compare it with the other type
+ * mode and verify that both single and multi produce the same set.
+ */
+static void dump_run(void)
+{
+ struct hashmap_iter iter_dir;
+ struct hashmap_iter iter_cache;
+
+ /* Stolen from name-hash.c */
+ struct dir_entry {
+ struct hashmap_entry ent;
+ struct dir_entry *parent;
+ int nr;
+ unsigned int namelen;
+ char name[FLEX_ARRAY];
+ };
+
+ struct dir_entry *dir;
+ struct cache_entry *ce;
+
+ read_cache();
+ if (single) {
+ test_lazy_init_name_hash(&the_index, 0);
+ } else {
+ int nr_threads_used = test_lazy_init_name_hash(&the_index, 1);
+ if (!nr_threads_used)
+ die("non-threaded code path used");
+ }
+
+ dir = hashmap_iter_first(&the_index.dir_hash, &iter_dir);
+ while (dir) {
+ printf("dir %08x %7d %s\n", dir->ent.hash, dir->nr, dir->name);
+ dir = hashmap_iter_next(&iter_dir);
+ }
+
+ ce = hashmap_iter_first(&the_index.name_hash, &iter_cache);
+ while (ce) {
+ printf("name %08x %s\n", ce->ent.hash, ce->name);
+ ce = hashmap_iter_next(&iter_cache);
+ }
+
+ discard_cache();
+}
+
+/*
+ * Run the single or multi threaded version "count" times and
+ * report on the time taken.
+ */
+static uint64_t time_runs(int try_threaded)
+{
+ uint64_t t0, t1, t2;
+ uint64_t sum = 0;
+ uint64_t avg;
+ int nr_threads_used;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ t0 = getnanotime();
+ read_cache();
+ t1 = getnanotime();
+ nr_threads_used = test_lazy_init_name_hash(&the_index, try_threaded);
+ t2 = getnanotime();
+
+ sum += (t2 - t1);
+
+ if (try_threaded && !nr_threads_used)
+ die("non-threaded code path used");
+
+ if (nr_threads_used)
+ printf("%f %f %d multi %d\n",
+ ((double)(t1 - t0))/1000000000,
+ ((double)(t2 - t1))/1000000000,
+ the_index.cache_nr,
+ nr_threads_used);
+ else
+ printf("%f %f %d single\n",
+ ((double)(t1 - t0))/1000000000,
+ ((double)(t2 - t1))/1000000000,
+ the_index.cache_nr);
+ fflush(stdout);
+
+ discard_cache();
+ }
+
+ avg = sum / count;
+ if (count > 1)
+ printf("avg %f %s\n",
+ (double)avg/1000000000,
+ (try_threaded) ? "multi" : "single");
+
+ return avg;
+}
+
+/*
+ * Try a series of runs varying the "istate->cache_nr" and
+ * try to find a good value for the multi-threaded criteria.
+ */
+static void analyze_run(void)
+{
+ uint64_t t1s, t1m, t2s, t2m;
+ int cache_nr_limit;
+ int nr_threads_used;
+ int i;
+ int nr;
+
+ read_cache();
+ cache_nr_limit = the_index.cache_nr;
+ discard_cache();
+
+ nr = analyze;
+ while (1) {
+ uint64_t sum_single = 0;
+ uint64_t sum_multi = 0;
+ uint64_t avg_single;
+ uint64_t avg_multi;
+
+ if (nr > cache_nr_limit)
+ nr = cache_nr_limit;
+
+ for (i = 0; i < count; i++) {
+ read_cache();
+ the_index.cache_nr = nr; /* cheap truncate of index */
+ t1s = getnanotime();
+ test_lazy_init_name_hash(&the_index, 0);
+ t2s = getnanotime();
+ sum_single += (t2s - t1s);
+ the_index.cache_nr = cache_nr_limit;
+ discard_cache();
+
+ read_cache();
+ the_index.cache_nr = nr; /* cheap truncate of index */
+ t1m = getnanotime();
+ nr_threads_used = test_lazy_init_name_hash(&the_index, 1);
+ t2m = getnanotime();
+ sum_multi += (t2m - t1m);
+ the_index.cache_nr = cache_nr_limit;
+ discard_cache();
+
+ if (!nr_threads_used)
+ printf(" [size %8d] [single %f] non-threaded code path used\n",
+ nr, ((double)(t2s - t1s))/1000000000);
+ else
+ printf(" [size %8d] [single %f] %c [multi %f %d]\n",
+ nr,
+ ((double)(t2s - t1s))/1000000000,
+ (((t2s - t1s) < (t2m - t1m)) ? '<' : '>'),
+ ((double)(t2m - t1m))/1000000000,
+ nr_threads_used);
+ fflush(stdout);
+ }
+ if (count > 1) {
+ avg_single = sum_single / count;
+ avg_multi = sum_multi / count;
+ if (!nr_threads_used)
+ printf("avg [size %8d] [single %f]\n",
+ nr,
+ (double)avg_single/1000000000);
+ else
+ printf("avg [size %8d] [single %f] %c [multi %f %d]\n",
+ nr,
+ (double)avg_single/1000000000,
+ (avg_single < avg_multi ? '<' : '>'),
+ (double)avg_multi/1000000000,
+ nr_threads_used);
+ fflush(stdout);
+ }
+
+ if (nr >= cache_nr_limit)
+ return;
+ nr += analyze_step;
+ }
+}
+
+int cmd_main(int argc, const char **argv)
+{
+ const char *usage[] = {
+ "test-lazy-init-name-hash -d (-s | -m)",
+ "test-lazy-init-name-hash -p [-c c]",
+ "test-lazy-init-name-hash -a a [--step s] [-c c]",
+ "test-lazy-init-name-hash (-s | -m) [-c c]",
+ "test-lazy-init-name-hash -s -m [-c c]",
+ NULL
+ };
+ struct option options[] = {
+ OPT_BOOL('s', "single", &single, "run single-threaded code"),
+ OPT_BOOL('m', "multi", &multi, "run multi-threaded code"),
+ OPT_INTEGER('c', "count", &count, "number of passes"),
+ OPT_BOOL('d', "dump", &dump, "dump hash tables"),
+ OPT_BOOL('p', "perf", &perf, "compare single vs multi"),
+ OPT_INTEGER('a', "analyze", &analyze, "analyze different multi sizes"),
+ OPT_INTEGER(0, "step", &analyze_step, "analyze step factor"),
+ OPT_END(),
+ };
+ const char *prefix;
+ uint64_t avg_single, avg_multi;
+
+ prefix = setup_git_directory();
+
+ argc = parse_options(argc, argv, prefix, options, usage, 0);
+
+ /*
+ * istate->dir_hash is only created when ignore_case is set.
+ */
+ ignore_case = 1;
+
+ if (dump) {
+ if (perf || analyze > 0)
+ die("cannot combine dump, perf, or analyze");
+ if (count > 1)
+ die("count not valid with dump");
+ if (single && multi)
+ die("cannot use both single and multi with dump");
+ if (!single && !multi)
+ die("dump requires either single or multi");
+ dump_run();
+ return 0;
+ }
+
+ if (perf) {
+ if (analyze > 0)
+ die("cannot combine dump, perf, or analyze");
+ if (single || multi)
+ die("cannot use single or multi with perf");
+ avg_single = time_runs(0);
+ avg_multi = time_runs(1);
+ if (avg_multi > avg_single)
+ die("multi is slower");
+ return 0;
+ }
+
+ if (analyze) {
+ if (analyze < 500)
+ die("analyze must be at least 500");
+ if (!analyze_step)
+ analyze_step = analyze;
+ if (single || multi)
+ die("cannot use single or multi with analyze");
+ analyze_run();
+ return 0;
+ }
+
+ if (!single && !multi)
+ die("require either -s or -m or both");
+
+ if (single)
+ time_runs(0);
+ if (multi)
+ time_runs(1);
+
+ return 0;
+}
diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh
index 915eb4a..fb4f7b0 100755
--- a/t/lib-submodule-update.sh
+++ b/t/lib-submodule-update.sh
@@ -4,6 +4,7 @@
# - New submodule (no_submodule => add_sub1)
# - Removed submodule (add_sub1 => remove_sub1)
# - Updated submodule (add_sub1 => modify_sub1)
+# - Updated submodule recursively (add_nested_sub => modify_sub1_recursively)
# - Submodule updated to invalid commit (add_sub1 => invalid_sub1)
# - Submodule updated from invalid commit (invalid_sub1 => valid_sub1)
# - Submodule replaced by tracked files in directory (add_sub1 =>
@@ -15,23 +16,50 @@
# - Tracked file replaced by submodule (replace_sub1_with_file =>
# replace_file_with_sub1)
#
-# --O-----O
-# / ^ replace_directory_with_sub1
-# / replace_sub1_with_directory
-# /----O
-# / ^
-# / modify_sub1
-# O------O-------O
-# ^ ^\ ^
-# | | \ remove_sub1
-# | | -----O-----O
-# | | \ ^ replace_file_with_sub1
-# | | \ replace_sub1_with_file
-# | add_sub1 --O-----O
-# no_submodule ^ valid_sub1
-# invalid_sub1
+# ----O
+# / ^
+# / remove_sub1
+# /
+# add_sub1 /-------O---------O--------O modify_sub1_recursively
+# | / ^ add_nested_sub
+# | / modify_sub1
+# v/
+# O------O-----------O---------O
+# ^ \ ^ replace_directory_with_sub1
+# | \ replace_sub1_with_directory
+# no_submodule \
+# --------O---------O
+# \ ^ replace_file_with_sub1
+# \ replace_sub1_with_file
+# \
+# ----O---------O
+# ^ valid_sub1
+# invalid_sub1
#
+
create_lib_submodule_repo () {
+ git init submodule_update_sub1 &&
+ (
+ cd submodule_update_sub1 &&
+ echo "expect" >>.gitignore &&
+ echo "actual" >>.gitignore &&
+ echo "x" >file1 &&
+ echo "y" >file2 &&
+ git add .gitignore file1 file2 &&
+ git commit -m "Base inside first submodule" &&
+ git branch "no_submodule"
+ ) &&
+ git init submodule_update_sub2 &&
+ (
+ cd submodule_update_sub2
+ echo "expect" >>.gitignore &&
+ echo "actual" >>.gitignore &&
+ echo "x" >file1 &&
+ echo "y" >file2 &&
+ git add .gitignore file1 file2 &&
+ git commit -m "nested submodule base" &&
+ git branch "no_submodule"
+ ) &&
git init submodule_update_repo &&
(
cd submodule_update_repo &&
@@ -44,15 +72,16 @@ create_lib_submodule_repo () {
git branch "no_submodule" &&
git checkout -b "add_sub1" &&
- git submodule add ./. sub1 &&
+ git submodule add ../submodule_update_sub1 sub1 &&
git config -f .gitmodules submodule.sub1.ignore all &&
git config submodule.sub1.ignore all &&
git add .gitmodules &&
git commit -m "Add sub1" &&
- git checkout -b remove_sub1 &&
+
+ git checkout -b remove_sub1 add_sub1 &&
git revert HEAD &&
- git checkout -b "modify_sub1" "add_sub1" &&
+ git checkout -b modify_sub1 add_sub1 &&
git submodule update &&
(
cd sub1 &&
@@ -67,7 +96,27 @@ create_lib_submodule_repo () {
git add sub1 &&
git commit -m "Modify sub1" &&
- git checkout -b "replace_sub1_with_directory" "add_sub1" &&
+ git checkout -b add_nested_sub modify_sub1 &&
+ git -C sub1 checkout -b "add_nested_sub" &&
+ git -C sub1 submodule add --branch no_submodule ../submodule_update_sub2 sub2 &&
+ git -C sub1 commit -a -m "add a nested submodule" &&
+ git add sub1 &&
+ git commit -a -m "update submodule, that updates a nested submodule" &&
+ git checkout -b modify_sub1_recursively &&
+ git -C sub1 checkout -b modify_sub1_recursively &&
+ git -C sub1/sub2 checkout -b modify_sub1_recursively &&
+ echo change >sub1/sub2/file3 &&
+ git -C sub1/sub2 add file3 &&
+ git -C sub1/sub2 commit -m "make a change in nested sub" &&
+ git -C sub1 add sub2 &&
+ git -C sub1 commit -m "update nested sub" &&
+ git add sub1 &&
+ git commit -m "update sub1, that updates nested sub" &&
+ git -C sub1 push origin modify_sub1_recursively &&
+ git -C sub1/sub2 push origin modify_sub1_recursively &&
+ git -C sub1 submodule deinit -f --all &&
+
+ git checkout -b replace_sub1_with_directory add_sub1 &&
git submodule update &&
git -C sub1 checkout modifications &&
git rm --cached sub1 &&
@@ -75,22 +124,25 @@ create_lib_submodule_repo () {
git config -f .gitmodules --remove-section "submodule.sub1" &&
git add .gitmodules sub1/* &&
git commit -m "Replace sub1 with directory" &&
+
git checkout -b replace_directory_with_sub1 &&
git revert HEAD &&
- git checkout -b "replace_sub1_with_file" "add_sub1" &&
+ git checkout -b replace_sub1_with_file add_sub1 &&
git rm sub1 &&
echo "content" >sub1 &&
git add sub1 &&
git commit -m "Replace sub1 with file" &&
+
git checkout -b replace_file_with_sub1 &&
git revert HEAD &&
- git checkout -b "invalid_sub1" "add_sub1" &&
+ git checkout -b invalid_sub1 add_sub1 &&
git update-index --cacheinfo 160000 0123456789012345678901234567890123456789 sub1 &&
git commit -m "Invalid sub1 commit" &&
git checkout -b valid_sub1 &&
git revert HEAD &&
+
git checkout master
)
}
@@ -130,6 +182,15 @@ test_git_directory_is_unchanged () {
)
}
+test_git_directory_exists() {
+ test -e ".git/modules/$1" &&
+ if test -f sub1/.git
+ then
+ # does core.worktree point at the right place?
+ test "$(git -C .git/modules/$1 config core.worktree)" = "../../../$1"
+ fi
+}
+
# Helper function to be executed at the start of every test below, it sets up
# the submodule repo if it doesn't exist and configures the most problematic
# settings for diff.ignoreSubmodules.
@@ -151,15 +212,36 @@ reset_work_tree_to () {
git checkout -f "$1" &&
git status -u -s >actual &&
test_must_be_empty actual &&
- sha1=$(git rev-parse --revs-only HEAD:sub1) &&
- if test -n "$sha1" &&
- test $(cd "sub1" && git rev-parse --verify "$sha1^{commit}")
+ hash=$(git rev-parse --revs-only HEAD:sub1) &&
+ if test -n "$hash" &&
+ test $(cd "../submodule_update_sub1" && git rev-parse --verify "$hash^{commit}")
then
git submodule update --init --recursive "sub1"
fi
)
}
+reset_work_tree_to_interested () {
+ reset_work_tree_to $1 &&
+ # make the submodule git dirs available
+ if ! test -d submodule_update/.git/modules/sub1
+ then
+ mkdir -p submodule_update/.git/modules &&
+ cp -r submodule_update_repo/.git/modules/sub1 submodule_update/.git/modules/sub1
+ GIT_WORK_TREE=. git -C submodule_update/.git/modules/sub1 config --unset core.worktree
+ fi &&
+ if ! test -d submodule_update/.git/modules/sub1/modules/sub2
+ then
+ mkdir -p submodule_update/.git/modules/sub1/modules &&
+ cp -r submodule_update_repo/.git/modules/sub1/modules/sub2 submodule_update/.git/modules/sub1/modules/sub2
+ GIT_WORK_TREE=. git -C submodule_update/.git/modules/sub1/modules/sub2 config --unset core.worktree
+ fi &&
+ # indicate we are interested in the submodule:
+ git -C submodule_update config submodule.sub1.url "bogus" &&
+ # sub1 might not be checked out, so use the git dir
+ git -C submodule_update/.git/modules/sub1 config submodule.sub2.url "bogus"
+}
+
# Test that the superproject contains the content according to commit "$1"
# (the work tree must match the index for everything but submodules but the
# index must exactly match the given commit including any submodule SHA-1s).
@@ -173,6 +255,11 @@ test_superproject_content () {
# Test that the given submodule at path "$1" contains the content according
# to the submodule commit recorded in the superproject's commit "$2"
test_submodule_content () {
+ if test x"$1" = "x-C"
+ then
+ cd "$2"
+ shift; shift;
+ fi
if test $# != 2
then
echo "test_submodule_content needs two arguments"
@@ -675,3 +762,464 @@ test_submodule_forced_switch () {
)
'
}
+
+# Test that submodule contents are correctly updated when switching
+# between commits that change a submodule.
+# Test that the following transitions are correctly handled:
+# (These tests are also above in the case where we expect no change
+# in the submodule)
+# - Updated submodule
+# - New submodule
+# - Removed submodule
+# - Directory containing tracked files replaced by submodule
+# - Submodule replaced by tracked files in directory
+# - Submodule replaced by tracked file with the same name
+# - tracked file replaced by submodule
+#
+# New test cases
+# - Removing a submodule with a git directory absorbs the submodules
+# git directory first into the superproject.
+
+test_submodule_switch_recursing () {
+ command="$1"
+ RESULTDS=success
+ if test "$KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS" = 1
+ then
+ RESULTDS=failure
+ fi
+ RESULTR=success
+ if test "$KNOWN_FAILURE_SUBMODULE_RECURSIVE_NESTED" = 1
+ then
+ RESULTR=failure
+ fi
+ RESULTOI=success
+ if test "$KNOWN_FAILURE_SUBMODULE_OVERWRITE_IGNORED_UNTRACKED" = 1
+ then
+ RESULTOI=failure
+ fi
+ ######################### Appearing submodule #########################
+ # Switching to a commit letting a submodule appear checks it out ...
+ test_expect_success "$command: added submodule is checked out" '
+ prolog &&
+ reset_work_tree_to_interested no_submodule &&
+ (
+ cd submodule_update &&
+ git branch -t add_sub1 origin/add_sub1 &&
+ $command add_sub1 &&
+ test_superproject_content origin/add_sub1 &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+ # ... ignoring an empty existing directory ...
+ test_expect_success "$command: added submodule is checked out in empty dir" '
+ prolog &&
+ reset_work_tree_to_interested no_submodule &&
+ (
+ cd submodule_update &&
+ mkdir sub1 &&
+ git branch -t add_sub1 origin/add_sub1 &&
+ $command add_sub1 &&
+ test_superproject_content origin/add_sub1 &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+ # ... unless there is an untracked file in its place.
+ test_expect_success "$command: added submodule doesn't remove untracked file with same name" '
+ prolog &&
+ reset_work_tree_to_interested no_submodule &&
+ (
+ cd submodule_update &&
+ git branch -t add_sub1 origin/add_sub1 &&
+ : >sub1 &&
+ test_must_fail $command add_sub1 &&
+ test_superproject_content origin/no_submodule &&
+ test_must_be_empty sub1
+ )
+ '
+ # ... but an ignored file is fine.
+ test_expect_$RESULTOI "$command: added submodule removes an untracked ignored file" '
+ test_when_finished "rm submodule_update/.git/info/exclude" &&
+ prolog &&
+ reset_work_tree_to_interested no_submodule &&
+ (
+ cd submodule_update &&
+ git branch -t add_sub1 origin/add_sub1 &&
+ : >sub1 &&
+ echo sub1 >.git/info/exclude
+ $command add_sub1 &&
+ test_superproject_content origin/add_sub1 &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+ # Replacing a tracked file with a submodule produces a checked out submodule
+ test_expect_success "$command: replace tracked file with submodule checks out submodule" '
+ prolog &&
+ reset_work_tree_to_interested replace_sub1_with_file &&
+ (
+ cd submodule_update &&
+ git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&
+ $command replace_file_with_sub1 &&
+ test_superproject_content origin/replace_file_with_sub1 &&
+ test_submodule_content sub1 origin/replace_file_with_sub1
+ )
+ '
+ # ... as does removing a directory with tracked files with a submodule.
+ test_expect_success "$command: replace directory with submodule" '
+ prolog &&
+ reset_work_tree_to_interested replace_sub1_with_directory &&
+ (
+ cd submodule_update &&
+ git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
+ $command replace_directory_with_sub1 &&
+ test_superproject_content origin/replace_directory_with_sub1 &&
+ test_submodule_content sub1 origin/replace_directory_with_sub1
+ )
+ '
+
+ ######################## Disappearing submodule #######################
+ # Removing a submodule removes its work tree ...
+ test_expect_success "$command: removed submodule removes submodules working tree" '
+ prolog &&
+ reset_work_tree_to_interested add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t remove_sub1 origin/remove_sub1 &&
+ $command remove_sub1 &&
+ test_superproject_content origin/remove_sub1 &&
+ ! test -e sub1
+ )
+ '
+ # ... absorbing a .git directory along the way.
+ test_expect_success "$command: removed submodule absorbs submodules .git directory" '
+ prolog &&
+ reset_work_tree_to_interested add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t remove_sub1 origin/remove_sub1 &&
+ replace_gitfile_with_git_dir sub1 &&
+ rm -rf .git/modules &&
+ $command remove_sub1 &&
+ test_superproject_content origin/remove_sub1 &&
+ ! test -e sub1 &&
+ test_git_directory_exists sub1
+ )
+ '
+ # Replacing a submodule with files in a directory must succeeds
+ # when the submodule is clean
+ test_expect_$RESULTDS "$command: replace submodule with a directory" '
+ prolog &&
+ reset_work_tree_to_interested add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+ $command replace_sub1_with_directory &&
+ test_superproject_content origin/replace_sub1_with_directory &&
+ test_submodule_content sub1 origin/replace_sub1_with_directory
+ )
+ '
+ # ... absorbing a .git directory.
+ test_expect_$RESULTDS "$command: replace submodule containing a .git directory with a directory must absorb the git dir" '
+ prolog &&
+ reset_work_tree_to_interested add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+ replace_gitfile_with_git_dir sub1 &&
+ rm -rf .git/modules &&
+ $command replace_sub1_with_directory &&
+ test_superproject_content origin/replace_sub1_with_directory &&
+ test_git_directory_exists sub1
+ )
+ '
+
+ # Replacing it with a file ...
+ test_expect_success "$command: replace submodule with a file" '
+ prolog &&
+ reset_work_tree_to_interested add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+ $command replace_sub1_with_file &&
+ test_superproject_content origin/replace_sub1_with_file &&
+ test -f sub1
+ )
+ '
+
+ # ... must check its local work tree for untracked files
+ test_expect_$RESULTDS "$command: replace submodule with a file must fail with untracked files" '
+ prolog &&
+ reset_work_tree_to_interested add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+ : >sub1/untrackedfile &&
+ test_must_fail $command replace_sub1_with_file &&
+ test_superproject_content origin/add_sub1 &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+
+ # ... and ignored files are ignored
+ test_expect_success "$command: replace submodule with a file works ignores ignored files in submodule" '
+ test_when_finished "rm submodule_update/.git/modules/sub1/info/exclude" &&
+ prolog &&
+ reset_work_tree_to_interested add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+ : >sub1/ignored &&
+ $command replace_sub1_with_file &&
+ test_superproject_content origin/replace_sub1_with_file &&
+ test -f sub1
+ )
+ '
+
+ ########################## Modified submodule #########################
+ # Updating a submodule sha1 updates the submodule's work tree
+ test_expect_success "$command: modified submodule updates submodule work tree" '
+ prolog &&
+ reset_work_tree_to_interested add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t modify_sub1 origin/modify_sub1 &&
+ $command modify_sub1 &&
+ test_superproject_content origin/modify_sub1 &&
+ test_submodule_content sub1 origin/modify_sub1
+ )
+ '
+
+ # Updating a submodule to an invalid sha1 doesn't update the
+ # superproject nor the submodule's work tree.
+ test_expect_success "$command: updating to a missing submodule commit fails" '
+ prolog &&
+ reset_work_tree_to_interested add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t invalid_sub1 origin/invalid_sub1 &&
+ test_must_fail $command invalid_sub1 &&
+ test_superproject_content origin/add_sub1 &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+
+ # recursing deeper than one level doesn't work yet.
+ test_expect_$RESULTR "$command: modified submodule updates submodule recursively" '
+ prolog &&
+ reset_work_tree_to_interested add_nested_sub &&
+ (
+ cd submodule_update &&
+ git branch -t modify_sub1_recursively origin/modify_sub1_recursively &&
+ $command modify_sub1_recursively &&
+ test_superproject_content origin/modify_sub1_recursively &&
+ test_submodule_content sub1 origin/modify_sub1_recursively &&
+ test_submodule_content -C sub1 sub2 origin/modify_sub1_recursively
+ )
+ '
+}
+
+# Test that submodule contents are updated when switching between commits
+# that change a submodule, but throwing away local changes in
+# the superproject as well as the submodule is allowed.
+test_submodule_forced_switch_recursing () {
+ command="$1"
+ RESULT=success
+ if test "$KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS" = 1
+ then
+ RESULT=failure
+ fi
+ ######################### Appearing submodule #########################
+ # Switching to a commit letting a submodule appear creates empty dir ...
+ test_expect_success "$command: added submodule is checked out" '
+ prolog &&
+ reset_work_tree_to_interested no_submodule &&
+ (
+ cd submodule_update &&
+ git branch -t add_sub1 origin/add_sub1 &&
+ $command add_sub1 &&
+ test_superproject_content origin/add_sub1 &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+ # ... and doesn't care if it already exists ...
+ test_expect_success "$command: added submodule ignores empty directory" '
+ prolog &&
+ reset_work_tree_to_interested no_submodule &&
+ (
+ cd submodule_update &&
+ git branch -t add_sub1 origin/add_sub1 &&
+ mkdir sub1 &&
+ $command add_sub1 &&
+ test_superproject_content origin/add_sub1 &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+ # ... not caring about an untracked file either
+ test_expect_success "$command: added submodule does remove untracked unignored file with same name when forced" '
+ prolog &&
+ reset_work_tree_to_interested no_submodule &&
+ (
+ cd submodule_update &&
+ git branch -t add_sub1 origin/add_sub1 &&
+ >sub1 &&
+ $command add_sub1 &&
+ test_superproject_content origin/add_sub1 &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+ # Replacing a tracked file with a submodule checks out the submodule
+ test_expect_success "$command: replace tracked file with submodule populates the submodule" '
+ prolog &&
+ reset_work_tree_to_interested replace_sub1_with_file &&
+ (
+ cd submodule_update &&
+ git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&
+ $command replace_file_with_sub1 &&
+ test_superproject_content origin/replace_file_with_sub1 &&
+ test_submodule_content sub1 origin/replace_file_with_sub1
+ )
+ '
+ # ... as does removing a directory with tracked files with a
+ # submodule.
+ test_expect_success "$command: replace directory with submodule" '
+ prolog &&
+ reset_work_tree_to_interested replace_sub1_with_directory &&
+ (
+ cd submodule_update &&
+ git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
+ $command replace_directory_with_sub1 &&
+ test_superproject_content origin/replace_directory_with_sub1 &&
+ test_submodule_content sub1 origin/replace_directory_with_sub1
+ )
+ '
+
+ ######################## Disappearing submodule #######################
+ # Removing a submodule doesn't remove its work tree ...
+ test_expect_success "$command: removed submodule leaves submodule directory and its contents in place" '
+ prolog &&
+ reset_work_tree_to_interested add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t remove_sub1 origin/remove_sub1 &&
+ $command remove_sub1 &&
+ test_superproject_content origin/remove_sub1 &&
+ ! test -e sub1
+ )
+ '
+ # ... especially when it contains a .git directory.
+ test_expect_success "$command: removed submodule leaves submodule containing a .git directory alone" '
+ prolog &&
+ reset_work_tree_to_interested add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t remove_sub1 origin/remove_sub1 &&
+ replace_gitfile_with_git_dir sub1 &&
+ rm -rf .git/modules/sub1 &&
+ $command remove_sub1 &&
+ test_superproject_content origin/remove_sub1 &&
+ test_git_directory_exists sub1 &&
+ ! test -e sub1
+ )
+ '
+ # Replacing a submodule with files in a directory ...
+ test_expect_success "$command: replace submodule with a directory" '
+ prolog &&
+ reset_work_tree_to_interested add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+ $command replace_sub1_with_directory &&
+ test_superproject_content origin/replace_sub1_with_directory
+ )
+ '
+ # ... absorbing a .git directory.
+ test_expect_success "$command: replace submodule containing a .git directory with a directory must fail" '
+ prolog &&
+ reset_work_tree_to_interested add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+ replace_gitfile_with_git_dir sub1 &&
+ rm -rf .git/modules/sub1 &&
+ $command replace_sub1_with_directory &&
+ test_superproject_content origin/replace_sub1_with_directory &&
+ test_submodule_content sub1 origin/modify_sub1
+ test_git_directory_exists sub1
+ )
+ '
+ # Replacing it with a file
+ test_expect_success "$command: replace submodule with a file" '
+ prolog &&
+ reset_work_tree_to_interested add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+ $command replace_sub1_with_file &&
+ test_superproject_content origin/replace_sub1_with_file
+ )
+ '
+
+ # ... even if the submodule contains ignored files
+ test_expect_success "$command: replace submodule with a file ignoring ignored files" '
+ prolog &&
+ reset_work_tree_to_interested add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+ : >sub1/expect &&
+ $command replace_sub1_with_file &&
+ test_superproject_content origin/replace_sub1_with_file
+ )
+ '
+
+ # ... but stops for untracked files that would be lost
+ test_expect_$RESULT "$command: replace submodule with a file stops for untracked files" '
+ prolog &&
+ reset_work_tree_to_interested add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+ : >sub1/untracked_file &&
+ test_must_fail $command replace_sub1_with_file &&
+ test_superproject_content origin/add_sub1 &&
+ test -f sub1/untracked_file
+ )
+ '
+
+ ########################## Modified submodule #########################
+ # Updating a submodule sha1 updates the submodule's work tree
+ test_expect_success "$command: modified submodule updates submodule work tree" '
+ prolog &&
+ reset_work_tree_to_interested add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t modify_sub1 origin/modify_sub1 &&
+ $command modify_sub1 &&
+ test_superproject_content origin/modify_sub1 &&
+ test_submodule_content sub1 origin/modify_sub1
+ )
+ '
+ # Updating a submodule to an invalid sha1 doesn't update the
+ # submodule's work tree, subsequent update will fail
+ test_expect_success "$command: modified submodule does not update submodule work tree to invalid commit" '
+ prolog &&
+ reset_work_tree_to_interested add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t invalid_sub1 origin/invalid_sub1 &&
+ test_must_fail $command invalid_sub1 &&
+ test_superproject_content origin/add_sub1 &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+ # Updating a submodule from an invalid sha1 updates
+ test_expect_success "$command: modified submodule does not update submodule work tree from invalid commit" '
+ prolog &&
+ reset_work_tree_to_interested invalid_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t valid_sub1 origin/valid_sub1 &&
+ test_must_fail $command valid_sub1 &&
+ test_superproject_content origin/invalid_sub1
+ )
+ '
+}
diff --git a/t/perf/p0004-lazy-init-name-hash.sh b/t/perf/p0004-lazy-init-name-hash.sh
new file mode 100644
index 0000000..5afa8c8
--- /dev/null
+++ b/t/perf/p0004-lazy-init-name-hash.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+test_description='Tests multi-threaded lazy_init_name_hash'
+. ./perf-lib.sh
+
+test_perf_large_repo
+test_checkout_worktree
+
+test_expect_success 'verify both methods build the same hashmaps' '
+ $GIT_BUILD_DIR/t/helper/test-lazy-init-name-hash$X --dump --single | sort >out.single &&
+ $GIT_BUILD_DIR/t/helper/test-lazy-init-name-hash$X --dump --multi | sort >out.multi &&
+ test_cmp out.single out.multi
+'
+
+test_expect_success 'multithreaded should be faster' '
+ $GIT_BUILD_DIR/t/helper/test-lazy-init-name-hash$X --perf >out.perf
+'
+
+test_done
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index e424de5..c4814d2 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -315,6 +315,20 @@ test_expect_success 'init with separate gitdir' '
test_path_is_dir realgitdir/refs
'
+test_expect_success 'init in long base path' '
+ # exceed initial buffer size of strbuf_getcwd()
+ component=123456789abcdef &&
+ test_when_finished "chmod 0700 $component; rm -rf $component" &&
+ p31=$component/$component &&
+ p127=$p31/$p31/$p31/$p31 &&
+ mkdir -p $p127 &&
+ chmod 0111 $component &&
+ (
+ cd $p127 &&
+ git init newdir
+ )
+'
+
test_expect_success 're-init on .git file' '
( cd newdir && git init )
'
diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh
index c5245c5..532682f 100755
--- a/t/t1007-hash-object.sh
+++ b/t/t1007-hash-object.sh
@@ -134,6 +134,16 @@ test_expect_success 'gitattributes also work in a subdirectory' '
)
'
+test_expect_success '--path works in a subdirectory' '
+ (
+ cd subdir &&
+ path1_sha=$(git hash-object --path=../file1 ../file0) &&
+ path0_sha=$(git hash-object --path=../file0 ../file1) &&
+ test "$file0_sha" = "$path0_sha" &&
+ test "$file1_sha" = "$path1_sha"
+ )
+'
+
test_expect_success 'check that --no-filters option works' '
nofilters_file1=$(git hash-object --no-filters file1) &&
test "$file0_sha" = "$nofilters_file1" &&
diff --git a/t/t1013-read-tree-submodule.sh b/t/t1013-read-tree-submodule.sh
index 20526ae..de1ba02 100755
--- a/t/t1013-read-tree-submodule.sh
+++ b/t/t1013-read-tree-submodule.sh
@@ -5,6 +5,14 @@ test_description='read-tree can handle submodules'
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-submodule-update.sh
+KNOWN_FAILURE_SUBMODULE_RECURSIVE_NESTED=1
+KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS=1
+KNOWN_FAILURE_SUBMODULE_OVERWRITE_IGNORED_UNTRACKED=1
+
+test_submodule_switch_recursing "git read-tree --recurse-submodules -u -m"
+
+test_submodule_forced_switch_recursing "git read-tree --recurse-submodules -u --reset"
+
test_submodule_switch "git read-tree -u -m"
test_submodule_forced_switch "git read-tree -u --reset"
diff --git a/t/t1060-object-corruption.sh b/t/t1060-object-corruption.sh
index 3f87051..ac1f189 100755
--- a/t/t1060-object-corruption.sh
+++ b/t/t1060-object-corruption.sh
@@ -21,6 +21,14 @@ test_expect_success 'setup corrupt repo' '
cd bit-error &&
test_commit content &&
corrupt_byte HEAD:content.t 10
+ ) &&
+ git init no-bit-error &&
+ (
+ # distinct commit from bit-error, but containing a
+ # non-corrupted version of the same blob
+ cd no-bit-error &&
+ test_tick &&
+ test_commit content
)
'
@@ -53,6 +61,13 @@ test_expect_success 'streaming a corrupt blob fails' '
)
'
+test_expect_success 'getting type of a corrupt blob fails' '
+ (
+ cd bit-error &&
+ test_must_fail git cat-file -s HEAD:content.t
+ )
+'
+
test_expect_success 'read-tree -u detects bit-errors in blobs' '
(
cd bit-error &&
@@ -101,4 +116,13 @@ test_expect_failure 'clone --local detects misnamed objects' '
test_must_fail git clone --local misnamed misnamed-checkout
'
+test_expect_success 'fetch into corrupted repo with index-pack' '
+ (
+ cd bit-error &&
+ test_must_fail git -c transfer.unpackLimit=1 \
+ fetch ../no-bit-error 2>stderr &&
+ test_i18ngrep ! -i collision stderr
+ )
+'
+
test_done
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index 8254223..a23cd7b 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -40,7 +40,7 @@ test_expect_success \
"git update-ref $m $A &&
test $A"' = $(cat .git/'"$m"')'
test_expect_success \
- "create $m" \
+ "create $m with oldvalue verification" \
"git update-ref $m $B $A &&
test $B"' = $(cat .git/'"$m"')'
test_expect_success "fail to delete $m with stale ref" '
@@ -48,31 +48,31 @@ test_expect_success "fail to delete $m with stale ref" '
test $B = "$(cat .git/$m)"
'
test_expect_success "delete $m" '
+ test_when_finished "rm -f .git/$m" &&
git update-ref -d $m $B &&
- ! test -f .git/$m
+ test_path_is_missing .git/$m
'
-rm -f .git/$m
-test_expect_success "delete $m without oldvalue verification" "
+test_expect_success "delete $m without oldvalue verification" '
+ test_when_finished "rm -f .git/$m" &&
git update-ref $m $A &&
- test $A = \$(cat .git/$m) &&
+ test $A = $(cat .git/$m) &&
git update-ref -d $m &&
- ! test -f .git/$m
-"
-rm -f .git/$m
+ test_path_is_missing .git/$m
+'
-test_expect_success \
- "fail to create $n" \
- "touch .git/$n_dir &&
- test_must_fail git update-ref $n $A >out 2>err"
-rm -f .git/$n_dir out err
+test_expect_success "fail to create $n" '
+ test_when_finished "rm -f .git/$n_dir" &&
+ touch .git/$n_dir &&
+ test_must_fail git update-ref $n $A
+'
test_expect_success \
"create $m (by HEAD)" \
"git update-ref HEAD $A &&
test $A"' = $(cat .git/'"$m"')'
test_expect_success \
- "create $m (by HEAD)" \
+ "create $m (by HEAD) with oldvalue verification" \
"git update-ref HEAD $B $A &&
test $B"' = $(cat .git/'"$m"')'
test_expect_success "fail to delete $m (by HEAD) with stale ref" '
@@ -80,28 +80,28 @@ test_expect_success "fail to delete $m (by HEAD) with stale ref" '
test $B = $(cat .git/$m)
'
test_expect_success "delete $m (by HEAD)" '
+ test_when_finished "rm -f .git/$m" &&
git update-ref -d HEAD $B &&
- ! test -f .git/$m
+ test_path_is_missing .git/$m
'
-rm -f .git/$m
test_expect_success "deleting current branch adds message to HEAD's log" '
+ test_when_finished "rm -f .git/$m" &&
git update-ref $m $A &&
git symbolic-ref HEAD $m &&
git update-ref -m delete-$m -d $m &&
- ! test -f .git/$m &&
+ test_path_is_missing .git/$m &&
grep "delete-$m$" .git/logs/HEAD
'
-rm -f .git/$m
test_expect_success "deleting by HEAD adds message to HEAD's log" '
+ test_when_finished "rm -f .git/$m" &&
git update-ref $m $A &&
git symbolic-ref HEAD $m &&
git update-ref -m delete-by-head -d HEAD &&
- ! test -f .git/$m &&
+ test_path_is_missing .git/$m &&
grep "delete-by-head$" .git/logs/HEAD
'
-rm -f .git/$m
test_expect_success 'update-ref does not create reflogs by default' '
test_when_finished "git update-ref -d $outside" &&
@@ -188,28 +188,29 @@ test_expect_success \
"git update-ref HEAD $B $A &&
test $B"' = $(cat .git/'"$m"')'
test_expect_success "delete $m (by HEAD) should remove both packed and loose $m" '
+ test_when_finished "rm -f .git/$m" &&
git update-ref -d HEAD $B &&
! grep "$m" .git/packed-refs &&
- ! test -f .git/$m
+ test_path_is_missing .git/$m
'
-rm -f .git/$m
cp -f .git/HEAD .git/HEAD.orig
test_expect_success "delete symref without dereference" '
+ test_when_finished "cp -f .git/HEAD.orig .git/HEAD" &&
git update-ref --no-deref -d HEAD &&
- ! test -f .git/HEAD
+ test_path_is_missing .git/HEAD
'
-cp -f .git/HEAD.orig .git/HEAD
test_expect_success "delete symref without dereference when the referred ref is packed" '
+ test_when_finished "cp -f .git/HEAD.orig .git/HEAD" &&
echo foo >foo.c &&
git add foo.c &&
git commit -m foo &&
git pack-refs --all &&
git update-ref --no-deref -d HEAD &&
- ! test -f .git/HEAD
+ test_path_is_missing .git/HEAD
'
-cp -f .git/HEAD.orig .git/HEAD
+
git update-ref -d $m
test_expect_success 'update-ref -d is not confused by self-reference' '
@@ -241,10 +242,10 @@ test_expect_success 'update-ref --no-deref -d can delete reference to bad ref' '
test_expect_success '(not) create HEAD with old sha1' "
test_must_fail git update-ref HEAD $A $B
"
-test_expect_success "(not) prior created .git/$m" "
- ! test -f .git/$m
-"
-rm -f .git/$m
+test_expect_success "(not) prior created .git/$m" '
+ test_when_finished "rm -f .git/$m" &&
+ test_path_is_missing .git/$m
+'
test_expect_success \
"create HEAD" \
@@ -252,38 +253,41 @@ test_expect_success \
test_expect_success '(not) change HEAD with wrong SHA1' "
test_must_fail git update-ref HEAD $B $Z
"
-test_expect_success "(not) changed .git/$m" "
- ! test $B"' = $(cat .git/'"$m"')
+test_expect_success "(not) changed .git/$m" '
+ test_when_finished "rm -f .git/$m" &&
+ ! test $B = $(cat .git/$m)
'
-rm -f .git/$m
rm -f .git/logs/refs/heads/master
test_expect_success \
"create $m (logged by touch)" \
- 'GIT_COMMITTER_DATE="2005-05-26 23:30" \
+ 'test_config core.logAllRefUpdates false &&
+ GIT_COMMITTER_DATE="2005-05-26 23:30" \
git update-ref --create-reflog HEAD '"$A"' -m "Initial Creation" &&
test '"$A"' = $(cat .git/'"$m"')'
test_expect_success \
"update $m (logged by touch)" \
- 'GIT_COMMITTER_DATE="2005-05-26 23:31" \
+ 'test_config core.logAllRefUpdates false &&
+ GIT_COMMITTER_DATE="2005-05-26 23:31" \
git update-ref HEAD'" $B $A "'-m "Switch" &&
test '"$B"' = $(cat .git/'"$m"')'
test_expect_success \
"set $m (logged by touch)" \
- 'GIT_COMMITTER_DATE="2005-05-26 23:41" \
+ 'test_config core.logAllRefUpdates false &&
+ GIT_COMMITTER_DATE="2005-05-26 23:41" \
git update-ref HEAD'" $A &&
test $A"' = $(cat .git/'"$m"')'
test_expect_success "empty directory removal" '
git branch d1/d2/r1 HEAD &&
git branch d1/r2 HEAD &&
- test -f .git/refs/heads/d1/d2/r1 &&
- test -f .git/logs/refs/heads/d1/d2/r1 &&
+ test_path_is_file .git/refs/heads/d1/d2/r1 &&
+ test_path_is_file .git/logs/refs/heads/d1/d2/r1 &&
git branch -d d1/d2/r1 &&
- ! test -e .git/refs/heads/d1/d2 &&
- ! test -e .git/logs/refs/heads/d1/d2 &&
- test -f .git/refs/heads/d1/r2 &&
- test -f .git/logs/refs/heads/d1/r2
+ test_path_is_missing .git/refs/heads/d1/d2 &&
+ test_path_is_missing .git/logs/refs/heads/d1/d2 &&
+ test_path_is_file .git/refs/heads/d1/r2 &&
+ test_path_is_file .git/logs/refs/heads/d1/r2
'
test_expect_success "symref empty directory removal" '
@@ -291,14 +295,14 @@ test_expect_success "symref empty directory removal" '
git branch e1/r2 HEAD &&
git checkout e1/e2/r1 &&
test_when_finished "git checkout master" &&
- test -f .git/refs/heads/e1/e2/r1 &&
- test -f .git/logs/refs/heads/e1/e2/r1 &&
+ test_path_is_file .git/refs/heads/e1/e2/r1 &&
+ test_path_is_file .git/logs/refs/heads/e1/e2/r1 &&
git update-ref -d HEAD &&
- ! test -e .git/refs/heads/e1/e2 &&
- ! test -e .git/logs/refs/heads/e1/e2 &&
- test -f .git/refs/heads/e1/r2 &&
- test -f .git/logs/refs/heads/e1/r2 &&
- test -f .git/logs/HEAD
+ test_path_is_missing .git/refs/heads/e1/e2 &&
+ test_path_is_missing .git/logs/refs/heads/e1/e2 &&
+ test_path_is_file .git/refs/heads/e1/r2 &&
+ test_path_is_file .git/logs/refs/heads/e1/r2 &&
+ test_path_is_file .git/logs/HEAD
'
cat >expect <<EOF
@@ -306,29 +310,27 @@ $Z $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 Initial Creati
$A $B $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150260 +0000 Switch
$B $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150860 +0000
EOF
-test_expect_success \
- "verifying $m's log" \
- "test_cmp expect .git/logs/$m"
-rm -rf .git/$m .git/logs expect
-
-test_expect_success \
- 'enable core.logAllRefUpdates' \
- 'git config core.logAllRefUpdates true &&
- test true = $(git config --bool --get core.logAllRefUpdates)'
+test_expect_success "verifying $m's log (logged by touch)" '
+ test_when_finished "rm -rf .git/$m .git/logs expect" &&
+ test_cmp expect .git/logs/$m
+'
test_expect_success \
"create $m (logged by config)" \
- 'GIT_COMMITTER_DATE="2005-05-26 23:32" \
+ 'test_config core.logAllRefUpdates true &&
+ GIT_COMMITTER_DATE="2005-05-26 23:32" \
git update-ref HEAD'" $A "'-m "Initial Creation" &&
test '"$A"' = $(cat .git/'"$m"')'
test_expect_success \
"update $m (logged by config)" \
- 'GIT_COMMITTER_DATE="2005-05-26 23:33" \
+ 'test_config core.logAllRefUpdates true &&
+ GIT_COMMITTER_DATE="2005-05-26 23:33" \
git update-ref HEAD'" $B $A "'-m "Switch" &&
test '"$B"' = $(cat .git/'"$m"')'
test_expect_success \
"set $m (logged by config)" \
- 'GIT_COMMITTER_DATE="2005-05-26 23:43" \
+ 'test_config core.logAllRefUpdates true &&
+ GIT_COMMITTER_DATE="2005-05-26 23:43" \
git update-ref HEAD '"$A &&
test $A"' = $(cat .git/'"$m"')'
@@ -338,9 +340,9 @@ $A $B $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150380 +0000 Switch
$B $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150980 +0000
EOF
test_expect_success \
- "verifying $m's log" \
- 'test_cmp expect .git/logs/$m'
-rm -f .git/$m .git/logs/$m expect
+ "verifying $m's log (logged by config)" \
+ 'test_when_finished "rm -f .git/$m .git/logs/$m expect" &&
+ test_cmp expect .git/logs/$m'
git update-ref $m $D
cat >.git/logs/$m <<EOF
@@ -356,55 +358,55 @@ gd="Thu, 26 May 2005 18:33:00 -0500"
ld="Thu, 26 May 2005 18:43:00 -0500"
test_expect_success \
'Query "master@{May 25 2005}" (before history)' \
- 'rm -f o e &&
+ 'test_when_finished "rm -f o e" &&
git rev-parse --verify "master@{May 25 2005}" >o 2>e &&
test '"$C"' = $(cat o) &&
test "warning: Log for '\'master\'' only goes back to $ed." = "$(cat e)"'
test_expect_success \
"Query master@{2005-05-25} (before history)" \
- 'rm -f o e &&
+ 'test_when_finished "rm -f o e" &&
git rev-parse --verify master@{2005-05-25} >o 2>e &&
test '"$C"' = $(cat o) &&
echo test "warning: Log for '\'master\'' only goes back to $ed." = "$(cat e)"'
test_expect_success \
'Query "master@{May 26 2005 23:31:59}" (1 second before history)' \
- 'rm -f o e &&
+ 'test_when_finished "rm -f o e" &&
git rev-parse --verify "master@{May 26 2005 23:31:59}" >o 2>e &&
test '"$C"' = $(cat o) &&
test "warning: Log for '\''master'\'' only goes back to $ed." = "$(cat e)"'
test_expect_success \
'Query "master@{May 26 2005 23:32:00}" (exactly history start)' \
- 'rm -f o e &&
+ 'test_when_finished "rm -f o e" &&
git rev-parse --verify "master@{May 26 2005 23:32:00}" >o 2>e &&
test '"$C"' = $(cat o) &&
test "" = "$(cat e)"'
test_expect_success \
'Query "master@{May 26 2005 23:32:30}" (first non-creation change)' \
- 'rm -f o e &&
+ 'test_when_finished "rm -f o e" &&
git rev-parse --verify "master@{May 26 2005 23:32:30}" >o 2>e &&
test '"$A"' = $(cat o) &&
test "" = "$(cat e)"'
test_expect_success \
'Query "master@{2005-05-26 23:33:01}" (middle of history with gap)' \
- 'rm -f o e &&
+ 'test_when_finished "rm -f o e" &&
git rev-parse --verify "master@{2005-05-26 23:33:01}" >o 2>e &&
test '"$B"' = $(cat o) &&
test "warning: Log for ref '"$m has gap after $gd"'." = "$(cat e)"'
test_expect_success \
'Query "master@{2005-05-26 23:38:00}" (middle of history)' \
- 'rm -f o e &&
+ 'test_when_finished "rm -f o e" &&
git rev-parse --verify "master@{2005-05-26 23:38:00}" >o 2>e &&
test '"$Z"' = $(cat o) &&
test "" = "$(cat e)"'
test_expect_success \
'Query "master@{2005-05-26 23:43:00}" (exact end of history)' \
- 'rm -f o e &&
+ 'test_when_finished "rm -f o e" &&
git rev-parse --verify "master@{2005-05-26 23:43:00}" >o 2>e &&
test '"$E"' = $(cat o) &&
test "" = "$(cat e)"'
test_expect_success \
'Query "master@{2005-05-28}" (past end of history)' \
- 'rm -f o e &&
+ 'test_when_finished "rm -f o e" &&
git rev-parse --verify "master@{2005-05-28}" >o 2>e &&
test '"$D"' = $(cat o) &&
test "warning: Log for ref '"$m unexpectedly ended on $ld"'." = "$(cat e)"'
@@ -414,7 +416,8 @@ rm -f .git/$m .git/logs/$m expect
test_expect_success \
'creating initial files' \
- 'echo TEST >F &&
+ 'test_when_finished rm -f M &&
+ echo TEST >F &&
git add F &&
GIT_AUTHOR_DATE="2005-05-26 23:30" \
GIT_COMMITTER_DATE="2005-05-26 23:30" git commit -m add -a &&
@@ -432,8 +435,7 @@ test_expect_success \
echo $h_TEST >.git/MERGE_HEAD &&
GIT_AUTHOR_DATE="2005-05-26 23:45" \
GIT_COMMITTER_DATE="2005-05-26 23:45" git commit -F M &&
- h_MERGED=$(git rev-parse --verify HEAD) &&
- rm -f M'
+ h_MERGED=$(git rev-parse --verify HEAD)'
cat >expect <<EOF
$Z $h_TEST $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 commit (initial): add
diff --git a/t/t1507-rev-parse-upstream.sh b/t/t1507-rev-parse-upstream.sh
index 46ef1f2..b23c4e3 100755
--- a/t/t1507-rev-parse-upstream.sh
+++ b/t/t1507-rev-parse-upstream.sh
@@ -46,11 +46,14 @@ error_message () {
}
test_expect_success '@{upstream} resolves to correct full name' '
- test refs/remotes/origin/master = "$(full_name @{upstream})"
+ test refs/remotes/origin/master = "$(full_name @{upstream})" &&
+ test refs/remotes/origin/master = "$(full_name @{UPSTREAM})" &&
+ test refs/remotes/origin/master = "$(full_name @{UpSTReam})"
'
test_expect_success '@{u} resolves to correct full name' '
- test refs/remotes/origin/master = "$(full_name @{u})"
+ test refs/remotes/origin/master = "$(full_name @{u})" &&
+ test refs/remotes/origin/master = "$(full_name @{U})"
'
test_expect_success 'my-side@{upstream} resolves to correct full name' '
@@ -60,6 +63,8 @@ test_expect_success 'my-side@{upstream} resolves to correct full name' '
test_expect_success 'upstream of branch with @ in middle' '
full_name fun@ny@{u} >actual &&
echo refs/remotes/origin/side >expect &&
+ test_cmp expect actual &&
+ full_name fun@ny@{U} >actual &&
test_cmp expect actual
'
@@ -96,12 +101,14 @@ test_expect_success 'not-tracking@{u} fails' '
test_expect_success '<branch>@{u}@{1} resolves correctly' '
test_commit 6 &&
(cd clone && git fetch) &&
- test 5 = $(commit_subject my-side@{u}@{1})
+ test 5 = $(commit_subject my-side@{u}@{1}) &&
+ test 5 = $(commit_subject my-side@{U}@{1})
'
test_expect_success '@{u} without specifying branch fails on a detached HEAD' '
git checkout HEAD^0 &&
- test_must_fail git rev-parse @{u}
+ test_must_fail git rev-parse @{u} &&
+ test_must_fail git rev-parse @{U}
'
test_expect_success 'checkout -b new my-side@{u} forks from the same' '
diff --git a/t/t1514-rev-parse-push.sh b/t/t1514-rev-parse-push.sh
index 623a32a..788cc91 100755
--- a/t/t1514-rev-parse-push.sh
+++ b/t/t1514-rev-parse-push.sh
@@ -24,12 +24,16 @@ test_expect_success 'setup' '
test_expect_success '@{push} with default=nothing' '
test_config push.default nothing &&
- test_must_fail git rev-parse master@{push}
+ test_must_fail git rev-parse master@{push} &&
+ test_must_fail git rev-parse master@{PUSH} &&
+ test_must_fail git rev-parse master@{PuSH}
'
test_expect_success '@{push} with default=simple' '
test_config push.default simple &&
- resolve master@{push} refs/remotes/origin/master
+ resolve master@{push} refs/remotes/origin/master &&
+ resolve master@{PUSH} refs/remotes/origin/master &&
+ resolve master@{pUSh} refs/remotes/origin/master
'
test_expect_success 'triangular @{push} fails with default=simple' '
diff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh
index 6847f75..e8f70b8 100755
--- a/t/t2013-checkout-submodule.sh
+++ b/t/t2013-checkout-submodule.sh
@@ -63,6 +63,12 @@ test_expect_success '"checkout <submodule>" honors submodule.*.ignore from .git/
! test -s actual
'
+KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS=1
+KNOWN_FAILURE_SUBMODULE_RECURSIVE_NESTED=1
+test_submodule_switch_recursing "git checkout --recurse-submodules"
+
+test_submodule_forced_switch_recursing "git checkout -f --recurse-submodules"
+
test_submodule_switch "git checkout"
test_submodule_forced_switch "git checkout -f"
diff --git a/t/t3007-ls-files-recurse-submodules.sh b/t/t3007-ls-files-recurse-submodules.sh
index a542617..4cf6ccf 100755
--- a/t/t3007-ls-files-recurse-submodules.sh
+++ b/t/t3007-ls-files-recurse-submodules.sh
@@ -188,6 +188,45 @@ test_expect_success '--recurse-submodules and pathspecs' '
test_cmp expect actual
'
+test_expect_success '--recurse-submodules and relative paths' '
+ # From subdir
+ cat >expect <<-\EOF &&
+ b
+ EOF
+ git -C b ls-files --recurse-submodules >actual &&
+ test_cmp expect actual &&
+
+ # Relative path to top
+ cat >expect <<-\EOF &&
+ ../.gitmodules
+ ../a
+ b
+ ../h.txt
+ ../sib/file
+ ../sub/file
+ ../submodule/.gitmodules
+ ../submodule/c
+ ../submodule/f.TXT
+ ../submodule/g.txt
+ ../submodule/subsub/d
+ ../submodule/subsub/e.txt
+ EOF
+ git -C b ls-files --recurse-submodules -- .. >actual &&
+ test_cmp expect actual &&
+
+ # Relative path to submodule
+ cat >expect <<-\EOF &&
+ ../submodule/.gitmodules
+ ../submodule/c
+ ../submodule/f.TXT
+ ../submodule/g.txt
+ ../submodule/subsub/d
+ ../submodule/subsub/e.txt
+ EOF
+ git -C b ls-files --recurse-submodules -- ../submodule >actual &&
+ test_cmp expect actual
+'
+
test_expect_success '--recurse-submodules does not support --error-unmatch' '
test_must_fail git ls-files --recurse-submodules --error-unmatch 2>actual &&
test_i18ngrep "does not support --error-unmatch" actual
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 9f353c0..fe62e7c 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -978,6 +978,10 @@ test_expect_success '--merged catches invalid object names' '
test_must_fail git branch --merged 0000000000000000000000000000000000000000
'
+test_expect_success '--merged is incompatible with --no-merged' '
+ test_must_fail git branch --merged HEAD --no-merged HEAD
+'
+
test_expect_success 'tracking with unexpected .fetch refspec' '
rm -rf a b c d &&
git init a &&
diff --git a/t/t3201-branch-contains.sh b/t/t3201-branch-contains.sh
index 7f3ec47..0ef1b6f 100755
--- a/t/t3201-branch-contains.sh
+++ b/t/t3201-branch-contains.sh
@@ -1,6 +1,6 @@
#!/bin/sh
-test_description='branch --contains <commit>, --merged, and --no-merged'
+test_description='branch --contains <commit>, --no-contains <commit> --merged, and --no-merged'
. ./test-lib.sh
@@ -45,6 +45,22 @@ test_expect_success 'branch --contains master' '
'
+test_expect_success 'branch --no-contains=master' '
+
+ git branch --no-contains=master >actual &&
+ >expect &&
+ test_cmp expect actual
+
+'
+
+test_expect_success 'branch --no-contains master' '
+
+ git branch --no-contains master >actual &&
+ >expect &&
+ test_cmp expect actual
+
+'
+
test_expect_success 'branch --contains=side' '
git branch --contains=side >actual &&
@@ -55,6 +71,16 @@ test_expect_success 'branch --contains=side' '
'
+test_expect_success 'branch --no-contains=side' '
+
+ git branch --no-contains=side >actual &&
+ {
+ echo " master"
+ } >expect &&
+ test_cmp expect actual
+
+'
+
test_expect_success 'branch --contains with pattern implies --list' '
git branch --contains=master master >actual &&
@@ -65,6 +91,14 @@ test_expect_success 'branch --contains with pattern implies --list' '
'
+test_expect_success 'branch --no-contains with pattern implies --list' '
+
+ git branch --no-contains=master master >actual &&
+ >expect &&
+ test_cmp expect actual
+
+'
+
test_expect_success 'side: branch --merged' '
git branch --merged >actual &&
@@ -126,8 +160,20 @@ test_expect_success 'branch --no-merged with pattern implies --list' '
test_expect_success 'implicit --list conflicts with modification options' '
test_must_fail git branch --contains=master -d &&
- test_must_fail git branch --contains=master -m foo
+ test_must_fail git branch --contains=master -m foo &&
+ test_must_fail git branch --no-contains=master -d &&
+ test_must_fail git branch --no-contains=master -m foo
+
+'
+test_expect_success 'Assert that --contains only works on commits, not trees & blobs' '
+ test_must_fail git branch --contains master^{tree} &&
+ blob=$(git hash-object -w --stdin <<-\EOF
+ Some blob
+ EOF
+ ) &&
+ test_must_fail git branch --contains $blob &&
+ test_must_fail git branch --no-contains $blob
'
# We want to set up a case where the walk for the tracking info
@@ -159,4 +205,15 @@ test_expect_success 'branch --merged with --verbose' '
test_i18ncmp expect actual
'
+test_expect_success 'branch --contains combined with --no-contains' '
+ git branch --contains zzz --no-contains topic >actual &&
+ cat >expect <<-\EOF &&
+ master
+ side
+ zzz
+ EOF
+ test_cmp expect actual
+
+'
+
test_done
diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh
index 5aa6db5..5f9913b 100755
--- a/t/t3600-rm.sh
+++ b/t/t3600-rm.sh
@@ -268,6 +268,14 @@ cat >expect.modified <<EOF
M submod
EOF
+cat >expect.modified_inside <<EOF
+ m submod
+EOF
+
+cat >expect.modified_untracked <<EOF
+ ? submod
+EOF
+
cat >expect.cached <<EOF
D submod
EOF
@@ -421,7 +429,7 @@ test_expect_success 'rm of a populated submodule with modifications fails unless
test -d submod &&
test -f submod/.git &&
git status -s -uno --ignore-submodules=none >actual &&
- test_cmp expect.modified actual &&
+ test_cmp expect.modified_inside actual &&
git rm -f submod &&
test ! -d submod &&
git status -s -uno --ignore-submodules=none >actual &&
@@ -436,7 +444,7 @@ test_expect_success 'rm of a populated submodule with untracked files fails unle
test -d submod &&
test -f submod/.git &&
git status -s -uno --ignore-submodules=none >actual &&
- test_cmp expect.modified actual &&
+ test_cmp expect.modified_untracked actual &&
git rm -f submod &&
test ! -d submod &&
git status -s -uno --ignore-submodules=none >actual &&
@@ -621,7 +629,7 @@ test_expect_success 'rm of a populated nested submodule with different nested HE
test -d submod &&
test -f submod/.git &&
git status -s -uno --ignore-submodules=none >actual &&
- test_cmp expect.modified actual &&
+ test_cmp expect.modified_inside actual &&
git rm -f submod &&
test ! -d submod &&
git status -s -uno --ignore-submodules=none >actual &&
@@ -636,7 +644,7 @@ test_expect_success 'rm of a populated nested submodule with nested modification
test -d submod &&
test -f submod/.git &&
git status -s -uno --ignore-submodules=none >actual &&
- test_cmp expect.modified actual &&
+ test_cmp expect.modified_inside actual &&
git rm -f submod &&
test ! -d submod &&
git status -s -uno --ignore-submodules=none >actual &&
@@ -651,14 +659,14 @@ test_expect_success 'rm of a populated nested submodule with nested untracked fi
test -d submod &&
test -f submod/.git &&
git status -s -uno --ignore-submodules=none >actual &&
- test_cmp expect.modified actual &&
+ test_cmp expect.modified_untracked actual &&
git rm -f submod &&
test ! -d submod &&
git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect actual
'
-test_expect_success 'rm of a populated nested submodule with a nested .git directory fails even when forced' '
+test_expect_success "rm absorbs submodule's nested .git directory" '
git reset --hard &&
git submodule update --recursive &&
(cd submod/subsubmod &&
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 89877e4..b71d1e6 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -663,7 +663,7 @@ test_expect_success 'stash apply shows status same as git status (relative to cu
sane_unset GIT_MERGE_VERBOSITY &&
git stash apply
) |
- sed -e 1,2d >actual && # drop "Saved..." and "HEAD is now..."
+ sed -e 1d >actual && # drop "Saved..."
test_i18ncmp expect actual
'
@@ -907,4 +907,18 @@ test_expect_success 'stash without verb with pathspec' '
test_path_is_file bar
'
+test_expect_success 'stash -k -- <pathspec> leaves unstaged files intact' '
+ git reset &&
+ >foo &&
+ >bar &&
+ git add foo bar &&
+ git commit -m "test" &&
+ echo "foo" >foo &&
+ echo "bar" >bar &&
+ git stash -k -- foo &&
+ test "",bar = $(cat foo),$(cat bar) &&
+ git stash pop &&
+ test foo,bar = $(cat foo),$(cat bar)
+'
+
test_done
diff --git a/t/t3904-stash-patch.sh b/t/t3904-stash-patch.sh
index 38e7300..83744f8 100755
--- a/t/t3904-stash-patch.sh
+++ b/t/t3904-stash-patch.sh
@@ -77,6 +77,14 @@ test_expect_success 'git stash --no-keep-index -p' '
verify_state dir/foo work index
'
+test_expect_success 'stash -p --no-keep-index -- <pathspec> does not unstage other files' '
+ set_state HEAD HEADfile_work HEADfile_index &&
+ set_state dir/foo work index &&
+ echo y | git stash push -p --no-keep-index -- HEAD &&
+ verify_state HEAD committed committed &&
+ verify_state dir/foo work index
+'
+
test_expect_success 'none of this moved HEAD' '
verify_saved_head
'
diff --git a/t/t4060-diff-submodule-option-diff-format.sh b/t/t4060-diff-submodule-option-diff-format.sh
index 7e23b55..d4a3ffa 100755
--- a/t/t4060-diff-submodule-option-diff-format.sh
+++ b/t/t4060-diff-submodule-option-diff-format.sh
@@ -746,4 +746,33 @@ test_expect_success 'diff --submodule=diff with .git file' '
test_cmp expected actual
'
+test_expect_success 'setup nested submodule' '
+ git submodule add -f ./sm2 &&
+ git commit -a -m "add sm2" &&
+ git -C sm2 submodule add ../sm2 nested &&
+ git -C sm2 commit -a -m "nested sub"
+'
+
+test_expect_success 'move nested submodule HEAD' '
+ echo "nested content" >sm2/nested/file &&
+ git -C sm2/nested add file &&
+ git -C sm2/nested commit --allow-empty -m "new HEAD"
+'
+
+test_expect_success 'diff --submodule=diff with moved nested submodule HEAD' '
+ cat >expected <<-EOF &&
+ Submodule nested a5a65c9..b55928c:
+ diff --git a/nested/file b/nested/file
+ new file mode 100644
+ index 0000000..ca281f5
+ --- /dev/null
+ +++ b/nested/file
+ @@ -0,0 +1 @@
+ +nested content
+ EOF
+ git -C sm2 diff --submodule=diff >actual 2>err &&
+ test_must_be_empty err &&
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index 48b55bf..f577990 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -4,6 +4,7 @@ test_description='git log'
. ./test-lib.sh
. "$TEST_DIRECTORY/lib-gpg.sh"
+. "$TEST_DIRECTORY/lib-terminal.sh"
test_expect_success setup '
@@ -520,7 +521,7 @@ test_expect_success 'log --graph with merge' '
'
test_expect_success 'log.decorate configuration' '
- git log --oneline >expect.none &&
+ git log --oneline --no-decorate >expect.none &&
git log --oneline --decorate >expect.short &&
git log --oneline --decorate=full >expect.full &&
@@ -576,6 +577,13 @@ test_expect_success 'log.decorate configuration' '
'
+test_expect_success TTY 'log output on a TTY' '
+ git log --oneline --decorate >expect.short &&
+
+ test_terminal git log --oneline >actual &&
+ test_cmp expect.short actual
+'
+
test_expect_success 'reflog is expected format' '
git log -g --abbrev-commit --pretty=oneline >expect &&
git reflog >actual &&
diff --git a/t/t5545-push-options.sh b/t/t5545-push-options.sh
index 9a57a7d..97065e6 100755
--- a/t/t5545-push-options.sh
+++ b/t/t5545-push-options.sh
@@ -102,17 +102,46 @@ test_expect_success 'two push options work' '
test_cmp expect upstream/.git/hooks/post-receive.push_options
'
-test_expect_success 'push option denied properly by http remote helper' '\
+test_expect_success 'push option denied properly by http server' '
+ test_when_finished "rm -rf test_http_clone" &&
+ test_when_finished "rm -rf \"$HTTPD_DOCUMENT_ROOT_PATH\"/upstream.git" &&
mk_repo_pair &&
git -C upstream config receive.advertisePushOptions false &&
git -C upstream config http.receivepack true &&
cp -R upstream/.git "$HTTPD_DOCUMENT_ROOT_PATH"/upstream.git &&
git clone "$HTTPD_URL"/smart/upstream test_http_clone &&
test_commit -C test_http_clone one &&
- test_must_fail git -C test_http_clone push --push-option=asdf origin master &&
+ test_must_fail git -C test_http_clone push --push-option=asdf origin master 2>actual &&
+ test_i18ngrep "the receiving end does not support push options" actual &&
git -C test_http_clone push origin master
'
+test_expect_success 'push options work properly across http' '
+ test_when_finished "rm -rf test_http_clone" &&
+ test_when_finished "rm -rf \"$HTTPD_DOCUMENT_ROOT_PATH\"/upstream.git" &&
+ mk_repo_pair &&
+ git -C upstream config receive.advertisePushOptions true &&
+ git -C upstream config http.receivepack true &&
+ cp -R upstream/.git "$HTTPD_DOCUMENT_ROOT_PATH"/upstream.git &&
+ git clone "$HTTPD_URL"/smart/upstream test_http_clone &&
+
+ test_commit -C test_http_clone one &&
+ git -C test_http_clone push origin master &&
+ git -C "$HTTPD_DOCUMENT_ROOT_PATH"/upstream.git rev-parse --verify master >expect &&
+ git -C test_http_clone rev-parse --verify master >actual &&
+ test_cmp expect actual &&
+
+ test_commit -C test_http_clone two &&
+ git -C test_http_clone push --push-option=asdf --push-option="more structured text" origin master &&
+ printf "asdf\nmore structured text\n" >expect &&
+ test_cmp expect "$HTTPD_DOCUMENT_ROOT_PATH"/upstream.git/hooks/pre-receive.push_options &&
+ test_cmp expect "$HTTPD_DOCUMENT_ROOT_PATH"/upstream.git/hooks/post-receive.push_options &&
+
+ git -C "$HTTPD_DOCUMENT_ROOT_PATH"/upstream.git rev-parse --verify master >expect &&
+ git -C test_http_clone rev-parse --verify master >actual &&
+ test_cmp expect actual
+'
+
stop_httpd
test_done
diff --git a/t/t5615-alternate-env.sh b/t/t5615-alternate-env.sh
index 26ebb03..d2d883f 100755
--- a/t/t5615-alternate-env.sh
+++ b/t/t5615-alternate-env.sh
@@ -77,6 +77,7 @@ test_expect_success 'mix of quoted and unquoted alternates' '
check_obj "$quoted:$unquoted" <<-EOF
$one blob
$two blob
+ EOF
'
test_expect_success !MINGW 'broken quoting falls back to interpreting raw' '
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index 167491f..16952e4 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -233,4 +233,24 @@ test_expect_success 'describe --contains and --no-match' '
test_cmp expect actual
'
+test_expect_success 'setup and absorb a submodule' '
+ test_create_repo sub1 &&
+ test_commit -C sub1 initial &&
+ git submodule add ./sub1 &&
+ git submodule absorbgitdirs &&
+ git commit -a -m "add submodule" &&
+ git describe --dirty >expect &&
+ git describe --broken >out &&
+ test_cmp expect out
+'
+
+test_expect_success 'describe chokes on severly broken submodules' '
+ mv .git/modules/sub1/ .git/modules/sub_moved &&
+ test_must_fail git describe --dirty
+'
+test_expect_success 'describe ignoring a borken submodule' '
+ git describe --broken >out &&
+ grep broken out
+'
+
test_done
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index a09a1a4..fc067ed 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -93,6 +93,22 @@ test_expect_success 'filtering with --contains' '
test_cmp expect actual
'
+test_expect_success 'filtering with --no-contains' '
+ cat >expect <<-\EOF &&
+ refs/tags/one
+ EOF
+ git for-each-ref --format="%(refname)" --no-contains=two >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'filtering with --contains and --no-contains' '
+ cat >expect <<-\EOF &&
+ refs/tags/two
+ EOF
+ git for-each-ref --format="%(refname)" --contains=two --no-contains=three >actual &&
+ test_cmp expect actual
+'
+
test_expect_success '%(color) must fail' '
test_must_fail git for-each-ref --format="%(color)%(refname)"
'
@@ -421,4 +437,8 @@ test_expect_success 'check %(if:notequals=<string>)' '
test_cmp expect actual
'
+test_expect_success '--merged is incompatible with --no-merged' '
+ test_must_fail git for-each-ref --merged HEAD --no-merged HEAD
+'
+
test_done
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index b4698ab..bb2e4d7 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -16,7 +16,6 @@ tag_exists () {
git show-ref --quiet --verify refs/tags/"$1"
}
-# todo: git tag -l now returns always zero, when fixed, change this test
test_expect_success 'listing all tags in an empty tree should succeed' '
git tag -l &&
git tag
@@ -119,6 +118,18 @@ test_expect_success 'listing all tags if one exists should succeed' '
git tag
'
+cat >expect <<EOF
+mytag
+EOF
+test_expect_success 'Multiple -l or --list options are equivalent to one -l option' '
+ git tag -l -l >actual &&
+ test_cmp expect actual &&
+ git tag --list --list >actual &&
+ test_cmp expect actual &&
+ git tag --list -l --list >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'listing all tags if one exists should output that tag' '
test $(git tag -l) = mytag &&
test $(git tag) = mytag
@@ -136,9 +147,8 @@ test_expect_success \
'listing a tag using a matching pattern should output that tag' \
'test $(git tag -l mytag) = mytag'
-# todo: git tag -l now returns always zero, when fixed, change this test
test_expect_success \
- 'listing tags using a non-matching pattern should suceed' \
+ 'listing tags using a non-matching pattern should succeed' \
'git tag -l xxx'
test_expect_success \
@@ -338,6 +348,19 @@ test_expect_success 'tag -l can accept multiple patterns' '
test_cmp expect actual
'
+# Between v1.7.7 & v2.13.0 a fair reading of the git-tag documentation
+# could leave you with the impression that "-l <pattern> -l <pattern>"
+# was how we wanted to accept multiple patterns.
+#
+# This test should not imply that this is a sane thing to support. but
+# since the documentation was worded like it was let's at least find
+# out if we're going to break this long-documented form of taking
+# multiple patterns.
+test_expect_success 'tag -l <pattern> -l <pattern> works, as our buggy documentation previously suggested' '
+ git tag -l "v1*" -l "v0*" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'listing tags in column' '
COLUMNS=40 git tag -l --column=row >actual &&
cat >expected <<\EOF &&
@@ -620,6 +643,11 @@ test_expect_success \
git tag -n0 -l tag-one-line >actual &&
test_cmp expect actual &&
+ git tag -n0 | grep "^tag-one-line" >actual &&
+ test_cmp expect actual &&
+ git tag -n0 tag-one-line >actual &&
+ test_cmp expect actual &&
+
echo "tag-one-line A msg" >expect &&
git tag -n1 -l | grep "^tag-one-line" >actual &&
test_cmp expect actual &&
@@ -633,6 +661,17 @@ test_expect_success \
test_cmp expect actual
'
+test_expect_success 'The -n 100 invocation means -n --list 100, not -n100' '
+ >expect &&
+ git tag -n 100 >actual &&
+ test_cmp expect actual &&
+
+ git tag -m "A msg" 100 &&
+ echo "100 A msg" >expect &&
+ git tag -n 100 >actual &&
+ test_cmp expect actual
+'
+
test_expect_success \
'listing the zero-lines message of a non-signed tag should succeed' '
git tag -m "" tag-zero-lines &&
@@ -895,18 +934,16 @@ test_expect_success GPG 'verifying a forged tag should fail' '
test_must_fail git tag -v forged-tag
'
-test_expect_success 'verifying a proper tag with --format pass and format accordingly' '
- cat >expect <<-\EOF
+test_expect_success GPG 'verifying a proper tag with --format pass and format accordingly' '
+ cat >expect <<-\EOF &&
tagname : signed-tag
- EOF &&
+ EOF
git tag -v --format="tagname : %(tag)" "signed-tag" >actual &&
test_cmp expect actual
'
-test_expect_success 'verifying a forged tag with --format fail and format accordingly' '
- cat >expect <<-\EOF
- tagname : forged-tag
- EOF &&
+test_expect_success GPG 'verifying a forged tag with --format should fail silently' '
+ >expect &&
test_must_fail git tag -v --format="tagname : %(tag)" "forged-tag" >actual &&
test_cmp expect actual
'
@@ -1385,6 +1422,23 @@ test_expect_success 'checking that first commit is in all tags (relative)' "
test_cmp expected actual
"
+# All the --contains tests above, but with --no-contains
+test_expect_success 'checking that first commit is not listed in any tag with --no-contains (hash)' "
+ >expected &&
+ git tag -l --no-contains $hash1 v* >actual &&
+ test_cmp expected actual
+"
+
+test_expect_success 'checking that first commit is in all tags (tag)' "
+ git tag -l --no-contains v1.0 v* >actual &&
+ test_cmp expected actual
+"
+
+test_expect_success 'checking that first commit is in all tags (relative)' "
+ git tag -l --no-contains HEAD~2 v* >actual &&
+ test_cmp expected actual
+"
+
cat > expected <<EOF
v2.0
EOF
@@ -1394,6 +1448,17 @@ test_expect_success 'checking that second commit only has one tag' "
test_cmp expected actual
"
+cat > expected <<EOF
+v0.2.1
+v1.0
+v1.0.1
+v1.1.3
+EOF
+
+test_expect_success 'inverse of the last test, with --no-contains' "
+ git tag -l --no-contains $hash2 v* >actual &&
+ test_cmp expected actual
+"
cat > expected <<EOF
EOF
@@ -1403,6 +1468,19 @@ test_expect_success 'checking that third commit has no tags' "
test_cmp expected actual
"
+cat > expected <<EOF
+v0.2.1
+v1.0
+v1.0.1
+v1.1.3
+v2.0
+EOF
+
+test_expect_success 'conversely --no-contains on the third commit lists all tags' "
+ git tag -l --no-contains $hash3 v* >actual &&
+ test_cmp expected actual
+"
+
# how about a simple merge?
test_expect_success 'creating simple branch' '
@@ -1424,6 +1502,19 @@ test_expect_success 'checking that branch head only has one tag' "
test_cmp expected actual
"
+cat > expected <<EOF
+v0.2.1
+v1.0
+v1.0.1
+v1.1.3
+v2.0
+EOF
+
+test_expect_success 'checking that branch head with --no-contains lists all but one tag' "
+ git tag -l --no-contains $hash4 v* >actual &&
+ test_cmp expected actual
+"
+
test_expect_success 'merging original branch into this branch' '
git merge --strategy=ours master &&
git tag v4.0
@@ -1445,6 +1536,20 @@ v1.0.1
v1.1.3
v2.0
v3.0
+EOF
+
+test_expect_success 'checking that original branch head with --no-contains lists all but one tag now' "
+ git tag -l --no-contains $hash3 v* >actual &&
+ test_cmp expected actual
+"
+
+cat > expected <<EOF
+v0.2.1
+v1.0
+v1.0.1
+v1.1.3
+v2.0
+v3.0
v4.0
EOF
@@ -1453,21 +1558,76 @@ test_expect_success 'checking that initial commit is in all tags' "
test_cmp expected actual
"
+test_expect_success 'checking that --contains can be used in non-list mode' '
+ git tag --contains $hash1 v* >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'checking that initial commit is in all tags with --no-contains' "
+ >expected &&
+ git tag -l --no-contains $hash1 v* >actual &&
+ test_cmp expected actual
+"
+
# mixing modes and options:
test_expect_success 'mixing incompatibles modes and options is forbidden' '
test_must_fail git tag -a &&
+ test_must_fail git tag -a -l &&
+ test_must_fail git tag -s &&
+ test_must_fail git tag -s -l &&
+ test_must_fail git tag -m &&
+ test_must_fail git tag -m -l &&
+ test_must_fail git tag -m "hlagh" &&
+ test_must_fail git tag -m "hlagh" -l &&
+ test_must_fail git tag -F &&
+ test_must_fail git tag -F -l &&
+ test_must_fail git tag -f &&
+ test_must_fail git tag -f -l &&
+ test_must_fail git tag -a -s -m -F &&
+ test_must_fail git tag -a -s -m -F -l &&
test_must_fail git tag -l -v &&
- test_must_fail git tag -n 100 &&
+ test_must_fail git tag -l -d &&
+ test_must_fail git tag -l -v -d &&
+ test_must_fail git tag -n 100 -v &&
test_must_fail git tag -l -m msg &&
test_must_fail git tag -l -F some file &&
- test_must_fail git tag -v -s
-'
+ test_must_fail git tag -v -s &&
+ test_must_fail git tag --contains tag-tree &&
+ test_must_fail git tag --contains tag-blob &&
+ test_must_fail git tag --no-contains tag-tree &&
+ test_must_fail git tag --no-contains tag-blob &&
+ test_must_fail git tag --contains --no-contains &&
+ test_must_fail git tag --no-with HEAD &&
+ test_must_fail git tag --no-without HEAD
+'
+
+for option in --contains --with --no-contains --without --merged --no-merged --points-at
+do
+ test_expect_success "mixing incompatible modes with $option is forbidden" "
+ test_must_fail git tag -d $option HEAD &&
+ test_must_fail git tag -d $option HEAD some-tag &&
+ test_must_fail git tag -v $option HEAD
+ "
+ test_expect_success "Doing 'git tag --list-like $option <commit> <pattern> is permitted" "
+ git tag -n $option HEAD HEAD &&
+ git tag $option HEAD HEAD &&
+ git tag $option
+ "
+done
# check points-at
-test_expect_success '--points-at cannot be used in non-list mode' '
- test_must_fail git tag --points-at=v4.0 foo
+test_expect_success '--points-at can be used in non-list mode' '
+ echo v4.0 >expect &&
+ git tag --points-at=v4.0 "v*" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--points-at is a synonym for --points-at HEAD' '
+ echo v4.0 >expect &&
+ git tag --points-at >actual &&
+ test_cmp expect actual
'
test_expect_success '--points-at finds lightweight tags' '
@@ -1709,7 +1869,7 @@ run_with_limited_stack () {
test_lazy_prereq ULIMIT_STACK_SIZE 'run_with_limited_stack true'
# we require ulimit, this excludes Windows
-test_expect_success ULIMIT_STACK_SIZE '--contains works in a deep repo' '
+test_expect_success ULIMIT_STACK_SIZE '--contains and --no-contains work in a deep repo' '
>expect &&
i=1 &&
while test $i -lt 8000
@@ -1725,7 +1885,9 @@ EOF"
git checkout master &&
git tag far-far-away HEAD^ &&
run_with_limited_stack git tag --contains HEAD >actual &&
- test_cmp expect actual
+ test_cmp expect actual &&
+ run_with_limited_stack git tag --no-contains HEAD >actual &&
+ test_line_count ">" 10 actual
'
test_expect_success '--format should list tags as per format given' '
@@ -1744,8 +1906,17 @@ test_expect_success 'setup --merged test tags' '
git tag mergetest-3 HEAD
'
-test_expect_success '--merged cannot be used in non-list mode' '
- test_must_fail git tag --merged=mergetest-2 foo
+test_expect_success '--merged can be used in non-list mode' '
+ cat >expect <<-\EOF &&
+ mergetest-1
+ mergetest-2
+ EOF
+ git tag --merged=mergetest-2 "mergetest*" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--merged is incompatible with --no-merged' '
+ test_must_fail git tag --merged HEAD --no-merged HEAD
'
test_expect_success '--merged shows merged tags' '
@@ -1765,6 +1936,11 @@ test_expect_success '--no-merged show unmerged tags' '
test_cmp expect actual
'
+test_expect_success '--no-merged can be used in non-list mode' '
+ git tag --no-merged=mergetest-2 mergetest-* >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'ambiguous branch/tags not marked' '
git tag ambiguous &&
git branch ambiguous &&
@@ -1773,4 +1949,47 @@ test_expect_success 'ambiguous branch/tags not marked' '
test_cmp expect actual
'
+test_expect_success '--contains combined with --no-contains' '
+ (
+ git init no-contains &&
+ cd no-contains &&
+ test_commit v0.1 &&
+ test_commit v0.2 &&
+ test_commit v0.3 &&
+ test_commit v0.4 &&
+ test_commit v0.5 &&
+ cat >expected <<-\EOF &&
+ v0.2
+ v0.3
+ v0.4
+ EOF
+ git tag --contains v0.2 --no-contains v0.5 >actual &&
+ test_cmp expected actual
+ )
+'
+
+# As the docs say, list tags which contain a specified *commit*. We
+# don't recurse down to tags for trees or blobs pointed to by *those*
+# commits.
+test_expect_success 'Does --[no-]contains stop at commits? Yes!' '
+ cd no-contains &&
+ blob=$(git rev-parse v0.3:v0.3.t) &&
+ tree=$(git rev-parse v0.3^{tree}) &&
+ git tag tag-blob $blob &&
+ git tag tag-tree $tree &&
+ git tag --contains v0.3 >actual &&
+ cat >expected <<-\EOF &&
+ v0.3
+ v0.4
+ v0.5
+ EOF
+ test_cmp expected actual &&
+ git tag --no-contains v0.3 >actual &&
+ cat >expected <<-\EOF &&
+ v0.1
+ v0.2
+ EOF
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t7030-verify-tag.sh b/t/t7030-verify-tag.sh
index d62ccbb..b4b49ee 100755
--- a/t/t7030-verify-tag.sh
+++ b/t/t7030-verify-tag.sh
@@ -125,18 +125,16 @@ test_expect_success GPG 'verify multiple tags' '
test_cmp expect.stderr actual.stderr
'
-test_expect_success 'verifying tag with --format' '
- cat >expect <<-\EOF
+test_expect_success GPG 'verifying tag with --format' '
+ cat >expect <<-\EOF &&
tagname : fourth-signed
- EOF &&
+ EOF
git verify-tag --format="tagname : %(tag)" "fourth-signed" >actual &&
test_cmp expect actual
'
-test_expect_success 'verifying a forged tag with --format fail and format accordingly' '
- cat >expect <<-\EOF
- tagname : 7th forged-signed
- EOF &&
+test_expect_success GPG 'verifying a forged tag with --format should fail silently' '
+ >expect &&
test_must_fail git verify-tag --format="tagname : %(tag)" $(cat forged1.tag) >actual-forged &&
test_cmp expect actual-forged
'
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index c09ce0d..cf77a3a 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -1130,5 +1130,141 @@ test_expect_success 'submodule helper list is not confused by common prefixes' '
test_cmp expect actual
'
+test_expect_success 'setup superproject with submodules' '
+ git init sub1 &&
+ test_commit -C sub1 test &&
+ test_commit -C sub1 test2 &&
+ git init multisuper &&
+ git -C multisuper submodule add ../sub1 sub0 &&
+ git -C multisuper submodule add ../sub1 sub1 &&
+ git -C multisuper submodule add ../sub1 sub2 &&
+ git -C multisuper submodule add ../sub1 sub3 &&
+ git -C multisuper commit -m "add some submodules"
+'
+
+cat >expect <<-EOF
+-sub0
+ sub1 (test2)
+ sub2 (test2)
+ sub3 (test2)
+EOF
+
+test_expect_success 'submodule update --init with a specification' '
+ test_when_finished "rm -rf multisuper_clone" &&
+ pwd=$(pwd) &&
+ git clone file://"$pwd"/multisuper multisuper_clone &&
+ git -C multisuper_clone submodule update --init . ":(exclude)sub0" &&
+ git -C multisuper_clone submodule status |cut -c 1,43- >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'submodule update --init with submodule.active set' '
+ test_when_finished "rm -rf multisuper_clone" &&
+ pwd=$(pwd) &&
+ git clone file://"$pwd"/multisuper multisuper_clone &&
+ git -C multisuper_clone config submodule.active "." &&
+ git -C multisuper_clone config --add submodule.active ":(exclude)sub0" &&
+ git -C multisuper_clone submodule update --init &&
+ git -C multisuper_clone submodule status |cut -c 1,43- >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'submodule update and setting submodule.<name>.active' '
+ test_when_finished "rm -rf multisuper_clone" &&
+ pwd=$(pwd) &&
+ git clone file://"$pwd"/multisuper multisuper_clone &&
+ git -C multisuper_clone config --bool submodule.sub0.active "true" &&
+ git -C multisuper_clone config --bool submodule.sub1.active "false" &&
+ git -C multisuper_clone config --bool submodule.sub2.active "true" &&
+
+ cat >expect <<-\EOF &&
+ sub0 (test2)
+ -sub1
+ sub2 (test2)
+ -sub3
+ EOF
+ git -C multisuper_clone submodule update &&
+ git -C multisuper_clone submodule status |cut -c 1,43- >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'clone --recurse-submodules with a pathspec works' '
+ test_when_finished "rm -rf multisuper_clone" &&
+ cat >expected <<-\EOF &&
+ sub0 (test2)
+ -sub1
+ -sub2
+ -sub3
+ EOF
+
+ git clone --recurse-submodules="sub0" multisuper multisuper_clone &&
+ git -C multisuper_clone submodule status |cut -c1,43- >actual &&
+ test_cmp actual expected
+'
+
+test_expect_success 'clone with multiple --recurse-submodules options' '
+ test_when_finished "rm -rf multisuper_clone" &&
+ cat >expect <<-\EOF &&
+ -sub0
+ sub1 (test2)
+ -sub2
+ sub3 (test2)
+ EOF
+
+ git clone --recurse-submodules="." \
+ --recurse-submodules=":(exclude)sub0" \
+ --recurse-submodules=":(exclude)sub2" \
+ multisuper multisuper_clone &&
+ git -C multisuper_clone submodule status |cut -c1,43- >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'clone and subsequent updates correctly auto-initialize submodules' '
+ test_when_finished "rm -rf multisuper_clone" &&
+ cat <<-\EOF >expect &&
+ -sub0
+ sub1 (test2)
+ -sub2
+ sub3 (test2)
+ EOF
+
+ cat <<-\EOF >expect2 &&
+ -sub0
+ sub1 (test2)
+ -sub2
+ sub3 (test2)
+ -sub4
+ sub5 (test2)
+ EOF
+
+ git clone --recurse-submodules="." \
+ --recurse-submodules=":(exclude)sub0" \
+ --recurse-submodules=":(exclude)sub2" \
+ --recurse-submodules=":(exclude)sub4" \
+ multisuper multisuper_clone &&
+
+ git -C multisuper_clone submodule status |cut -c1,43- >actual &&
+ test_cmp expect actual &&
+
+ git -C multisuper submodule add ../sub1 sub4 &&
+ git -C multisuper submodule add ../sub1 sub5 &&
+ git -C multisuper commit -m "add more submodules" &&
+ # obtain the new superproject
+ git -C multisuper_clone pull &&
+ git -C multisuper_clone submodule update --init &&
+ git -C multisuper_clone submodule status |cut -c1,43- >actual &&
+ test_cmp expect2 actual
+'
+
+test_expect_success 'init properly sets the config' '
+ test_when_finished "rm -rf multisuper_clone" &&
+ git clone --recurse-submodules="." \
+ --recurse-submodules=":(exclude)sub0" \
+ multisuper multisuper_clone &&
+
+ git -C multisuper_clone submodule init -- sub0 sub1 &&
+ git -C multisuper_clone config --get submodule.sub0.active &&
+ test_must_fail git -C multisuper_clone config --get submodule.sub1.active
+'
test_done
diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index 347857f..4ac386d 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -442,11 +442,11 @@ test_expect_success 'submodule update - command in .git/config catches failure -
'
test_expect_success 'submodule update - command run for initial population of submodule' '
- cat <<-\ EOF >expect
+ cat >expect <<-EOF &&
Execution of '\''false $submodulesha1'\'' failed in submodule path '\''submodule'\''
- EOF &&
+ EOF
rm -rf super/submodule &&
- test_must_fail git -C super submodule update >../actual &&
+ test_must_fail git -C super submodule update 2>actual &&
test_cmp expect actual &&
git -C super submodule update --checkout
'
diff --git a/t/t7413-submodule-is-active.sh b/t/t7413-submodule-is-active.sh
new file mode 100755
index 0000000..9c785b0
--- /dev/null
+++ b/t/t7413-submodule-is-active.sh
@@ -0,0 +1,107 @@
+#!/bin/sh
+
+test_description='Test submodule--helper is-active
+
+This test verifies that `git submodue--helper is-active` correclty identifies
+submodules which are "active" and interesting to the user.
+'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ git init sub &&
+ test_commit -C sub initial &&
+ git init super &&
+ test_commit -C super initial &&
+ git -C super submodule add ../sub sub1 &&
+ git -C super submodule add ../sub sub2 &&
+
+ # Remove submodule.<name>.active entries in order to test in an
+ # environment where only URLs are present in the conifg
+ git -C super config --unset submodule.sub1.active &&
+ git -C super config --unset submodule.sub2.active &&
+
+ git -C super commit -a -m "add 2 submodules at sub{1,2}"
+'
+
+test_expect_success 'is-active works with urls' '
+ git -C super submodule--helper is-active sub1 &&
+ git -C super submodule--helper is-active sub2 &&
+
+ git -C super config --unset submodule.sub1.URL &&
+ test_must_fail git -C super submodule--helper is-active sub1 &&
+ git -C super config submodule.sub1.URL ../sub &&
+ git -C super submodule--helper is-active sub1
+'
+
+test_expect_success 'is-active works with submodule.<name>.active config' '
+ test_when_finished "git -C super config --unset submodule.sub1.active" &&
+ test_when_finished "git -C super config submodule.sub1.URL ../sub" &&
+
+ git -C super config --bool submodule.sub1.active "false" &&
+ test_must_fail git -C super submodule--helper is-active sub1 &&
+
+ git -C super config --bool submodule.sub1.active "true" &&
+ git -C super config --unset submodule.sub1.URL &&
+ git -C super submodule--helper is-active sub1
+'
+
+test_expect_success 'is-active works with basic submodule.active config' '
+ test_when_finished "git -C super config submodule.sub1.URL ../sub" &&
+ test_when_finished "git -C super config --unset-all submodule.active" &&
+
+ git -C super config --add submodule.active "." &&
+ git -C super config --unset submodule.sub1.URL &&
+
+ git -C super submodule--helper is-active sub1 &&
+ git -C super submodule--helper is-active sub2
+'
+
+test_expect_success 'is-active correctly works with paths that are not submodules' '
+ test_when_finished "git -C super config --unset-all submodule.active" &&
+
+ test_must_fail git -C super submodule--helper is-active not-a-submodule &&
+
+ git -C super config --add submodule.active "." &&
+ test_must_fail git -C super submodule--helper is-active not-a-submodule
+'
+
+test_expect_success 'is-active works with exclusions in submodule.active config' '
+ test_when_finished "git -C super config --unset-all submodule.active" &&
+
+ git -C super config --add submodule.active "." &&
+ git -C super config --add submodule.active ":(exclude)sub1" &&
+
+ test_must_fail git -C super submodule--helper is-active sub1 &&
+ git -C super submodule--helper is-active sub2
+'
+
+test_expect_success 'is-active with submodule.active and submodule.<name>.active' '
+ test_when_finished "git -C super config --unset-all submodule.active" &&
+ test_when_finished "git -C super config --unset submodule.sub1.active" &&
+ test_when_finished "git -C super config --unset submodule.sub2.active" &&
+
+ git -C super config --add submodule.active "sub1" &&
+ git -C super config --bool submodule.sub1.active "false" &&
+ git -C super config --bool submodule.sub2.active "true" &&
+
+ test_must_fail git -C super submodule--helper is-active sub1 &&
+ git -C super submodule--helper is-active sub2
+'
+
+test_expect_success 'is-active, submodule.active and submodule add' '
+ test_when_finished "rm -rf super2" &&
+ git init super2 &&
+ test_commit -C super2 initial &&
+ git -C super2 config --add submodule.active "sub*" &&
+
+ # submodule add should only add submodule.<name>.active
+ # to the config if not matched by the pathspec
+ git -C super2 submodule add ../sub sub1 &&
+ test_must_fail git -C super2 config --get submodule.sub1.active &&
+
+ git -C super2 submodule add ../sub mod &&
+ git -C super2 config --get submodule.mod.active
+'
+
+test_done
diff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh
index 8728db6..88d4cda 100755
--- a/t/t7504-commit-msg-hook.sh
+++ b/t/t7504-commit-msg-hook.sh
@@ -220,4 +220,21 @@ test_expect_success "hook doesn't edit commit message (editor)" '
'
+# set up fake editor to replace `pick` by `reword`
+cat > reword-editor <<'EOF'
+#!/bin/sh
+mv "$1" "$1".bup &&
+sed 's/^pick/reword/' <"$1".bup >"$1"
+EOF
+chmod +x reword-editor
+REWORD_EDITOR="$(pwd)/reword-editor"
+export REWORD_EDITOR
+
+test_expect_success 'hook is called for reword during `rebase -i`' '
+
+ GIT_SEQUENCE_EDITOR="\"$REWORD_EDITOR\"" git rebase -i HEAD^ &&
+ commit_msg_is "new message"
+
+'
+
test_done
diff --git a/t/t7506-status-submodule.sh b/t/t7506-status-submodule.sh
index d31b34d..055c907 100755
--- a/t/t7506-status-submodule.sh
+++ b/t/t7506-status-submodule.sh
@@ -17,6 +17,12 @@ test_create_repo_with_commit () {
)
}
+sanitize_output () {
+ sed -e "s/$_x40/HASH/" -e "s/$_x40/HASH/" output >output2 &&
+ mv output2 output
+}
+
+
test_expect_success 'setup' '
test_create_repo_with_commit sub &&
echo output > .gitignore &&
@@ -50,6 +56,15 @@ test_expect_success 'status with modified file in submodule (porcelain)' '
EOF
'
+test_expect_success 'status with modified file in submodule (short)' '
+ (cd sub && git reset --hard) &&
+ echo "changed" >sub/foo &&
+ git status --short >output &&
+ diff output - <<-\EOF
+ m sub
+ EOF
+'
+
test_expect_success 'status with added file in submodule' '
(cd sub && git reset --hard && echo >foo && git add foo) &&
git status >output &&
@@ -64,6 +79,14 @@ test_expect_success 'status with added file in submodule (porcelain)' '
EOF
'
+test_expect_success 'status with added file in submodule (short)' '
+ (cd sub && git reset --hard && echo >foo && git add foo) &&
+ git status --short >output &&
+ diff output - <<-\EOF
+ m sub
+ EOF
+'
+
test_expect_success 'status with untracked file in submodule' '
(cd sub && git reset --hard) &&
echo "content" >sub/new-file &&
@@ -83,6 +106,13 @@ test_expect_success 'status with untracked file in submodule (porcelain)' '
EOF
'
+test_expect_success 'status with untracked file in submodule (short)' '
+ git status --short >output &&
+ diff output - <<-\EOF
+ ? sub
+ EOF
+'
+
test_expect_success 'status with added and untracked file in submodule' '
(cd sub && git reset --hard && echo >foo && git add foo) &&
echo "content" >sub/new-file &&
@@ -177,8 +207,24 @@ test_expect_success 'status with added file in modified submodule with .git file
test_i18ngrep "modified: sub (new commits, modified content)" output
'
+test_expect_success 'status with a lot of untracked files in the submodule' '
+ (
+ cd sub
+ i=0 &&
+ while test $i -lt 1024
+ do
+ >some-file-$i
+ i=$(( $i + 1 ))
+ done
+ ) &&
+ git status --porcelain sub 2>err.actual &&
+ test_must_be_empty err.actual &&
+ rm err.actual
+'
+
test_expect_success 'rm submodule contents' '
- rm -rf sub/* sub/.git
+ rm -rf sub &&
+ mkdir sub
'
test_expect_success 'status clean (empty submodule dir)' '
@@ -271,4 +317,91 @@ test_expect_success 'diff --submodule with merge conflict in .gitmodules' '
test_cmp diff_submodule_actual diff_submodule_expect
'
+# We'll setup different cases for further testing:
+# sub1 will contain a nested submodule,
+# sub2 will have an untracked file
+# sub3 will have an untracked repository
+test_expect_success 'setup superproject with untracked file in nested submodule' '
+ (
+ cd super &&
+ git clean -dfx &&
+ rm .gitmodules &&
+ git submodule add -f ./sub1 &&
+ git submodule add -f ./sub2 &&
+ git submodule add -f ./sub1 sub3 &&
+ git commit -a -m "messy merge in superproject" &&
+ (
+ cd sub1 &&
+ git submodule add ../sub2 &&
+ git commit -a -m "add sub2 to sub1"
+ ) &&
+ git add sub1 &&
+ git commit -a -m "update sub1 to contain nested sub"
+ ) &&
+ echo content >super/sub1/sub2/file &&
+ echo content >super/sub2/file &&
+ git -C super/sub3 clone ../../sub2 untracked_repository
+'
+
+test_expect_success 'status with untracked file in nested submodule (porcelain)' '
+ git -C super status --porcelain >output &&
+ diff output - <<-\EOF
+ M sub1
+ M sub2
+ M sub3
+ EOF
+'
+
+test_expect_success 'status with untracked file in nested submodule (porcelain=2)' '
+ git -C super status --porcelain=2 >output &&
+ sanitize_output output &&
+ diff output - <<-\EOF
+ 1 .M S..U 160000 160000 160000 HASH HASH sub1
+ 1 .M S..U 160000 160000 160000 HASH HASH sub2
+ 1 .M S..U 160000 160000 160000 HASH HASH sub3
+ EOF
+'
+
+test_expect_success 'status with untracked file in nested submodule (short)' '
+ git -C super status --short >output &&
+ diff output - <<-\EOF
+ ? sub1
+ ? sub2
+ ? sub3
+ EOF
+'
+
+test_expect_success 'setup superproject with modified file in nested submodule' '
+ git -C super/sub1/sub2 add file &&
+ git -C super/sub2 add file
+'
+
+test_expect_success 'status with added file in nested submodule (porcelain)' '
+ git -C super status --porcelain >output &&
+ diff output - <<-\EOF
+ M sub1
+ M sub2
+ M sub3
+ EOF
+'
+
+test_expect_success 'status with added file in nested submodule (porcelain=2)' '
+ git -C super status --porcelain=2 >output &&
+ sanitize_output output &&
+ diff output - <<-\EOF
+ 1 .M S.M. 160000 160000 160000 HASH HASH sub1
+ 1 .M S.M. 160000 160000 160000 HASH HASH sub2
+ 1 .M S..U 160000 160000 160000 HASH HASH sub3
+ EOF
+'
+
+test_expect_success 'status with added file in nested submodule (short)' '
+ git -C super status --short >output &&
+ diff output - <<-\EOF
+ m sub1
+ m sub2
+ ? sub3
+ EOF
+'
+
test_done
diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh
index 0e7f30d..7f09867 100755
--- a/t/t7800-difftool.sh
+++ b/t/t7800-difftool.sh
@@ -393,6 +393,25 @@ test_expect_success 'setup change in subdirectory' '
git commit -m "modified both"
'
+test_expect_success 'difftool -d with growing paths' '
+ a=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&
+ git init growing &&
+ (
+ cd growing &&
+ echo "test -f \"\$2/b\"" | write_script .git/test-for-b.sh &&
+ one=$(printf 1 | git hash-object -w --stdin) &&
+ two=$(printf 2 | git hash-object -w --stdin) &&
+ git update-index --add \
+ --cacheinfo 100644,$one,$a --cacheinfo 100644,$two,b &&
+ tree1=$(git write-tree) &&
+ git update-index --add \
+ --cacheinfo 100644,$two,$a --cacheinfo 100644,$one,b &&
+ tree2=$(git write-tree) &&
+ git checkout -- $a &&
+ git difftool -d --extcmd .git/test-for-b.sh $tree1 $tree2
+ )
+'
+
run_dir_diff_test () {
test_expect_success "$1 --no-symlinks" "
symlinks=--no-symlinks &&
diff --git a/t/t7814-grep-recurse-submodules.sh b/t/t7814-grep-recurse-submodules.sh
index 67247a0..5b6eb3a 100755
--- a/t/t7814-grep-recurse-submodules.sh
+++ b/t/t7814-grep-recurse-submodules.sh
@@ -227,6 +227,81 @@ test_expect_success 'grep history with moved submoules' '
test_cmp expect actual
'
+test_expect_success 'grep using relative path' '
+ test_when_finished "rm -rf parent sub" &&
+ git init sub &&
+ echo "foobar" >sub/file &&
+ git -C sub add file &&
+ git -C sub commit -m "add file" &&
+
+ git init parent &&
+ echo "foobar" >parent/file &&
+ git -C parent add file &&
+ mkdir parent/src &&
+ echo "foobar" >parent/src/file2 &&
+ git -C parent add src/file2 &&
+ git -C parent submodule add ../sub &&
+ git -C parent commit -m "add files and submodule" &&
+
+ # From top works
+ cat >expect <<-\EOF &&
+ file:foobar
+ src/file2:foobar
+ sub/file:foobar
+ EOF
+ git -C parent grep --recurse-submodules -e "foobar" >actual &&
+ test_cmp expect actual &&
+
+ # Relative path to top
+ cat >expect <<-\EOF &&
+ ../file:foobar
+ file2:foobar
+ ../sub/file:foobar
+ EOF
+ git -C parent/src grep --recurse-submodules -e "foobar" -- .. >actual &&
+ test_cmp expect actual &&
+
+ # Relative path to submodule
+ cat >expect <<-\EOF &&
+ ../sub/file:foobar
+ EOF
+ git -C parent/src grep --recurse-submodules -e "foobar" -- ../sub >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'grep from a subdir' '
+ test_when_finished "rm -rf parent sub" &&
+ git init sub &&
+ echo "foobar" >sub/file &&
+ git -C sub add file &&
+ git -C sub commit -m "add file" &&
+
+ git init parent &&
+ mkdir parent/src &&
+ echo "foobar" >parent/src/file &&
+ git -C parent add src/file &&
+ git -C parent submodule add ../sub src/sub &&
+ git -C parent submodule add ../sub sub &&
+ git -C parent commit -m "add files and submodules" &&
+
+ # Verify grep from root works
+ cat >expect <<-\EOF &&
+ src/file:foobar
+ src/sub/file:foobar
+ sub/file:foobar
+ EOF
+ git -C parent grep --recurse-submodules -e "foobar" >actual &&
+ test_cmp expect actual &&
+
+ # Verify grep from a subdir works
+ cat >expect <<-\EOF &&
+ file:foobar
+ sub/file:foobar
+ EOF
+ git -C parent/src grep --recurse-submodules -e "foobar" >actual &&
+ test_cmp expect actual
+'
+
test_incompatible_with_recurse_submodules ()
{
test_expect_success "--recurse-submodules and $1 are incompatible" "
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index d711bef..5ed2813 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -400,6 +400,22 @@ test_expect_success '__gitdir - remote as argument' '
test_cmp expected "$actual"
'
+test_expect_success '__gitcomp_direct - puts everything into COMPREPLY as-is' '
+ sed -e "s/Z$//g" >expected <<-EOF &&
+ with-trailing-space Z
+ without-trailing-spaceZ
+ --option Z
+ --option=Z
+ $invalid_variable_name Z
+ EOF
+ (
+ cur=should_be_ignored &&
+ __gitcomp_direct "$(cat expected)" &&
+ print_comp
+ ) &&
+ test_cmp expected out
+'
+
test_expect_success '__gitcomp - trailing space - options' '
test_gitcomp "--re" "--dry-run --reuse-message= --reedit-message=
--reset-author" <<-EOF
@@ -555,6 +571,9 @@ test_expect_success '__git_refs - full refs' '
cat >expected <<-EOF &&
refs/heads/master
refs/heads/matching-branch
+ refs/remotes/other/branch-in-other
+ refs/remotes/other/master-in-other
+ refs/tags/matching-tag
EOF
(
cur=refs/heads/ &&
@@ -620,6 +639,7 @@ test_expect_success '__git_refs - configured remote' '
test_expect_success '__git_refs - configured remote - full refs' '
cat >expected <<-EOF &&
+ HEAD
refs/heads/branch-in-other
refs/heads/master-in-other
refs/tags/tag-in-other
@@ -648,6 +668,7 @@ test_expect_success '__git_refs - configured remote - repo given on the command
test_expect_success '__git_refs - configured remote - full refs - repo given on the command line' '
cat >expected <<-EOF &&
+ HEAD
refs/heads/branch-in-other
refs/heads/master-in-other
refs/tags/tag-in-other
@@ -692,6 +713,7 @@ test_expect_success '__git_refs - URL remote' '
test_expect_success '__git_refs - URL remote - full refs' '
cat >expected <<-EOF &&
+ HEAD
refs/heads/branch-in-other
refs/heads/master-in-other
refs/tags/tag-in-other
@@ -775,6 +797,371 @@ test_expect_success '__git_refs - unique remote branches for git checkout DWIMer
test_cmp expected "$actual"
'
+test_expect_success '__git_refs - after --opt=' '
+ cat >expected <<-EOF &&
+ HEAD
+ master
+ matching-branch
+ other/branch-in-other
+ other/master-in-other
+ matching-tag
+ EOF
+ (
+ cur="--opt=" &&
+ __git_refs "" "" "" "" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_refs - after --opt= - full refs' '
+ cat >expected <<-EOF &&
+ refs/heads/master
+ refs/heads/matching-branch
+ refs/remotes/other/branch-in-other
+ refs/remotes/other/master-in-other
+ refs/tags/matching-tag
+ EOF
+ (
+ cur="--opt=refs/" &&
+ __git_refs "" "" "" refs/ >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git refs - exluding refs' '
+ cat >expected <<-EOF &&
+ ^HEAD
+ ^master
+ ^matching-branch
+ ^other/branch-in-other
+ ^other/master-in-other
+ ^matching-tag
+ EOF
+ (
+ cur=^ &&
+ __git_refs >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git refs - exluding full refs' '
+ cat >expected <<-EOF &&
+ ^refs/heads/master
+ ^refs/heads/matching-branch
+ ^refs/remotes/other/branch-in-other
+ ^refs/remotes/other/master-in-other
+ ^refs/tags/matching-tag
+ EOF
+ (
+ cur=^refs/ &&
+ __git_refs >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'setup for filtering matching refs' '
+ git branch matching/branch &&
+ git tag matching/tag &&
+ git -C otherrepo branch matching/branch-in-other &&
+ git fetch --no-tags other &&
+ rm -f .git/FETCH_HEAD
+'
+
+test_expect_success '__git_refs - dont filter refs unless told so' '
+ cat >expected <<-EOF &&
+ HEAD
+ master
+ matching-branch
+ matching/branch
+ other/branch-in-other
+ other/master-in-other
+ other/matching/branch-in-other
+ matching-tag
+ matching/tag
+ EOF
+ (
+ cur=master &&
+ __git_refs >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_refs - only matching refs' '
+ cat >expected <<-EOF &&
+ matching-branch
+ matching/branch
+ matching-tag
+ matching/tag
+ EOF
+ (
+ cur=mat &&
+ __git_refs "" "" "" "$cur" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_refs - only matching refs - full refs' '
+ cat >expected <<-EOF &&
+ refs/heads/matching-branch
+ refs/heads/matching/branch
+ EOF
+ (
+ cur=refs/heads/mat &&
+ __git_refs "" "" "" "$cur" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_refs - only matching refs - remote on local file system' '
+ cat >expected <<-EOF &&
+ master-in-other
+ matching/branch-in-other
+ EOF
+ (
+ cur=ma &&
+ __git_refs otherrepo "" "" "$cur" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_refs - only matching refs - configured remote' '
+ cat >expected <<-EOF &&
+ master-in-other
+ matching/branch-in-other
+ EOF
+ (
+ cur=ma &&
+ __git_refs other "" "" "$cur" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_refs - only matching refs - remote - full refs' '
+ cat >expected <<-EOF &&
+ refs/heads/master-in-other
+ refs/heads/matching/branch-in-other
+ EOF
+ (
+ cur=refs/heads/ma &&
+ __git_refs other "" "" "$cur" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_refs - only matching refs - checkout DWIMery' '
+ cat >expected <<-EOF &&
+ matching-branch
+ matching/branch
+ matching-tag
+ matching/tag
+ matching/branch-in-other
+ EOF
+ for remote_ref in refs/remotes/other/ambiguous \
+ refs/remotes/remote/ambiguous \
+ refs/remotes/remote/branch-in-remote
+ do
+ git update-ref $remote_ref master &&
+ test_when_finished "git update-ref -d $remote_ref"
+ done &&
+ (
+ cur=mat &&
+ __git_refs "" 1 "" "$cur" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'teardown after filtering matching refs' '
+ git branch -d matching/branch &&
+ git tag -d matching/tag &&
+ git update-ref -d refs/remotes/other/matching/branch-in-other &&
+ git -C otherrepo branch -D matching/branch-in-other
+'
+
+test_expect_success '__git_refs - for-each-ref format specifiers in prefix' '
+ cat >expected <<-EOF &&
+ evil-%%-%42-%(refname)..master
+ EOF
+ (
+ cur="evil-%%-%42-%(refname)..mas" &&
+ __git_refs "" "" "evil-%%-%42-%(refname).." mas >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_complete_refs - simple' '
+ sed -e "s/Z$//" >expected <<-EOF &&
+ HEAD Z
+ master Z
+ matching-branch Z
+ other/branch-in-other Z
+ other/master-in-other Z
+ matching-tag Z
+ EOF
+ (
+ cur= &&
+ __git_complete_refs &&
+ print_comp
+ ) &&
+ test_cmp expected out
+'
+
+test_expect_success '__git_complete_refs - matching' '
+ sed -e "s/Z$//" >expected <<-EOF &&
+ matching-branch Z
+ matching-tag Z
+ EOF
+ (
+ cur=mat &&
+ __git_complete_refs &&
+ print_comp
+ ) &&
+ test_cmp expected out
+'
+
+test_expect_success '__git_complete_refs - remote' '
+ sed -e "s/Z$//" >expected <<-EOF &&
+ HEAD Z
+ branch-in-other Z
+ master-in-other Z
+ EOF
+ (
+ cur=
+ __git_complete_refs --remote=other &&
+ print_comp
+ ) &&
+ test_cmp expected out
+'
+
+test_expect_success '__git_complete_refs - track' '
+ sed -e "s/Z$//" >expected <<-EOF &&
+ HEAD Z
+ master Z
+ matching-branch Z
+ other/branch-in-other Z
+ other/master-in-other Z
+ matching-tag Z
+ branch-in-other Z
+ master-in-other Z
+ EOF
+ (
+ cur=
+ __git_complete_refs --track &&
+ print_comp
+ ) &&
+ test_cmp expected out
+'
+
+test_expect_success '__git_complete_refs - current word' '
+ sed -e "s/Z$//" >expected <<-EOF &&
+ matching-branch Z
+ matching-tag Z
+ EOF
+ (
+ cur="--option=mat" &&
+ __git_complete_refs --cur="${cur#*=}" &&
+ print_comp
+ ) &&
+ test_cmp expected out
+'
+
+test_expect_success '__git_complete_refs - prefix' '
+ sed -e "s/Z$//" >expected <<-EOF &&
+ v1.0..matching-branch Z
+ v1.0..matching-tag Z
+ EOF
+ (
+ cur=v1.0..mat &&
+ __git_complete_refs --pfx=v1.0.. --cur=mat &&
+ print_comp
+ ) &&
+ test_cmp expected out
+'
+
+test_expect_success '__git_complete_refs - suffix' '
+ cat >expected <<-EOF &&
+ HEAD.
+ master.
+ matching-branch.
+ other/branch-in-other.
+ other/master-in-other.
+ matching-tag.
+ EOF
+ (
+ cur= &&
+ __git_complete_refs --sfx=. &&
+ print_comp
+ ) &&
+ test_cmp expected out
+'
+
+test_expect_success '__git_complete_fetch_refspecs - simple' '
+ sed -e "s/Z$//" >expected <<-EOF &&
+ HEAD:HEAD Z
+ branch-in-other:branch-in-other Z
+ master-in-other:master-in-other Z
+ EOF
+ (
+ cur= &&
+ __git_complete_fetch_refspecs other &&
+ print_comp
+ ) &&
+ test_cmp expected out
+'
+
+test_expect_success '__git_complete_fetch_refspecs - matching' '
+ sed -e "s/Z$//" >expected <<-EOF &&
+ branch-in-other:branch-in-other Z
+ EOF
+ (
+ cur=br &&
+ __git_complete_fetch_refspecs other "" br &&
+ print_comp
+ ) &&
+ test_cmp expected out
+'
+
+test_expect_success '__git_complete_fetch_refspecs - prefix' '
+ sed -e "s/Z$//" >expected <<-EOF &&
+ +HEAD:HEAD Z
+ +branch-in-other:branch-in-other Z
+ +master-in-other:master-in-other Z
+ EOF
+ (
+ cur="+" &&
+ __git_complete_fetch_refspecs other "+" "" &&
+ print_comp
+ ) &&
+ test_cmp expected out
+'
+
+test_expect_success '__git_complete_fetch_refspecs - fully qualified' '
+ sed -e "s/Z$//" >expected <<-EOF &&
+ refs/heads/branch-in-other:refs/heads/branch-in-other Z
+ refs/heads/master-in-other:refs/heads/master-in-other Z
+ refs/tags/tag-in-other:refs/tags/tag-in-other Z
+ EOF
+ (
+ cur=refs/ &&
+ __git_complete_fetch_refspecs other "" refs/ &&
+ print_comp
+ ) &&
+ test_cmp expected out
+'
+
+test_expect_success '__git_complete_fetch_refspecs - fully qualified & prefix' '
+ sed -e "s/Z$//" >expected <<-EOF &&
+ +refs/heads/branch-in-other:refs/heads/branch-in-other Z
+ +refs/heads/master-in-other:refs/heads/master-in-other Z
+ +refs/tags/tag-in-other:refs/tags/tag-in-other Z
+ EOF
+ (
+ cur=+refs/ &&
+ __git_complete_fetch_refspecs other + refs/ &&
+ print_comp
+ ) &&
+ test_cmp expected out
+'
+
test_expect_success 'teardown after ref completion' '
git branch -d matching-branch &&
git tag -d matching-tag &&
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 23c29bc..13b5696 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -625,9 +625,9 @@ test_run_ () {
trace=
# 117 is magic because it is unlikely to match the exit
# code of other programs
- test_eval_ "(exit 117) && $1"
- if test "$?" != 117; then
- error "bug in the test script: broken &&-chain: $1"
+ if test "OK-117" != "$(test_eval_ "(exit 117) && $1${LF}${LF}echo OK-\$?" 3>&1)"
+ then
+ error "bug in the test script: broken &&-chain or run-away HERE-DOC: $1"
fi
trace=$trace_tmp
fi