diff options
Diffstat (limited to 't')
144 files changed, 3709 insertions, 655 deletions
@@ -196,11 +196,10 @@ appropriately before running "make". variable to "1" or "0", respectively. --stress:: ---stress=<N>:: Run the test script repeatedly in multiple parallel jobs until one of them fails. Useful for reproducing rare failures in flaky tests. The number of parallel jobs is, in order of - precedence: <N>, or the value of the GIT_TEST_STRESS_LOAD + precedence: the value of the GIT_TEST_STRESS_LOAD environment variable, or twice the number of available processors (as shown by the 'getconf' utility), or 8. Implies `--verbose -x --immediate` to get the most information @@ -211,10 +210,13 @@ appropriately before running "make". '.stress-<nr>' suffix, and the trash directory of the failed test job is renamed to end with a '.stress-failed' suffix. +--stress-jobs=<N>:: + Override the number of parallel jobs. Implies `--stress`. + --stress-limit=<N>:: When combined with --stress run the test script repeatedly this many times in each of the parallel jobs or until one of - them fails, whichever comes first. + them fails, whichever comes first. Implies `--stress`. You can also set the GIT_TEST_INSTALLED environment variable to the bindir of an existing git installation to test that installation. @@ -341,6 +343,9 @@ marked strings" in po/README for details. GIT_TEST_SPLIT_INDEX=<boolean> forces split-index mode on the whole test suite. Accept any boolean values that are accepted by git-config. +GIT_TEST_PROTOCOL_VERSION=<n>, when set, overrides the +'protocol.version' setting to n if it is less than n. + GIT_TEST_FULL_IN_PACK_ARRAY=<boolean> exercises the uncommon pack-objects code path where there are more than 1024 packs even if the actual number of packs in repository is below this limit. Accept @@ -379,8 +384,8 @@ the --no-sparse command-line argument. GIT_TEST_PRELOAD_INDEX=<boolean> exercises the preload-index code path by overriding the minimum number of cache entries required per thread. -GIT_TEST_REBASE_USE_BUILTIN=<boolean>, when false, disables the -builtin version of git-rebase. See 'rebase.useBuiltin' in +GIT_TEST_STASH_USE_BUILTIN=<boolean>, when false, disables the +built-in version of git-stash. See 'stash.useBuiltin' in git-config(1). GIT_TEST_INDEX_THREADS=<n> enables exercising the multi-threaded loading @@ -397,6 +402,10 @@ GIT_TEST_SIDEBAND_ALL=<boolean>, when true, overrides the fetch-pack to not request sideband-all (even if the server advertises sideband-all). +GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=<boolean>, when true (which is +the default when running tests), errors out when an abbreviated option +is used. + Naming Tests ------------ @@ -862,6 +871,26 @@ library for your script to use. ... ' + - test_atexit <script> + + Prepend <script> to a list of commands to run unconditionally to + clean up before the test script exits, e.g. to stop a daemon: + + test_expect_success 'test git daemon' ' + git daemon & + daemon_pid=$! && + test_atexit 'kill $daemon_pid' && + hello world + ' + + The commands will be executed before the trash directory is removed, + i.e. the atexit commands will still be able to access any pidfiles or + socket files. + + Note that these commands will be run even when a test script run + with '--immediate' fails. Be careful with your atexit commands to + minimize any changes to the failed state. + - test_write_lines <lines> Write <lines> on standard output, one line per argument. @@ -932,6 +961,15 @@ library for your script to use. test_oid_init or test_oid_cache. Providing an unknown key is an error. + - yes [<string>] + + This is often seen in modern UNIX but some platforms lack it, so + the test harness overrides the platform implementation with a + more limited one. Use this only when feeding a handful lines of + output to the downstream---unlike the real version, it generates + only up to 99 lines. + + Prerequisites ------------- diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index 6da48a2e0a..d933af5714 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -68,6 +68,14 @@ test_expect_success 'blame 1 author' ' check_count A 2 ' +test_expect_success 'blame in a bare repo without starting commit' ' + git clone --bare . bare.git && + ( + cd bare.git && + check_count A 2 + ) +' + test_expect_success 'blame by tag objects' ' git tag -m "test tag" testTag && git tag -m "test tag #2" testTag2 testTag && diff --git a/t/helper/test-date.c b/t/helper/test-date.c index b3253803ac..585347ea48 100644 --- a/t/helper/test-date.c +++ b/t/helper/test-date.c @@ -55,7 +55,7 @@ static void show_dates(const char **argv, const char *format) } } -static void parse_dates(const char **argv, struct timeval *now) +static void parse_dates(const char **argv) { struct strbuf result = STRBUF_INIT; @@ -124,7 +124,7 @@ int cmd__date(int argc, const char **argv) else if (skip_prefix(*argv, "show:", &x)) show_dates(argv+1, x); else if (!strcmp(*argv, "parse")) - parse_dates(argv+1, &now); + parse_dates(argv+1); else if (!strcmp(*argv, "approxidate")) parse_approxidate(argv+1, &now); else if (!strcmp(*argv, "timestamp")) diff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c index 47fee660b8..2232b2f79e 100644 --- a/t/helper/test-parse-options.c +++ b/t/helper/test-parse-options.c @@ -2,6 +2,7 @@ #include "cache.h" #include "parse-options.h" #include "string-list.h" +#include "trace2.h" static int boolean = 0; static int integer = 0; @@ -131,7 +132,7 @@ int cmd__parse_options(int argc, const char **argv) OPT_NOOP_NOARG(0, "obsolete"), OPT_STRING_LIST(0, "list", &list, "str", "add str to list"), OPT_GROUP("Magic arguments"), - OPT_ARGUMENT("quux", "means --quux"), + OPT_ARGUMENT("quux", NULL, "means --quux"), OPT_NUMBER_CALLBACK(&integer, "set integer to NUM", number_callback), { OPTION_COUNTUP, '+', NULL, &boolean, NULL, "same as -b", @@ -153,6 +154,8 @@ int cmd__parse_options(int argc, const char **argv) int i; int ret = 0; + trace2_cmd_name("_parse_"); + argc = parse_options(argc, (const char **)argv, prefix, options, usage, 0); if (length_cb.called) { diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c index 99db7409b8..53c06932c4 100644 --- a/t/helper/test-tool.c +++ b/t/helper/test-tool.c @@ -1,5 +1,6 @@ #include "git-compat-util.h" #include "test-tool.h" +#include "trace2.h" struct test_cmd { const char *name; @@ -51,6 +52,7 @@ static struct test_cmd cmds[] = { { "submodule-config", cmd__submodule_config }, { "submodule-nested-repo-config", cmd__submodule_nested_repo_config }, { "subprocess", cmd__subprocess }, + { "trace2", cmd__trace2 }, { "urlmatch-normalization", cmd__urlmatch_normalization }, { "xml-encode", cmd__xml_encode }, { "wildmatch", cmd__wildmatch }, @@ -82,6 +84,8 @@ int cmd_main(int argc, const char **argv) if (!strcmp(cmds[i].name, argv[1])) { argv++; argc--; + trace2_cmd_name(cmds[i].name); + trace2_cmd_list_config(); return cmds[i].fn(argc, argv); } } diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h index 25abed1cf2..ffab4d19d7 100644 --- a/t/helper/test-tool.h +++ b/t/helper/test-tool.h @@ -48,6 +48,7 @@ int cmd__string_list(int argc, const char **argv); int cmd__submodule_config(int argc, const char **argv); int cmd__submodule_nested_repo_config(int argc, const char **argv); int cmd__subprocess(int argc, const char **argv); +int cmd__trace2(int argc, const char **argv); int cmd__urlmatch_normalization(int argc, const char **argv); int cmd__xml_encode(int argc, const char **argv); int cmd__wildmatch(int argc, const char **argv); diff --git a/t/helper/test-trace2.c b/t/helper/test-trace2.c new file mode 100644 index 0000000000..197819c872 --- /dev/null +++ b/t/helper/test-trace2.c @@ -0,0 +1,273 @@ +#include "test-tool.h" +#include "cache.h" +#include "argv-array.h" +#include "run-command.h" +#include "exec-cmd.h" +#include "config.h" + +typedef int(fn_unit_test)(int argc, const char **argv); + +struct unit_test { + fn_unit_test *ut_fn; + const char *ut_name; + const char *ut_usage; +}; + +#define MyOk 0 +#define MyError 1 + +static int get_i(int *p_value, const char *data) +{ + char *endptr; + + if (!data || !*data) + return MyError; + + *p_value = strtol(data, &endptr, 10); + if (*endptr || errno == ERANGE) + return MyError; + + return MyOk; +} + +/* + * Cause process to exit with the requested value via "return". + * + * Rely on test-tool.c:cmd_main() to call trace2_cmd_exit() + * with our result. + * + * Test harness can confirm: + * [] the process-exit value. + * [] the "code" field in the "exit" trace2 event. + * [] the "code" field in the "atexit" trace2 event. + * [] the "name" field in the "cmd_name" trace2 event. + * [] "def_param" events for all of the "interesting" pre-defined + * config settings. + */ +static int ut_001return(int argc, const char **argv) +{ + int rc; + + if (get_i(&rc, argv[0])) + die("expect <exit_code>"); + + return rc; +} + +/* + * Cause the process to exit with the requested value via "exit()". + * + * Test harness can confirm: + * [] the "code" field in the "exit" trace2 event. + * [] the "code" field in the "atexit" trace2 event. + * [] the "name" field in the "cmd_name" trace2 event. + * [] "def_param" events for all of the "interesting" pre-defined + * config settings. + */ +static int ut_002exit(int argc, const char **argv) +{ + int rc; + + if (get_i(&rc, argv[0])) + die("expect <exit_code>"); + + exit(rc); +} + +/* + * Send an "error" event with each value in argv. Normally, git only issues + * a single "error" event immediately before issuing an "exit" event (such + * as in die() or BUG()), but multiple "error" events are allowed. + * + * Test harness can confirm: + * [] a trace2 "error" event for each value in argv. + * [] the "name" field in the "cmd_name" trace2 event. + * [] (optional) the file:line in the "exit" event refers to this function. + */ +static int ut_003error(int argc, const char **argv) +{ + int k; + + if (!argv[0] || !*argv[0]) + die("expect <error_message>"); + + for (k = 0; k < argc; k++) + error("%s", argv[k]); + + return 0; +} + +/* + * Run a child process and wait for it to finish and exit with its return code. + * test-tool trace2 004child [<child-command-line>] + * + * For example: + * test-tool trace2 004child git version + * test-tool trace2 004child test-tool trace2 001return 0 + * test-tool trace2 004child test-tool trace2 004child test-tool trace2 004child + * test-tool trace2 004child git -c alias.xyz=version xyz + * + * Test harness can confirm: + * [] the "name" field in the "cmd_name" trace2 event. + * [] that the outer process has a single component SID (or depth "d0" in + * the PERF stream). + * [] that "child_start" and "child_exit" events are generated for the child. + * [] if the child process is an instrumented executable: + * [] that "version", "start", ..., "exit", and "atexit" events are + * generated by the child process. + * [] that the child process events have a multiple component SID (or + * depth "dN+1" in the PERF stream). + * [] that the child exit code is propagated to the parent process "exit" + * and "atexit" events.. + * [] (optional) that the "t_abs" field in the child process "atexit" event + * is less than the "t_rel" field in the "child_exit" event of the parent + * process. + * [] if the child process is like the alias example above, + * [] (optional) the child process attempts to run "git-xyx" as a dashed + * command. + * [] the child process emits an "alias" event with "xyz" => "version" + * [] the child process runs "git version" as a child process. + * [] the child process has a 3 component SID (or depth "d2" in the PERF + * stream). + */ +static int ut_004child(int argc, const char **argv) +{ + int result; + + /* + * Allow empty <child_command_line> so we can do arbitrarily deep + * command nesting and let the last one be null. + */ + if (!argc) + return 0; + + result = run_command_v_opt(argv, 0); + exit(result); +} + +/* + * Exec a git command. This may either create a child process (Windows) + * or replace the existing process. + * test-tool trace2 005exec <git_command_args> + * + * For example: + * test-tool trace2 005exec version + * + * Test harness can confirm (on Windows): + * [] the "name" field in the "cmd_name" trace2 event. + * [] that the outer process has a single component SID (or depth "d0" in + * the PERF stream). + * [] that "exec" and "exec_result" events are generated for the child + * process (since the Windows compatibility layer fakes an exec() with + * a CreateProcess(), WaitForSingleObject(), and exit()). + * [] that the child process has multiple component SID (or depth "dN+1" + * in the PERF stream). + * + * Test harness can confirm (on platforms with a real exec() function): + * [] TODO talk about process replacement and how it affects SID. + */ +static int ut_005exec(int argc, const char **argv) +{ + int result; + + if (!argc) + return 0; + + result = execv_git_cmd(argv); + return result; +} + +static int ut_006data(int argc, const char **argv) +{ + const char *usage_error = + "expect <cat0> <k0> <v0> [<cat1> <k1> <v1> [...]]"; + + if (argc % 3 != 0) + die("%s", usage_error); + + while (argc) { + if (!argv[0] || !*argv[0] || !argv[1] || !*argv[1] || + !argv[2] || !*argv[2]) + die("%s", usage_error); + + trace2_data_string(argv[0], the_repository, argv[1], argv[2]); + argv += 3; + argc -= 3; + } + + return 0; +} + +/* + * Usage: + * test-tool trace2 <ut_name_1> <ut_usage_1> + * test-tool trace2 <ut_name_2> <ut_usage_2> + * ... + */ +#define USAGE_PREFIX "test-tool trace2" + +/* clang-format off */ +static struct unit_test ut_table[] = { + { ut_001return, "001return", "<exit_code>" }, + { ut_002exit, "002exit", "<exit_code>" }, + { ut_003error, "003error", "<error_message>+" }, + { ut_004child, "004child", "[<child_command_line>]" }, + { ut_005exec, "005exec", "<git_command_args>" }, + { ut_006data, "006data", "[<category> <key> <value>]+" }, +}; +/* clang-format on */ + +/* clang-format off */ +#define for_each_ut(k, ut_k) \ + for (k = 0, ut_k = &ut_table[k]; \ + k < ARRAY_SIZE(ut_table); \ + k++, ut_k = &ut_table[k]) +/* clang-format on */ + +static int print_usage(void) +{ + int k; + struct unit_test *ut_k; + + fprintf(stderr, "usage:\n"); + for_each_ut (k, ut_k) + fprintf(stderr, "\t%s %s %s\n", USAGE_PREFIX, ut_k->ut_name, + ut_k->ut_usage); + + return 129; +} + +/* + * Issue various trace2 events for testing. + * + * We assume that these trace2 routines has already been called: + * [] trace2_initialize() [common-main.c:main()] + * [] trace2_cmd_start() [common-main.c:main()] + * [] trace2_cmd_name() [test-tool.c:cmd_main()] + * [] tracd2_cmd_list_config() [test-tool.c:cmd_main()] + * So that: + * [] the various trace2 streams are open. + * [] the process SID has been created. + * [] the "version" event has been generated. + * [] the "start" event has been generated. + * [] the "cmd_name" event has been generated. + * [] this writes various "def_param" events for interesting config values. + * + * We further assume that if we return (rather than exit()), trace2_cmd_exit() + * will be called by test-tool.c:cmd_main(). + */ +int cmd__trace2(int argc, const char **argv) +{ + int k; + struct unit_test *ut_k; + + argc--; /* skip over "trace2" arg */ + argv++; + + if (argc) + for_each_ut (k, ut_k) + if (!strcmp(argv[0], ut_k->ut_name)) + return ut_k->ut_fn(argc - 1, argv + 1); + + return print_usage(); +} diff --git a/t/interop/i5500-git-daemon.sh b/t/interop/i5500-git-daemon.sh index 1daf69420b..4d22e42f84 100755 --- a/t/interop/i5500-git-daemon.sh +++ b/t/interop/i5500-git-daemon.sh @@ -37,5 +37,4 @@ test_expect_success "fetch with $VERSION_B" ' test_cmp expect actual ' -stop_git_daemon test_done diff --git a/t/lib-git-daemon.sh b/t/lib-git-daemon.sh index 79db3b7ae5..7b3407134e 100644 --- a/t/lib-git-daemon.sh +++ b/t/lib-git-daemon.sh @@ -13,7 +13,6 @@ # # test_expect_success ... # -# stop_git_daemon # test_done test_tristate GIT_TEST_GIT_DAEMON @@ -31,10 +30,12 @@ fi test_set_port LIB_GIT_DAEMON_PORT GIT_DAEMON_PID= +GIT_DAEMON_PIDFILE="$PWD"/daemon.pid GIT_DAEMON_DOCUMENT_ROOT_PATH="$PWD"/repo GIT_DAEMON_HOST_PORT=127.0.0.1:$LIB_GIT_DAEMON_PORT GIT_DAEMON_URL=git://$GIT_DAEMON_HOST_PORT +registered_stop_git_daemon_atexit_handler= start_git_daemon() { if test -n "$GIT_DAEMON_PID" then @@ -43,13 +44,19 @@ start_git_daemon() { mkdir -p "$GIT_DAEMON_DOCUMENT_ROOT_PATH" - trap 'code=$?; stop_git_daemon; (exit $code); die' EXIT + # One of the test scripts stops and then re-starts 'git daemon'. + # Don't register and then run the same atexit handlers several times. + if test -z "$registered_stop_git_daemon_atexit_handler" + then + test_atexit 'stop_git_daemon' + registered_stop_git_daemon_atexit_handler=AlreadyDone + fi say >&3 "Starting git daemon ..." mkfifo git_daemon_output ${LIB_GIT_DAEMON_COMMAND:-git daemon} \ --listen=127.0.0.1 --port="$LIB_GIT_DAEMON_PORT" \ - --reuseaddr --verbose \ + --reuseaddr --verbose --pid-file="$GIT_DAEMON_PIDFILE" \ --base-path="$GIT_DAEMON_DOCUMENT_ROOT_PATH" \ "$@" "$GIT_DAEMON_DOCUMENT_ROOT_PATH" \ >&3 2>git_daemon_output & @@ -65,7 +72,7 @@ start_git_daemon() { then kill "$GIT_DAEMON_PID" wait "$GIT_DAEMON_PID" - trap 'die' EXIT + unset GIT_DAEMON_PID test_skip_or_die $GIT_TEST_GIT_DAEMON \ "git daemon failed to start" fi @@ -77,8 +84,6 @@ stop_git_daemon() { return fi - trap 'die' EXIT - # kill git-daemon child of git say >&3 "Stopping git daemon ..." kill "$GIT_DAEMON_PID" @@ -88,8 +93,9 @@ stop_git_daemon() { then error "git daemon exited with status: $ret" fi + kill "$(cat "$GIT_DAEMON_PIDFILE")" 2>/dev/null GIT_DAEMON_PID= - rm -f git_daemon_output + rm -f git_daemon_output "$GIT_DAEMON_PIDFILE" } # A stripped-down version of a netcat client, that connects to a "host:port" diff --git a/t/lib-git-p4.sh b/t/lib-git-p4.sh index b3be3ba011..547b9f88e1 100644 --- a/t/lib-git-p4.sh +++ b/t/lib-git-p4.sh @@ -44,15 +44,6 @@ native_path () { echo "$path" } -# On Solaris the 'date +%s' function is not supported and therefore we -# need this replacement. -# Attention: This function is not safe again against time offset updates -# at runtime (e.g. via NTP). The 'clock_gettime(CLOCK_MONOTONIC)' -# function could fix that but it is not in Python until 3.3. -time_in_seconds () { - (cd / && "$PYTHON_PATH" -c 'import time; print(int(time.time()))') -} - test_set_port P4DPORT P4PORT=localhost:$P4DPORT @@ -67,14 +58,9 @@ cli="$TRASH_DIRECTORY/cli" git="$TRASH_DIRECTORY/git" pidfile="$TRASH_DIRECTORY/p4d.pid" -# Sometimes "prove" seems to hang on exit because p4d is still running -cleanup () { - if test -f "$pidfile" - then - kill -9 $(cat "$pidfile") 2>/dev/null && exit 255 - fi +stop_p4d_and_watchdog () { + kill -9 $p4d_pid $watchdog_pid } -trap cleanup EXIT # git p4 submit generates a temp file, which will # not get cleaned up if the submission fails. Don't @@ -82,7 +68,16 @@ trap cleanup EXIT TMPDIR="$TRASH_DIRECTORY" export TMPDIR +registered_stop_p4d_atexit_handler= start_p4d () { + # One of the test scripts stops and then re-starts p4d. + # Don't register and then run the same atexit handlers several times. + if test -z "$registered_stop_p4d_atexit_handler" + then + test_atexit 'stop_p4d_and_watchdog' + registered_stop_p4d_atexit_handler=AlreadyDone + fi + mkdir -p "$db" "$cli" "$git" && rm -f "$pidfile" && ( @@ -92,6 +87,7 @@ start_p4d () { echo $! >"$pidfile" } ) && + p4d_pid=$(cat "$pidfile") # This gives p4d a long time to start up, as it can be # quite slow depending on the machine. Set this environment @@ -99,18 +95,18 @@ start_p4d () { # an automated test setup. If the p4d process dies, that # will be caught with the "kill -0" check below. i=${P4D_START_PATIENCE:-300} - pid=$(cat "$pidfile") - timeout=$(($(time_in_seconds) + $P4D_TIMEOUT)) + nr_tries_left=$P4D_TIMEOUT while true do - if test $(time_in_seconds) -gt $timeout + if test $nr_tries_left -eq 0 then - kill -9 $pid + kill -9 $p4d_pid exit 1 fi sleep 1 - done & + nr_tries_left=$(($nr_tries_left - 1)) + done 2>/dev/null 4>&2 & watchdog_pid=$! ready= @@ -123,7 +119,7 @@ start_p4d () { break fi # fail if p4d died - kill -0 $pid 2>/dev/null || break + kill -0 $p4d_pid 2>/dev/null || break echo waiting for p4d to start sleep 1 i=$(( $i - 1 )) @@ -163,29 +159,18 @@ p4_add_job () { } retry_until_success () { - timeout=$(($(time_in_seconds) + $RETRY_TIMEOUT)) - until "$@" 2>/dev/null || test $(time_in_seconds) -gt $timeout - do - sleep 1 - done -} - -retry_until_fail () { - timeout=$(($(time_in_seconds) + $RETRY_TIMEOUT)) - until ! "$@" 2>/dev/null || test $(time_in_seconds) -gt $timeout + nr_tries_left=$RETRY_TIMEOUT + until "$@" 2>/dev/null || test $nr_tries_left -eq 0 do sleep 1 + nr_tries_left=$(($nr_tries_left - 1)) done } -kill_p4d () { - pid=$(cat "$pidfile") - retry_until_fail kill $pid - retry_until_fail kill -9 $pid - # complain if it would not die - test_must_fail kill $pid >/dev/null 2>&1 && - rm -rf "$db" "$cli" "$pidfile" && - retry_until_fail kill -9 $watchdog_pid +stop_and_cleanup_p4d () { + kill -9 $p4d_pid $watchdog_pid + wait $p4d_pid + rm -rf "$db" "$cli" "$pidfile" } cleanup_git () { diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh index f3b478c307..c1271d6863 100644 --- a/t/lib-git-svn.sh +++ b/t/lib-git-svn.sh @@ -76,11 +76,6 @@ maybe_start_httpd () { LIB_HTTPD_SVN="$loc" start_httpd ;; - *) - stop_httpd () { - : noop - } - ;; esac } diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh index 0dfb48c2f6..b3cc62bd36 100644 --- a/t/lib-httpd.sh +++ b/t/lib-httpd.sh @@ -14,7 +14,6 @@ # # test_expect_success ... # -# stop_httpd # test_done # # Can be configured using the following variables. @@ -176,7 +175,7 @@ prepare_httpd() { start_httpd() { prepare_httpd >&3 2>&4 - trap 'code=$?; stop_httpd; (exit $code); die' EXIT + test_atexit stop_httpd "$LIB_HTTPD_PATH" -d "$HTTPD_ROOT_PATH" \ -f "$TEST_PATH/apache.conf" $HTTPD_PARA \ @@ -184,15 +183,12 @@ start_httpd() { >&3 2>&4 if test $? -ne 0 then - trap 'die' EXIT cat "$HTTPD_ROOT_PATH"/error.log >&4 2>/dev/null test_skip_or_die $GIT_TEST_HTTPD "web server setup failed" fi } stop_httpd() { - trap 'die' EXIT - "$LIB_HTTPD_PATH" -d "$HTTPD_ROOT_PATH" \ -f "$TEST_PATH/apache.conf" $HTTPD_PARA -k stop } diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh index 5b56b23166..1dd17fc03e 100755 --- a/t/lib-submodule-update.sh +++ b/t/lib-submodule-update.sh @@ -139,7 +139,7 @@ create_lib_submodule_repo () { git revert HEAD && git checkout -b invalid_sub1 add_sub1 && - git update-index --cacheinfo 160000 0123456789012345678901234567890123456789 sub1 && + git update-index --cacheinfo 160000 $(test_oid numeric) sub1 && git commit -m "Invalid sub1 commit" && git checkout -b valid_sub1 && git revert HEAD && @@ -196,6 +196,7 @@ test_git_directory_exists() { # the submodule repo if it doesn't exist and configures the most problematic # settings for diff.ignoreSubmodules. prolog () { + test_oid_init && (test -d submodule_update_repo || create_lib_submodule_repo) && test_config_global diff.ignoreSubmodules all && test_config diff.ignoreSubmodules all diff --git a/t/perf/p0001-rev-list.sh b/t/perf/p0001-rev-list.sh index ebf172401b..3042a85666 100755 --- a/t/perf/p0001-rev-list.sh +++ b/t/perf/p0001-rev-list.sh @@ -14,6 +14,24 @@ test_perf 'rev-list --all --objects' ' git rev-list --all --objects >/dev/null ' +test_perf 'rev-list --parents' ' + git rev-list --parents HEAD >/dev/null +' + +test_expect_success 'create dummy file' ' + echo unlikely-to-already-be-there >dummy && + git add dummy && + git commit -m dummy +' + +test_perf 'rev-list -- dummy' ' + git rev-list HEAD -- dummy +' + +test_perf 'rev-list --parents -- dummy' ' + git rev-list --parents HEAD -- dummy +' + test_expect_success 'create new unreferenced commit' ' commit=$(git commit-tree HEAD^{tree} -p HEAD) && test_export commit diff --git a/t/perf/p5304-prune.sh b/t/perf/p5304-prune.sh new file mode 100755 index 0000000000..83baedb8a4 --- /dev/null +++ b/t/perf/p5304-prune.sh @@ -0,0 +1,35 @@ +#!/bin/sh + +test_description='performance tests of prune' +. ./perf-lib.sh + +test_perf_default_repo + +test_expect_success 'remove reachable loose objects' ' + git repack -ad +' + +test_expect_success 'remove unreachable loose objects' ' + git prune +' + +test_expect_success 'confirm there are no loose objects' ' + git count-objects | grep ^0 +' + +test_perf 'prune with no objects' ' + git prune +' + +test_expect_success 'repack with bitmaps' ' + git repack -adb +' + +# We have to create the object in each trial run, since otherwise +# runs after the first see no object and just skip the traversal entirely! +test_perf 'prune with bitmaps' ' + echo "probably not present in repo" | git hash-object -w --stdin && + git prune +' + +test_done diff --git a/t/perf/perf-lib.sh b/t/perf/perf-lib.sh index 2e33ab3ec3..169f92eae3 100644 --- a/t/perf/perf-lib.sh +++ b/t/perf/perf-lib.sh @@ -17,37 +17,25 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . -# do the --tee work early; it otherwise confuses our careful -# GIT_BUILD_DIR mangling -case "$GIT_TEST_TEE_STARTED, $* " in -done,*) - # do not redirect again - ;; -*' --tee '*|*' --va'*) - mkdir -p test-results - BASE=test-results/$(basename "$0" .sh) - (GIT_TEST_TEE_STARTED=done ${SHELL-sh} "$0" "$@" 2>&1; - echo $? > $BASE.exit) | tee $BASE.out - test "$(cat $BASE.exit)" = 0 - exit - ;; -esac - +# These variables must be set before the inclusion of test-lib.sh below, +# because it will change our working directory. TEST_DIRECTORY=$(pwd)/.. TEST_OUTPUT_DIRECTORY=$(pwd) -if test -z "$GIT_TEST_INSTALLED"; then - perf_results_prefix= -else - perf_results_prefix=$(printf "%s" "${GIT_TEST_INSTALLED%/bin-wrappers}" | tr -c "[a-zA-Z0-9]" "[_*]")"." - # make the tested dir absolute - GIT_TEST_INSTALLED=$(cd "$GIT_TEST_INSTALLED" && pwd) -fi +ABSOLUTE_GIT_TEST_INSTALLED=$( + test -n "$GIT_TEST_INSTALLED" && cd "$GIT_TEST_INSTALLED" && pwd) TEST_NO_CREATE_REPO=t TEST_NO_MALLOC_CHECK=t . ../test-lib.sh +if test -z "$GIT_TEST_INSTALLED"; then + perf_results_prefix= +else + perf_results_prefix=$(printf "%s" "${GIT_TEST_INSTALLED%/bin-wrappers}" | tr -c "[a-zA-Z0-9]" "[_*]")"." + GIT_TEST_INSTALLED=$ABSOLUTE_GIT_TEST_INSTALLED +fi + # Variables from test-lib that are normally internal to the tests; we # need to export them for test_perf subshells export TEST_DIRECTORY TRASH_DIRECTORY GIT_BUILD_DIR GIT_TEST_CMP diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index b6566003dd..c03054c538 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -825,6 +825,24 @@ test_expect_success 'tests clean up even on failures' " EOF " +test_expect_success 'test_atexit is run' " + test_must_fail run_sub_test_lib_test \ + atexit-cleanup 'Run atexit commands' -i <<-\\EOF && + test_expect_success 'tests clean up even after a failure' ' + > ../../clean-atexit && + test_atexit rm ../../clean-atexit && + > ../../also-clean-atexit && + test_atexit rm ../../also-clean-atexit && + > ../../dont-clean-atexit && + (exit 1) + ' + test_done + EOF + test_path_is_file dont-clean-atexit && + test_path_is_missing clean-atexit && + test_path_is_missing also-clean-atexit +" + test_expect_success 'test_oid setup' ' test_oid_init ' diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 42a263cada..1f462204ea 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -93,6 +93,7 @@ test_expect_success 'No extra GIT_* on alias scripts' ' sed -n \ -e "/^GIT_PREFIX=/d" \ -e "/^GIT_TEXTDOMAINDIR=/d" \ + -e "/^GIT_TR2_PARENT/d" \ -e "/^GIT_/s/=.*//p" | sort EOF @@ -453,6 +454,17 @@ test_expect_success 're-init from a linked worktree' ' ) ' +test_expect_success MINGW 'core.hidedotfiles = false' ' + git config --global core.hidedotfiles false && + rm -rf newdir && + mkdir newdir && + ( + sane_unset GIT_DIR GIT_WORK_TREE GIT_CONFIG && + git -C newdir init + ) && + ! is_hidden newdir/.git +' + test_expect_success MINGW 'redirect std handles' ' GIT_REDIRECT_STDOUT=output.txt git rev-parse --git-dir && test .git = "$(cat output.txt)" && diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index b8f366c442..800b3ea5f5 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -203,20 +203,24 @@ file: (not set) EOF test_expect_success 'unambiguously abbreviated option' ' + GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \ test-tool parse-options --int 2 --boolean --no-bo >output 2>output.err && test_must_be_empty output.err && test_cmp expect output ' test_expect_success 'unambiguously abbreviated option with "="' ' + GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \ test-tool parse-options --expect="integer: 2" --int=2 ' test_expect_success 'ambiguously abbreviated option' ' - test_expect_code 129 test-tool parse-options --strin 123 + test_expect_code 129 env GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \ + test-tool parse-options --strin 123 ' test_expect_success 'non ambiguous option (after two options it abbreviates)' ' + GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \ test-tool parse-options --expect="string: 123" --st 123 ' @@ -325,6 +329,7 @@ file: (not set) EOF test_expect_success 'negation of OPT_NONEG flags is not ambiguous' ' + GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \ test-tool parse-options --no-ambig >output 2>output.err && test_must_be_empty output.err && test_cmp expect output @@ -370,4 +375,11 @@ test_expect_success '--no-verbose resets multiple verbose to 0' ' test-tool parse-options --expect="verbose: 0" -v -v -v --no-verbose ' +test_expect_success 'GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS works' ' + GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \ + test-tool parse-options --ye && + test_must_fail env GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=true \ + test-tool parse-options --ye +' + test_done diff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh new file mode 100755 index 0000000000..03a0aedb1d --- /dev/null +++ b/t/t0210-trace2-normal.sh @@ -0,0 +1,135 @@ +#!/bin/sh + +test_description='test trace2 facility (normal target)' +. ./test-lib.sh + +# Add t/helper directory to PATH so that we can use a relative +# path to run nested instances of test-tool.exe (see 004child). +# This helps with HEREDOC comparisons later. +TTDIR="$GIT_BUILD_DIR/t/helper/" && export TTDIR +PATH="$TTDIR:$PATH" && export PATH + +# Warning: use of 'test_cmp' may run test-tool.exe and/or git.exe +# Warning: to do the actual diff/comparison, so the HEREDOCs here +# Warning: only cover our actual calls to test-tool and/or git. +# Warning: So you may see extra lines in artifact files when +# Warning: interactively debugging. + +# Turn off any inherited trace2 settings for this test. +unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT +unset GIT_TR2_BRIEF +unset GIT_TR2_CONFIG_PARAMS + +V=$(git version | sed -e 's/^git version //') && export V + +# There are multiple trace2 targets: normal, perf, and event. +# Trace2 events will/can be written to each active target (subject +# to whatever filtering that target decides to do). +# This script tests the normal target in isolation. +# +# Defer setting GIT_TR2 until the actual command line we want to test +# because hidden git and test-tool commands run by the test harness +# can contaminate our output. + +# Enable "brief" feature which turns off "<clock> <file>:<line> " prefix. +GIT_TR2_BRIEF=1 && export GIT_TR2_BRIEF + +# Basic tests of the trace2 normal stream. Since this stream is used +# primarily with printf-style debugging/tracing, we do limited testing +# here. +# +# We do confirm the following API features: +# [] the 'version <v>' event +# [] the 'start <argv>' event +# [] the 'cmd_name <name>' event +# [] the 'exit <time> code:<code>' event +# [] the 'atexit <time> code:<code>' event +# +# Fields of the form _FIELD_ are tokens that have been replaced (such +# as the elapsed time). + +# Verb 001return +# +# Implicit return from cmd_<verb> function propagates <code>. + +test_expect_success 'normal stream, return code 0' ' + test_when_finished "rm trace.normal actual expect" && + GIT_TR2="$(pwd)/trace.normal" test-tool trace2 001return 0 && + perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual && + cat >expect <<-EOF && + version $V + start _EXE_ trace2 001return 0 + cmd_name trace2 (trace2) + exit elapsed:_TIME_ code:0 + atexit elapsed:_TIME_ code:0 + EOF + test_cmp expect actual +' + +test_expect_success 'normal stream, return code 1' ' + test_when_finished "rm trace.normal actual expect" && + test_must_fail env GIT_TR2="$(pwd)/trace.normal" test-tool trace2 001return 1 && + perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual && + cat >expect <<-EOF && + version $V + start _EXE_ trace2 001return 1 + cmd_name trace2 (trace2) + exit elapsed:_TIME_ code:1 + atexit elapsed:_TIME_ code:1 + EOF + test_cmp expect actual +' + +# Verb 002exit +# +# Explicit exit(code) from within cmd_<verb> propagates <code>. + +test_expect_success 'normal stream, exit code 0' ' + test_when_finished "rm trace.normal actual expect" && + GIT_TR2="$(pwd)/trace.normal" test-tool trace2 002exit 0 && + perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual && + cat >expect <<-EOF && + version $V + start _EXE_ trace2 002exit 0 + cmd_name trace2 (trace2) + exit elapsed:_TIME_ code:0 + atexit elapsed:_TIME_ code:0 + EOF + test_cmp expect actual +' + +test_expect_success 'normal stream, exit code 1' ' + test_when_finished "rm trace.normal actual expect" && + test_must_fail env GIT_TR2="$(pwd)/trace.normal" test-tool trace2 002exit 1 && + perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual && + cat >expect <<-EOF && + version $V + start _EXE_ trace2 002exit 1 + cmd_name trace2 (trace2) + exit elapsed:_TIME_ code:1 + atexit elapsed:_TIME_ code:1 + EOF + test_cmp expect actual +' + +# Verb 003error +# +# To the above, add multiple 'error <msg>' events + +test_expect_success 'normal stream, error event' ' + test_when_finished "rm trace.normal actual expect" && + GIT_TR2="$(pwd)/trace.normal" test-tool trace2 003error "hello world" "this is a test" && + perl "$TEST_DIRECTORY/t0210/scrub_normal.perl" <trace.normal >actual && + cat >expect <<-EOF && + version $V + start _EXE_ trace2 003error '\''hello world'\'' '\''this is a test'\'' + cmd_name trace2 (trace2) + error hello world + error this is a test + exit elapsed:_TIME_ code:0 + atexit elapsed:_TIME_ code:0 + EOF + test_cmp expect actual +' + +test_done diff --git a/t/t0210/scrub_normal.perl b/t/t0210/scrub_normal.perl new file mode 100644 index 0000000000..c65d1a815e --- /dev/null +++ b/t/t0210/scrub_normal.perl @@ -0,0 +1,48 @@ +#!/usr/bin/perl +# +# Scrub the variable fields from the normal trace2 output to +# make testing easier. + +use strict; +use warnings; + +my $float = '[0-9]*\.[0-9]+([eE][-+]?[0-9]+)?'; + +# This code assumes that the trace2 data was written with bare +# turned on (which omits the "<clock> <file>:<line>" prefix. + +while (<>) { + # Various messages include an elapsed time in the middle + # of the message. Replace the time with a placeholder to + # simplify our HEREDOC in the test script. + s/elapsed:$float/elapsed:_TIME_/g; + + my $line = $_; + + # we expect: + # start <argv0> [<argv1> [<argv2> [...]]] + # + # where argv0 might be a relative or absolute path, with + # or without quotes, and platform dependent. Replace argv0 + # with a token for HEREDOC matching in the test script. + + if ($line =~ m/^start/) { + $line =~ /^start\s+(.*)/; + my $argv = $1; + $argv =~ m/(\'[^\']*\'|[^ ]+)\s+(.*)/; + my $argv_0 = $1; + my $argv_rest = $2; + + print "start _EXE_ $argv_rest\n"; + } + elsif ($line =~ m/^cmd_path/) { + # Likewise, the 'cmd_path' message breaks out argv[0]. + # + # This line is only emitted when RUNTIME_PREFIX is defined, + # so just omit it for testing purposes. + # print "cmd_path _EXE_\n"; + } + else { + print "$line"; + } +} diff --git a/t/t0211-trace2-perf.sh b/t/t0211-trace2-perf.sh new file mode 100755 index 0000000000..953e2f7847 --- /dev/null +++ b/t/t0211-trace2-perf.sh @@ -0,0 +1,153 @@ +#!/bin/sh + +test_description='test trace2 facility (perf target)' +. ./test-lib.sh + +# Add t/helper directory to PATH so that we can use a relative +# path to run nested instances of test-tool.exe (see 004child). +# This helps with HEREDOC comparisons later. +TTDIR="$GIT_BUILD_DIR/t/helper/" && export TTDIR +PATH="$TTDIR:$PATH" && export PATH + +# Warning: use of 'test_cmp' may run test-tool.exe and/or git.exe +# Warning: to do the actual diff/comparison, so the HEREDOCs here +# Warning: only cover our actual calls to test-tool and/or git. +# Warning: So you may see extra lines in artifact files when +# Warning: interactively debugging. + +# Turn off any inherited trace2 settings for this test. +unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT +unset GIT_TR2_PERF_BRIEF +unset GIT_TR2_CONFIG_PARAMS + +V=$(git version | sed -e 's/^git version //') && export V + +# There are multiple trace2 targets: normal, perf, and event. +# Trace2 events will/can be written to each active target (subject +# to whatever filtering that target decides to do). +# Test each target independently. +# +# Defer setting GIT_TR2_PERF until the actual command we want to +# test because hidden git and test-tool commands in the test +# harness can contaminate our output. + +# Enable "brief" feature which turns off the prefix: +# "<clock> <file>:<line> | <nr_parents> | " +GIT_TR2_PERF_BRIEF=1 && export GIT_TR2_PERF_BRIEF + +# Repeat some of the t0210 tests using the perf target stream instead of +# the normal stream. +# +# Tokens here of the form _FIELD_ have been replaced in the observed output. + +# Verb 001return +# +# Implicit return from cmd_<verb> function propagates <code>. + +test_expect_success 'perf stream, return code 0' ' + test_when_finished "rm trace.perf actual expect" && + GIT_TR2_PERF="$(pwd)/trace.perf" test-tool trace2 001return 0 && + perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <trace.perf >actual && + cat >expect <<-EOF && + d0|main|version|||||$V + d0|main|start|||||_EXE_ trace2 001return 0 + d0|main|cmd_name|||||trace2 (trace2) + d0|main|exit||_T_ABS_|||code:0 + d0|main|atexit||_T_ABS_|||code:0 + EOF + test_cmp expect actual +' + +test_expect_success 'perf stream, return code 1' ' + test_when_finished "rm trace.perf actual expect" && + test_must_fail env GIT_TR2_PERF="$(pwd)/trace.perf" test-tool trace2 001return 1 && + perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <trace.perf >actual && + cat >expect <<-EOF && + d0|main|version|||||$V + d0|main|start|||||_EXE_ trace2 001return 1 + d0|main|cmd_name|||||trace2 (trace2) + d0|main|exit||_T_ABS_|||code:1 + d0|main|atexit||_T_ABS_|||code:1 + EOF + test_cmp expect actual +' + +# Verb 003error +# +# To the above, add multiple 'error <msg>' events + +test_expect_success 'perf stream, error event' ' + test_when_finished "rm trace.perf actual expect" && + GIT_TR2_PERF="$(pwd)/trace.perf" test-tool trace2 003error "hello world" "this is a test" && + perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <trace.perf >actual && + cat >expect <<-EOF && + d0|main|version|||||$V + d0|main|start|||||_EXE_ trace2 003error '\''hello world'\'' '\''this is a test'\'' + d0|main|cmd_name|||||trace2 (trace2) + d0|main|error|||||hello world + d0|main|error|||||this is a test + d0|main|exit||_T_ABS_|||code:0 + d0|main|atexit||_T_ABS_|||code:0 + EOF + test_cmp expect actual +' + +# Verb 004child +# +# Test nested spawning of child processes. +# +# Conceptually, this looks like: +# P1: TT trace2 004child +# P2: |--- TT trace2 004child +# P3: |--- TT trace2 001return 0 +# +# Which should generate events: +# P1: version +# P1: start +# P1: cmd_name +# P1: child_start +# P2: version +# P2: start +# P2: cmd_name +# P2: child_start +# P3: version +# P3: start +# P3: cmd_name +# P3: exit +# P3: atexit +# P2: child_exit +# P2: exit +# P2: atexit +# P1: child_exit +# P1: exit +# P1: atexit + +test_expect_success 'perf stream, child processes' ' + test_when_finished "rm trace.perf actual expect" && + GIT_TR2_PERF="$(pwd)/trace.perf" test-tool trace2 004child test-tool trace2 004child test-tool trace2 001return 0 && + perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <trace.perf >actual && + cat >expect <<-EOF && + d0|main|version|||||$V + d0|main|start|||||_EXE_ trace2 004child test-tool trace2 004child test-tool trace2 001return 0 + d0|main|cmd_name|||||trace2 (trace2) + d0|main|child_start||_T_ABS_|||[ch0] class:? argv: test-tool trace2 004child test-tool trace2 001return 0 + d1|main|version|||||$V + d1|main|start|||||_EXE_ trace2 004child test-tool trace2 001return 0 + d1|main|cmd_name|||||trace2 (trace2/trace2) + d1|main|child_start||_T_ABS_|||[ch0] class:? argv: test-tool trace2 001return 0 + d2|main|version|||||$V + d2|main|start|||||_EXE_ trace2 001return 0 + d2|main|cmd_name|||||trace2 (trace2/trace2/trace2) + d2|main|exit||_T_ABS_|||code:0 + d2|main|atexit||_T_ABS_|||code:0 + d1|main|child_exit||_T_ABS_|_T_REL_||[ch0] pid:_PID_ code:0 + d1|main|exit||_T_ABS_|||code:0 + d1|main|atexit||_T_ABS_|||code:0 + d0|main|child_exit||_T_ABS_|_T_REL_||[ch0] pid:_PID_ code:0 + d0|main|exit||_T_ABS_|||code:0 + d0|main|atexit||_T_ABS_|||code:0 + EOF + test_cmp expect actual +' + +test_done diff --git a/t/t0211/scrub_perf.perl b/t/t0211/scrub_perf.perl new file mode 100644 index 0000000000..351af7844e --- /dev/null +++ b/t/t0211/scrub_perf.perl @@ -0,0 +1,76 @@ +#!/usr/bin/perl +# +# Scrub the variable fields from the perf trace2 output to +# make testing easier. + +use strict; +use warnings; + +my $qpath = '\'[^\']*\'|[^ ]*'; + +my $col_depth=0; +my $col_thread=1; +my $col_event=2; +my $col_repo=3; +my $col_t_abs=4; +my $col_t_rel=5; +my $col_category=6; +my $col_rest=7; + +# This code assumes that the trace2 data was written with bare +# turned on (which omits the "<clock> <file>:<line> | <parents>" +# prefix. + +while (<>) { + my @tokens = split /\|/; + + foreach my $col (@tokens) { $col =~ s/^\s+|\s+$//g; } + + if ($tokens[$col_event] =~ m/^start/) { + # The 'start' message lists the contents of argv in $col_rest. + # On some platforms (Windows), argv[0] is *sometimes* a canonical + # absolute path to the EXE rather than the value passed in the + # shell script. Replace it with a placeholder to simplify our + # HEREDOC in the test script. + my $argv0; + my $argvRest; + $tokens[$col_rest] =~ s/^($qpath)\W*(.*)/_EXE_ $2/; + } + elsif ($tokens[$col_event] =~ m/cmd_path/) { + # Likewise, the 'cmd_path' message breaks out argv[0]. + # + # This line is only emitted when RUNTIME_PREFIX is defined, + # so just omit it for testing purposes. + # $tokens[$col_rest] = "_EXE_"; + goto SKIP_LINE; + } + elsif ($tokens[$col_event] =~ m/child_exit/) { + $tokens[$col_rest] =~ s/ pid:\d* / pid:_PID_ /; + } + elsif ($tokens[$col_event] =~ m/data/) { + if ($tokens[$col_category] =~ m/process/) { + # 'data' and 'data_json' events containing 'process' + # category data are assumed to be platform-specific + # and highly variable. Just omit them. + goto SKIP_LINE; + } + } + + # t_abs and t_rel are either blank or a float. Replace the float + # with a constant for matching the HEREDOC in the test script. + if ($tokens[$col_t_abs] =~ m/\d/) { + $tokens[$col_t_abs] = "_T_ABS_"; + } + if ($tokens[$col_t_rel] =~ m/\d/) { + $tokens[$col_t_rel] = "_T_REL_"; + } + + my $out; + + $out = join('|', @tokens); + print "$out\n"; + + SKIP_LINE: +} + + diff --git a/t/t0212-trace2-event.sh b/t/t0212-trace2-event.sh new file mode 100755 index 0000000000..028b6c5671 --- /dev/null +++ b/t/t0212-trace2-event.sh @@ -0,0 +1,236 @@ +#!/bin/sh + +test_description='test trace2 facility' +. ./test-lib.sh + +perl -MJSON::PP -e 0 >/dev/null 2>&1 && test_set_prereq JSON_PP + +# Add t/helper directory to PATH so that we can use a relative +# path to run nested instances of test-tool.exe (see 004child). +# This helps with HEREDOC comparisons later. +TTDIR="$GIT_BUILD_DIR/t/helper/" && export TTDIR +PATH="$TTDIR:$PATH" && export PATH + +# Warning: use of 'test_cmp' may run test-tool.exe and/or git.exe +# Warning: to do the actual diff/comparison, so the HEREDOCs here +# Warning: only cover our actual calls to test-tool and/or git. +# Warning: So you may see extra lines in artifact files when +# Warning: interactively debugging. + +# Turn off any inherited trace2 settings for this test. +unset GIT_TR2 GIT_TR2_PERF GIT_TR2_EVENT +unset GIT_TR2_BARE +unset GIT_TR2_CONFIG_PARAMS + +V=$(git version | sed -e 's/^git version //') && export V + +# There are multiple trace2 targets: normal, perf, and event. +# Trace2 events will/can be written to each active target (subject +# to whatever filtering that target decides to do). +# Test each target independently. +# +# Defer setting GIT_TR2_PERF until the actual command we want to +# test because hidden git and test-tool commands in the test +# harness can contaminate our output. + +# We don't bother repeating the 001return and 002exit tests, since they +# have coverage in the normal and perf targets. + +# Verb 003error +# +# To the above, add multiple 'error <msg>' events + +test_expect_success JSON_PP 'event stream, error event' ' + test_when_finished "rm trace.event actual expect" && + GIT_TR2_EVENT="$(pwd)/trace.event" test-tool trace2 003error "hello world" "this is a test" && + perl "$TEST_DIRECTORY/t0212/parse_events.perl" <trace.event >actual && + sed -e "s/^|//" >expect <<-EOF && + |VAR1 = { + | "_SID0_":{ + | "argv":[ + | "_EXE_", + | "trace2", + | "003error", + | "hello world", + | "this is a test" + | ], + | "errors":[ + | "%s", + | "%s" + | ], + | "exit_code":0, + | "hierarchy":"trace2", + | "name":"trace2", + | "version":"$V" + | } + |}; + EOF + test_cmp expect actual +' + +# Verb 004child +# +# Test nested spawning of child processes. +# +# Conceptually, this looks like: +# P1: TT trace2 004child +# P2: |--- TT trace2 004child +# P3: |--- TT trace2 001return 0 + +test_expect_success JSON_PP 'event stream, return code 0' ' + test_when_finished "rm trace.event actual expect" && + GIT_TR2_EVENT="$(pwd)/trace.event" test-tool trace2 004child test-tool trace2 004child test-tool trace2 001return 0 && + perl "$TEST_DIRECTORY/t0212/parse_events.perl" <trace.event >actual && + sed -e "s/^|//" >expect <<-EOF && + |VAR1 = { + | "_SID0_":{ + | "argv":[ + | "_EXE_", + | "trace2", + | "004child", + | "test-tool", + | "trace2", + | "004child", + | "test-tool", + | "trace2", + | "001return", + | "0" + | ], + | "child":{ + | "0":{ + | "child_argv":[ + | "_EXE_", + | "trace2", + | "004child", + | "test-tool", + | "trace2", + | "001return", + | "0" + | ], + | "child_class":"?", + | "child_code":0, + | "use_shell":0 + | } + | }, + | "exit_code":0, + | "hierarchy":"trace2", + | "name":"trace2", + | "version":"$V" + | }, + | "_SID0_/_SID1_":{ + | "argv":[ + | "_EXE_", + | "trace2", + | "004child", + | "test-tool", + | "trace2", + | "001return", + | "0" + | ], + | "child":{ + | "0":{ + | "child_argv":[ + | "_EXE_", + | "trace2", + | "001return", + | "0" + | ], + | "child_class":"?", + | "child_code":0, + | "use_shell":0 + | } + | }, + | "exit_code":0, + | "hierarchy":"trace2/trace2", + | "name":"trace2", + | "version":"$V" + | }, + | "_SID0_/_SID1_/_SID2_":{ + | "argv":[ + | "_EXE_", + | "trace2", + | "001return", + | "0" + | ], + | "exit_code":0, + | "hierarchy":"trace2/trace2/trace2", + | "name":"trace2", + | "version":"$V" + | } + |}; + EOF + test_cmp expect actual +' + +# Test listing of all "interesting" config settings. + +test_expect_success JSON_PP 'event stream, list config' ' + test_when_finished "rm trace.event actual expect" && + git config --local t0212.abc 1 && + git config --local t0212.def "hello world" && + GIT_TR2_EVENT="$(pwd)/trace.event" GIT_TR2_CONFIG_PARAMS="t0212.*" test-tool trace2 001return 0 && + perl "$TEST_DIRECTORY/t0212/parse_events.perl" <trace.event >actual && + sed -e "s/^|//" >expect <<-EOF && + |VAR1 = { + | "_SID0_":{ + | "argv":[ + | "_EXE_", + | "trace2", + | "001return", + | "0" + | ], + | "exit_code":0, + | "hierarchy":"trace2", + | "name":"trace2", + | "params":[ + | { + | "param":"t0212.abc", + | "value":"1" + | }, + | { + | "param":"t0212.def", + | "value":"hello world" + | } + | ], + | "version":"$V" + | } + |}; + EOF + test_cmp expect actual +' + +test_expect_success JSON_PP 'basic trace2_data' ' + test_when_finished "rm trace.event actual expect" && + GIT_TR2_EVENT="$(pwd)/trace.event" test-tool trace2 006data test_category k1 v1 test_category k2 v2 && + perl "$TEST_DIRECTORY/t0212/parse_events.perl" <trace.event >actual && + sed -e "s/^|//" >expect <<-EOF && + |VAR1 = { + | "_SID0_":{ + | "argv":[ + | "_EXE_", + | "trace2", + | "006data", + | "test_category", + | "k1", + | "v1", + | "test_category", + | "k2", + | "v2" + | ], + | "data":{ + | "test_category":{ + | "k1":"v1", + | "k2":"v2" + | } + | }, + | "exit_code":0, + | "hierarchy":"trace2", + | "name":"trace2", + | "version":"$V" + | } + |}; + EOF + test_cmp expect actual +' + +test_done diff --git a/t/t0212/parse_events.perl b/t/t0212/parse_events.perl new file mode 100644 index 0000000000..a2776ba216 --- /dev/null +++ b/t/t0212/parse_events.perl @@ -0,0 +1,251 @@ +#!/usr/bin/perl +# +# Parse event stream and convert individual events into a summary +# record for the process. +# +# Git.exe generates one or more "event" records for each API method, +# such as "start <argv>" and "exit <code>", during the life of the git +# process. Additionally, the input may contain interleaved events +# from multiple concurrent git processes and/or multiple threads from +# within a git process. +# +# Accumulate events for each process (based on its unique SID) in a +# dictionary and emit process summary records. +# +# Convert some of the variable fields (such as elapsed time) into +# placeholders (or omit them) to make HEREDOC comparisons easier in +# the test scripts. +# +# We may also omit fields not (currently) useful for testing purposes. + +use strict; +use warnings; +use JSON::PP; +use Data::Dumper; +use Getopt::Long; + +# The version of the trace2 event target format that we understand. +# This is reported in the 'version' event in the 'evt' field. +# It comes from the GIT_TR2_EVENT_VERSION macro in trace2/tr2_tgt_event.c +my $evt_version = '1'; + +my $show_children = 1; +my $show_exec = 1; +my $show_threads = 1; + +# A hack to generate test HEREDOC data for pasting into the test script. +# Usage: +# cd "t/trash directory.t0212-trace2-event" +# $TT trace ... >trace.event +# VV=$(../../git.exe version | sed -e 's/^git version //') +# perl ../t0212/parse_events.perl --HEREDOC --VERSION=$VV <trace.event >heredoc +# Then paste heredoc into your new test. + +my $gen_heredoc = 0; +my $gen_version = ''; + +GetOptions("children!" => \$show_children, + "exec!" => \$show_exec, + "threads!" => \$show_threads, + "HEREDOC!" => \$gen_heredoc, + "VERSION=s" => \$gen_version ) + or die("Error in command line arguments\n"); + + +# SIDs contains timestamps and PIDs of the process and its parents. +# This makes it difficult to match up in a HEREDOC in the test script. +# Build a map from actual SIDs to predictable constant values and yet +# keep the parent/child relationships. For example: +# {..., "sid":"1539706952458276-8652", ...} +# {..., "sid":"1539706952458276-8652/1539706952649493-15452", ...} +# becomes: +# {..., "sid":"_SID1_", ...} +# {..., "sid":"_SID1_/_SID2_", ...} +my $sid_map; +my $sid_count = 0; + +my $processes; + +while (<>) { + my $line = decode_json( $_ ); + + my $sid = ""; + my $sid_sep = ""; + + my $raw_sid = $line->{'sid'}; + my @raw_sid_parts = split /\//, $raw_sid; + foreach my $raw_sid_k (@raw_sid_parts) { + if (!exists $sid_map->{$raw_sid_k}) { + $sid_map->{$raw_sid_k} = '_SID' . $sid_count . '_'; + $sid_count++; + } + $sid = $sid . $sid_sep . $sid_map->{$raw_sid_k}; + $sid_sep = '/'; + } + + my $event = $line->{'event'}; + + if ($event eq 'version') { + $processes->{$sid}->{'version'} = $line->{'exe'}; + if ($gen_heredoc == 1 && $gen_version eq $line->{'exe'}) { + # If we are generating data FOR the test script, replace + # the reported git.exe version with a reference to an + # environment variable. When our output is pasted into + # the test script, it will then be expanded in future + # test runs to the THEN current version of git.exe. + # We assume that the test script uses env var $V. + $processes->{$sid}->{'version'} = "\$V"; + } + } + + elsif ($event eq 'start') { + $processes->{$sid}->{'argv'} = $line->{'argv'}; + $processes->{$sid}->{'argv'}[0] = "_EXE_"; + } + + elsif ($event eq 'exit') { + $processes->{$sid}->{'exit_code'} = $line->{'code'}; + } + + elsif ($event eq 'atexit') { + $processes->{$sid}->{'exit_code'} = $line->{'code'}; + } + + elsif ($event eq 'error') { + # For HEREDOC purposes, use the error message format string if + # available, rather than the formatted message (which probably + # has an absolute pathname). + if (exists $line->{'fmt'}) { + push( @{$processes->{$sid}->{'errors'}}, $line->{'fmt'} ); + } + elsif (exists $line->{'msg'}) { + push( @{$processes->{$sid}->{'errors'}}, $line->{'msg'} ); + } + } + + elsif ($event eq 'cmd_path') { + ## $processes->{$sid}->{'path'} = $line->{'path'}; + # + # Like in the 'start' event, we need to replace the value of + # argv[0] with a token for HEREDOC purposes. However, the + # event is only emitted when RUNTIME_PREFIX is defined, so + # just omit it for testing purposes. + # $processes->{$sid}->{'path'} = "_EXE_"; + } + + elsif ($event eq 'cmd_name') { + $processes->{$sid}->{'name'} = $line->{'name'}; + $processes->{$sid}->{'hierarchy'} = $line->{'hierarchy'}; + } + + elsif ($event eq 'alias') { + $processes->{$sid}->{'alias'}->{'key'} = $line->{'alias'}; + $processes->{$sid}->{'alias'}->{'argv'} = $line->{'argv'}; + } + + elsif ($event eq 'def_param') { + my $kv; + $kv->{'param'} = $line->{'param'}; + $kv->{'value'} = $line->{'value'}; + push( @{$processes->{$sid}->{'params'}}, $kv ); + } + + elsif ($event eq 'child_start') { + if ($show_children == 1) { + $processes->{$sid}->{'child'}->{$line->{'child_id'}}->{'child_class'} = $line->{'child_class'}; + $processes->{$sid}->{'child'}->{$line->{'child_id'}}->{'child_argv'} = $line->{'argv'}; + $processes->{$sid}->{'child'}->{$line->{'child_id'}}->{'child_argv'}[0] = "_EXE_"; + $processes->{$sid}->{'child'}->{$line->{'child_id'}}->{'use_shell'} = $line->{'use_shell'} ? 1 : 0; + } + } + + elsif ($event eq 'child_exit') { + if ($show_children == 1) { + $processes->{$sid}->{'child'}->{$line->{'child_id'}}->{'child_code'} = $line->{'code'}; + } + } + + # TODO decide what information we want to test from thread events. + + elsif ($event eq 'thread_start') { + if ($show_threads == 1) { + } + } + + elsif ($event eq 'thread_exit') { + if ($show_threads == 1) { + } + } + + # TODO decide what information we want to test from exec events. + + elsif ($event eq 'exec') { + if ($show_exec == 1) { + } + } + + elsif ($event eq 'exec_result') { + if ($show_exec == 1) { + } + } + + elsif ($event eq 'def_param') { + # Accumulate parameter key/value pairs by key rather than in an array + # so that we get overwrite (last one wins) effects. + $processes->{$sid}->{'params'}->{$line->{'param'}} = $line->{'value'}; + } + + elsif ($event eq 'def_repo') { + # $processes->{$sid}->{'repos'}->{$line->{'repo'}} = $line->{'worktree'}; + $processes->{$sid}->{'repos'}->{$line->{'repo'}} = "_WORKTREE_"; + } + + # A series of potentially nested and threaded region and data events + # is fundamentally incompatibile with the type of summary record we + # are building in this script. Since they are intended for + # perf-trace-like analysis rather than a result summary, we ignore + # most of them here. + + # elsif ($event eq 'region_enter') { + # } + # elsif ($event eq 'region_leave') { + # } + + elsif ($event eq 'data') { + my $cat = $line->{'category'}; + if ($cat eq 'test_category') { + + my $key = $line->{'key'}; + my $value = $line->{'value'}; + $processes->{$sid}->{'data'}->{$cat}->{$key} = $value; + } + } + + # This trace2 target does not emit 'printf' events. + # + # elsif ($event eq 'printf') { + # } +} + +# Dump the resulting hash into something that we can compare against +# in the test script. These options make Dumper output look a little +# bit like JSON. Also convert variable references of the form "$VAR*" +# so that the matching HEREDOC doesn't need to escape it. + +$Data::Dumper::Sortkeys = 1; +$Data::Dumper::Indent = 1; +$Data::Dumper::Purity = 1; +$Data::Dumper::Pair = ':'; + +my $out = Dumper($processes); +$out =~ s/'/"/g; +$out =~ s/\$VAR/VAR/g; + +# Finally, if we're running this script to generate (manually confirmed) +# data to add to the test script, guard the indentation. + +if ($gen_heredoc == 1) { + $out =~ s/^/\t\|/gms; +} + +print $out; diff --git a/t/t0301-credential-cache.sh b/t/t0301-credential-cache.sh index fd92533acf..ebd5fa5249 100755 --- a/t/t0301-credential-cache.sh +++ b/t/t0301-credential-cache.sh @@ -10,7 +10,7 @@ test -z "$NO_UNIX_SOCKETS" || { } # don't leave a stale daemon running -trap 'code=$?; git credential-cache exit; (exit $code); die' EXIT +test_atexit 'git credential-cache exit' # test that the daemon works with no special setup helper_test cache @@ -108,9 +108,4 @@ test_expect_success SYMLINKS 'use user socket if user directory is a symlink to helper_test_timeout cache --timeout=1 -# we can't rely on our "trap" above working after test_done, -# as test_done will delete the trash directory containing -# our socket, leaving us with no way to access the daemon. -git credential-cache exit - test_done diff --git a/t/t0410-partial-clone.sh b/t/t0410-partial-clone.sh index bce02788e6..5bd892f2f7 100755 --- a/t/t0410-partial-clone.sh +++ b/t/t0410-partial-clone.sh @@ -518,6 +518,4 @@ test_expect_success 'fetching of missing objects from an HTTP server' ' git verify-pack --verbose "$IDX" | grep "$HASH" ' -stop_httpd - test_done diff --git a/t/t1060-object-corruption.sh b/t/t1060-object-corruption.sh index 4feb65157d..bc89371f53 100755 --- a/t/t1060-object-corruption.sh +++ b/t/t1060-object-corruption.sh @@ -127,4 +127,14 @@ test_expect_success 'fetch into corrupted repo with index-pack' ' ) ' +test_expect_success 'internal tree objects are not "missing"' ' + git init missing-empty && + ( + cd missing-empty && + empty_tree=$(git hash-object -t tree /dev/null) && + commit=$(echo foo | git commit-tree $empty_tree) && + git rev-list --objects $commit + ) +' + test_done diff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh index 635918505d..579a86b7f8 100755 --- a/t/t1305-config-include.sh +++ b/t/t1305-config-include.sh @@ -229,6 +229,19 @@ test_expect_success 'conditional include, early config reading' ' ) ' +test_expect_success 'conditional include with /**/' ' + REPO=foo/bar/repo && + git init $REPO && + cat >>$REPO/.git/config <<-\EOF && + [includeIf "gitdir:**/foo/**/bar/**"] + path=bar7 + EOF + echo "[test]seven=7" >$REPO/.git/bar7 && + echo 7 >expect && + git -C $REPO config test.seven >actual && + test_cmp expect actual +' + test_expect_success SYMLINKS 'conditional include, set up symlinked $HOME' ' mkdir real-home && ln -s real-home home && diff --git a/t/t1404-update-ref-errors.sh b/t/t1404-update-ref-errors.sh index 6b6a8e2292..970c5c36b9 100755 --- a/t/t1404-update-ref-errors.sh +++ b/t/t1404-update-ref-errors.sh @@ -618,4 +618,20 @@ test_expect_success 'delete fails cleanly if packed-refs file is locked' ' test_cmp unchanged actual ' +test_expect_success 'delete fails cleanly if packed-refs.new write fails' ' + # Setup and expectations are similar to the test above. + prefix=refs/failed-packed-refs && + git update-ref $prefix/foo $C && + git pack-refs --all && + git update-ref $prefix/foo $D && + git for-each-ref $prefix >unchanged && + # This should not happen in practice, but it is an easy way to get a + # reliable error (we open with create_tempfile(), which uses O_EXCL). + : >.git/packed-refs.new && + test_when_finished "rm -f .git/packed-refs.new" && + test_must_fail git update-ref -d $prefix/foo && + git for-each-ref $prefix >actual && + test_cmp unchanged actual +' + test_done diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh index ae8a448e34..79f731db37 100755 --- a/t/t1410-reflog.sh +++ b/t/t1410-reflog.sh @@ -232,25 +232,34 @@ test_expect_success '--expire=never' ' ' test_expect_success 'gc.reflogexpire=never' ' + test_config gc.reflogexpire never && + test_config gc.reflogexpireunreachable never && + + git reflog expire --verbose --all >output && + test_line_count = 9 output && - git config gc.reflogexpire never && - git config gc.reflogexpireunreachable never && - git reflog expire --verbose --all && git reflog refs/heads/master >output && test_line_count = 4 output ' test_expect_success 'gc.reflogexpire=false' ' + test_config gc.reflogexpire false && + test_config gc.reflogexpireunreachable false && - git config gc.reflogexpire false && - git config gc.reflogexpireunreachable false && git reflog expire --verbose --all && git reflog refs/heads/master >output && - test_line_count = 4 output && + test_line_count = 4 output + +' - git config --unset gc.reflogexpire && - git config --unset gc.reflogexpireunreachable +test_expect_success 'git reflog expire unknown reference' ' + test_config gc.reflogexpire never && + test_config gc.reflogexpireunreachable never && + test_must_fail git reflog expire master@{123} 2>stderr && + test_i18ngrep "points nowhere" stderr && + test_must_fail git reflog expire does-not-exist 2>stderr && + test_i18ngrep "points nowhere" stderr ' test_expect_success 'checkout should not delete log for packed ref' ' diff --git a/t/t1415-worktree-refs.sh b/t/t1415-worktree-refs.sh index b664e51250..bb2c7572a3 100755 --- a/t/t1415-worktree-refs.sh +++ b/t/t1415-worktree-refs.sh @@ -76,4 +76,39 @@ test_expect_success 'reflog of worktrees/xx/HEAD' ' test_cmp expected actual.wt2 ' +test_expect_success 'for-each-ref from main repo' ' + mkdir fer1 && + git -C fer1 init repo && + test_commit -C fer1/repo initial && + git -C fer1/repo worktree add ../second && + git -C fer1/repo update-ref refs/bisect/main HEAD && + git -C fer1/repo update-ref refs/rewritten/main HEAD && + git -C fer1/repo update-ref refs/worktree/main HEAD && + git -C fer1/repo for-each-ref --format="%(refname)" | grep main >actual && + cat >expected <<-\EOF && + refs/bisect/main + refs/rewritten/main + refs/worktree/main + EOF + test_cmp expected actual +' + +test_expect_success 'for-each-ref from linked repo' ' + mkdir fer2 && + git -C fer2 init repo && + test_commit -C fer2/repo initial && + git -C fer2/repo worktree add ../second && + git -C fer2/second update-ref refs/bisect/second HEAD && + git -C fer2/second update-ref refs/rewritten/second HEAD && + git -C fer2/second update-ref refs/worktree/second HEAD && + git -C fer2/second for-each-ref --format="%(refname)" | grep second >actual && + cat >expected <<-\EOF && + refs/bisect/second + refs/heads/second + refs/rewritten/second + refs/worktree/second + EOF + test_cmp expected actual +' + test_done diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh index c61f972141..49f08d5b9c 100755 --- a/t/t1450-fsck.sh +++ b/t/t1450-fsck.sh @@ -740,7 +740,7 @@ test_expect_success 'fsck detects truncated loose object' ' # for each of type, we have one version which is referenced by another object # (and so while unreachable, not dangling), and another variant which really is # dangling. -test_expect_success 'fsck notices dangling objects' ' +test_expect_success 'create dangling-object repository' ' git init dangling && ( cd dangling && @@ -751,12 +751,17 @@ test_expect_success 'fsck notices dangling objects' ' commit=$(git commit-tree $tree) && dcommit=$(git commit-tree -p $commit $tree) && - cat >expect <<-EOF && + cat >expect <<-EOF dangling blob $dblob dangling commit $dcommit dangling tree $dtree EOF + ) +' +test_expect_success 'fsck notices dangling objects' ' + ( + cd dangling && git fsck >actual && # the output order is non-deterministic, as it comes from a hash sort <actual >actual.sorted && @@ -764,6 +769,16 @@ test_expect_success 'fsck notices dangling objects' ' ) ' +test_expect_success 'fsck --connectivity-only notices dangling objects' ' + ( + cd dangling && + git fsck --connectivity-only >actual && + # the output order is non-deterministic, as it comes from a hash + sort <actual >actual.sorted && + test_i18ncmp expect actual.sorted + ) +' + test_expect_success 'fsck $name notices bogus $name' ' test_must_fail git fsck bogus && test_must_fail git fsck $ZERO_OID diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh index 4667e1a190..4f2f84f309 100755 --- a/t/t1700-split-index.sh +++ b/t/t1700-split-index.sh @@ -472,4 +472,22 @@ test_expect_success 'writing split index with null sha1 does not write cache tre test_line_count = 0 cache-tree.out ' +test_expect_success 'do not refresh null base index' ' + test_create_repo merge && + ( + cd merge && + test_commit initial && + git checkout -b side-branch && + test_commit extra && + git checkout master && + git update-index --split-index && + test_commit more && + # must not write a new shareindex, or we wont catch the problem + git -c splitIndex.maxPercentChange=100 merge --no-edit side-branch 2>err && + # i.e. do not expect warnings like + # could not freshen shared index .../shareindex.00000... + test_must_be_empty err + ) +' + test_done diff --git a/t/t2023-checkout-m.sh b/t/t2023-checkout-m.sh index 7e18985134..fca3f85824 100755 --- a/t/t2023-checkout-m.sh +++ b/t/t2023-checkout-m.sh @@ -46,4 +46,28 @@ test_expect_success '-m restores 3-way conflicted+resolved file' ' test_cmp both.txt.conflicted.cleaned both.txt.cleaned ' +test_expect_success 'force checkout a conflict file creates stage zero entry' ' + git init co-force && + ( + cd co-force && + echo a >a && + git add a && + git commit -ama && + A_OBJ=$(git rev-parse :a) && + git branch topic && + echo b >a && + git commit -amb && + B_OBJ=$(git rev-parse :a) && + git checkout topic && + echo c >a && + C_OBJ=$(git hash-object a) && + git checkout -m master && + test_cmp_rev :1:a $A_OBJ && + test_cmp_rev :2:a $B_OBJ && + test_cmp_rev :3:a $C_OBJ && + git checkout -f topic && + test_cmp_rev :0:a $A_OBJ + ) +' + test_done diff --git a/t/t2025-checkout-no-overlay.sh b/t/t2025-checkout-no-overlay.sh new file mode 100755 index 0000000000..76330cb5ab --- /dev/null +++ b/t/t2025-checkout-no-overlay.sh @@ -0,0 +1,47 @@ +#!/bin/sh + +test_description='checkout --no-overlay <tree-ish> -- <pathspec>' + +. ./test-lib.sh + +test_expect_success 'setup' ' + git commit --allow-empty -m "initial" +' + +test_expect_success 'checkout --no-overlay deletes files not in <tree-ish>' ' + >file && + mkdir dir && + >dir/file1 && + git add file dir/file1 && + git checkout --no-overlay HEAD -- file && + test_path_is_missing file && + test_path_is_file dir/file1 +' + +test_expect_success 'checkout --no-overlay removing last file from directory' ' + git checkout --no-overlay HEAD -- dir/file1 && + test_path_is_missing dir +' + +test_expect_success 'checkout -p --overlay is disallowed' ' + test_must_fail git checkout -p --overlay HEAD 2>actual && + test_i18ngrep "fatal: -p and --overlay are mutually exclusive" actual +' + +test_expect_success '--no-overlay --theirs with D/F conflict deletes file' ' + test_commit file1 file1 && + test_commit file2 file2 && + git rm --cached file1 && + echo 1234 >file1 && + F1=$(git rev-parse HEAD:file1) && + F2=$(git rev-parse HEAD:file2) && + { + echo "100644 $F1 1 file1" && + echo "100644 $F2 2 file1" + } | git update-index --index-info && + test_path_is_file file1 && + git checkout --theirs --no-overlay -- file1 && + test_path_is_missing file1 +' + +test_done diff --git a/t/t2025-worktree-add.sh b/t/t2400-worktree-add.sh index 286bba35d8..286bba35d8 100755 --- a/t/t2025-worktree-add.sh +++ b/t/t2400-worktree-add.sh diff --git a/t/t2026-worktree-prune.sh b/t/t2401-worktree-prune.sh index b7d6d5d45a..b7d6d5d45a 100755 --- a/t/t2026-worktree-prune.sh +++ b/t/t2401-worktree-prune.sh diff --git a/t/t2027-worktree-list.sh b/t/t2402-worktree-list.sh index bb6fb9b12c..bb6fb9b12c 100755 --- a/t/t2027-worktree-list.sh +++ b/t/t2402-worktree-list.sh diff --git a/t/t2028-worktree-move.sh b/t/t2403-worktree-move.sh index 939d18d728..939d18d728 100755 --- a/t/t2028-worktree-move.sh +++ b/t/t2403-worktree-move.sh diff --git a/t/t2029-worktree-config.sh b/t/t2404-worktree-config.sh index 286121d8de..286121d8de 100755 --- a/t/t2029-worktree-config.sh +++ b/t/t2404-worktree-config.sh diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh index ee6787614c..be55148930 100755 --- a/t/t3203-branch-output.sh +++ b/t/t3203-branch-output.sh @@ -100,6 +100,50 @@ test_expect_success 'git branch -v pattern does not show branch summaries' ' test_must_fail git branch -v branch* ' +test_expect_success 'git branch `--show-current` shows current branch' ' + cat >expect <<-\EOF && + branch-two + EOF + git checkout branch-two && + git branch --show-current >actual && + test_cmp expect actual +' + +test_expect_success 'git branch `--show-current` is silent when detached HEAD' ' + git checkout HEAD^0 && + git branch --show-current >actual && + test_must_be_empty actual +' + +test_expect_success 'git branch `--show-current` works properly when tag exists' ' + cat >expect <<-\EOF && + branch-and-tag-name + EOF + test_when_finished " + git checkout branch-one + git branch -D branch-and-tag-name + " && + git checkout -b branch-and-tag-name && + test_when_finished "git tag -d branch-and-tag-name" && + git tag branch-and-tag-name && + git branch --show-current >actual && + test_cmp expect actual +' + +test_expect_success 'git branch `--show-current` works properly with worktrees' ' + cat >expect <<-\EOF && + branch-one + branch-two + EOF + git checkout branch-one && + git worktree add worktree branch-two && + { + git branch --show-current && + git -C worktree branch --show-current + } >actual && + test_cmp expect actual +' + test_expect_success 'git branch shows detached HEAD properly' ' cat >expect <<EOF && * (HEAD detached at $(git rev-parse --short HEAD^0)) diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index 3e73f7584c..42f147858d 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -59,6 +59,14 @@ test_expect_success 'rebase against master' ' git rebase master ' +test_expect_success 'rebase sets ORIG_HEAD to pre-rebase state' ' + git checkout -b orig-head topic && + pre="$(git rev-parse --verify HEAD)" && + git rebase master && + test_cmp_rev "$pre" ORIG_HEAD && + ! test_cmp_rev "$pre" HEAD +' + test_expect_success 'rebase, with <onto> and <upstream> specified as :/quuxery' ' test_when_finished "git branch -D torebase" && git checkout -b torebase my-topic-branch^ && @@ -311,4 +319,20 @@ test_expect_success 'rebase--merge.sh and --show-current-patch' ' ) ' +test_expect_success 'rebase -c rebase.useBuiltin=false warning' ' + expected="rebase.useBuiltin support has been removed" && + + # Only warn when the legacy rebase is requested... + test_must_fail git -c rebase.useBuiltin=false rebase 2>err && + test_i18ngrep "$expected" err && + test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=false git rebase 2>err && + test_i18ngrep "$expected" err && + + # ...not when we would have used the built-in anyway + test_must_fail git -c rebase.useBuiltin=true rebase 2>err && + test_must_be_empty err && + test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true git rebase 2>err && + test_must_be_empty err +' + test_done diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index b60b11f9f2..1723e1a858 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -149,12 +149,10 @@ test_expect_success 'rebase -i with the exec command checks tree cleanness' ' test_expect_success 'rebase -x with empty command fails' ' test_when_finished "git rebase --abort ||:" && - test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \ - git rebase -x "" @ 2>actual && + test_must_fail env git rebase -x "" @ 2>actual && test_write_lines "error: empty exec command" >expected && test_i18ncmp expected actual && - test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \ - git rebase -x " " @ 2>actual && + test_must_fail env git rebase -x " " @ 2>actual && test_i18ncmp expected actual ' @@ -162,8 +160,7 @@ LF=' ' test_expect_success 'rebase -x with newline in command fails' ' test_when_finished "git rebase --abort ||:" && - test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true \ - git rebase -x "a${LF}b" @ 2>actual && + test_must_fail env git rebase -x "a${LF}b" @ 2>actual && test_write_lines "error: exec commands cannot contain newlines" \ >expected && test_i18ncmp expected actual diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh index 13f5688135..22d218698e 100755 --- a/t/t3415-rebase-autosquash.sh +++ b/t/t3415-rebase-autosquash.sh @@ -277,7 +277,7 @@ test_expect_success 'autosquash with empty custom instructionFormat' ' ( set_cat_todo_editor && test_must_fail git -c rebase.instructionFormat= \ - rebase --autosquash --force -i HEAD^ >actual && + rebase --autosquash --force-rebase -i HEAD^ >actual && git log -1 --format="pick %h %s" >expect && test_cmp expect actual ) diff --git a/t/t3429-rebase-edit-todo.sh b/t/t3429-rebase-edit-todo.sh index b9292dfc2a..76f6d306ea 100755 --- a/t/t3429-rebase-edit-todo.sh +++ b/t/t3429-rebase-edit-todo.sh @@ -11,4 +11,26 @@ test_expect_success 'rebase exec modifies rebase-todo' ' test -e F ' +test_expect_success SHA1 'loose object cache vs re-reading todo list' ' + GIT_REBASE_TODO=.git/rebase-merge/git-rebase-todo && + export GIT_REBASE_TODO && + write_script append-todo.sh <<-\EOS && + # For values 5 and 6, this yields SHA-1s with the same first two digits + echo "pick $(git rev-parse --short \ + $(printf "%s\\n" \ + "tree $EMPTY_TREE" \ + "author A U Thor <author@example.org> $1 +0000" \ + "committer A U Thor <author@example.org> $1 +0000" \ + "" \ + "$1" | + git hash-object -t commit -w --stdin))" >>$GIT_REBASE_TODO + + shift + test -z "$*" || + echo "exec $0 $*" >>$GIT_REBASE_TODO + EOS + + git rebase HEAD -x "./append-todo.sh 5 6" +' + test_done diff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh index 4c69255ee6..42ba5b9f09 100755 --- a/t/t3430-rebase-merges.sh +++ b/t/t3430-rebase-merges.sh @@ -271,7 +271,7 @@ test_expect_success 'root commits' ' EOF test_config sequence.editor \""$PWD"/replace-editor.sh\" && test_tick && - git rebase -i --force --root -r && + git rebase -i --force-rebase --root -r && test "Parsnip" = "$(git show -s --format=%an HEAD^)" && test $(git rev-parse second-root^0) != $(git rev-parse HEAD^) && test $(git rev-parse second-root:second-root.t) = \ @@ -364,7 +364,7 @@ test_expect_success 'octopus merges' ' test_cmp_rev HEAD $before && test_tick && - git rebase -i --force -r HEAD^^ && + git rebase -i --force-rebase -r HEAD^^ && test "Hank" = "$(git show -s --format=%an HEAD)" && test "$before" != $(git rev-parse HEAD) && test_cmp_graph HEAD^^.. <<-\EOF diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh index 0db166152a..1ef8e9d534 100755 --- a/t/t3507-cherry-pick-conflict.sh +++ b/t/t3507-cherry-pick-conflict.sh @@ -25,6 +25,11 @@ test_expect_success setup ' test_commit base foo b && test_commit picked foo c && test_commit --signoff picked-signed foo d && + git checkout -b topic initial && + test_commit redundant-pick foo c redundant && + git commit --allow-empty --allow-empty-message && + git tag empty && + git checkout master && git config advice.detachedhead false ' @@ -405,4 +410,23 @@ test_expect_success 'cherry-pick preserves sparse-checkout' ' test_i18ngrep ! "Changes not staged for commit:" actual ' +test_expect_success 'cherry-pick --continue remembers --keep-redundant-commits' ' + test_when_finished "git cherry-pick --abort || :" && + pristine_detach initial && + test_must_fail git cherry-pick --keep-redundant-commits picked redundant && + echo c >foo && + git add foo && + git cherry-pick --continue +' + +test_expect_success 'cherry-pick --continue remembers --allow-empty and --allow-empty-message' ' + test_when_finished "git cherry-pick --abort || :" && + pristine_detach initial && + test_must_fail git cherry-pick --allow-empty --allow-empty-message \ + picked empty && + echo c >foo && + git add foo && + git cherry-pick --continue +' + test_done diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index 04e5d42bd3..85ae7dc1e4 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -8,91 +8,92 @@ test_description='Test of the various options to git rm.' . ./test-lib.sh # Setup some files to be removed, some with funny characters -test_expect_success \ - 'Initialize test directory' \ - "touch -- foo bar baz 'space embedded' -q && - git add -- foo bar baz 'space embedded' -q && - git commit -m 'add normal files'" +test_expect_success 'Initialize test directory' ' + touch -- foo bar baz "space embedded" -q && + git add -- foo bar baz "space embedded" -q && + git commit -m "add normal files" +' -if test_have_prereq !FUNNYNAMES; then +if test_have_prereq !FUNNYNAMES +then say 'Your filesystem does not allow tabs in filenames.' fi -test_expect_success FUNNYNAMES 'add files with funny names' " - touch -- 'tab embedded' 'newline -embedded' && - git add -- 'tab embedded' 'newline -embedded' && - git commit -m 'add files with tabs and newlines' -" - -test_expect_success \ - 'Pre-check that foo exists and is in index before git rm foo' \ - '[ -f foo ] && git ls-files --error-unmatch foo' - -test_expect_success \ - 'Test that git rm foo succeeds' \ - 'git rm --cached foo' - -test_expect_success \ - 'Test that git rm --cached foo succeeds if the index matches the file' \ - 'echo content >foo && - git add foo && - git rm --cached foo' - -test_expect_success \ - 'Test that git rm --cached foo succeeds if the index matches the file' \ - 'echo content >foo && - git add foo && - git commit -m foo && - echo "other content" >foo && - git rm --cached foo' - -test_expect_success \ - 'Test that git rm --cached foo fails if the index matches neither the file nor HEAD' ' - echo content >foo && - git add foo && - git commit -m foo --allow-empty && - echo "other content" >foo && - git add foo && - echo "yet another content" >foo && - test_must_fail git rm --cached foo -' - -test_expect_success \ - 'Test that git rm --cached -f foo works in case where --cached only did not' \ - 'echo content >foo && - git add foo && - git commit -m foo --allow-empty && - echo "other content" >foo && - git add foo && - echo "yet another content" >foo && - git rm --cached -f foo' - -test_expect_success \ - 'Post-check that foo exists but is not in index after git rm foo' \ - '[ -f foo ] && test_must_fail git ls-files --error-unmatch foo' - -test_expect_success \ - 'Pre-check that bar exists and is in index before "git rm bar"' \ - '[ -f bar ] && git ls-files --error-unmatch bar' - -test_expect_success \ - 'Test that "git rm bar" succeeds' \ - 'git rm bar' - -test_expect_success \ - 'Post-check that bar does not exist and is not in index after "git rm -f bar"' \ - '! [ -f bar ] && test_must_fail git ls-files --error-unmatch bar' - -test_expect_success \ - 'Test that "git rm -- -q" succeeds (remove a file that looks like an option)' \ - 'git rm -- -q' - -test_expect_success FUNNYNAMES \ - "Test that \"git rm -f\" succeeds with embedded space, tab, or newline characters." \ - "git rm -f 'space embedded' 'tab embedded' 'newline -embedded'" +test_expect_success FUNNYNAMES 'add files with funny names' ' + touch -- "tab embedded" "newline${LF}embedded" && + git add -- "tab embedded" "newline${LF}embedded" && + git commit -m "add files with tabs and newlines" +' + +test_expect_success 'Pre-check that foo exists and is in index before git rm foo' ' + test_path_is_file foo && + git ls-files --error-unmatch foo +' + +test_expect_success 'Test that git rm foo succeeds' ' + git rm --cached foo +' + +test_expect_success 'Test that git rm --cached foo succeeds if the index matches the file' ' + echo content >foo && + git add foo && + git rm --cached foo +' + +test_expect_success 'Test that git rm --cached foo succeeds if the index matches the file' ' + echo content >foo && + git add foo && + git commit -m foo && + echo "other content" >foo && + git rm --cached foo +' + +test_expect_success 'Test that git rm --cached foo fails if the index matches neither the file nor HEAD' ' + echo content >foo && + git add foo && + git commit -m foo --allow-empty && + echo "other content" >foo && + git add foo && + echo "yet another content" >foo && + test_must_fail git rm --cached foo +' + +test_expect_success 'Test that git rm --cached -f foo works in case where --cached only did not' ' + echo content >foo && + git add foo && + git commit -m foo --allow-empty && + echo "other content" >foo && + git add foo && + echo "yet another content" >foo && + git rm --cached -f foo +' + +test_expect_success 'Post-check that foo exists but is not in index after git rm foo' ' + test_path_is_file foo && + test_must_fail git ls-files --error-unmatch foo +' + +test_expect_success 'Pre-check that bar exists and is in index before "git rm bar"' ' + test_path_is_file bar && + git ls-files --error-unmatch bar +' + +test_expect_success 'Test that "git rm bar" succeeds' ' + git rm bar +' + +test_expect_success 'Post-check that bar does not exist and is not in index after "git rm -f bar"' ' + test_path_is_missing bar && + test_must_fail git ls-files --error-unmatch bar +' + +test_expect_success 'Test that "git rm -- -q" succeeds (remove a file that looks like an option)' ' + git rm -- -q +' + +test_expect_success FUNNYNAMES 'Test that "git rm -f" succeeds with embedded space, tab, or newline characters.' ' + git rm -f "space embedded" "tab embedded" "newline${LF}embedded" +' test_expect_success SANITY 'Test that "git rm -f" fails if its rm fails' ' test_when_finished "chmod 775 ." && @@ -100,9 +101,9 @@ test_expect_success SANITY 'Test that "git rm -f" fails if its rm fails' ' test_must_fail git rm -f baz ' -test_expect_success \ - 'When the rm in "git rm -f" fails, it should not remove the file from the index' \ - 'git ls-files --error-unmatch baz' +test_expect_success 'When the rm in "git rm -f" fails, it should not remove the file from the index' ' + git ls-files --error-unmatch baz +' test_expect_success 'Remove nonexistent file with --ignore-unmatch' ' git rm --ignore-unmatch nonexistent @@ -137,15 +138,15 @@ test_expect_success 'Re-add foo and baz' ' test_expect_success 'Modify foo -- rm should refuse' ' echo >>foo && test_must_fail git rm foo baz && - test -f foo && - test -f baz && + test_path_is_file foo && + test_path_is_file baz && git ls-files --error-unmatch foo baz ' test_expect_success 'Modified foo -- rm -f should work' ' git rm -f foo baz && - test ! -f foo && - test ! -f baz && + test_path_is_missing foo && + test_path_is_missing baz && test_must_fail git ls-files --error-unmatch foo && test_must_fail git ls-files --error-unmatch bar ' @@ -159,15 +160,15 @@ test_expect_success 'Re-add foo and baz for HEAD tests' ' test_expect_success 'foo is different in index from HEAD -- rm should refuse' ' test_must_fail git rm foo baz && - test -f foo && - test -f baz && + test_path_is_file foo && + test_path_is_file baz && git ls-files --error-unmatch foo baz ' test_expect_success 'but with -f it should work.' ' git rm -f foo baz && - test ! -f foo && - test ! -f baz && + test_path_is_missing foo && + test_path_is_missing baz && test_must_fail git ls-files --error-unmatch foo && test_must_fail git ls-files --error-unmatch baz ' @@ -194,21 +195,21 @@ test_expect_success 'Recursive test setup' ' test_expect_success 'Recursive without -r fails' ' test_must_fail git rm frotz && - test -d frotz && - test -f frotz/nitfol + test_path_is_dir frotz && + test_path_is_file frotz/nitfol ' test_expect_success 'Recursive with -r but dirty' ' echo qfwfq >>frotz/nitfol && test_must_fail git rm -r frotz && - test -d frotz && - test -f frotz/nitfol + test_path_is_dir frotz && + test_path_is_file frotz/nitfol ' test_expect_success 'Recursive with -r -f' ' git rm -f -r frotz && - ! test -f frotz/nitfol && - ! test -d frotz + test_path_is_missing frotz/nitfol && + test_path_is_missing frotz ' test_expect_success 'Remove nonexistent file returns nonzero exit status' ' @@ -217,23 +218,25 @@ test_expect_success 'Remove nonexistent file returns nonzero exit status' ' test_expect_success 'Call "rm" from outside the work tree' ' mkdir repo && - (cd repo && - git init && - echo something >somefile && - git add somefile && - git commit -m "add a file" && - (cd .. && - git --git-dir=repo/.git --work-tree=repo rm somefile) && - test_must_fail git ls-files --error-unmatch somefile) + ( + cd repo && + git init && + echo something >somefile && + git add somefile && + git commit -m "add a file" && + ( + cd .. && + git --git-dir=repo/.git --work-tree=repo rm somefile + ) && + test_must_fail git ls-files --error-unmatch somefile + ) ' test_expect_success 'refresh index before checking if it is up-to-date' ' - git reset --hard && test-tool chmtime -86400 frotz/nitfol && git rm frotz/nitfol && - test ! -f frotz/nitfol - + test_path_is_missing frotz/nitfol ' test_expect_success 'choking "git rm" should not let it die with cruft' ' @@ -242,8 +245,8 @@ test_expect_success 'choking "git rm" should not let it die with cruft' ' i=0 && while test $i -lt 12000 do - echo "100644 1234567890123456789012345678901234567890 0 some-file-$i" - i=$(( $i + 1 )) + echo "100644 1234567890123456789012345678901234567890 0 some-file-$i" + i=$(( $i + 1 )) done | git update-index --index-info && git rm -n "some-file-*" | : && test_path_is_missing .git/index.lock @@ -254,7 +257,7 @@ test_expect_success 'rm removes subdirectories recursively' ' echo content >dir/subdir/subsubdir/file && git add dir/subdir/subsubdir/file && git rm -f dir/subdir/subsubdir/file && - ! test -d dir + test_path_is_missing dir ' cat >expect <<EOF @@ -292,7 +295,7 @@ test_expect_success 'rm removes empty submodules from work tree' ' git add .gitmodules && git commit -m "add submodule" && git rm submod && - test ! -e submod && + test_path_is_missing submod && git status -s -uno --ignore-submodules=none >actual && test_cmp expect actual && test_must_fail git config -f .gitmodules submodule.sub.url && @@ -314,7 +317,7 @@ test_expect_success 'rm removes work tree of unmodified submodules' ' git reset --hard && git submodule update && git rm submod && - test ! -d submod && + test_path_is_missing submod && git status -s -uno --ignore-submodules=none >actual && test_cmp expect actual && test_must_fail git config -f .gitmodules submodule.sub.url && @@ -325,7 +328,7 @@ test_expect_success 'rm removes a submodule with a trailing /' ' git reset --hard && git submodule update && git rm submod/ && - test ! -d submod && + test_path_is_missing submod && git status -s -uno --ignore-submodules=none >actual && test_cmp expect actual ' @@ -343,12 +346,12 @@ test_expect_success 'rm of a populated submodule with different HEAD fails unles git submodule update && git -C submod checkout HEAD^ && test_must_fail git rm submod && - test -d submod && - test -f submod/.git && + test_path_is_dir submod && + test_path_is_file submod/.git && git status -s -uno --ignore-submodules=none >actual && test_cmp expect.modified actual && git rm -f submod && - test ! -d submod && + test_path_is_missing submod && git status -s -uno --ignore-submodules=none >actual && test_cmp expect actual && test_must_fail git config -f .gitmodules submodule.sub.url && @@ -359,8 +362,8 @@ test_expect_success 'rm --cached leaves work tree of populated submodules and .g git reset --hard && git submodule update && git rm --cached submod && - test -d submod && - test -f submod/.git && + test_path_is_dir submod && + test_path_is_file submod/.git && git status -s -uno >actual && test_cmp expect.cached actual && git config -f .gitmodules submodule.sub.url && @@ -371,7 +374,7 @@ test_expect_success 'rm --dry-run does not touch the submodule or .gitmodules' ' git reset --hard && git submodule update && git rm -n submod && - test -f submod/.git && + test_path_is_file submod/.git && git diff-index --exit-code HEAD ' @@ -381,8 +384,8 @@ test_expect_success 'rm does not complain when no .gitmodules file is found' ' git rm .gitmodules && git rm submod >actual 2>actual.err && test_must_be_empty actual.err && - ! test -d submod && - ! test -f submod/.git && + test_path_is_missing submod && + test_path_is_missing submod/.git && git status -s -uno >actual && test_cmp expect.both_deleted actual ' @@ -392,15 +395,15 @@ test_expect_success 'rm will error out on a modified .gitmodules file unless sta git submodule update && git config -f .gitmodules foo.bar true && test_must_fail git rm submod >actual 2>actual.err && - test -s actual.err && - test -d submod && - test -f submod/.git && + test_file_not_empty actual.err && + test_path_is_dir submod && + test_path_is_file submod/.git && git diff-files --quiet -- submod && git add .gitmodules && git rm submod >actual 2>actual.err && test_must_be_empty actual.err && - ! test -d submod && - ! test -f submod/.git && + test_path_is_missing submod && + test_path_is_missing submod/.git && git status -s -uno >actual && test_cmp expect actual ' @@ -413,8 +416,8 @@ test_expect_success 'rm issues a warning when section is not found in .gitmodule echo "warning: Could not find section in .gitmodules where path=submod" >expect.err && git rm submod >actual 2>actual.err && test_i18ncmp expect.err actual.err && - ! test -d submod && - ! test -f submod/.git && + test_path_is_missing submod && + test_path_is_missing submod/.git && git status -s -uno >actual && test_cmp expect actual ' @@ -424,12 +427,12 @@ test_expect_success 'rm of a populated submodule with modifications fails unless git submodule update && echo X >submod/empty && test_must_fail git rm submod && - test -d submod && - test -f submod/.git && + test_path_is_dir submod && + test_path_is_file submod/.git && git status -s -uno --ignore-submodules=none >actual && test_cmp expect.modified_inside actual && git rm -f submod && - test ! -d submod && + test_path_is_missing submod && git status -s -uno --ignore-submodules=none >actual && test_cmp expect actual ' @@ -439,12 +442,12 @@ test_expect_success 'rm of a populated submodule with untracked files fails unle git submodule update && echo X >submod/untracked && test_must_fail git rm submod && - test -d submod && - test -f submod/.git && + test_path_is_dir submod && + test_path_is_file submod/.git && git status -s -uno --ignore-submodules=none >actual && test_cmp expect.modified_untracked actual && git rm -f submod && - test ! -d submod && + test_path_is_missing submod && git status -s -uno --ignore-submodules=none >actual && test_cmp expect actual ' @@ -481,7 +484,7 @@ test_expect_success 'rm removes work tree of unmodified conflicted submodule' ' git submodule update && test_must_fail git merge conflict2 && git rm submod && - test ! -d submod && + test_path_is_missing submod && git status -s -uno --ignore-submodules=none >actual && test_cmp expect actual ' @@ -493,12 +496,12 @@ test_expect_success 'rm of a conflicted populated submodule with different HEAD git -C submod checkout HEAD^ && test_must_fail git merge conflict2 && test_must_fail git rm submod && - test -d submod && - test -f submod/.git && + test_path_is_dir submod && + test_path_is_file submod/.git && git status -s -uno --ignore-submodules=none >actual && test_cmp expect.conflict actual && git rm -f submod && - test ! -d submod && + test_path_is_missing submod && git status -s -uno --ignore-submodules=none >actual && test_cmp expect actual && test_must_fail git config -f .gitmodules submodule.sub.url && @@ -512,12 +515,12 @@ test_expect_success 'rm of a conflicted populated submodule with modifications f echo X >submod/empty && test_must_fail git merge conflict2 && test_must_fail git rm submod && - test -d submod && - test -f submod/.git && + test_path_is_dir submod && + test_path_is_file submod/.git && git status -s -uno --ignore-submodules=none >actual && test_cmp expect.conflict actual && git rm -f submod && - test ! -d submod && + test_path_is_missing submod && git status -s -uno --ignore-submodules=none >actual && test_cmp expect actual && test_must_fail git config -f .gitmodules submodule.sub.url && @@ -531,12 +534,12 @@ test_expect_success 'rm of a conflicted populated submodule with untracked files echo X >submod/untracked && test_must_fail git merge conflict2 && test_must_fail git rm submod && - test -d submod && - test -f submod/.git && + test_path_is_dir submod && + test_path_is_file submod/.git && git status -s -uno --ignore-submodules=none >actual && test_cmp expect.conflict actual && git rm -f submod && - test ! -d submod && + test_path_is_missing submod && git status -s -uno --ignore-submodules=none >actual && test_cmp expect actual ' @@ -545,20 +548,21 @@ test_expect_success 'rm of a conflicted populated submodule with a .git director git checkout conflict1 && git reset --hard && git submodule update && - (cd submod && + ( + cd submod && rm .git && cp -R ../.git/modules/sub .git && GIT_WORK_TREE=. git config --unset core.worktree ) && test_must_fail git merge conflict2 && test_must_fail git rm submod && - test -d submod && - test -d submod/.git && + test_path_is_dir submod && + test_path_is_dir submod/.git && git status -s -uno --ignore-submodules=none >actual && test_cmp expect.conflict actual && test_must_fail git rm -f submod && - test -d submod && - test -d submod/.git && + test_path_is_dir submod && + test_path_is_dir submod/.git && git status -s -uno --ignore-submodules=none >actual && test_cmp expect.conflict actual && git merge --abort && @@ -570,7 +574,7 @@ test_expect_success 'rm of a conflicted unpopulated submodule succeeds' ' git reset --hard && test_must_fail git merge conflict2 && git rm submod && - test ! -d submod && + test_path_is_missing submod && git status -s -uno --ignore-submodules=none >actual && test_cmp expect actual ' @@ -579,17 +583,18 @@ test_expect_success 'rm of a populated submodule with a .git directory migrates git checkout -f master && git reset --hard && git submodule update && - (cd submod && + ( + cd submod && rm .git && cp -R ../.git/modules/sub .git && GIT_WORK_TREE=. git config --unset core.worktree && rm -r ../.git/modules/sub ) && git rm submod 2>output.err && - ! test -d submod && - ! test -d submod/.git && + test_path_is_missing submod && + test_path_is_missing submod/.git && git status -s -uno --ignore-submodules=none >actual && - test -s actual && + test_file_not_empty actual && test_i18ngrep Migrating output.err ' @@ -600,7 +605,8 @@ EOF test_expect_success 'setup subsubmodule' ' git reset --hard && git submodule update && - (cd submod && + ( + cd submod && git update-index --add --cacheinfo 160000 $(git rev-parse HEAD) subsubmod && git config -f .gitmodules submodule.sub.url ../. && git config -f .gitmodules submodule.sub.path subsubmod && @@ -614,7 +620,7 @@ test_expect_success 'setup subsubmodule' ' test_expect_success 'rm recursively removes work tree of unmodified submodules' ' git rm submod && - test ! -d submod && + test_path_is_missing submod && git status -s -uno --ignore-submodules=none >actual && test_cmp expect actual ' @@ -624,12 +630,12 @@ test_expect_success 'rm of a populated nested submodule with different nested HE git submodule update --recursive && git -C submod/subsubmod checkout HEAD^ && test_must_fail git rm submod && - test -d submod && - test -f submod/.git && + test_path_is_dir submod && + test_path_is_file submod/.git && git status -s -uno --ignore-submodules=none >actual && test_cmp expect.modified_inside actual && git rm -f submod && - test ! -d submod && + test_path_is_missing submod && git status -s -uno --ignore-submodules=none >actual && test_cmp expect actual ' @@ -639,12 +645,12 @@ test_expect_success 'rm of a populated nested submodule with nested modification git submodule update --recursive && echo X >submod/subsubmod/empty && test_must_fail git rm submod && - test -d submod && - test -f submod/.git && + test_path_is_dir submod && + test_path_is_file submod/.git && git status -s -uno --ignore-submodules=none >actual && test_cmp expect.modified_inside actual && git rm -f submod && - test ! -d submod && + test_path_is_missing submod && git status -s -uno --ignore-submodules=none >actual && test_cmp expect actual ' @@ -654,12 +660,12 @@ test_expect_success 'rm of a populated nested submodule with nested untracked fi git submodule update --recursive && echo X >submod/subsubmod/untracked && test_must_fail git rm submod && - test -d submod && - test -f submod/.git && + test_path_is_dir submod && + test_path_is_file submod/.git && git status -s -uno --ignore-submodules=none >actual && test_cmp expect.modified_untracked actual && git rm -f submod && - test ! -d submod && + test_path_is_missing submod && git status -s -uno --ignore-submodules=none >actual && test_cmp expect actual ' @@ -667,16 +673,17 @@ test_expect_success 'rm of a populated nested submodule with nested untracked fi test_expect_success "rm absorbs submodule's nested .git directory" ' git reset --hard && git submodule update --recursive && - (cd submod/subsubmod && + ( + cd submod/subsubmod && rm .git && mv ../../.git/modules/sub/modules/sub .git && GIT_WORK_TREE=. git config --unset core.worktree ) && git rm submod 2>output.err && - ! test -d submod && - ! test -d submod/subsubmod/.git && + test_path_is_missing submod && + test_path_is_missing submod/subsubmod/.git && git status -s -uno --ignore-submodules=none >actual && - test -s actual && + test_file_not_empty actual && test_i18ngrep Migrating output.err ' diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index 5f8272b6f9..ea30d5f6a0 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -8,22 +8,22 @@ test_description='Test git stash' . ./test-lib.sh test_expect_success 'stash some dirty working directory' ' - echo 1 > file && + echo 1 >file && git add file && echo unrelated >other-file && git add other-file && test_tick && git commit -m initial && - echo 2 > file && + echo 2 >file && git add file && - echo 3 > file && + echo 3 >file && test_tick && git stash && git diff-files --quiet && git diff-index --cached --quiet HEAD ' -cat > expect << EOF +cat >expect <<EOF diff --git a/file b/file index 0cfbf08..00750ed 100644 --- a/file @@ -35,7 +35,7 @@ EOF test_expect_success 'parents of stash' ' test $(git rev-parse stash^) = $(git rev-parse HEAD) && - git diff stash^2..stash > output && + git diff stash^2..stash >output && test_cmp expect output ' @@ -74,7 +74,7 @@ test_expect_success 'apply stashed changes' ' test_expect_success 'apply stashed changes (including index)' ' git reset --hard HEAD^ && - echo 6 > other-file && + echo 6 >other-file && git add other-file && test_tick && git commit -m other-file && @@ -99,12 +99,12 @@ test_expect_success 'stash drop complains of extra options' ' test_expect_success 'drop top stash' ' git reset --hard && - git stash list > stashlist1 && - echo 7 > file && + git stash list >expected && + echo 7 >file && git stash && git stash drop && - git stash list > stashlist2 && - test_cmp stashlist1 stashlist2 && + git stash list >actual && + test_cmp expected actual && git stash apply && test 3 = $(cat file) && test 1 = $(git show :file) && @@ -113,9 +113,9 @@ test_expect_success 'drop top stash' ' test_expect_success 'drop middle stash' ' git reset --hard && - echo 8 > file && + echo 8 >file && git stash && - echo 9 > file && + echo 9 >file && git stash && git stash drop stash@{1} && test 2 = $(git stash list | wc -l) && @@ -160,7 +160,7 @@ test_expect_success 'stash pop' ' test 0 = $(git stash list | wc -l) ' -cat > expect << EOF +cat >expect <<EOF diff --git a/file2 b/file2 new file mode 100644 index 0000000..1fe912c @@ -170,7 +170,7 @@ index 0000000..1fe912c +bar2 EOF -cat > expect1 << EOF +cat >expect1 <<EOF diff --git a/file b/file index 257cc56..5716ca5 100644 --- a/file @@ -180,7 +180,7 @@ index 257cc56..5716ca5 100644 +bar EOF -cat > expect2 << EOF +cat >expect2 <<EOF diff --git a/file b/file index 7601807..5716ca5 100644 --- a/file @@ -198,79 +198,79 @@ index 0000000..1fe912c EOF test_expect_success 'stash branch' ' - echo foo > file && + echo foo >file && git commit file -m first && - echo bar > file && - echo bar2 > file2 && + echo bar >file && + echo bar2 >file2 && git add file2 && git stash && - echo baz > file && + echo baz >file && git commit file -m second && git stash branch stashbranch && test refs/heads/stashbranch = $(git symbolic-ref HEAD) && test $(git rev-parse HEAD) = $(git rev-parse master^) && - git diff --cached > output && + git diff --cached >output && test_cmp expect output && - git diff > output && + git diff >output && test_cmp expect1 output && git add file && git commit -m alternate\ second && - git diff master..stashbranch > output && + git diff master..stashbranch >output && test_cmp output expect2 && test 0 = $(git stash list | wc -l) ' test_expect_success 'apply -q is quiet' ' - echo foo > file && + echo foo >file && git stash && - git stash apply -q > output.out 2>&1 && + git stash apply -q >output.out 2>&1 && test_must_be_empty output.out ' test_expect_success 'save -q is quiet' ' - git stash save --quiet > output.out 2>&1 && + git stash save --quiet >output.out 2>&1 && test_must_be_empty output.out ' test_expect_success 'pop -q is quiet' ' - git stash pop -q > output.out 2>&1 && + git stash pop -q >output.out 2>&1 && test_must_be_empty output.out ' test_expect_success 'pop -q --index works and is quiet' ' - echo foo > file && + echo foo >file && git add file && git stash save --quiet && - git stash pop -q --index > output.out 2>&1 && + git stash pop -q --index >output.out 2>&1 && test foo = "$(git show :file)" && test_must_be_empty output.out ' test_expect_success 'drop -q is quiet' ' git stash && - git stash drop -q > output.out 2>&1 && + git stash drop -q >output.out 2>&1 && test_must_be_empty output.out ' test_expect_success 'stash -k' ' - echo bar3 > file && - echo bar4 > file2 && + echo bar3 >file && + echo bar4 >file2 && git add file2 && git stash -k && test bar,bar4 = $(cat file),$(cat file2) ' test_expect_success 'stash --no-keep-index' ' - echo bar33 > file && - echo bar44 > file2 && + echo bar33 >file && + echo bar44 >file2 && git add file2 && git stash --no-keep-index && test bar,bar2 = $(cat file),$(cat file2) ' test_expect_success 'stash --invalid-option' ' - echo bar5 > file && - echo bar6 > file2 && + echo bar5 >file && + echo bar6 >file2 && git add file2 && test_must_fail git stash --invalid-option && test_must_fail git stash save --invalid-option && @@ -287,6 +287,14 @@ test_expect_success 'stash an added file' ' test new = "$(cat file3)" ' +test_expect_success 'stash --intent-to-add file' ' + git reset --hard && + echo new >file4 && + git add --intent-to-add file4 && + test_when_finished "git rm -f file4" && + test_must_fail git stash +' + test_expect_success 'stash rm then recreate' ' git reset --hard && git rm file && @@ -444,6 +452,36 @@ test_expect_failure 'stash file to directory' ' test foo = "$(cat file/file)" ' +test_expect_success 'giving too many ref arguments does not modify files' ' + git stash clear && + test_when_finished "git reset --hard HEAD" && + echo foo >file2 && + git stash && + echo bar >file2 && + git stash && + test-tool chmtime =123456789 file2 && + for type in apply pop "branch stash-branch" + do + test_must_fail git stash $type stash@{0} stash@{1} 2>err && + test_i18ngrep "Too many revisions" err && + test 123456789 = $(test-tool chmtime -g file2) || return 1 + done +' + +test_expect_success 'drop: too many arguments errors out (does nothing)' ' + git stash list >expect && + test_must_fail git stash drop stash@{0} stash@{1} 2>err && + test_i18ngrep "Too many revisions" err && + git stash list >actual && + test_cmp expect actual +' + +test_expect_success 'show: too many arguments errors out (does nothing)' ' + test_must_fail git stash show stash@{0} stash@{1} 2>err 1>out && + test_i18ngrep "Too many revisions" err && + test_must_be_empty out +' + test_expect_success 'stash create - no changes' ' git stash clear && test_when_finished "git reset --hard HEAD" && @@ -456,11 +494,12 @@ test_expect_success 'stash branch - no stashes on stack, stash-like argument' ' git stash clear && test_when_finished "git reset --hard HEAD" && git reset --hard && - echo foo >> file && + echo foo >>file && STASH_ID=$(git stash create) && git reset --hard && git stash branch stash-branch ${STASH_ID} && - test_when_finished "git reset --hard HEAD && git checkout master && git branch -D stash-branch" && + test_when_finished "git reset --hard HEAD && git checkout master && + git branch -D stash-branch" && test $(git ls-files --modified | wc -l) -eq 1 ' @@ -468,25 +507,31 @@ test_expect_success 'stash branch - stashes on stack, stash-like argument' ' git stash clear && test_when_finished "git reset --hard HEAD" && git reset --hard && - echo foo >> file && + echo foo >>file && git stash && test_when_finished "git stash drop" && - echo bar >> file && + echo bar >>file && STASH_ID=$(git stash create) && git reset --hard && git stash branch stash-branch ${STASH_ID} && - test_when_finished "git reset --hard HEAD && git checkout master && git branch -D stash-branch" && + test_when_finished "git reset --hard HEAD && git checkout master && + git branch -D stash-branch" && test $(git ls-files --modified | wc -l) -eq 1 ' +test_expect_success 'stash branch complains with no arguments' ' + test_must_fail git stash branch 2>err && + test_i18ngrep "No branch name specified" err +' + test_expect_success 'stash show format defaults to --stat' ' git stash clear && test_when_finished "git reset --hard HEAD" && git reset --hard && - echo foo >> file && + echo foo >>file && git stash && test_when_finished "git stash drop" && - echo bar >> file && + echo bar >>file && STASH_ID=$(git stash create) && git reset --hard && cat >expected <<-EOF && @@ -501,10 +546,10 @@ test_expect_success 'stash show - stashes on stack, stash-like argument' ' git stash clear && test_when_finished "git reset --hard HEAD" && git reset --hard && - echo foo >> file && + echo foo >>file && git stash && test_when_finished "git stash drop" && - echo bar >> file && + echo bar >>file && STASH_ID=$(git stash create) && git reset --hard && echo "1 0 file" >expected && @@ -516,10 +561,10 @@ test_expect_success 'stash show -p - stashes on stack, stash-like argument' ' git stash clear && test_when_finished "git reset --hard HEAD" && git reset --hard && - echo foo >> file && + echo foo >>file && git stash && test_when_finished "git stash drop" && - echo bar >> file && + echo bar >>file && STASH_ID=$(git stash create) && git reset --hard && cat >expected <<-EOF && @@ -539,7 +584,7 @@ test_expect_success 'stash show - no stashes on stack, stash-like argument' ' git stash clear && test_when_finished "git reset --hard HEAD" && git reset --hard && - echo foo >> file && + echo foo >>file && STASH_ID=$(git stash create) && git reset --hard && echo "1 0 file" >expected && @@ -551,7 +596,7 @@ test_expect_success 'stash show -p - no stashes on stack, stash-like argument' ' git stash clear && test_when_finished "git reset --hard HEAD" && git reset --hard && - echo foo >> file && + echo foo >>file && STASH_ID=$(git stash create) && git reset --hard && cat >expected <<-EOF && @@ -567,13 +612,31 @@ test_expect_success 'stash show -p - no stashes on stack, stash-like argument' ' test_cmp expected actual ' -test_expect_success 'stash drop - fail early if specified stash is not a stash reference' ' +test_expect_success 'stash show --patience shows diff' ' + git reset --hard && + echo foo >>file && + STASH_ID=$(git stash create) && + git reset --hard && + cat >expected <<-EOF && + diff --git a/file b/file + index 7601807..71b52c4 100644 + --- a/file + +++ b/file + @@ -1 +1,2 @@ + baz + +foo + EOF + git stash show --patience ${STASH_ID} >actual && + test_cmp expected actual +' + +test_expect_success 'drop: fail early if specified stash is not a stash ref' ' git stash clear && test_when_finished "git reset --hard HEAD && git stash clear" && git reset --hard && - echo foo > file && + echo foo >file && git stash && - echo bar > file && + echo bar >file && git stash && test_must_fail git stash drop $(git rev-parse stash@{0}) && git stash pop && @@ -581,13 +644,13 @@ test_expect_success 'stash drop - fail early if specified stash is not a stash r git reset --hard HEAD ' -test_expect_success 'stash pop - fail early if specified stash is not a stash reference' ' +test_expect_success 'pop: fail early if specified stash is not a stash ref' ' git stash clear && test_when_finished "git reset --hard HEAD && git stash clear" && git reset --hard && - echo foo > file && + echo foo >file && git stash && - echo bar > file && + echo bar >file && git stash && test_must_fail git stash pop $(git rev-parse stash@{0}) && git stash pop && @@ -597,8 +660,8 @@ test_expect_success 'stash pop - fail early if specified stash is not a stash re test_expect_success 'ref with non-existent reflog' ' git stash clear && - echo bar5 > file && - echo bar6 > file2 && + echo bar5 >file && + echo bar6 >file2 && git add file2 && git stash && test_must_fail git rev-parse --quiet --verify does-not-exist && @@ -618,8 +681,8 @@ test_expect_success 'ref with non-existent reflog' ' test_expect_success 'invalid ref of the form stash@{n}, n >= N' ' git stash clear && test_must_fail git stash drop stash@{0} && - echo bar5 > file && - echo bar6 > file2 && + echo bar5 >file && + echo bar6 >file2 && git add file2 && git stash && test_must_fail git stash drop stash@{1} && @@ -645,7 +708,7 @@ test_expect_success 'invalid ref of the form "n", n >= N' ' git stash drop ' -test_expect_success 'stash branch should not drop the stash if the branch exists' ' +test_expect_success 'branch: do not drop the stash if the branch exists' ' git stash clear && echo foo >file && git add file && @@ -656,7 +719,7 @@ test_expect_success 'stash branch should not drop the stash if the branch exists git rev-parse stash@{0} -- ' -test_expect_success 'stash branch should not drop the stash if the apply fails' ' +test_expect_success 'branch: should not drop the stash if the apply fails' ' git stash clear && git reset HEAD~1 --hard && echo foo >file && @@ -670,7 +733,7 @@ test_expect_success 'stash branch should not drop the stash if the apply fails' git rev-parse stash@{0} -- ' -test_expect_success 'stash apply shows status same as git status (relative to current directory)' ' +test_expect_success 'apply: show same status as git status (relative to ./)' ' git stash clear && echo 1 >subdir/subfile1 && echo 2 >subdir/subfile2 && @@ -689,7 +752,7 @@ test_expect_success 'stash apply shows status same as git status (relative to cu test_i18ncmp expect actual ' -cat > expect << EOF +cat >expect <<EOF diff --git a/HEAD b/HEAD new file mode 100644 index 0000000..fe0cbee @@ -702,14 +765,14 @@ EOF test_expect_success 'stash where working directory contains "HEAD" file' ' git stash clear && git reset --hard && - echo file-not-a-ref > HEAD && + echo file-not-a-ref >HEAD && git add HEAD && test_tick && git stash && git diff-files --quiet && git diff-index --cached --quiet HEAD && test "$(git rev-parse stash^)" = "$(git rev-parse HEAD)" && - git diff stash^..stash > output && + git diff stash^..stash >output && test_cmp expect output ' @@ -1011,7 +1074,7 @@ test_expect_success 'stash push -p with pathspec shows no changes only once' ' test_i18ncmp expect actual ' -test_expect_success 'stash push with pathspec shows no changes when there are none' ' +test_expect_success 'push <pathspec>: show no changes when there are none' ' >foo && git add foo && git commit -m "tmp" && @@ -1021,12 +1084,35 @@ test_expect_success 'stash push with pathspec shows no changes when there are no test_i18ncmp expect actual ' -test_expect_success 'stash push with pathspec not in the repository errors out' ' +test_expect_success 'push: <pathspec> not in the repository errors out' ' >untracked && test_must_fail git stash push untracked && test_path_is_file untracked ' +test_expect_success 'push: -q is quiet with changes' ' + >foo && + git add foo && + git stash push -q >output 2>&1 && + test_must_be_empty output +' + +test_expect_success 'push: -q is quiet with no changes' ' + git stash push -q >output 2>&1 && + test_must_be_empty output +' + +test_expect_success 'push: -q is quiet even if there is no initial commit' ' + git init foo_dir && + test_when_finished rm -rf foo_dir && + ( + cd foo_dir && + >bar && + test_must_fail git stash push -q >output 2>&1 && + test_must_be_empty output + ) +' + test_expect_success 'untracked files are left in place when -u is not given' ' >file && git add file && @@ -1096,6 +1182,12 @@ test_expect_success 'stash -- <subdir> works with binary files' ' test_path_is_file subdir/untracked ' +test_expect_success 'stash with user.name and user.email set works' ' + test_config user.name "A U Thor" && + test_config user.email "a.u@thor" && + git stash +' + test_expect_success 'stash works when user.name and user.email are not set' ' git reset && >1 && diff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh index cc1c8a7bb2..29ca76f2fb 100755 --- a/t/t3905-stash-include-untracked.sh +++ b/t/t3905-stash-include-untracked.sh @@ -283,4 +283,10 @@ test_expect_success 'stash -u -- <non-existant> shows no changes when there are test_i18ncmp expect actual ' +test_expect_success 'stash -u with globs' ' + >untracked.txt && + git stash -u -- ":(glob)**/*.txt" && + test_path_is_missing untracked.txt +' + test_done diff --git a/t/t3907-stash-show-config.sh b/t/t3907-stash-show-config.sh new file mode 100755 index 0000000000..10914bba7b --- /dev/null +++ b/t/t3907-stash-show-config.sh @@ -0,0 +1,83 @@ +#!/bin/sh + +test_description='Test git stash show configuration.' + +. ./test-lib.sh + +test_expect_success 'setup' ' + test_commit file +' + +# takes three parameters: +# 1. the stash.showStat value (or "<unset>") +# 2. the stash.showPatch value (or "<unset>") +# 3. the diff options of the expected output (or nothing for no output) +test_stat_and_patch () { + if test "<unset>" = "$1" + then + test_unconfig stash.showStat + else + test_config stash.showStat "$1" + fi && + + if test "<unset>" = "$2" + then + test_unconfig stash.showPatch + else + test_config stash.showPatch "$2" + fi && + + shift 2 && + echo 2 >file.t && + if test $# != 0 + then + git diff "$@" >expect + fi && + git stash && + git stash show >actual && + + if test $# = 0 + then + test_must_be_empty actual + else + test_cmp expect actual + fi +} + +test_expect_success 'showStat unset showPatch unset' ' + test_stat_and_patch "<unset>" "<unset>" --stat +' + +test_expect_success 'showStat unset showPatch false' ' + test_stat_and_patch "<unset>" false --stat +' + +test_expect_success 'showStat unset showPatch true' ' + test_stat_and_patch "<unset>" true --stat -p +' + +test_expect_success 'showStat false showPatch unset' ' + test_stat_and_patch false "<unset>" +' + +test_expect_success 'showStat false showPatch false' ' + test_stat_and_patch false false +' + +test_expect_success 'showStat false showPatch true' ' + test_stat_and_patch false true -p +' + +test_expect_success 'showStat true showPatch unset' ' + test_stat_and_patch true "<unset>" --stat +' + +test_expect_success 'showStat true showPatch false' ' + test_stat_and_patch true false --stat +' + +test_expect_success 'showStat true showPatch true' ' + test_stat_and_patch true true --stat -p +' + +test_done diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index 909c743c13..b6e2fdbc44 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -589,6 +589,12 @@ test_expect_success 'excessive subject' ' ls patches/0004-This-is-an-excessively-long-subject-line-for-a-messa.patch ' +test_expect_success 'failure to write cover-letter aborts gracefully' ' + test_when_finished "rmdir 0000-cover-letter.patch" && + mkdir 0000-cover-letter.patch && + test_must_fail git format-patch --no-renames --cover-letter -1 +' + test_expect_success 'cover-letter inherits diff options' ' git mv file foo && git commit -m foo && diff --git a/t/t4038-diff-combined.sh b/t/t4038-diff-combined.sh index e2824d3437..d4afe12554 100755 --- a/t/t4038-diff-combined.sh +++ b/t/t4038-diff-combined.sh @@ -435,4 +435,92 @@ test_expect_success 'combine diff gets tree sorting right' ' test_cmp expect actual ' +test_expect_success 'setup for --combined-all-paths' ' + git branch side1c && + git branch side2c && + git checkout side1c && + test_seq 1 10 >filename-side1c && + git add filename-side1c && + git commit -m with && + git checkout side2c && + test_seq 1 9 >filename-side2c && + echo ten >>filename-side2c && + git add filename-side2c && + git commit -m iam && + git checkout -b mergery side1c && + git merge --no-commit side2c && + git rm filename-side1c && + echo eleven >>filename-side2c && + git mv filename-side2c filename-merged && + git add filename-merged && + git commit +' + +test_expect_success '--combined-all-paths and --raw' ' + cat <<-\EOF >expect && + ::100644 100644 100644 f00c965d8307308469e537302baa73048488f162 088bd5d92c2a8e0203ca8e7e4c2a5c692f6ae3f7 333b9c62519f285e1854830ade0fe1ef1d40ee1b RR filename-side1c filename-side2c filename-merged + EOF + git diff-tree -c -M --raw --combined-all-paths HEAD >actual.tmp && + sed 1d <actual.tmp >actual && + test_cmp expect actual +' + +test_expect_success '--combined-all-paths and --cc' ' + cat <<-\EOF >expect && + --- a/filename-side1c + --- a/filename-side2c + +++ b/filename-merged + EOF + git diff-tree --cc -M --combined-all-paths HEAD >actual.tmp && + grep ^[-+][-+][-+] <actual.tmp >actual && + test_cmp expect actual +' + +test_expect_success FUNNYNAMES 'setup for --combined-all-paths with funny names' ' + git branch side1d && + git branch side2d && + git checkout side1d && + test_seq 1 10 >"$(printf "file\twith\ttabs")" && + git add file* && + git commit -m with && + git checkout side2d && + test_seq 1 9 >"$(printf "i\tam\ttabbed")" && + echo ten >>"$(printf "i\tam\ttabbed")" && + git add *tabbed && + git commit -m iam && + git checkout -b funny-names-mergery side1d && + git merge --no-commit side2d && + git rm *tabs && + echo eleven >>"$(printf "i\tam\ttabbed")" && + git mv "$(printf "i\tam\ttabbed")" "$(printf "fickle\tnaming")" && + git add fickle* && + git commit +' + +test_expect_success FUNNYNAMES '--combined-all-paths and --raw and funny names' ' + cat <<-\EOF >expect && + ::100644 100644 100644 f00c965d8307308469e537302baa73048488f162 088bd5d92c2a8e0203ca8e7e4c2a5c692f6ae3f7 333b9c62519f285e1854830ade0fe1ef1d40ee1b RR "file\twith\ttabs" "i\tam\ttabbed" "fickle\tnaming" + EOF + git diff-tree -c -M --raw --combined-all-paths HEAD >actual.tmp && + sed 1d <actual.tmp >actual && + test_cmp expect actual +' + +test_expect_success FUNNYNAMES '--combined-all-paths and --raw -and -z and funny names' ' + printf "aaf8087c3cbd4db8e185a2d074cf27c53cfb75d7\0::100644 100644 100644 f00c965d8307308469e537302baa73048488f162 088bd5d92c2a8e0203ca8e7e4c2a5c692f6ae3f7 333b9c62519f285e1854830ade0fe1ef1d40ee1b RR\0file\twith\ttabs\0i\tam\ttabbed\0fickle\tnaming\0" >expect && + git diff-tree -c -M --raw --combined-all-paths -z HEAD >actual && + test_cmp -a expect actual +' + +test_expect_success FUNNYNAMES '--combined-all-paths and --cc and funny names' ' + cat <<-\EOF >expect && + --- "a/file\twith\ttabs" + --- "a/i\tam\ttabbed" + +++ "b/fickle\tnaming" + EOF + git diff-tree --cc -M --combined-all-paths HEAD >actual.tmp && + grep ^[-+][-+][-+] <actual.tmp >actual && + test_cmp expect actual +' + test_done diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh index 6e0dd6f9e5..0168946b63 100755 --- a/t/t4053-diff-no-index.sh +++ b/t/t4053-diff-no-index.sh @@ -50,8 +50,7 @@ test_expect_success 'git diff --no-index executed outside repo gives correct err export GIT_CEILING_DIRECTORIES && cd non/git && test_must_fail git diff --no-index a 2>actual.err && - echo "usage: git diff --no-index <path> <path>" >expect.err && - test_cmp expect.err actual.err + test_i18ngrep "usage: git diff --no-index" actual.err ) ' @@ -137,4 +136,12 @@ test_expect_success 'diff --no-index from repo subdir with absolute paths' ' test_cmp expect actual ' +test_expect_success 'diff --no-index allows external diff' ' + test_expect_code 1 \ + env GIT_EXTERNAL_DIFF="echo external ;:" \ + git diff --no-index non/git/a non/git/b >actual && + echo external >expect && + test_cmp expect actual +' + test_done diff --git a/t/t4067-diff-partial-clone.sh b/t/t4067-diff-partial-clone.sh new file mode 100755 index 0000000000..90c8fb2901 --- /dev/null +++ b/t/t4067-diff-partial-clone.sh @@ -0,0 +1,103 @@ +#!/bin/sh + +test_description='behavior of diff when reading objects in a partial clone' + +. ./test-lib.sh + +test_expect_success 'git show batches blobs' ' + test_when_finished "rm -rf server client trace" && + + test_create_repo server && + echo a >server/a && + echo b >server/b && + git -C server add a b && + git -C server commit -m x && + + test_config -C server uploadpack.allowfilter 1 && + test_config -C server uploadpack.allowanysha1inwant 1 && + git clone --bare --filter=blob:limit=0 "file://$(pwd)/server" client && + + # Ensure that there is exactly 1 negotiation by checking that there is + # only 1 "done" line sent. ("done" marks the end of negotiation.) + GIT_TRACE_PACKET="$(pwd)/trace" git -C client show HEAD && + grep "git> done" trace >done_lines && + test_line_count = 1 done_lines +' + +test_expect_success 'diff batches blobs' ' + test_when_finished "rm -rf server client trace" && + + test_create_repo server && + echo a >server/a && + echo b >server/b && + git -C server add a b && + git -C server commit -m x && + echo c >server/c && + echo d >server/d && + git -C server add c d && + git -C server commit -m x && + + test_config -C server uploadpack.allowfilter 1 && + test_config -C server uploadpack.allowanysha1inwant 1 && + git clone --bare --filter=blob:limit=0 "file://$(pwd)/server" client && + + # Ensure that there is exactly 1 negotiation by checking that there is + # only 1 "done" line sent. ("done" marks the end of negotiation.) + GIT_TRACE_PACKET="$(pwd)/trace" git -C client diff HEAD^ HEAD && + grep "git> done" trace >done_lines && + test_line_count = 1 done_lines +' + +test_expect_success 'diff skips same-OID blobs' ' + test_when_finished "rm -rf server client trace" && + + test_create_repo server && + echo a >server/a && + echo b >server/b && + git -C server add a b && + git -C server commit -m x && + echo another-a >server/a && + git -C server add a && + git -C server commit -m x && + + test_config -C server uploadpack.allowfilter 1 && + test_config -C server uploadpack.allowanysha1inwant 1 && + git clone --bare --filter=blob:limit=0 "file://$(pwd)/server" client && + + echo a | git hash-object --stdin >hash-old-a && + echo another-a | git hash-object --stdin >hash-new-a && + echo b | git hash-object --stdin >hash-b && + + # Ensure that only a and another-a are fetched. + GIT_TRACE_PACKET="$(pwd)/trace" git -C client diff HEAD^ HEAD && + grep "want $(cat hash-old-a)" trace && + grep "want $(cat hash-new-a)" trace && + ! grep "want $(cat hash-b)" trace +' + +test_expect_success 'diff with rename detection batches blobs' ' + test_when_finished "rm -rf server client trace" && + + test_create_repo server && + echo a >server/a && + printf "b\nb\nb\nb\nb\n" >server/b && + git -C server add a b && + git -C server commit -m x && + rm server/b && + printf "b\nb\nb\nb\nbX\n" >server/c && + git -C server add c && + git -C server commit -a -m x && + + test_config -C server uploadpack.allowfilter 1 && + test_config -C server uploadpack.allowanysha1inwant 1 && + git clone --bare --filter=blob:limit=0 "file://$(pwd)/server" client && + + # Ensure that there is exactly 1 negotiation by checking that there is + # only 1 "done" line sent. ("done" marks the end of negotiation.) + GIT_TRACE_PACKET="$(pwd)/trace" git -C client diff -M HEAD^ HEAD >out && + grep "similarity index" out && + grep "git> done" trace >done_lines && + test_line_count = 1 done_lines +' + +test_done diff --git a/t/t4150-am.sh b/t/t4150-am.sh index 55b577d919..3f7f750cc8 100755 --- a/t/t4150-am.sh +++ b/t/t4150-am.sh @@ -77,14 +77,12 @@ test_expect_success 'setup: messages' ' printf "Subject: " >subject-prefix && - cat - subject-prefix msg-without-scissors-line >msg-with-scissors-line <<-\EOF && + cat - subject-prefix msg-without-scissors-line >msg-with-scissors-line <<-\EOF This line should not be included in the commit message with --scissors enabled. - - >8 - - remove everything above this line - - >8 - - EOF - - signoff="Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" ' test_expect_success setup ' diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh index 7df8c3d4ec..f42a69faa2 100755 --- a/t/t4205-log-pretty-formats.sh +++ b/t/t4205-log-pretty-formats.sh @@ -578,6 +578,24 @@ test_expect_success '%(trailers:only) shows only "key: value" trailers' ' test_cmp expect actual ' +test_expect_success '%(trailers:only=yes) shows only "key: value" trailers' ' + git log --no-walk --pretty=format:"%(trailers:only=yes)" >actual && + grep -v patch.description <trailers >expect && + test_cmp expect actual +' + +test_expect_success '%(trailers:only=no) shows all trailers' ' + git log --no-walk --pretty=format:"%(trailers:only=no)" >actual && + cat trailers >expect && + test_cmp expect actual +' + +test_expect_success '%(trailers:only=no,only=true) shows only "key: value" trailers' ' + git log --no-walk --pretty=format:"%(trailers:only=yes)" >actual && + grep -v patch.description <trailers >expect && + test_cmp expect actual +' + test_expect_success '%(trailers:unfold) unfolds trailers' ' git log --no-walk --pretty="%(trailers:unfold)" >actual && { @@ -598,6 +616,105 @@ test_expect_success ':only and :unfold work together' ' test_cmp expect actual ' +test_expect_success 'pretty format %(trailers:key=foo) shows that trailer' ' + git log --no-walk --pretty="format:%(trailers:key=Acked-by)" >actual && + echo "Acked-by: A U Thor <author@example.com>" >expect && + test_cmp expect actual +' + +test_expect_success 'pretty format %(trailers:key=foo) is case insensitive' ' + git log --no-walk --pretty="format:%(trailers:key=AcKed-bY)" >actual && + echo "Acked-by: A U Thor <author@example.com>" >expect && + test_cmp expect actual +' + +test_expect_success 'pretty format %(trailers:key=foo:) trailing colon also works' ' + git log --no-walk --pretty="format:%(trailers:key=Acked-by:)" >actual && + echo "Acked-by: A U Thor <author@example.com>" >expect && + test_cmp expect actual +' + +test_expect_success 'pretty format %(trailers:key=foo) multiple keys' ' + git log --no-walk --pretty="format:%(trailers:key=Acked-by:,key=Signed-off-By)" >actual && + grep -v patch.description <trailers >expect && + test_cmp expect actual +' + +test_expect_success '%(trailers:key=nonexistant) becomes empty' ' + git log --no-walk --pretty="x%(trailers:key=Nacked-by)x" >actual && + echo "xx" >expect && + test_cmp expect actual +' + +test_expect_success '%(trailers:key=foo) handles multiple lines even if folded' ' + git log --no-walk --pretty="format:%(trailers:key=Signed-Off-by)" >actual && + grep -v patch.description <trailers | grep -v Acked-by >expect && + test_cmp expect actual +' + +test_expect_success '%(trailers:key=foo,unfold) properly unfolds' ' + git log --no-walk --pretty="format:%(trailers:key=Signed-Off-by,unfold)" >actual && + unfold <trailers | grep Signed-off-by >expect && + test_cmp expect actual +' + +test_expect_success 'pretty format %(trailers:key=foo,only=no) also includes nontrailer lines' ' + git log --no-walk --pretty="format:%(trailers:key=Acked-by,only=no)" >actual && + { + echo "Acked-by: A U Thor <author@example.com>" && + grep patch.description <trailers + } >expect && + test_cmp expect actual +' + +test_expect_success '%(trailers:key) without value is error' ' + git log --no-walk --pretty="tformat:%(trailers:key)" >actual && + echo "%(trailers:key)" >expect && + test_cmp expect actual +' + +test_expect_success '%(trailers:key=foo,valueonly) shows only value' ' + git log --no-walk --pretty="format:%(trailers:key=Acked-by,valueonly)" >actual && + echo "A U Thor <author@example.com>" >expect && + test_cmp expect actual +' + +test_expect_success 'pretty format %(trailers:separator) changes separator' ' + git log --no-walk --pretty=format:"X%(trailers:separator=%x00,unfold)X" >actual && + printf "XSigned-off-by: A U Thor <author@example.com>\0Acked-by: A U Thor <author@example.com>\0[ v2 updated patch description ]\0Signed-off-by: A U Thor <author@example.com>X" >expect && + test_cmp expect actual +' + +test_expect_success 'pretty format %(trailers) combining separator/key/valueonly' ' + git commit --allow-empty -F - <<-\EOF && + Important fix + + The fix is explained here + + Closes: #1234 + EOF + + git commit --allow-empty -F - <<-\EOF && + Another fix + + The fix is explained here + + Closes: #567 + Closes: #890 + EOF + + git commit --allow-empty -F - <<-\EOF && + Does not close any tickets + EOF + + git log --pretty="%s% (trailers:separator=%x2c%x20,key=Closes,valueonly)" HEAD~3.. >actual && + test_write_lines \ + "Does not close any tickets" \ + "Another fix #567, #890" \ + "Important fix #1234" >expect && + test_cmp expect actual +' + test_expect_success 'trailer parsing not fooled by --- line' ' git commit --allow-empty -F - <<-\EOF && this is the subject diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh index bd5fe4d148..1db7bd0f59 100755 --- a/t/t4211-line-log.sh +++ b/t/t4211-line-log.sh @@ -115,4 +115,21 @@ test_expect_success 'range_set_union' ' git log $(for x in $(test_seq 200); do echo -L $((2*x)),+1:c.c; done) ' +test_expect_success '-s shows only line-log commits' ' + git log --format="commit %s" -L1,24:b.c >expect.raw && + grep ^commit expect.raw >expect && + git log --format="commit %s" -L1,24:b.c -s >actual && + test_cmp expect actual +' + +test_expect_success '-p shows the default patch output' ' + git log -L1,24:b.c >expect && + git log -L1,24:b.c -p >actual && + test_cmp expect actual +' + +test_expect_success '--raw is forbidden' ' + test_must_fail git log -L1,24:b.c --raw +' + test_done diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh index 270da21ac3..1eeb828a15 100755 --- a/t/t5304-prune.sh +++ b/t/t5304-prune.sh @@ -118,10 +118,10 @@ test_expect_success 'prune: do not prune detached HEAD with no reflog' ' test_expect_success 'prune: prune former HEAD after checking out branch' ' - head_sha1=$(git rev-parse HEAD) && + head_oid=$(git rev-parse HEAD) && git checkout --quiet master && git prune -v >prune_actual && - grep "$head_sha1" prune_actual + grep "$head_oid" prune_actual ' @@ -265,15 +265,27 @@ EOF ' test_expect_success 'prune .git/shallow' ' - SHA1=$(echo hi|git commit-tree HEAD^{tree}) && - echo $SHA1 >.git/shallow && + oid=$(echo hi|git commit-tree HEAD^{tree}) && + echo $oid >.git/shallow && git prune --dry-run >out && - grep $SHA1 .git/shallow && - grep $SHA1 out && + grep $oid .git/shallow && + grep $oid out && git prune && test_path_is_missing .git/shallow ' +test_expect_success 'prune .git/shallow when there are no loose objects' ' + oid=$(echo hi|git commit-tree HEAD^{tree}) && + echo $oid >.git/shallow && + git update-ref refs/heads/shallow-tip $oid && + git repack -ad && + # verify assumption that all loose objects are gone + git count-objects | grep ^0 && + git prune && + echo $oid >expect && + test_cmp expect .git/shallow +' + test_expect_success 'prune: handle alternate object database' ' test_create_repo A && git -C A commit --allow-empty -m "initial commit" && @@ -314,8 +326,8 @@ test_expect_success 'prune: handle HEAD reflog in multiple worktrees' ' git reset --hard HEAD^ ) && git prune --expire=now && - SHA1=`git hash-object expected` && - git -C third-worktree show "$SHA1" >actual && + oid=`git hash-object expected` && + git -C third-worktree show "$oid" >actual && test_cmp expected actual ' diff --git a/t/t5317-pack-objects-filter-objects.sh b/t/t5317-pack-objects-filter-objects.sh index 24541ea137..4c0201c34b 100755 --- a/t/t5317-pack-objects-filter-objects.sh +++ b/t/t5317-pack-objects-filter-objects.sh @@ -25,7 +25,7 @@ test_expect_success 'verify blob count in normal packfile' ' awk -f print_2.awk ls_files_result | sort >expected && - git -C r1 pack-objects --rev --stdout >all.pack <<-EOF && + git -C r1 pack-objects --revs --stdout >all.pack <<-EOF && HEAD EOF git -C r1 index-pack ../all.pack && @@ -39,7 +39,7 @@ test_expect_success 'verify blob count in normal packfile' ' ' test_expect_success 'verify blob:none packfile has no blobs' ' - git -C r1 pack-objects --rev --stdout --filter=blob:none >filter.pack <<-EOF && + git -C r1 pack-objects --revs --stdout --filter=blob:none >filter.pack <<-EOF && HEAD EOF git -C r1 index-pack ../filter.pack && @@ -74,7 +74,7 @@ test_expect_success 'get an error for missing tree object' ' git -C r5 commit -m "foo" && del=$(git -C r5 rev-parse HEAD^{tree} | sed "s|..|&/|") && rm r5/.git/objects/$del && - test_must_fail git -C r5 pack-objects --rev --stdout 2>bad_tree <<-EOF && + test_must_fail git -C r5 pack-objects --revs --stdout 2>bad_tree <<-EOF && HEAD EOF grep "bad tree object" bad_tree @@ -88,7 +88,7 @@ test_expect_success 'setup for tests of tree:0' ' ' test_expect_success 'verify tree:0 packfile has no blobs or trees' ' - git -C r1 pack-objects --rev --stdout --filter=tree:0 >commitsonly.pack <<-EOF && + git -C r1 pack-objects --revs --stdout --filter=tree:0 >commitsonly.pack <<-EOF && HEAD EOF git -C r1 index-pack ../commitsonly.pack && @@ -98,7 +98,7 @@ test_expect_success 'verify tree:0 packfile has no blobs or trees' ' test_expect_success 'grab tree directly when using tree:0' ' # We should get the tree specified directly but not its blobs or subtrees. - git -C r1 pack-objects --rev --stdout --filter=tree:0 >commitsonly.pack <<-EOF && + git -C r1 pack-objects --revs --stdout --filter=tree:0 >commitsonly.pack <<-EOF && HEAD: EOF git -C r1 index-pack ../commitsonly.pack && @@ -128,7 +128,7 @@ test_expect_success 'verify blob count in normal packfile' ' awk -f print_2.awk ls_files_result | sort >expected && - git -C r2 pack-objects --rev --stdout >all.pack <<-EOF && + git -C r2 pack-objects --revs --stdout >all.pack <<-EOF && HEAD EOF git -C r2 index-pack ../all.pack && @@ -142,7 +142,7 @@ test_expect_success 'verify blob count in normal packfile' ' ' test_expect_success 'verify blob:limit=500 omits all blobs' ' - git -C r2 pack-objects --rev --stdout --filter=blob:limit=500 >filter.pack <<-EOF && + git -C r2 pack-objects --revs --stdout --filter=blob:limit=500 >filter.pack <<-EOF && HEAD EOF git -C r2 index-pack ../filter.pack && @@ -157,7 +157,7 @@ test_expect_success 'verify blob:limit=500 omits all blobs' ' ' test_expect_success 'verify blob:limit=1000' ' - git -C r2 pack-objects --rev --stdout --filter=blob:limit=1000 >filter.pack <<-EOF && + git -C r2 pack-objects --revs --stdout --filter=blob:limit=1000 >filter.pack <<-EOF && HEAD EOF git -C r2 index-pack ../filter.pack && @@ -176,7 +176,7 @@ test_expect_success 'verify blob:limit=1001' ' awk -f print_2.awk ls_files_result | sort >expected && - git -C r2 pack-objects --rev --stdout --filter=blob:limit=1001 >filter.pack <<-EOF && + git -C r2 pack-objects --revs --stdout --filter=blob:limit=1001 >filter.pack <<-EOF && HEAD EOF git -C r2 index-pack ../filter.pack && @@ -194,7 +194,7 @@ test_expect_success 'verify blob:limit=10001' ' awk -f print_2.awk ls_files_result | sort >expected && - git -C r2 pack-objects --rev --stdout --filter=blob:limit=10001 >filter.pack <<-EOF && + git -C r2 pack-objects --revs --stdout --filter=blob:limit=10001 >filter.pack <<-EOF && HEAD EOF git -C r2 index-pack ../filter.pack && @@ -212,7 +212,7 @@ test_expect_success 'verify blob:limit=1k' ' awk -f print_2.awk ls_files_result | sort >expected && - git -C r2 pack-objects --rev --stdout --filter=blob:limit=1k >filter.pack <<-EOF && + git -C r2 pack-objects --revs --stdout --filter=blob:limit=1k >filter.pack <<-EOF && HEAD EOF git -C r2 index-pack ../filter.pack && @@ -230,7 +230,7 @@ test_expect_success 'verify explicitly specifying oversized blob in input' ' awk -f print_2.awk ls_files_result | sort >expected && - git -C r2 pack-objects --rev --stdout --filter=blob:limit=1k >filter.pack <<-EOF && + git -C r2 pack-objects --revs --stdout --filter=blob:limit=1k >filter.pack <<-EOF && HEAD $(git -C r2 rev-parse HEAD:large.10000) EOF @@ -249,7 +249,7 @@ test_expect_success 'verify blob:limit=1m' ' awk -f print_2.awk ls_files_result | sort >expected && - git -C r2 pack-objects --rev --stdout --filter=blob:limit=1m >filter.pack <<-EOF && + git -C r2 pack-objects --revs --stdout --filter=blob:limit=1m >filter.pack <<-EOF && HEAD EOF git -C r2 index-pack ../filter.pack && @@ -302,7 +302,7 @@ test_expect_success 'verify blob count in normal packfile' ' awk -f print_2.awk ls_files_result | sort >expected && - git -C r3 pack-objects --rev --stdout >all.pack <<-EOF && + git -C r3 pack-objects --revs --stdout >all.pack <<-EOF && HEAD EOF git -C r3 index-pack ../all.pack && @@ -320,7 +320,7 @@ test_expect_success 'verify sparse:path=pattern1' ' awk -f print_2.awk ls_files_result | sort >expected && - git -C r3 pack-objects --rev --stdout --filter=sparse:path=../pattern1 >filter.pack <<-EOF && + git -C r3 pack-objects --revs --stdout --filter=sparse:path=../pattern1 >filter.pack <<-EOF && HEAD EOF git -C r3 index-pack ../filter.pack && @@ -352,7 +352,7 @@ test_expect_success 'verify sparse:path=pattern2' ' awk -f print_2.awk ls_files_result | sort >expected && - git -C r3 pack-objects --rev --stdout --filter=sparse:path=../pattern2 >filter.pack <<-EOF && + git -C r3 pack-objects --revs --stdout --filter=sparse:path=../pattern2 >filter.pack <<-EOF && HEAD EOF git -C r3 index-pack ../filter.pack && @@ -404,7 +404,7 @@ test_expect_success 'verify blob count in normal packfile' ' awk -f print_2.awk ls_files_result | sort >expected && - git -C r4 pack-objects --rev --stdout >all.pack <<-EOF && + git -C r4 pack-objects --revs --stdout >all.pack <<-EOF && HEAD EOF git -C r4 index-pack ../all.pack && @@ -423,7 +423,7 @@ test_expect_success 'verify sparse:oid=OID' ' sort >expected && oid=$(git -C r4 ls-files -s pattern | awk -f print_2.awk) && - git -C r4 pack-objects --rev --stdout --filter=sparse:oid=$oid >filter.pack <<-EOF && + git -C r4 pack-objects --revs --stdout --filter=sparse:oid=$oid >filter.pack <<-EOF && HEAD EOF git -C r4 index-pack ../filter.pack && @@ -441,7 +441,7 @@ test_expect_success 'verify sparse:oid=oid-ish' ' awk -f print_2.awk ls_files_result | sort >expected && - git -C r4 pack-objects --rev --stdout --filter=sparse:oid=master:pattern >filter.pack <<-EOF && + git -C r4 pack-objects --revs --stdout --filter=sparse:oid=master:pattern >filter.pack <<-EOF && HEAD EOF git -C r4 index-pack ../filter.pack && @@ -470,19 +470,19 @@ test_expect_success 'setup r1 - delete loose blobs' ' ' test_expect_success 'verify pack-objects fails w/ missing objects' ' - test_must_fail git -C r1 pack-objects --rev --stdout >miss.pack <<-EOF + test_must_fail git -C r1 pack-objects --revs --stdout >miss.pack <<-EOF HEAD EOF ' test_expect_success 'verify pack-objects fails w/ --missing=error' ' - test_must_fail git -C r1 pack-objects --rev --stdout --missing=error >miss.pack <<-EOF + test_must_fail git -C r1 pack-objects --revs --stdout --missing=error >miss.pack <<-EOF HEAD EOF ' test_expect_success 'verify pack-objects w/ --missing=allow-any' ' - git -C r1 pack-objects --rev --stdout --missing=allow-any >miss.pack <<-EOF + git -C r1 pack-objects --revs --stdout --missing=allow-any >miss.pack <<-EOF HEAD EOF ' diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh index 561796f280..840ad4d8ac 100755 --- a/t/t5318-commit-graph.sh +++ b/t/t5318-commit-graph.sh @@ -75,7 +75,7 @@ graph_read_expect() { test_expect_success 'write graph' ' cd "$TRASH_DIRECTORY/full" && - graph1=$(git commit-graph write) && + git commit-graph write && test_path_is_file $objdir/info/commit-graph && graph_read_expect "3" ' @@ -366,6 +366,26 @@ GRAPH_OCTOPUS_DATA_OFFSET=$(($GRAPH_COMMIT_DATA_OFFSET + \ GRAPH_BYTE_OCTOPUS=$(($GRAPH_OCTOPUS_DATA_OFFSET + 4)) GRAPH_BYTE_FOOTER=$(($GRAPH_OCTOPUS_DATA_OFFSET + 4 * $NUM_OCTOPUS_EDGES)) +corrupt_graph_setup() { + cd "$TRASH_DIRECTORY/full" && + test_when_finished mv commit-graph-backup $objdir/info/commit-graph && + cp $objdir/info/commit-graph commit-graph-backup +} + +corrupt_graph_verify() { + grepstr=$1 + test_must_fail git commit-graph verify 2>test_err && + grep -v "^+" test_err >err && + test_i18ngrep "$grepstr" err && + if test "$2" != "no-copy" + then + cp $objdir/info/commit-graph commit-graph-pre-write-test + fi && + git status --short && + GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD=true git commit-graph write && + git commit-graph verify +} + # usage: corrupt_graph_and_verify <position> <data> <string> [<zero_pos>] # Manipulates the commit-graph file at the position # by inserting the data, optionally zeroing the file @@ -376,19 +396,28 @@ corrupt_graph_and_verify() { pos=$1 data="${2:-\0}" grepstr=$3 - cd "$TRASH_DIRECTORY/full" && + corrupt_graph_setup && orig_size=$(wc -c < $objdir/info/commit-graph) && zero_pos=${4:-${orig_size}} && - test_when_finished mv commit-graph-backup $objdir/info/commit-graph && - cp $objdir/info/commit-graph commit-graph-backup && printf "$data" | dd of="$objdir/info/commit-graph" bs=1 seek="$pos" conv=notrunc && dd of="$objdir/info/commit-graph" bs=1 seek="$zero_pos" if=/dev/null && generate_zero_bytes $(($orig_size - $zero_pos)) >>"$objdir/info/commit-graph" && - test_must_fail git commit-graph verify 2>test_err && - grep -v "^+" test_err >err && - test_i18ngrep "$grepstr" err + corrupt_graph_verify "$grepstr" + } +test_expect_success POSIXPERM,SANITY 'detect permission problem' ' + corrupt_graph_setup && + chmod 000 $objdir/info/commit-graph && + corrupt_graph_verify "Could not open" "no-copy" +' + +test_expect_success 'detect too small' ' + corrupt_graph_setup && + echo "a small graph" >$objdir/info/commit-graph && + corrupt_graph_verify "too small" +' + test_expect_success 'detect bad signature' ' corrupt_graph_and_verify 0 "\0" \ "graph signature" @@ -499,6 +528,7 @@ test_expect_success 'git fsck (checks commit-graph)' ' git fsck && corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \ "incorrect checksum" && + cp commit-graph-pre-write-test $objdir/info/commit-graph && test_must_fail git fsck ' diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh index 70926b5bc0..1ebf19ec3c 100755 --- a/t/t5319-multi-pack-index.sh +++ b/t/t5319-multi-pack-index.sh @@ -86,13 +86,14 @@ test_expect_success 'write midx with one v1 pack' ' ' midx_git_two_modes () { + git -c core.multiPackIndex=false $1 >expect && + git -c core.multiPackIndex=true $1 >actual && if [ "$2" = "sorted" ] then - git -c core.multiPackIndex=false $1 | sort >expect && - git -c core.multiPackIndex=true $1 | sort >actual - else - git -c core.multiPackIndex=false $1 >expect && - git -c core.multiPackIndex=true $1 >actual + sort <expect >expect.sorted && + mv expect.sorted expect && + sort <actual >actual.sorted && + mv actual.sorted actual fi && test_cmp expect actual } @@ -103,8 +104,8 @@ compare_results_with_midx () { midx_git_two_modes "rev-list --objects --all" && midx_git_two_modes "log --raw" && midx_git_two_modes "count-objects --verbose" && - midx_git_two_modes "cat-file --batch-all-objects --buffer --batch-check" && - midx_git_two_modes "cat-file --batch-all-objects --buffer --batch-check --unsorted" sorted + midx_git_two_modes "cat-file --batch-all-objects --batch-check" && + midx_git_two_modes "cat-file --batch-all-objects --batch-check --unordered" sorted ' } @@ -116,6 +117,20 @@ test_expect_success 'write midx with one v2 pack' ' compare_results_with_midx "one v2 pack" +test_expect_success 'corrupt idx not opened' ' + idx=$(test-tool read-midx $objdir | grep "\.idx\$") && + mv $objdir/pack/$idx backup-$idx && + test_when_finished "mv backup-\$idx \$objdir/pack/\$idx" && + + # This is the minimum size for a sha-1 based .idx; this lets + # us pass perfunctory tests, but anything that actually opens and reads + # the idx file will complain. + test_copy_bytes 1064 <backup-$idx >$objdir/pack/$idx && + + git -c core.multiPackIndex=true rev-list --objects --all 2>err && + test_must_be_empty err +' + test_expect_success 'add more objects' ' for i in $(test_seq 6 10) do diff --git a/t/t5323-pack-redundant.sh b/t/t5323-pack-redundant.sh new file mode 100755 index 0000000000..6b4d1ca353 --- /dev/null +++ b/t/t5323-pack-redundant.sh @@ -0,0 +1,467 @@ +#!/bin/sh +# +# Copyright (c) 2018 Jiang Xin +# + +test_description='Test git pack-redundant + +In order to test git-pack-redundant, we will create a number of objects and +packs in the repository `master.git`. The relationship between packs (P1-P8) +and objects (T, A-R) is showed in the following chart. Objects of a pack will +be marked with letter x, while objects of redundant packs will be marked with +exclamation point, and redundant pack itself will be marked with asterisk. + + | T A B C D E F G H I J K L M N O P Q R + ----+-------------------------------------- + P1 | x x x x x x x x + P2* | ! ! ! ! ! ! ! + P3 | x x x x x x + P4* | ! ! ! ! ! + P5 | x x x x + P6* | ! ! ! + P7 | x x + P8* | ! + ----+-------------------------------------- + ALL | x x x x x x x x x x x x x x x x x x x + +Another repository `shared.git` has unique objects (X-Z), while other objects +(marked with letter s) are shared through alt-odb (of `master.git`). The +relationship between packs and objects is as follows: + + | T A B C D E F G H I J K L M N O P Q R X Y Z + ----+---------------------------------------------- + Px1 | s s s x x x + Px2 | s s s x x x +' + +. ./test-lib.sh + +master_repo=master.git +shared_repo=shared.git + +# Create commits in <repo> and assign each commit's oid to shell variables +# given in the arguments (A, B, and C). E.g.: +# +# create_commits_in <repo> A B C +# +# NOTE: Avoid calling this function from a subshell since variable +# assignments will disappear when subshell exits. +create_commits_in () { + repo="$1" && + if ! parent=$(git -C "$repo" rev-parse HEAD^{} 2>/dev/null) + then + parent= + fi && + T=$(git -C "$repo" write-tree) && + shift && + while test $# -gt 0 + do + name=$1 && + test_tick && + if test -z "$parent" + then + oid=$(echo $name | git -C "$repo" commit-tree $T) + else + oid=$(echo $name | git -C "$repo" commit-tree -p $parent $T) + fi && + eval $name=$oid && + parent=$oid && + shift || + return 1 + done && + git -C "$repo" update-ref refs/heads/master $oid +} + +# Create pack in <repo> and assign pack id to variable given in the 2nd argument +# (<name>). Commits in the pack will be read from stdin. E.g.: +# +# create_pack_in <repo> <name> <<-EOF +# ... +# EOF +# +# NOTE: commits from stdin should be given using heredoc, not using pipe, and +# avoid calling this function from a subshell since variable assignments will +# disappear when subshell exits. +create_pack_in () { + repo="$1" && + name="$2" && + pack=$(git -C "$repo/objects/pack" pack-objects -q pack) && + eval $name=$pack && + eval P$pack=$name:$pack +} + +format_packfiles () { + sed \ + -e "s#.*/pack-\(.*\)\.idx#\1#" \ + -e "s#.*/pack-\(.*\)\.pack#\1#" | + sort -u | + while read p + do + if test -z "$(eval echo \${P$p})" + then + echo $p + else + eval echo "\${P$p}" + fi + done | + sort +} + +test_expect_success 'setup master repo' ' + git init --bare "$master_repo" && + create_commits_in "$master_repo" A B C D E F G H I J K L M N O P Q R +' + +############################################################################# +# Chart of packs and objects for this test case +# +# | T A B C D E F G H I J K L M N O P Q R +# ----+-------------------------------------- +# P1 | x x x x x x x x +# P2 | x x x x x x x +# P3 | x x x x x x +# ----+-------------------------------------- +# ALL | x x x x x x x x x x x x x x x +# +############################################################################# +test_expect_success 'master: no redundant for pack 1, 2, 3' ' + create_pack_in "$master_repo" P1 <<-EOF && + $T + $A + $B + $C + $D + $E + $F + $R + EOF + create_pack_in "$master_repo" P2 <<-EOF && + $B + $C + $D + $E + $G + $H + $I + EOF + create_pack_in "$master_repo" P3 <<-EOF && + $F + $I + $J + $K + $L + $M + EOF + ( + cd "$master_repo" && + git pack-redundant --all >out && + test_must_be_empty out + ) +' + +############################################################################# +# Chart of packs and objects for this test case +# +# | T A B C D E F G H I J K L M N O P Q R +# ----+-------------------------------------- +# P1 | x x x x x x x x +# P2 | x x x x x x x +# P3* | ! ! ! ! ! ! +# P4 | x x x x x +# P5 | x x x x +# ----+-------------------------------------- +# ALL | x x x x x x x x x x x x x x x x x x +# +############################################################################# +test_expect_success 'master: one of pack-2/pack-3 is redundant' ' + create_pack_in "$master_repo" P4 <<-EOF && + $J + $K + $L + $M + $P + EOF + create_pack_in "$master_repo" P5 <<-EOF && + $G + $H + $N + $O + EOF + ( + cd "$master_repo" && + cat >expect <<-EOF && + P3:$P3 + EOF + git pack-redundant --all >out && + format_packfiles <out >actual && + test_cmp expect actual + ) +' + +############################################################################# +# Chart of packs and objects for this test case +# +# | T A B C D E F G H I J K L M N O P Q R +# ----+-------------------------------------- +# P1 | x x x x x x x x +# P2* | ! ! ! ! ! ! ! +# P3 | x x x x x x +# P4* | ! ! ! ! ! +# P5 | x x x x +# P6* | ! ! ! +# P7 | x x +# ----+-------------------------------------- +# ALL | x x x x x x x x x x x x x x x x x x x +# +############################################################################# +test_expect_success 'master: pack 2, 4, and 6 are redundant' ' + create_pack_in "$master_repo" P6 <<-EOF && + $N + $O + $Q + EOF + create_pack_in "$master_repo" P7 <<-EOF && + $P + $Q + EOF + ( + cd "$master_repo" && + cat >expect <<-EOF && + P2:$P2 + P4:$P4 + P6:$P6 + EOF + git pack-redundant --all >out && + format_packfiles <out >actual && + test_cmp expect actual + ) +' + +############################################################################# +# Chart of packs and objects for this test case +# +# | T A B C D E F G H I J K L M N O P Q R +# ----+-------------------------------------- +# P1 | x x x x x x x x +# P2* | ! ! ! ! ! ! ! +# P3 | x x x x x x +# P4* | ! ! ! ! ! +# P5 | x x x x +# P6* | ! ! ! +# P7 | x x +# P8* | ! +# ----+-------------------------------------- +# ALL | x x x x x x x x x x x x x x x x x x x +# +############################################################################# +test_expect_success 'master: pack-8 (subset of pack-1) is also redundant' ' + create_pack_in "$master_repo" P8 <<-EOF && + $A + EOF + ( + cd "$master_repo" && + cat >expect <<-EOF && + P2:$P2 + P4:$P4 + P6:$P6 + P8:$P8 + EOF + git pack-redundant --all >out && + format_packfiles <out >actual && + test_cmp expect actual + ) +' + +test_expect_success 'master: clean loose objects' ' + ( + cd "$master_repo" && + git prune-packed && + find objects -type f | sed -e "/objects\/pack\//d" >out && + test_must_be_empty out + ) +' + +test_expect_success 'master: remove redundant packs and pass fsck' ' + ( + cd "$master_repo" && + git pack-redundant --all | xargs rm && + git fsck && + git pack-redundant --all >out && + test_must_be_empty out + ) +' + +# The following test cases will execute inside `shared.git`, instead of +# inside `master.git`. +test_expect_success 'setup shared.git' ' + git clone --mirror "$master_repo" "$shared_repo" && + ( + cd "$shared_repo" && + printf "../../$master_repo/objects\n" >objects/info/alternates + ) +' + +test_expect_success 'shared: all packs are redundant, but no output without --alt-odb' ' + ( + cd "$shared_repo" && + git pack-redundant --all >out && + test_must_be_empty out + ) +' + +############################################################################# +# Chart of packs and objects for this test case +# +# ================ master.git =============== +# | T A B C D E F G H I J K L M N O P Q R <----------+ +# ----+-------------------------------------- | +# P1 | x x x x x x x x | +# P3 | x x x x x x | +# P5 | x x x x | +# P7 | x x | +# ----+-------------------------------------- | +# ALL | x x x x x x x x x x x x x x x x x x x | +# | +# | +# ================ shared.git =============== | +# | T A B C D E F G H I J K L M N O P Q R <objects/info/alternates> +# ----+-------------------------------------- +# P1* | s s s s s s s s +# P3* | s s s s s s +# P5* | s s s s +# P7* | s s +# ----+-------------------------------------- +# ALL | x x x x x x x x x x x x x x x x x x x +# +############################################################################# +test_expect_success 'shared: show redundant packs in stderr for verbose mode' ' + ( + cd "$shared_repo" && + cat >expect <<-EOF && + P1:$P1 + P3:$P3 + P5:$P5 + P7:$P7 + EOF + git pack-redundant --all --verbose >out 2>out.err && + test_must_be_empty out && + grep "pack$" out.err | format_packfiles >actual && + test_cmp expect actual + ) +' + +test_expect_success 'shared: remove redundant packs, no packs left' ' + ( + cd "$shared_repo" && + cat >expect <<-EOF && + fatal: Zero packs found! + EOF + git pack-redundant --all --alt-odb | xargs rm && + git fsck && + test_must_fail git pack-redundant --all --alt-odb >actual 2>&1 && + test_cmp expect actual + ) +' + +test_expect_success 'shared: create new objects and packs' ' + create_commits_in "$shared_repo" X Y Z && + create_pack_in "$shared_repo" Px1 <<-EOF && + $X + $Y + $Z + $A + $B + $C + EOF + create_pack_in "$shared_repo" Px2 <<-EOF + $X + $Y + $Z + $D + $E + $F + EOF +' + +test_expect_success 'shared: no redundant without --alt-odb' ' + ( + cd "$shared_repo" && + git pack-redundant --all >out && + test_must_be_empty out + ) +' + +############################################################################# +# Chart of packs and objects for this test case +# +# ================ master.git =============== +# | T A B C D E F G H I J K L M N O P Q R <----------------+ +# ----+-------------------------------------- | +# P1 | x x x x x x x x | +# P3 | x x x x x x | +# P5 | x x x x | +# P7 | x x | +# ----+-------------------------------------- | +# ALL | x x x x x x x x x x x x x x x x x x x | +# | +# | +# ================ shared.git ======================= | +# | T A B C D E F G H I J K L M N O P Q R X Y Z <objects/info/alternates> +# ----+---------------------------------------------- +# Px1 | s s s x x x +# Px2*| s s s ! ! ! +# ----+---------------------------------------------- +# ALL | s s s s s s s s s s s s s s s s s s s x x x +# +############################################################################# +test_expect_success 'shared: one pack is redundant with --alt-odb' ' + ( + cd "$shared_repo" && + git pack-redundant --all --alt-odb >out && + format_packfiles <out >actual && + test_line_count = 1 actual + ) +' + +############################################################################# +# Chart of packs and objects for this test case +# +# ================ master.git =============== +# | T A B C D E F G H I J K L M N O P Q R <----------------+ +# ----+-------------------------------------- | +# P1 | x x x x x x x x | +# P3 | x x x x x x | +# P5 | x x x x | +# P7 | x x | +# ----+-------------------------------------- | +# ALL | x x x x x x x x x x x x x x x x x x x | +# | +# | +# ================ shared.git ======================= | +# | T A B C D E F G H I J K L M N O P Q R X Y Z <objects/info/alternates> +# ----+---------------------------------------------- +# Px1*| s s s i i i +# Px2*| s s s i i i +# ----+---------------------------------------------- +# ALL | s s s s s s s s s s s s s s s s s s s i i i +# (ignored objects, marked with i) +# +############################################################################# +test_expect_success 'shared: ignore unique objects and all two packs are redundant' ' + ( + cd "$shared_repo" && + cat >expect <<-EOF && + Px1:$Px1 + Px2:$Px2 + EOF + git pack-redundant --all --alt-odb >out <<-EOF && + $X + $Y + $Z + EOF + format_packfiles <out >actual && + test_cmp expect actual + ) +' + +test_done diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh index f1932ea431..571d620aed 100755 --- a/t/t5400-send-pack.sh +++ b/t/t5400-send-pack.sh @@ -288,7 +288,7 @@ test_expect_success 'receive-pack de-dupes .have lines' ' $shared .have EOF - GIT_TRACE_PACKET=$(pwd)/trace \ + GIT_TRACE_PACKET=$(pwd)/trace GIT_TEST_PROTOCOL_VERSION= \ git push \ --receive-pack="unset GIT_TRACE_PACKET; git-receive-pack" \ fork HEAD:foo && diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh index a4a5903cba..7344253bfb 100755 --- a/t/t5407-post-rewrite-hook.sh +++ b/t/t5407-post-rewrite-hook.sh @@ -131,7 +131,7 @@ test_expect_success 'git rebase -m --skip' ' test_expect_success 'git rebase with implicit use of interactive backend' ' git reset --hard D && clear_hook_input && - test_must_fail git rebase --keep --onto A B && + test_must_fail git rebase --keep-empty --onto A B && echo C > foo && git add foo && git rebase --continue && @@ -146,7 +146,7 @@ test_expect_success 'git rebase with implicit use of interactive backend' ' test_expect_success 'git rebase --skip with implicit use of interactive backend' ' git reset --hard D && clear_hook_input && - test_must_fail git rebase --keep --onto A B && + test_must_fail git rebase --keep-empty --onto A B && test_must_fail git rebase --skip && echo D > foo && git add foo && diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh index 49c540b1e1..1c71c0ec77 100755 --- a/t/t5500-fetch-pack.sh +++ b/t/t5500-fetch-pack.sh @@ -636,7 +636,9 @@ test_expect_success 'fetch-pack cannot fetch a raw sha1 that is not advertised a test_commit -C server 6 && git init client && - test_must_fail git -C client fetch-pack ../server \ + # Some protocol versions (e.g. 2) support fetching + # unadvertised objects, so restrict this test to v0. + test_must_fail env GIT_TEST_PROTOCOL_VERSION= git -C client fetch-pack ../server \ $(git -C server rev-parse refs/heads/master^) 2>err && test_i18ngrep "Server does not allow request for unadvertised object" err ' @@ -918,7 +920,4 @@ test_expect_success 'fetch with --filter=blob:limit=0 and HTTP' ' fetch_filter_blob_limit_zero "$HTTPD_DOCUMENT_ROOT_PATH/server" "$HTTPD_URL/smart/server" ' -stop_httpd - - test_done diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh index 4ca48f0276..6041a4dd32 100755 --- a/t/t5503-tagfollow.sh +++ b/t/t5503-tagfollow.sh @@ -47,7 +47,7 @@ get_needs () { test -s "$1" && perl -alne ' next unless $F[1] eq "upload-pack<"; - last if $F[2] eq "0000"; + next unless $F[2] eq "want"; print $F[2], " ", $F[3]; ' "$1" } diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 3b7b30568c..e98d90dd9b 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -978,6 +978,4 @@ test_expect_success '--negotiation-tip limits "have" lines sent with HTTP protoc check_negotiation_tip ' -stop_httpd - test_done diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh index ced15ae122..e3c4a48c85 100755 --- a/t/t5512-ls-remote.sh +++ b/t/t5512-ls-remote.sh @@ -223,7 +223,9 @@ test_expect_success 'ls-remote --symref' ' $(git rev-parse refs/tags/mark1.10) refs/tags/mark1.10 $(git rev-parse refs/tags/mark1.2) refs/tags/mark1.2 EOF - git ls-remote --symref >actual && + # Protocol v2 supports sending symrefs for refs other than HEAD, so use + # protocol v0 here. + GIT_TEST_PROTOCOL_VERSION= git ls-remote --symref >actual && test_cmp expect actual ' @@ -232,7 +234,9 @@ test_expect_success 'ls-remote with filtered symref (refname)' ' ref: refs/heads/master HEAD 1bd44cb9d13204b0fe1958db0082f5028a16eb3a HEAD EOF - git ls-remote --symref . HEAD >actual && + # Protocol v2 supports sending symrefs for refs other than HEAD, so use + # protocol v0 here. + GIT_TEST_PROTOCOL_VERSION= git ls-remote --symref . HEAD >actual && test_cmp expect actual ' @@ -243,7 +247,9 @@ test_expect_failure 'ls-remote with filtered symref (--heads)' ' 1bd44cb9d13204b0fe1958db0082f5028a16eb3a refs/heads/foo 1bd44cb9d13204b0fe1958db0082f5028a16eb3a refs/heads/master EOF - git ls-remote --symref --heads . >actual && + # Protocol v2 supports sending symrefs for refs other than HEAD, so use + # protocol v0 here. + GIT_TEST_PROTOCOL_VERSION= git ls-remote --symref --heads . >actual && test_cmp expect actual ' @@ -252,9 +258,11 @@ test_expect_success 'ls-remote --symref omits filtered-out matches' ' 1bd44cb9d13204b0fe1958db0082f5028a16eb3a refs/heads/foo 1bd44cb9d13204b0fe1958db0082f5028a16eb3a refs/heads/master EOF - git ls-remote --symref --heads . >actual && + # Protocol v2 supports sending symrefs for refs other than HEAD, so use + # protocol v0 here. + GIT_TEST_PROTOCOL_VERSION= git ls-remote --symref --heads . >actual && test_cmp expect actual && - git ls-remote --symref . "refs/heads/*" >actual && + GIT_TEST_PROTOCOL_VERSION= git ls-remote --symref . "refs/heads/*" >actual && test_cmp expect actual ' diff --git a/t/t5515-fetch-merge-logic.sh b/t/t5515-fetch-merge-logic.sh index 36b0dbc01c..e55d8474ef 100755 --- a/t/t5515-fetch-merge-logic.sh +++ b/t/t5515-fetch-merge-logic.sh @@ -6,6 +6,10 @@ test_description='Merge logic in fetch' +# NEEDSWORK: If the overspecification of the expected result is reduced, we +# might be able to run this test in all protocol versions. +GIT_TEST_PROTOCOL_VERSION= + . ./test-lib.sh LF=' diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 37e8e80893..49bf4280e8 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -1147,8 +1147,12 @@ test_expect_success 'fetch exact SHA1' ' git prune && test_must_fail git cat-file -t $the_commit && + # Some protocol versions (e.g. 2) support fetching + # unadvertised objects, so restrict this test to v0. + # fetching the hidden object should fail by default - test_must_fail git fetch -v ../testrepo $the_commit:refs/heads/copy 2>err && + test_must_fail env GIT_TEST_PROTOCOL_VERSION= \ + git fetch -v ../testrepo $the_commit:refs/heads/copy 2>err && test_i18ngrep "Server does not allow request for unadvertised object" err && test_must_fail git rev-parse --verify refs/heads/copy && @@ -1204,7 +1208,10 @@ do mk_empty shallow && ( cd shallow && - test_must_fail git fetch --depth=1 ../testrepo/.git $SHA1 && + # Some protocol versions (e.g. 2) support fetching + # unadvertised objects, so restrict this test to v0. + test_must_fail env GIT_TEST_PROTOCOL_VERSION= \ + git fetch --depth=1 ../testrepo/.git $SHA1 && git --git-dir=../testrepo/.git config uploadpack.allowreachablesha1inwant true && git fetch --depth=1 ../testrepo/.git $SHA1 && git cat-file commit $SHA1 @@ -1232,15 +1239,20 @@ do mk_empty shallow && ( cd shallow && - test_must_fail ok=sigpipe git fetch ../testrepo/.git $SHA1_3 && - test_must_fail ok=sigpipe git fetch ../testrepo/.git $SHA1_1 && + # Some protocol versions (e.g. 2) support fetching + # unadvertised objects, so restrict this test to v0. + test_must_fail ok=sigpipe env GIT_TEST_PROTOCOL_VERSION= \ + git fetch ../testrepo/.git $SHA1_3 && + test_must_fail ok=sigpipe env GIT_TEST_PROTOCOL_VERSION= \ + git fetch ../testrepo/.git $SHA1_1 && git --git-dir=../testrepo/.git config uploadpack.allowreachablesha1inwant true && git fetch ../testrepo/.git $SHA1_1 && git cat-file commit $SHA1_1 && test_must_fail git cat-file commit $SHA1_2 && git fetch ../testrepo/.git $SHA1_2 && git cat-file commit $SHA1_2 && - test_must_fail ok=sigpipe git fetch ../testrepo/.git $SHA1_3 + test_must_fail ok=sigpipe env GIT_TEST_PROTOCOL_VERSION= \ + git fetch ../testrepo/.git $SHA1_3 ) ' done @@ -1370,7 +1382,7 @@ test_expect_success 'push does not follow tags by default' ' test_cmp expect actual ' -test_expect_success 'push --follow-tag only pushes relevant tags' ' +test_expect_success 'push --follow-tags only pushes relevant tags' ' mk_test testrepo heads/master && rm -fr src dst && git init src && @@ -1384,7 +1396,7 @@ test_expect_success 'push --follow-tag only pushes relevant tags' ' git tag -m "future" future && git checkout master && git for-each-ref refs/heads/master refs/tags/tag >../expect && - git push --follow-tag ../dst master + git push --follow-tags ../dst master ) && ( cd dst && diff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh index e2c37fd978..4ad059e6be 100755 --- a/t/t5531-deep-submodule-push.sh +++ b/t/t5531-deep-submodule-push.sh @@ -363,7 +363,7 @@ test_expect_success 'push succeeds if submodule has no remote and is on the firs ) && git add b && git commit -m "added submodule" && - git push --recurse-submodule=check origin master + git push --recurse-submodules=check origin master ) ' diff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh index 6caf628efa..66f0b64d39 100755 --- a/t/t5537-fetch-shallow.sh +++ b/t/t5537-fetch-shallow.sh @@ -255,6 +255,4 @@ test_expect_success 'shallow fetches check connectivity before writing shallow f git -C client fsck ' -stop_httpd - test_done diff --git a/t/t5539-fetch-http-shallow.sh b/t/t5539-fetch-http-shallow.sh index 5fbf67c446..b4ad81f006 100755 --- a/t/t5539-fetch-http-shallow.sh +++ b/t/t5539-fetch-http-shallow.sh @@ -67,7 +67,10 @@ test_expect_success 'no shallow lines after receiving ACK ready' ' cd clone && git checkout --orphan newnew && test_commit new-too && - GIT_TRACE_PACKET="$TRASH_DIRECTORY/trace" git fetch --depth=2 && + # NEEDSWORK: If the overspecification of the expected result is reduced, we + # might be able to run this test in all protocol versions. + GIT_TRACE_PACKET="$TRASH_DIRECTORY/trace" GIT_TEST_PROTOCOL_VERSION= \ + git fetch --depth=2 && grep "fetch-pack< ACK .* ready" ../trace && ! grep "fetch-pack> done" ../trace ) @@ -146,5 +149,4 @@ test_expect_success 'fetching deepen' ' ) ' -stop_httpd test_done diff --git a/t/t5540-http-push-webdav.sh b/t/t5540-http-push-webdav.sh index 88ff5a49e4..a094fd5e71 100755 --- a/t/t5540-http-push-webdav.sh +++ b/t/t5540-http-push-webdav.sh @@ -176,6 +176,4 @@ test_expect_failure 'push to password-protected repository (no user in URL)' ' test_cmp expect actual ' -stop_httpd - test_done diff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh index 5475afc052..8ef8763e06 100755 --- a/t/t5541-http-push-smart.sh +++ b/t/t5541-http-push-smart.sh @@ -47,7 +47,12 @@ test_expect_success 'no empty path components' ' cd "$ROOT_PATH" && git clone $HTTPD_URL/smart/test_repo.git/ test_repo_clone && - check_access_log exp + # NEEDSWORK: If the overspecification of the expected result is reduced, we + # might be able to run this test in all protocol versions. + if test -z "$GIT_TEST_PROTOCOL_VERSION" + then + check_access_log exp + fi ' test_expect_success 'clone remote repository' ' @@ -128,7 +133,12 @@ GET /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200 POST /smart/test_repo.git/git-receive-pack HTTP/1.1 200 EOF test_expect_success 'used receive-pack service' ' - check_access_log exp + # NEEDSWORK: If the overspecification of the expected result is reduced, we + # might be able to run this test in all protocol versions. + if test -z "$GIT_TEST_PROTOCOL_VERSION" + then + check_access_log exp + fi ' test_http_push_nonff "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git \ @@ -373,5 +383,4 @@ test_expect_success 'colorize errors/hints' ' test_i18ngrep ! "^hint: " decoded ' -stop_httpd test_done diff --git a/t/t5542-push-http-shallow.sh b/t/t5542-push-http-shallow.sh index 5165833157..ddc1db722d 100755 --- a/t/t5542-push-http-shallow.sh +++ b/t/t5542-push-http-shallow.sh @@ -90,5 +90,4 @@ EOF ) ' -stop_httpd test_done diff --git a/t/t5545-push-options.sh b/t/t5545-push-options.sh index b47a95871c..6d1d59c9b1 100755 --- a/t/t5545-push-options.sh +++ b/t/t5545-push-options.sh @@ -278,6 +278,4 @@ test_expect_success 'push options keep quoted characters intact (http)' ' test_cmp expect "$HTTPD_DOCUMENT_ROOT_PATH"/upstream.git/hooks/pre-receive.push_options ' -stop_httpd - test_done diff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh index 6d7d88ccc9..b811d89cfd 100755 --- a/t/t5550-http-fetch-dumb.sh +++ b/t/t5550-http-fetch-dumb.sh @@ -408,5 +408,20 @@ test_expect_success 'print HTTP error when any intermediate redirect throws erro test_i18ngrep "unable to access.*/redir-to/502" stderr ' -stop_httpd +test_expect_success 'fetching via http alternates works' ' + parent=$HTTPD_DOCUMENT_ROOT_PATH/alt-parent.git && + git init --bare "$parent" && + git -C "$parent" --work-tree=. commit --allow-empty -m foo && + git -C "$parent" update-server-info && + commit=$(git -C "$parent" rev-parse HEAD) && + + child=$HTTPD_DOCUMENT_ROOT_PATH/alt-child.git && + git init --bare "$child" && + echo "../../alt-parent.git/objects" >"$child/objects/info/alternates" && + git -C "$child" update-ref HEAD $commit && + git -C "$child" update-server-info && + + git -c http.followredirects=true clone "$HTTPD_URL/dumb/alt-child.git" +' + test_done diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh index ba83e567e5..ac74626a7b 100755 --- a/t/t5551-http-fetch-smart.sh +++ b/t/t5551-http-fetch-smart.sh @@ -43,7 +43,8 @@ test_expect_success 'clone http repository' ' < Cache-Control: no-cache, max-age=0, must-revalidate < Content-Type: application/x-git-upload-pack-result EOF - GIT_TRACE_CURL=true git clone --quiet $HTTPD_URL/smart/repo.git clone 2>err && + GIT_TRACE_CURL=true GIT_TEST_PROTOCOL_VERSION= \ + git clone --quiet $HTTPD_URL/smart/repo.git clone 2>err && test_cmp file clone/file && tr '\''\015'\'' Q <err | sed -e " @@ -80,12 +81,18 @@ test_expect_success 'clone http repository' ' /^< Content-Length: /d /^< Transfer-Encoding: /d " >actual && - sed -e "s/^> Accept-Encoding: .*/> Accept-Encoding: ENCODINGS/" \ - actual >actual.smudged && - test_cmp exp actual.smudged && - grep "Accept-Encoding:.*gzip" actual >actual.gzip && - test_line_count = 2 actual.gzip + # NEEDSWORK: If the overspecification of the expected result is reduced, we + # might be able to run this test in all protocol versions. + if test -z "$GIT_TEST_PROTOCOL_VERSION" + then + sed -e "s/^> Accept-Encoding: .*/> Accept-Encoding: ENCODINGS/" \ + actual >actual.smudged && + test_cmp exp actual.smudged && + + grep "Accept-Encoding:.*gzip" actual >actual.gzip && + test_line_count = 2 actual.gzip + fi ' test_expect_success 'fetch changes via http' ' @@ -103,7 +110,13 @@ test_expect_success 'used upload-pack service' ' GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1 200 POST /smart/repo.git/git-upload-pack HTTP/1.1 200 EOF - check_access_log exp + + # NEEDSWORK: If the overspecification of the expected result is reduced, we + # might be able to run this test in all protocol versions. + if test -z "$GIT_TEST_PROTOCOL_VERSION" + then + check_access_log exp + fi ' test_expect_success 'follow redirects (301)' ' @@ -151,7 +164,17 @@ test_expect_success 'clone from auth-only-for-objects repository' ' test_expect_success 'no-op half-auth fetch does not require a password' ' set_askpass wrong && - git --git-dir=half-auth fetch && + + # NEEDSWORK: When using HTTP(S), protocol v0 supports a "half-auth" + # configuration with authentication required only when downloading + # objects and not refs, by having the HTTP server only require + # authentication for the "git-upload-pack" path and not "info/refs". + # This is not possible with protocol v2, since both objects and refs + # are obtained from the "git-upload-pack" path. A solution to this is + # to teach the server and client to be able to inline ls-refs requests + # as an Extra Parameter (see pack-protocol.txt), so that "info/refs" + # can serve refs, just like it does in protocol v0. + GIT_TEST_PROTOCOL_VERSION=0 git --git-dir=half-auth fetch && expect_askpass none ' @@ -215,8 +238,14 @@ test_expect_success 'cookies stored in http.cookiefile when http.savecookies set git config http.cookiefile cookies.txt && git config http.savecookies true && git ls-remote $HTTPD_URL/smart_cookies/repo.git master && - tail -3 cookies.txt | sort >cookies_tail.txt && - test_cmp expect_cookies.txt cookies_tail.txt + + # NEEDSWORK: If the overspecification of the expected result is reduced, we + # might be able to run this test in all protocol versions. + if test -z "$GIT_TEST_PROTOCOL_VERSION" + then + tail -3 cookies.txt | sort >cookies_tail.txt && + test_cmp expect_cookies.txt cookies_tail.txt + fi ' test_expect_success 'transfer.hiderefs works over smart-http' ' @@ -306,7 +335,10 @@ test_expect_success 'test allowreachablesha1inwant with unreachable' ' git init --bare test_reachable.git && git -C test_reachable.git remote add origin "$HTTPD_URL/smart/repo.git" && - test_must_fail git -C test_reachable.git fetch origin "$(git rev-parse HEAD)" + # Some protocol versions (e.g. 2) support fetching + # unadvertised objects, so restrict this test to v0. + test_must_fail env GIT_TEST_PROTOCOL_VERSION= \ + git -C test_reachable.git fetch origin "$(git rev-parse HEAD)" ' test_expect_success 'test allowanysha1inwant with unreachable' ' @@ -325,7 +357,10 @@ test_expect_success 'test allowanysha1inwant with unreachable' ' git init --bare test_reachable.git && git -C test_reachable.git remote add origin "$HTTPD_URL/smart/repo.git" && - test_must_fail git -C test_reachable.git fetch origin "$(git rev-parse HEAD)" && + # Some protocol versions (e.g. 2) support fetching + # unadvertised objects, so restrict this test to v0. + test_must_fail env GIT_TEST_PROTOCOL_VERSION= \ + git -C test_reachable.git fetch origin "$(git rev-parse HEAD)" && git -C "$server" config uploadpack.allowanysha1inwant 1 && git -C test_reachable.git fetch origin "$(git rev-parse HEAD)" @@ -434,5 +469,4 @@ test_expect_success 'server-side error detected' ' grep "server-side error" actual ' -stop_httpd test_done diff --git a/t/t5552-skipping-fetch-negotiator.sh b/t/t5552-skipping-fetch-negotiator.sh index 30857b84a8..8a14be51a1 100755 --- a/t/t5552-skipping-fetch-negotiator.sh +++ b/t/t5552-skipping-fetch-negotiator.sh @@ -127,7 +127,10 @@ test_expect_success 'use ref advertisement to filter out commits' ' # not need to send any ancestors of "c3", but we still need to send "c3" # itself. test_config -C client fetch.negotiationalgorithm skipping && - trace_fetch client origin to_fetch && + + # The ref advertisement itself is filtered when protocol v2 is used, so + # use v0. + GIT_TEST_PROTOCOL_VERSION= trace_fetch client origin to_fetch && have_sent c5 c4^ c2side && have_not_sent c4 c4^^ c4^^^ ' diff --git a/t/t5561-http-backend.sh b/t/t5561-http-backend.sh index 1c49054595..6eb0294978 100755 --- a/t/t5561-http-backend.sh +++ b/t/t5561-http-backend.sh @@ -132,5 +132,4 @@ test_expect_success 'server request log matches test results' ' check_access_log exp ' -stop_httpd test_done diff --git a/t/t5570-git-daemon.sh b/t/t5570-git-daemon.sh index 58ee787685..34487bbb8c 100755 --- a/t/t5570-git-daemon.sh +++ b/t/t5570-git-daemon.sh @@ -90,6 +90,7 @@ test_expect_success 'fetch notices corrupt pack' ' test_expect_success 'fetch notices corrupt idx' ' cp -R "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad2.git && (cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad2.git && + rm -f objects/pack/multi-pack-index && p=$(ls objects/pack/pack-*.idx) && chmod u+w $p && printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc @@ -198,5 +199,4 @@ test_expect_success FAKENC 'hostname interpolation works after LF-stripping' ' test_cmp expect actual ' -stop_git_daemon test_done diff --git a/t/t5581-http-curl-verbose.sh b/t/t5581-http-curl-verbose.sh index cd9283eeec..5129b0724f 100755 --- a/t/t5581-http-curl-verbose.sh +++ b/t/t5581-http-curl-verbose.sh @@ -23,6 +23,4 @@ test_expect_success 'failure in git-upload-pack is shown' ' grep "< HTTP/1.1 500 Intentional Breakage" curl_log ' -stop_httpd - test_done diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index d6948cbdab..23854cab26 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -345,7 +345,7 @@ expect_ssh () { } test_expect_success 'clone myhost:src uses ssh' ' - git clone myhost:src ssh-clone && + GIT_TEST_PROTOCOL_VERSION=0 git clone myhost:src ssh-clone && expect_ssh myhost src ' @@ -356,12 +356,12 @@ test_expect_success !MINGW,!CYGWIN 'clone local path foo:bar' ' ' test_expect_success 'bracketed hostnames are still ssh' ' - git clone "[myhost:123]:src" ssh-bracket-clone && + GIT_TEST_PROTOCOL_VERSION=0 git clone "[myhost:123]:src" ssh-bracket-clone && expect_ssh "-p 123" myhost src ' test_expect_success 'OpenSSH variant passes -4' ' - git clone -4 "[myhost:123]:src" ssh-ipv4-clone && + GIT_TEST_PROTOCOL_VERSION=0 git clone -4 "[myhost:123]:src" ssh-ipv4-clone && expect_ssh "-4 -p 123" myhost src ' @@ -405,7 +405,7 @@ test_expect_success 'OpenSSH-like uplink is treated as ssh' ' test_when_finished "rm -f \"\$TRASH_DIRECTORY/uplink\"" && GIT_SSH="$TRASH_DIRECTORY/uplink" && test_when_finished "GIT_SSH=\"\$TRASH_DIRECTORY/ssh\$X\"" && - git clone "[myhost:123]:src" ssh-bracket-clone-sshlike-uplink && + GIT_TEST_PROTOCOL_VERSION=0 git clone "[myhost:123]:src" ssh-bracket-clone-sshlike-uplink && expect_ssh "-p 123" myhost src ' @@ -444,14 +444,14 @@ test_expect_success 'single quoted plink.exe in GIT_SSH_COMMAND' ' test_expect_success 'GIT_SSH_VARIANT overrides plink detection' ' copy_ssh_wrapper_as "$TRASH_DIRECTORY/plink" && - GIT_SSH_VARIANT=ssh \ - git clone "[myhost:123]:src" ssh-bracket-clone-variant-1 && + GIT_TEST_PROTOCOL_VERSION=0 GIT_SSH_VARIANT=ssh \ + git clone "[myhost:123]:src" ssh-bracket-clone-variant-1 && expect_ssh "-p 123" myhost src ' test_expect_success 'ssh.variant overrides plink detection' ' copy_ssh_wrapper_as "$TRASH_DIRECTORY/plink" && - git -c ssh.variant=ssh \ + GIT_TEST_PROTOCOL_VERSION=0 git -c ssh.variant=ssh \ clone "[myhost:123]:src" ssh-bracket-clone-variant-2 && expect_ssh "-p 123" myhost src ' @@ -482,7 +482,7 @@ counter=0 # $3 path test_clone_url () { counter=$(($counter + 1)) - test_might_fail git clone "$1" tmp$counter && + test_might_fail env GIT_TEST_PROTOCOL_VERSION=0 git clone "$1" tmp$counter && shift && expect_ssh "$@" } @@ -733,6 +733,4 @@ test_expect_success 'partial clone using HTTP' ' partial_clone "$HTTPD_DOCUMENT_ROOT_PATH/server" "$HTTPD_URL/smart/server" ' -stop_httpd - test_done diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh index 9643acb161..9a8f9886b3 100755 --- a/t/t5616-partial-clone.sh +++ b/t/t5616-partial-clone.sh @@ -331,6 +331,4 @@ test_expect_success 'when partial cloning, tolerate server not sending target of ! test -e "$HTTPD_ROOT_PATH/one-time-sed" ' -stop_httpd - test_done diff --git a/t/t5700-protocol-v1.sh b/t/t5700-protocol-v1.sh index ba86a44eb1..7c9511c593 100755 --- a/t/t5700-protocol-v1.sh +++ b/t/t5700-protocol-v1.sh @@ -4,6 +4,9 @@ test_description='test git wire-protocol transition' TEST_NO_CREATE_REPO=1 +# This is a protocol-specific test. +GIT_TEST_PROTOCOL_VERSION= + . ./test-lib.sh # Test protocol v1 with 'git://' transport @@ -289,6 +292,4 @@ test_expect_success 'push with http:// using protocol v1' ' grep "git< version 1" log ' -stop_httpd - test_done diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh index db4ae09f2f..a089659337 100755 --- a/t/t5702-protocol-v2.sh +++ b/t/t5702-protocol-v2.sh @@ -542,7 +542,38 @@ test_expect_success 'clone with http:// using protocol v2' ' # Client requested to use protocol v2 grep "Git-Protocol: version=2" log && # Server responded using protocol v2 - grep "git< version 2" log + grep "git< version 2" log && + # Verify that the chunked encoding sending codepath is NOT exercised + ! grep "Send header: Transfer-Encoding: chunked" log +' + +test_expect_success 'clone big repository with http:// using protocol v2' ' + test_when_finished "rm -f log" && + + git init "$HTTPD_DOCUMENT_ROOT_PATH/big" && + # Ensure that the list of wants is greater than http.postbuffer below + for i in $(test_seq 1 1500) + do + # do not use here-doc, because it requires a process + # per loop iteration + echo "commit refs/heads/too-many-refs-$i" && + echo "committer git <git@example.com> $i +0000" && + echo "data 0" && + echo "M 644 inline bla.txt" && + echo "data 4" && + echo "bla" + done | git -C "$HTTPD_DOCUMENT_ROOT_PATH/big" fast-import && + + GIT_TRACE_PACKET="$(pwd)/log" GIT_TRACE_CURL="$(pwd)/log" git \ + -c protocol.version=2 -c http.postbuffer=65536 \ + clone "$HTTPD_URL/smart/big" big_child && + + # Client requested to use protocol v2 + grep "Git-Protocol: version=2" log && + # Server responded using protocol v2 + grep "git< version 2" log && + # Verify that the chunked encoding sending codepath is exercised + grep "Send header: Transfer-Encoding: chunked" log ' test_expect_success 'fetch with http:// using protocol v2' ' @@ -656,6 +687,4 @@ test_expect_success 'when server does not send "ready", expect FLUSH' ' test_i18ngrep "expected no other sections to be sent after no .ready." err ' -stop_httpd - test_done diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh index f87b2f6df3..b6a995e857 100755 --- a/t/t5703-upload-pack-ref-in-want.sh +++ b/t/t5703-upload-pack-ref-in-want.sh @@ -257,8 +257,6 @@ test_expect_success 'server loses a ref - ref in want' ' test_i18ngrep "fatal: remote error: unknown ref refs/heads/raster" err ' -stop_httpd - REPO="$(pwd)/repo" LOCAL_PRISTINE="$(pwd)/local_pristine" diff --git a/t/t5812-proto-disable-http.sh b/t/t5812-proto-disable-http.sh index 872788ac8c..af8772fada 100755 --- a/t/t5812-proto-disable-http.sh +++ b/t/t5812-proto-disable-http.sh @@ -34,5 +34,4 @@ test_expect_success 'http can be limited to from-user' ' clone "$HTTPD_URL/smart-redir-perm/repo.git" redir.git ' -stop_httpd test_done diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh index 55835ee4a4..49a394bd75 100755 --- a/t/t6030-bisect-porcelain.sh +++ b/t/t6030-bisect-porcelain.sh @@ -681,7 +681,7 @@ test_expect_success 'bisect: --no-checkout - target in breakage' ' check_same BROKEN_HASH6 BISECT_HEAD && git bisect bad BISECT_HEAD && check_same BROKEN_HASH5 BISECT_HEAD && - git bisect good BISECT_HEAD && + test_must_fail git bisect good BISECT_HEAD && check_same BROKEN_HASH6 bisect/bad && git bisect reset ' @@ -692,7 +692,7 @@ test_expect_success 'bisect: --no-checkout - target after breakage' ' check_same BROKEN_HASH6 BISECT_HEAD && git bisect good BISECT_HEAD && check_same BROKEN_HASH8 BISECT_HEAD && - git bisect good BISECT_HEAD && + test_must_fail git bisect good BISECT_HEAD && check_same BROKEN_HASH9 bisect/bad && git bisect reset ' @@ -701,7 +701,7 @@ test_expect_success 'bisect: demonstrate identification of damage boundary' " git bisect reset && git checkout broken && git bisect start broken master --no-checkout && - git bisect run \"\$SHELL_PATH\" -c ' + test_must_fail git bisect run \"\$SHELL_PATH\" -c ' GOOD=\$(git for-each-ref \"--format=%(objectname)\" refs/bisect/good-*) && git rev-list --objects BISECT_HEAD --not \$GOOD >tmp.\$\$ && git pack-objects --stdout >/dev/null < tmp.\$\$ diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh index 4684d06552..7411bf7fec 100755 --- a/t/t6500-gc.sh +++ b/t/t6500-gc.sh @@ -120,6 +120,25 @@ test_expect_success 'gc --quiet' ' test_must_be_empty stderr ' +test_expect_success 'gc.reflogExpire{Unreachable,}=never skips "expire" via "gc"' ' + test_config gc.reflogExpire never && + test_config gc.reflogExpireUnreachable never && + + GIT_TRACE=$(pwd)/trace.out git gc && + + # Check that git-pack-refs is run as a sanity check (done via + # gc_before_repack()) but that git-expire is not. + grep -E "^trace: (built-in|exec|run_command): git pack-refs --" trace.out && + ! grep -E "^trace: (built-in|exec|run_command): git reflog expire --" trace.out +' + +test_expect_success 'one of gc.reflogExpire{Unreachable,}=never does not skip "expire" via "gc"' ' + >trace.out && + test_config gc.reflogExpire never && + GIT_TRACE=$(pwd)/trace.out git gc && + grep -E "^trace: (built-in|exec|run_command): git reflog expire --" trace.out +' + run_and_wait_for_auto_gc () { # We read stdout from gc for the side effect of waiting until the # background gc process exits, closing its fd 9. Furthermore, the diff --git a/t/t7113-post-index-change-hook.sh b/t/t7113-post-index-change-hook.sh new file mode 100755 index 0000000000..f011ad7eec --- /dev/null +++ b/t/t7113-post-index-change-hook.sh @@ -0,0 +1,144 @@ +#!/bin/sh + +test_description='post index change hook' + +. ./test-lib.sh + +test_expect_success 'setup' ' + mkdir -p dir1 && + touch dir1/file1.txt && + echo testing >dir1/file2.txt && + git add . && + git commit -m "initial" +' + +test_expect_success 'test status, add, commit, others trigger hook without flags set' ' + mkdir -p .git/hooks && + write_script .git/hooks/post-index-change <<-\EOF && + if test "$1" -eq 1; then + echo "Invalid combination of flags passed to hook; updated_workdir is set." >testfailure + exit 1 + fi + if test "$2" -eq 1; then + echo "Invalid combination of flags passed to hook; updated_skipworktree is set." >testfailure + exit 1 + fi + if test -f ".git/index.lock"; then + echo ".git/index.lock exists" >testfailure + exit 3 + fi + if ! test -f ".git/index"; then + echo ".git/index does not exist" >testfailure + exit 3 + fi + echo "success" >testsuccess + EOF + mkdir -p dir2 && + touch dir2/file1.txt && + touch dir2/file2.txt && + : force index to be dirty && + test-tool chmtime +60 dir1/file1.txt && + git status && + test_path_is_file testsuccess && rm -f testsuccess && + test_path_is_missing testfailure && + git add . && + test_path_is_file testsuccess && rm -f testsuccess && + test_path_is_missing testfailure && + git commit -m "second" && + test_path_is_file testsuccess && rm -f testsuccess && + test_path_is_missing testfailure && + git checkout -- dir1/file1.txt && + test_path_is_file testsuccess && rm -f testsuccess && + test_path_is_missing testfailure && + git update-index && + test_path_is_missing testsuccess && + test_path_is_missing testfailure && + git reset --soft && + test_path_is_missing testsuccess && + test_path_is_missing testfailure +' + +test_expect_success 'test checkout and reset trigger the hook' ' + write_script .git/hooks/post-index-change <<-\EOF && + if test "$1" -eq 1 && test "$2" -eq 1; then + echo "Invalid combination of flags passed to hook; updated_workdir and updated_skipworktree are both set." >testfailure + exit 1 + fi + if test "$1" -eq 0 && test "$2" -eq 0; then + echo "Invalid combination of flags passed to hook; neither updated_workdir or updated_skipworktree are set." >testfailure + exit 2 + fi + if test "$1" -eq 1; then + if test -f ".git/index.lock"; then + echo "updated_workdir set but .git/index.lock exists" >testfailure + exit 3 + fi + if ! test -f ".git/index"; then + echo "updated_workdir set but .git/index does not exist" >testfailure + exit 3 + fi + else + echo "update_workdir should be set for checkout" >testfailure + exit 4 + fi + echo "success" >testsuccess + EOF + : force index to be dirty && + test-tool chmtime +60 dir1/file1.txt && + git checkout master && + test_path_is_file testsuccess && rm -f testsuccess && + test_path_is_missing testfailure && + test-tool chmtime +60 dir1/file1.txt && + git checkout HEAD && + test_path_is_file testsuccess && rm -f testsuccess && + test_path_is_missing testfailure && + test-tool chmtime +60 dir1/file1.txt && + git reset --hard && + test_path_is_file testsuccess && rm -f testsuccess && + test_path_is_missing testfailure && + git checkout -B test && + test_path_is_file testsuccess && rm -f testsuccess && + test_path_is_missing testfailure +' + +test_expect_success 'test reset --mixed and update-index triggers the hook' ' + write_script .git/hooks/post-index-change <<-\EOF && + if test "$1" -eq 1 && test "$2" -eq 1; then + echo "Invalid combination of flags passed to hook; updated_workdir and updated_skipworktree are both set." >testfailure + exit 1 + fi + if test "$1" -eq 0 && test "$2" -eq 0; then + echo "Invalid combination of flags passed to hook; neither updated_workdir or updated_skipworktree are set." >testfailure + exit 2 + fi + if test "$2" -eq 1; then + if test -f ".git/index.lock"; then + echo "updated_skipworktree set but .git/index.lock exists" >testfailure + exit 3 + fi + if ! test -f ".git/index"; then + echo "updated_skipworktree set but .git/index does not exist" >testfailure + exit 3 + fi + else + echo "updated_skipworktree should be set for reset --mixed and update-index" >testfailure + exit 4 + fi + echo "success" >testsuccess + EOF + : force index to be dirty && + test-tool chmtime +60 dir1/file1.txt && + git reset --mixed --quiet HEAD~1 && + test_path_is_file testsuccess && rm -f testsuccess && + test_path_is_missing testfailure && + git hash-object -w --stdin <dir1/file2.txt >expect && + git update-index --cacheinfo 100644 "$(cat expect)" dir1/file1.txt && + test_path_is_file testsuccess && rm -f testsuccess && + test_path_is_missing testfailure && + git update-index --skip-worktree dir1/file2.txt && + git update-index --remove dir1/file2.txt && + test_path_is_file testsuccess && rm -f testsuccess && + test_path_is_missing testfailure +' + +test_done diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 72b9b375ba..5990299fc9 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -223,13 +223,8 @@ test_expect_success 'switch to another branch while carrying a deletion' ' test_must_fail git checkout simple 2>errs && test_i18ngrep overwritten errs && - git checkout --merge simple 2>errs && - test_i18ngrep ! overwritten errs && - git ls-files -u && - test_must_fail git cat-file -t :0:two && - test "$(git cat-file -t :1:two)" = blob && - test "$(git cat-file -t :2:two)" = blob && - test_must_fail git cat-file -t :3:two + test_must_fail git read-tree --quiet -m -u HEAD simple 2>errs && + test_must_be_empty errs ' test_expect_success 'checkout to detach HEAD (with advice declined)' ' diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh index e87164aa8f..c973278300 100755 --- a/t/t7406-submodule-update.sh +++ b/t/t7406-submodule-update.sh @@ -943,7 +943,10 @@ test_expect_success 'submodule update clone shallow submodule outside of depth' cd super3 && sed -e "s#url = ../#url = file://$pwd/#" <.gitmodules >.gitmodules.tmp && mv -f .gitmodules.tmp .gitmodules && - test_must_fail git submodule update --init --depth=1 2>actual && + # Some protocol versions (e.g. 2) support fetching + # unadvertised objects, so restrict this test to v0. + test_must_fail env GIT_TEST_PROTOCOL_VERSION= \ + git submodule update --init --depth=1 2>actual && test_i18ngrep "Direct fetching of that commit failed." actual && git -C ../submodule config uploadpack.allowReachableSHA1InWant true && git submodule update --init --depth=1 >actual && diff --git a/t/t7411-submodule-config.sh b/t/t7411-submodule-config.sh index 89690b7adb..fcc0fb82d8 100755 --- a/t/t7411-submodule-config.sh +++ b/t/t7411-submodule-config.sh @@ -142,6 +142,15 @@ test_expect_success 'reading submodules config from the working tree with "submo ) ' +test_expect_success 'unsetting submodules config from the working tree with "submodule--helper config --unset"' ' + (cd super && + git submodule--helper config --unset submodule.submodule.url && + git submodule--helper config submodule.submodule.url >actual && + test_must_be_empty actual + ) +' + + test_expect_success 'writing submodules config with "submodule--helper config"' ' (cd super && echo "new_url" >expect && diff --git a/t/t7419-submodule-set-branch.sh b/t/t7419-submodule-set-branch.sh new file mode 100755 index 0000000000..c4b370ea85 --- /dev/null +++ b/t/t7419-submodule-set-branch.sh @@ -0,0 +1,93 @@ +#!/bin/sh +# +# Copyright (c) 2019 Denton Liu +# + +test_description='Test submodules set-branch subcommand + +This test verifies that the set-branch subcommand of git-submodule is working +as expected. +' + +TEST_NO_CREATE_REPO=1 +. ./test-lib.sh + +test_expect_success 'submodule config cache setup' ' + mkdir submodule && + (cd submodule && + git init && + echo a >a && + git add . && + git commit -ma && + git checkout -b topic && + echo b >a && + git add . && + git commit -mb + ) && + mkdir super && + (cd super && + git init && + git submodule add ../submodule && + git commit -m "add submodule" + ) +' + +test_expect_success 'ensure submodule branch is unset' ' + (cd super && + test_must_fail grep branch .gitmodules + ) +' + +test_expect_success 'test submodule set-branch --branch' ' + (cd super && + git submodule set-branch --branch topic submodule && + grep "branch = topic" .gitmodules && + git submodule update --remote && + cat <<-\EOF >expect && + b + EOF + git -C submodule show -s --pretty=%s >actual && + test_cmp expect actual + ) +' + +test_expect_success 'test submodule set-branch --default' ' + (cd super && + git submodule set-branch --default submodule && + test_must_fail grep branch .gitmodules && + git submodule update --remote && + cat <<-\EOF >expect && + a + EOF + git -C submodule show -s --pretty=%s >actual && + test_cmp expect actual + ) +' + +test_expect_success 'test submodule set-branch -b' ' + (cd super && + git submodule set-branch -b topic submodule && + grep "branch = topic" .gitmodules && + git submodule update --remote && + cat <<-\EOF >expect && + b + EOF + git -C submodule show -s --pretty=%s >actual && + test_cmp expect actual + ) +' + +test_expect_success 'test submodule set-branch -d' ' + (cd super && + git submodule set-branch -d submodule && + test_must_fail grep branch .gitmodules && + git submodule update --remote && + cat <<-\EOF >expect && + a + EOF + git -C submodule show -s --pretty=%s >actual && + test_cmp expect actual + ) +' + +test_done diff --git a/t/t7517-per-repo-email.sh b/t/t7517-per-repo-email.sh index 231b8cc19d..b2401cec3e 100755 --- a/t/t7517-per-repo-email.sh +++ b/t/t7517-per-repo-email.sh @@ -85,4 +85,78 @@ test_expect_success REBASE_P \ test_must_fail git rebase -p master ' +test_expect_success 'author.name overrides user.name' ' + test_config user.name user && + test_config user.email user@example.com && + test_config author.name author && + test_commit author-name-override-user && + echo author user@example.com > expected-author && + echo user user@example.com > expected-committer && + git log --format="%an %ae" -1 > actual-author && + git log --format="%cn %ce" -1 > actual-committer && + test_cmp expected-author actual-author && + test_cmp expected-committer actual-committer +' + +test_expect_success 'author.email overrides user.email' ' + test_config user.name user && + test_config user.email user@example.com && + test_config author.email author@example.com && + test_commit author-email-override-user && + echo user author@example.com > expected-author && + echo user user@example.com > expected-committer && + git log --format="%an %ae" -1 > actual-author && + git log --format="%cn %ce" -1 > actual-committer && + test_cmp expected-author actual-author && + test_cmp expected-committer actual-committer +' + +test_expect_success 'committer.name overrides user.name' ' + test_config user.name user && + test_config user.email user@example.com && + test_config committer.name committer && + test_commit committer-name-override-user && + echo user user@example.com > expected-author && + echo committer user@example.com > expected-committer && + git log --format="%an %ae" -1 > actual-author && + git log --format="%cn %ce" -1 > actual-committer && + test_cmp expected-author actual-author && + test_cmp expected-committer actual-committer +' + +test_expect_success 'committer.email overrides user.email' ' + test_config user.name user && + test_config user.email user@example.com && + test_config committer.email committer@example.com && + test_commit committer-email-override-user && + echo user user@example.com > expected-author && + echo user committer@example.com > expected-committer && + git log --format="%an %ae" -1 > actual-author && + git log --format="%cn %ce" -1 > actual-committer && + test_cmp expected-author actual-author && + test_cmp expected-committer actual-committer +' + +test_expect_success 'author and committer environment variables override config settings' ' + test_config user.name user && + test_config user.email user@example.com && + test_config author.name author && + test_config author.email author@example.com && + test_config committer.name committer && + test_config committer.email committer@example.com && + GIT_AUTHOR_NAME=env_author && export GIT_AUTHOR_NAME && + GIT_AUTHOR_EMAIL=env_author@example.com && export GIT_AUTHOR_EMAIL && + GIT_COMMITTER_NAME=env_commit && export GIT_COMMITTER_NAME && + GIT_COMMITTER_EMAIL=env_commit@example.com && export GIT_COMMITTER_EMAIL && + test_commit env-override-conf && + echo env_author env_author@example.com > expected-author && + echo env_commit env_commit@example.com > expected-committer && + git log --format="%an %ae" -1 > actual-author && + git log --format="%cn %ce" -1 > actual-committer && + sane_unset GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL && + sane_unset GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL && + test_cmp expected-author actual-author && + test_cmp expected-committer actual-committer +' + test_done diff --git a/t/t7525-status-rename.sh b/t/t7525-status-rename.sh index ef8b1b3078..a62736dce0 100755 --- a/t/t7525-status-rename.sh +++ b/t/t7525-status-rename.sh @@ -84,7 +84,7 @@ test_expect_success 'status score=100%' ' test_i18ngrep "deleted:" actual && test_i18ngrep "new file:" actual && - git status --find-rename=100% >actual && + git status --find-renames=100% >actual && test_i18ngrep "deleted:" actual && test_i18ngrep "new file:" actual ' @@ -93,11 +93,11 @@ test_expect_success 'status score=01%' ' git status -M=01% >actual && test_i18ngrep "renamed:" actual && - git status --find-rename=01% >actual && + git status --find-renames=01% >actual && test_i18ngrep "renamed:" actual ' -test_expect_success 'copies not overridden by find-rename' ' +test_expect_success 'copies not overridden by find-renames' ' cp renamed copy && git add copy && @@ -105,7 +105,7 @@ test_expect_success 'copies not overridden by find-rename' ' test_i18ngrep "copied:" actual && test_i18ngrep "renamed:" actual && - git -c status.renames=copies status --find-rename=01% >actual && + git -c status.renames=copies status --find-renames=01% >actual && test_i18ngrep "copied:" actual && test_i18ngrep "renamed:" actual ' diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh index 22b9199d59..480dd0633f 100755 --- a/t/t7800-difftool.sh +++ b/t/t7800-difftool.sh @@ -546,7 +546,7 @@ do done >actual EOF -test_expect_success SYMLINKS 'difftool --dir-diff --symlink without unstaged changes' ' +test_expect_success SYMLINKS 'difftool --dir-diff --symlinks without unstaged changes' ' cat >expect <<-EOF && file $PWD/file @@ -555,7 +555,7 @@ test_expect_success SYMLINKS 'difftool --dir-diff --symlink without unstaged cha sub/sub $PWD/sub/sub EOF - git difftool --dir-diff --symlink \ + git difftool --dir-diff --symlinks \ --extcmd "./.git/CHECK_SYMLINKS" branch HEAD && test_cmp expect actual ' @@ -705,4 +705,14 @@ test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' ' test_cmp expect actual ' +test_expect_success 'outside worktree' ' + echo 1 >1 && + echo 2 >2 && + test_expect_code 1 nongit git \ + -c diff.tool=echo -c difftool.echo.cmd="echo \$LOCAL \$REMOTE" \ + difftool --no-prompt --no-index ../1 ../2 >actual && + echo "../1 ../2" >expect && + test_cmp expect actual +' + test_done diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index 43aa4161cf..2e1bb61b41 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -119,33 +119,33 @@ do test_cmp expected actual ' - test_expect_success "grep -w $L (with --column, --invert)" ' + test_expect_success "grep -w $L (with --column, --invert-match)" ' { echo ${HC}file:1:foo mmap bar echo ${HC}file:1:foo_mmap bar echo ${HC}file:1:foo_mmap bar mmap echo ${HC}file:1:foo mmap bar_mmap } >expected && - git grep --column --invert -w -e baz $H -- file >actual && + git grep --column --invert-match -w -e baz $H -- file >actual && test_cmp expected actual ' - test_expect_success "grep $L (with --column, --invert, extended OR)" ' + test_expect_success "grep $L (with --column, --invert-match, extended OR)" ' { echo ${HC}hello_world:6:HeLLo_world } >expected && - git grep --column --invert -e ll --or --not -e _ $H -- hello_world \ + git grep --column --invert-match -e ll --or --not -e _ $H -- hello_world \ >actual && test_cmp expected actual ' - test_expect_success "grep $L (with --column, --invert, extended AND)" ' + test_expect_success "grep $L (with --column, --invert-match, extended AND)" ' { echo ${HC}hello_world:3:Hello world echo ${HC}hello_world:3:Hello_world echo ${HC}hello_world:6:HeLLo_world } >expected && - git grep --column --invert --not -e _ --and --not -e ll $H -- hello_world \ + git grep --column --invert-match --not -e _ --and --not -e ll $H -- hello_world \ >actual && test_cmp expected actual ' @@ -1010,7 +1010,7 @@ test_expect_success 'outside of git repository' ' echo ".gitignore:.*o*" && cat ../expect.full } >../expect.with.ignored && - git grep --no-index --no-exclude o >../actual.full && + git grep --no-index --no-exclude-standard o >../actual.full && test_cmp ../expect.with.ignored ../actual.full ) ' @@ -1051,7 +1051,7 @@ test_expect_success 'outside of git repository with fallbackToNoIndex' ' echo ".gitignore:.*o*" && cat ../expect.full } >../expect.with.ignored && - git -c grep.fallbackToNoIndex grep --no-exclude o >../actual.full && + git -c grep.fallbackToNoIndex grep --no-exclude-standard o >../actual.full && test_cmp ../expect.with.ignored ../actual.full ) ' diff --git a/t/t9115-git-svn-dcommit-funky-renames.sh b/t/t9115-git-svn-dcommit-funky-renames.sh index 64bb495834..9b44a44bc1 100755 --- a/t/t9115-git-svn-dcommit-funky-renames.sh +++ b/t/t9115-git-svn-dcommit-funky-renames.sh @@ -120,6 +120,4 @@ test_expect_success !MINGW,!UTF8_NFD_TO_NFC 'svn.pathnameencoding=cp932 rename o git svn dcommit ' -stop_httpd - test_done diff --git a/t/t9118-git-svn-funky-branch-names.sh b/t/t9118-git-svn-funky-branch-names.sh index 41a026637f..a159ff96b7 100755 --- a/t/t9118-git-svn-funky-branch-names.sh +++ b/t/t9118-git-svn-funky-branch-names.sh @@ -87,6 +87,4 @@ test_expect_success 'test dcommit to trailing_dotlock branch' ' ) ' -stop_httpd - test_done diff --git a/t/t9120-git-svn-clone-with-percent-escapes.sh b/t/t9120-git-svn-clone-with-percent-escapes.sh index b28a1741e3..40b714df31 100755 --- a/t/t9120-git-svn-clone-with-percent-escapes.sh +++ b/t/t9120-git-svn-clone-with-percent-escapes.sh @@ -74,6 +74,4 @@ test_expect_success 'test clone -s with unescaped space' ' ) ' -stop_httpd - test_done diff --git a/t/t9142-git-svn-shallow-clone.sh b/t/t9142-git-svn-shallow-clone.sh index 9ee23be640..a30730502d 100755 --- a/t/t9142-git-svn-shallow-clone.sh +++ b/t/t9142-git-svn-shallow-clone.sh @@ -26,6 +26,4 @@ test_expect_success 'clone trunk with "-r HEAD"' ' ( cd g && git rev-parse --symbolic --verify HEAD ) ' -stop_httpd - test_done diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 59a13b6a77..3668263c40 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -3262,4 +3262,41 @@ test_expect_success PIPE 'V: checkpoint updates tags after tag' ' background_import_still_running ' +### +### series W (get-mark and empty orphan commits) +### + +cat >>W-input <<-W_INPUT_END + commit refs/heads/W-branch + mark :1 + author Full Name <user@company.tld> 1000000000 +0100 + committer Full Name <user@company.tld> 1000000000 +0100 + data 27 + Intentionally empty commit + LFsget-mark :1 + W_INPUT_END + +test_expect_success !MINGW 'W: get-mark & empty orphan commit with no newlines' ' + sed -e s/LFs// W-input | tr L "\n" | git fast-import +' + +test_expect_success !MINGW 'W: get-mark & empty orphan commit with one newline' ' + sed -e s/LFs/L/ W-input | tr L "\n" | git fast-import +' + +test_expect_success !MINGW 'W: get-mark & empty orphan commit with ugly second newline' ' + # Technically, this should fail as it has too many linefeeds + # according to the grammar in fast-import.txt. But, for whatever + # reason, it works. Since using the correct number of newlines + # does not work with older (pre-2.22) versions of git, allow apps + # that used this second-newline workaround to keep working by + # checking it with this test... + sed -e s/LFs/LL/ W-input | tr L "\n" | git fast-import +' + +test_expect_success !MINGW 'W: get-mark & empty orphan commit with erroneous third newline' ' + # ...but do NOT allow more empty lines than that (see previous test). + sed -e s/LFs/LLL/ W-input | tr L "\n" | test_must_fail git fast-import +' + test_done diff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh index 729cd25770..5856563068 100755 --- a/t/t9800-git-p4-basic.sh +++ b/t/t9800-git-p4-basic.sh @@ -326,8 +326,4 @@ test_expect_success 'submit from worktree' ' ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9801-git-p4-branch.sh b/t/t9801-git-p4-branch.sh index 6a86d6996b..38d6b9043b 100755 --- a/t/t9801-git-p4-branch.sh +++ b/t/t9801-git-p4-branch.sh @@ -151,7 +151,7 @@ test_expect_success 'import depot, branch detection, branchList branch definitio ' test_expect_success 'restart p4d' ' - kill_p4d && + stop_and_cleanup_p4d && start_p4d ' @@ -505,7 +505,7 @@ test_expect_success 'use-client-spec detect-branches skips files in branches' ' ' test_expect_success 'restart p4d' ' - kill_p4d && + stop_and_cleanup_p4d && start_p4d ' @@ -610,8 +610,4 @@ test_expect_success 'Update a file in git side and submit to P4 using client vie ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9802-git-p4-filetype.sh b/t/t9802-git-p4-filetype.sh index 9978352d78..94edebe272 100755 --- a/t/t9802-git-p4-filetype.sh +++ b/t/t9802-git-p4-filetype.sh @@ -333,8 +333,4 @@ test_expect_success SYMLINKS 'empty symlink target' ' ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9803-git-p4-shell-metachars.sh b/t/t9803-git-p4-shell-metachars.sh index d5c3675100..2913277013 100755 --- a/t/t9803-git-p4-shell-metachars.sh +++ b/t/t9803-git-p4-shell-metachars.sh @@ -105,8 +105,4 @@ test_expect_success 'branch with shell char' ' ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9804-git-p4-label.sh b/t/t9804-git-p4-label.sh index e30f80e617..3236457106 100755 --- a/t/t9804-git-p4-label.sh +++ b/t/t9804-git-p4-label.sh @@ -108,8 +108,4 @@ test_expect_failure 'two labels on the same changelist' ' ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9805-git-p4-skip-submit-edit.sh b/t/t9805-git-p4-skip-submit-edit.sh index 5fbf904dc8..90ef647db7 100755 --- a/t/t9805-git-p4-skip-submit-edit.sh +++ b/t/t9805-git-p4-skip-submit-edit.sh @@ -98,8 +98,4 @@ test_expect_success 'no config, edited' ' ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9806-git-p4-options.sh b/t/t9806-git-p4-options.sh index 3f5291b857..4e794a01bf 100755 --- a/t/t9806-git-p4-options.sh +++ b/t/t9806-git-p4-options.sh @@ -300,9 +300,4 @@ test_expect_success 'use --git-dir option and GIT_DIR' ' test_path_is_file "$git"/cli_file2.t ' - -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9807-git-p4-submit.sh b/t/t9807-git-p4-submit.sh index 850d979119..eaaae414a1 100755 --- a/t/t9807-git-p4-submit.sh +++ b/t/t9807-git-p4-submit.sh @@ -593,8 +593,4 @@ test_expect_success 'update a shelve involving moved and copied files' ' ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9808-git-p4-chdir.sh b/t/t9808-git-p4-chdir.sh index 11d2b5102c..58a9b3b71e 100755 --- a/t/t9808-git-p4-chdir.sh +++ b/t/t9808-git-p4-chdir.sh @@ -83,8 +83,4 @@ test_expect_success SYMLINKS 'p4 client root symlink should stay symbolic' ' ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9809-git-p4-client-view.sh b/t/t9809-git-p4-client-view.sh index 897b3c3034..3cff1fce1b 100755 --- a/t/t9809-git-p4-client-view.sh +++ b/t/t9809-git-p4-client-view.sh @@ -836,8 +836,4 @@ test_expect_success 'quotes on both sides' ' git_verify "cdir 1/file11" "cdir 1/file12" ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9810-git-p4-rcs.sh b/t/t9810-git-p4-rcs.sh index cc53debe19..57b533dc6f 100755 --- a/t/t9810-git-p4-rcs.sh +++ b/t/t9810-git-p4-rcs.sh @@ -360,8 +360,4 @@ test_expect_failure 'Add keywords in git which do not match the default p4 value ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9811-git-p4-label-import.sh b/t/t9811-git-p4-label-import.sh index 602b0a5d5c..c1446f26ab 100755 --- a/t/t9811-git-p4-label-import.sh +++ b/t/t9811-git-p4-label-import.sh @@ -191,7 +191,7 @@ test_expect_success 'tag that cannot be exported' ' ( cd "$cli" && p4 sync ... && - !(p4 labels | grep GIT_TAG_ON_A_BRANCH) + ! p4 labels | grep GIT_TAG_ON_A_BRANCH ) ' @@ -259,9 +259,4 @@ test_expect_success 'importing labels with missing revisions' ' ) ' - -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9812-git-p4-wildcards.sh b/t/t9812-git-p4-wildcards.sh index 0206771fbb..254a7c2446 100755 --- a/t/t9812-git-p4-wildcards.sh +++ b/t/t9812-git-p4-wildcards.sh @@ -211,8 +211,4 @@ test_expect_success 'wildcard files requiring keyword scrub' ' ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9813-git-p4-preserve-users.sh b/t/t9813-git-p4-preserve-users.sh index 783c6ad165..fd018c87a8 100755 --- a/t/t9813-git-p4-preserve-users.sh +++ b/t/t9813-git-p4-preserve-users.sh @@ -138,8 +138,4 @@ test_expect_success 'not preserving user with mixed authorship' ' ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9814-git-p4-rename.sh b/t/t9814-git-p4-rename.sh index 60baa06e27..468767cbf4 100755 --- a/t/t9814-git-p4-rename.sh +++ b/t/t9814-git-p4-rename.sh @@ -242,8 +242,4 @@ test_expect_success P4D_HAVE_CONFIGURABLE_RUN_MOVE_ALLOW \ ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9815-git-p4-submit-fail.sh b/t/t9815-git-p4-submit-fail.sh index eaf03a6563..9779dc0d11 100755 --- a/t/t9815-git-p4-submit-fail.sh +++ b/t/t9815-git-p4-submit-fail.sh @@ -422,8 +422,4 @@ test_expect_success 'cleanup chmod after submit cancel' ' ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9816-git-p4-locked.sh b/t/t9816-git-p4-locked.sh index d048bd33fa..932841003c 100755 --- a/t/t9816-git-p4-locked.sh +++ b/t/t9816-git-p4-locked.sh @@ -138,8 +138,4 @@ test_expect_failure 'move with lock taken' ' ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9817-git-p4-exclude.sh b/t/t9817-git-p4-exclude.sh index aac568eadf..96d25f0c02 100755 --- a/t/t9817-git-p4-exclude.sh +++ b/t/t9817-git-p4-exclude.sh @@ -64,8 +64,4 @@ test_expect_success 'clone, then sync with exclude' ' ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9818-git-p4-block.sh b/t/t9818-git-p4-block.sh index ce7cb22ad3..0db7ab9918 100755 --- a/t/t9818-git-p4-block.sh +++ b/t/t9818-git-p4-block.sh @@ -146,8 +146,4 @@ test_expect_success 'Clone repo with self-sizing block size' ' test_line_count \> 10 log ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9819-git-p4-case-folding.sh b/t/t9819-git-p4-case-folding.sh index d808c008c1..600ce1e0b0 100755 --- a/t/t9819-git-p4-case-folding.sh +++ b/t/t9819-git-p4-case-folding.sh @@ -53,8 +53,4 @@ test_expect_failure 'Clone UC repo with lc name' ' test_must_fail git p4 clone //depot/uc/... ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9820-git-p4-editor-handling.sh b/t/t9820-git-p4-editor-handling.sh index 3c22f74bd4..fa1bba1dd9 100755 --- a/t/t9820-git-p4-editor-handling.sh +++ b/t/t9820-git-p4-editor-handling.sh @@ -31,8 +31,4 @@ test_expect_success 'EDITOR with options' ' ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9821-git-p4-path-variations.sh b/t/t9821-git-p4-path-variations.sh index 81e46acfa8..ef80f1690b 100755 --- a/t/t9821-git-p4-path-variations.sh +++ b/t/t9821-git-p4-path-variations.sh @@ -193,8 +193,4 @@ test_expect_success 'Add a new file and clone path with new file (ignorecase)' ' ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9822-git-p4-path-encoding.sh b/t/t9822-git-p4-path-encoding.sh index c78477c19b..1bf7635016 100755 --- a/t/t9822-git-p4-path-encoding.sh +++ b/t/t9822-git-p4-path-encoding.sh @@ -67,8 +67,4 @@ test_expect_success 'Delete iso8859-1 encoded paths and clone' ' ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9823-git-p4-mock-lfs.sh b/t/t9823-git-p4-mock-lfs.sh index 1f2dc369bf..88b76dc4d6 100755 --- a/t/t9823-git-p4-mock-lfs.sh +++ b/t/t9823-git-p4-mock-lfs.sh @@ -185,8 +185,4 @@ test_expect_success 'Run git p4 submit in repo configured with large file system ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9824-git-p4-git-lfs.sh b/t/t9824-git-p4-git-lfs.sh index ed80ca858c..a28dbbdd56 100755 --- a/t/t9824-git-p4-git-lfs.sh +++ b/t/t9824-git-p4-git-lfs.sh @@ -287,8 +287,4 @@ test_expect_success 'Add big files to repo and store files in LFS based on compr ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9825-git-p4-handle-utf16-without-bom.sh b/t/t9825-git-p4-handle-utf16-without-bom.sh index 1551845dc1..f049ff8229 100755 --- a/t/t9825-git-p4-handle-utf16-without-bom.sh +++ b/t/t9825-git-p4-handle-utf16-without-bom.sh @@ -43,8 +43,4 @@ test_expect_failure 'clone depot with invalid UTF-16 file in non-verbose mode' ' git p4 clone --dest="$git" //depot ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9826-git-p4-keep-empty-commits.sh b/t/t9826-git-p4-keep-empty-commits.sh index fa8b9daf1f..fd64afe064 100755 --- a/t/t9826-git-p4-keep-empty-commits.sh +++ b/t/t9826-git-p4-keep-empty-commits.sh @@ -127,8 +127,4 @@ test_expect_success 'Clone repo subdir with all history' ' ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9827-git-p4-change-filetype.sh b/t/t9827-git-p4-change-filetype.sh index 7433998f47..d3670bd7a2 100755 --- a/t/t9827-git-p4-change-filetype.sh +++ b/t/t9827-git-p4-change-filetype.sh @@ -59,8 +59,4 @@ test_expect_success SYMLINKS 'change symbolic link to file' ' ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9828-git-p4-map-user.sh b/t/t9828-git-p4-map-user.sh index e20395c89f..ca6c2942bd 100755 --- a/t/t9828-git-p4-map-user.sh +++ b/t/t9828-git-p4-map-user.sh @@ -54,8 +54,4 @@ test_expect_success 'Clone repo root path with all history' ' ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9829-git-p4-jobs.sh b/t/t9829-git-p4-jobs.sh index 971aeeea1f..88cfb1fcd3 100755 --- a/t/t9829-git-p4-jobs.sh +++ b/t/t9829-git-p4-jobs.sh @@ -92,8 +92,4 @@ test_expect_success 'check log message of changelist with more jobs' ' ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9830-git-p4-symlink-dir.sh b/t/t9830-git-p4-symlink-dir.sh index 2ad1b0810d..3fb6960c18 100755 --- a/t/t9830-git-p4-symlink-dir.sh +++ b/t/t9830-git-p4-symlink-dir.sh @@ -36,8 +36,4 @@ test_expect_success 'symlinked directory' ' ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9831-git-p4-triggers.sh b/t/t9831-git-p4-triggers.sh index be44c9751a..d743ca33ee 100755 --- a/t/t9831-git-p4-triggers.sh +++ b/t/t9831-git-p4-triggers.sh @@ -96,8 +96,4 @@ test_expect_success 'submit description with extra info lines from verbose p4 ch ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - test_done diff --git a/t/t9832-unshelve.sh b/t/t9832-unshelve.sh index 41c09f11f4..1286a5b824 100755 --- a/t/t9832-unshelve.sh +++ b/t/t9832-unshelve.sh @@ -174,8 +174,5 @@ test_expect_success 'unshelve specifying the origin' ' test_path_is_file file_to_shelve ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' test_done diff --git a/t/t9833-errors.sh b/t/t9833-errors.sh index 47b312e1c9..e22369ccdf 100755 --- a/t/t9833-errors.sh +++ b/t/t9833-errors.sh @@ -45,9 +45,4 @@ test_expect_success 'ticket logged out' ' ) ' -test_expect_success 'kill p4d' ' - kill_p4d -' - - test_done diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 3a2c6326d8..43cf313a1c 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -1437,6 +1437,7 @@ test_expect_success 'double dash "git checkout"' ' --guess Z --no-guess Z --no-... Z + --overlay Z EOF ' @@ -1483,6 +1484,12 @@ test_expect_success 'git --help completion' ' test_completion "git --help core" "core-tutorial " ' +test_expect_success 'completion.commands removes multiple commands' ' + test_config completion.commands "-cherry -mergetool" && + git --list-cmds=list-mainporcelain,list-complete,config >out && + ! grep -E "^(cherry|mergetool)$" out +' + test_expect_success 'setup for integration tests' ' echo content >file1 && echo more >file2 && diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index 80402a428f..788ea1f18b 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -593,6 +593,15 @@ test_dir_is_empty () { fi } +# Check if the file exists and has a size greater than zero +test_file_not_empty () { + if ! test -s "$1" + then + echo "'$1' is not a non-empty file." + false + fi +} + test_path_is_missing () { if test -e "$1" then @@ -934,6 +943,34 @@ test_when_finished () { } && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup" } +# This function can be used to schedule some commands to be run +# unconditionally at the end of the test script, e.g. to stop a daemon: +# +# test_expect_success 'test git daemon' ' +# git daemon & +# daemon_pid=$! && +# test_atexit 'kill $daemon_pid' && +# hello world +# ' +# +# The commands will be executed before the trash directory is removed, +# i.e. the atexit commands will still be able to access any pidfiles or +# socket files. +# +# Note that these commands will be run even when a test script run +# with '--immediate' fails. Be careful with your atexit commands to +# minimize any changes to the failed state. + +test_atexit () { + # We cannot detect when we are in a subshell in general, but by + # doing so on Bash is better than nothing (the test will + # silently pass on other shells). + test "${BASH_SUBSHELL-0}" = 0 || + error "bug in test script: test_atexit does nothing in a subshell" + test_atexit_cleanup="{ $* + } && (exit \"\$eval_ret\"); eval_ret=\$?; $test_atexit_cleanup" +} + # Most tests can use the created repository, but some may need to create more. # Usage: test_create_repo <directory> test_create_repo () { diff --git a/t/test-lib.sh b/t/test-lib.sh index 8665b0a9b6..d18387c255 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -57,6 +57,13 @@ fi . "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS export PERL_PATH SHELL_PATH +# Disallow the use of abbreviated options in the test suite by default +if test -z "${GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS}" +then + GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=true + export GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS +fi + ################################################################ # It appears that people try to run tests without building... "${GIT_TEST_INSTALLED:-$GIT_BUILD_DIR}/git$X" >/dev/null @@ -147,10 +154,16 @@ do --stress) stress=t ;; --stress=*) + echo "error: --stress does not accept an argument: '$opt'" >&2 + echo "did you mean --stress-jobs=${opt#*=} or --stress-limit=${opt#*=}?" >&2 + exit 1 + ;; + --stress-jobs=*) + stress=t; stress=${opt#--*=} case "$stress" in *[!0-9]*|0*|"") - echo "error: --stress=<N> requires the number of jobs to run" >&2 + echo "error: --stress-jobs=<N> requires the number of jobs to run" >&2 exit 1 ;; *) # Good. @@ -158,6 +171,7 @@ do esac ;; --stress-limit=*) + stress=t; stress_limit=${opt#--*=} case "$stress_limit" in *[!0-9]*|0*|"") @@ -372,6 +386,7 @@ unset VISUAL EMAIL LANGUAGE COLUMNS $("$PERL_PATH" -e ' my @env = keys %ENV; my $ok = join("|", qw( TRACE + TR2_ DEBUG TEST .*_TEST @@ -620,6 +635,10 @@ test_external_has_tap=0 die () { code=$? + # This is responsible for running the atexit commands even when a + # test script run with '--immediate' fails, or when the user hits + # ctrl-C, i.e. when 'test_done' is not invoked at all. + test_atexit_handler || code=$? if test -n "$GIT_EXIT_OK" then exit $code @@ -631,7 +650,10 @@ die () { GIT_EXIT_OK= trap 'die' EXIT -trap 'exit $?' INT TERM HUP +# Disable '-x' tracing, because with some shells, notably dash, it +# prevents running the cleanup commands when a test script run with +# '--verbose-log -x' is interrupted. +trap '{ code=$?; set +x; } 2>/dev/null; exit $code' INT TERM HUP # The user-facing functions are loaded from a separate file so that # test_perf subshells can have them too @@ -1042,9 +1064,28 @@ write_junit_xml_testcase () { junit_have_testcase=t } +test_atexit_cleanup=: +test_atexit_handler () { + # In a succeeding test script 'test_atexit_handler' is invoked + # twice: first from 'test_done', then from 'die' in the trap on + # EXIT. + # This condition and resetting 'test_atexit_cleanup' below makes + # sure that the registered cleanup commands are run only once. + test : != "$test_atexit_cleanup" || return 0 + + setup_malloc_check + test_eval_ "$test_atexit_cleanup" + test_atexit_cleanup=: + teardown_malloc_check +} + test_done () { GIT_EXIT_OK=t + # Run the atexit commands _before_ the trash directory is + # removed, so the commands can access pidfiles and socket files. + test_atexit_handler + if test -n "$write_junit_xml" && test -n "$junit_xml_path" then test -n "$junit_have_testcase" || { @@ -1327,7 +1368,11 @@ then fi fi -# Provide an implementation of the 'yes' utility +# Provide an implementation of the 'yes' utility; the upper bound +# limit is there to help Windows that cannot stop this loop from +# wasting cycles when the downstream stops reading, so do not be +# tempted to turn it into an infinite loop. cf. 6129c930 ("test-lib: +# limit the output of the yes utility", 2016-02-02) yes () { if test $# = 0 then |