diff options
Diffstat (limited to 't')
161 files changed, 5586 insertions, 2022 deletions
@@ -366,6 +366,13 @@ excluded as so much relies on it, but this might change in the future. 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_PASSING_SANITIZE_LEAK=<boolean> when compiled with +SANITIZE=leak will run only those tests that have whitelisted +themselves as passing with no memory leaks. Tests can be whitelisted +by setting "TEST_PASSES_SANITIZE_LEAK=true" before sourcing +"test-lib.sh" itself at the top of the test script. This test mode is +used by the "linux-leaks" CI target. + GIT_TEST_PROTOCOL_VERSION=<n>, when set, makes 'protocol.version' default to n. @@ -425,6 +432,10 @@ GIT_TEST_MULTI_PACK_INDEX=<boolean>, when true, forces the multi-pack- index to be written after every 'git repack' command, and overrides the 'core.multiPackIndex' setting to true. +GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=<boolean>, when true, sets the +'--bitmap' option on all invocations of 'git multi-pack-index write', +and ignores pack-objects' '--write-bitmap-index'. + GIT_TEST_SIDEBAND_ALL=<boolean>, when true, overrides the 'uploadpack.allowSidebandAll' setting to true, and when false, forces fetch-pack to not request sideband-all (even if the server advertises @@ -448,6 +459,16 @@ GIT_TEST_CHECKOUT_WORKERS=<n> overrides the 'checkout.workers' setting to <n> and 'checkout.thresholdForParallelism' to 0, forcing the execution of the parallel-checkout code. +GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=<boolean>, when true, makes +registering submodule ODBs as alternates a fatal action. Support for +this environment variable can be removed once the migration to +explicitly providing repositories when accessing submodule objects is +complete (in which case we might want to replace this with a trace2 +call so that users can make it visible if accessing submodule objects +without an explicit repository still happens) or needs to be abandoned +for whatever reason (in which case the migrated codepaths still retain +their performance benefits). + Naming Tests ------------ @@ -753,7 +774,8 @@ Test harness library -------------------- There are a handful helper functions defined in the test harness -library for your script to use. +library for your script to use. Some of them are listed below; +see test-lib-functions.sh for the full list and their options. - test_expect_success [<prereq>] <message> <script> @@ -799,10 +821,12 @@ library for your script to use. argument. This is primarily meant for use during the development of a new test script. - - debug <git-command> + - debug [options] <git-command> Run a git command inside a debugger. This is primarily meant for - use when debugging a failing test script. + use when debugging a failing test script. With '-t', use your + original TERM instead of test-lib.sh's "dumb", so that your + debugger interface has colors. - test_done @@ -989,7 +1013,7 @@ library for your script to use. EOF - - test_pause + - test_pause [options] This command is useful for writing and debugging tests and must be removed before submitting. It halts the execution of the test and diff --git a/t/helper/test-bitmap.c b/t/helper/test-bitmap.c index 134a1e9d76..ff35f5999b 100644 --- a/t/helper/test-bitmap.c +++ b/t/helper/test-bitmap.c @@ -7,6 +7,11 @@ static int bitmap_list_commits(void) return test_bitmap_commits(the_repository); } +static int bitmap_dump_hashes(void) +{ + return test_bitmap_hashes(the_repository); +} + int cmd__bitmap(int argc, const char **argv) { setup_git_directory(); @@ -16,9 +21,12 @@ int cmd__bitmap(int argc, const char **argv) if (!strcmp(argv[1], "list-commits")) return bitmap_list_commits(); + if (!strcmp(argv[1], "dump-hashes")) + return bitmap_dump_hashes(); usage: - usage("\ttest-tool bitmap list-commits"); + usage("\ttest-tool bitmap list-commits\n" + "\ttest-tool bitmap dump-hashes"); return -1; } diff --git a/t/helper/test-dump-untracked-cache.c b/t/helper/test-dump-untracked-cache.c index cf0f2c7228..99010614f6 100644 --- a/t/helper/test-dump-untracked-cache.c +++ b/t/helper/test-dump-untracked-cache.c @@ -45,8 +45,10 @@ int cmd__dump_untracked_cache(int ac, const char **av) struct untracked_cache *uc; struct strbuf base = STRBUF_INIT; - /* Hack to avoid modifying the untracked cache when we read it */ - ignore_untracked_cache_config = 1; + /* Set core.untrackedCache=keep before setup_git_directory() */ + xsetenv("GIT_CONFIG_COUNT", "1", 1); + xsetenv("GIT_CONFIG_KEY_0", "core.untrackedCache", 1); + xsetenv("GIT_CONFIG_VALUE_0", "keep", 1); setup_git_directory(); if (read_cache() < 0) diff --git a/t/helper/test-mergesort.c b/t/helper/test-mergesort.c index c5cffaa4b7..ebf68f7de8 100644 --- a/t/helper/test-mergesort.c +++ b/t/helper/test-mergesort.c @@ -2,6 +2,12 @@ #include "cache.h" #include "mergesort.h" +static uint32_t minstd_rand(uint32_t *state) +{ + *state = (uint64_t)*state * 48271 % 2147483647; + return *state; +} + struct line { char *text; struct line *next; @@ -23,14 +29,12 @@ static int compare_strings(const void *a, const void *b) return strcmp(x->text, y->text); } -int cmd__mergesort(int argc, const char **argv) +static int sort_stdin(void) { struct line *line, *p = NULL, *lines = NULL; struct strbuf sb = STRBUF_INIT; - for (;;) { - if (strbuf_getwholeline(&sb, stdin, '\n')) - break; + while (!strbuf_getline(&sb, stdin)) { line = xmalloc(sizeof(struct line)); line->text = strbuf_detach(&sb, NULL); if (p) { @@ -46,8 +50,362 @@ int cmd__mergesort(int argc, const char **argv) lines = llist_mergesort(lines, get_next, set_next, compare_strings); while (lines) { - printf("%s", lines->text); + puts(lines->text); lines = lines->next; } return 0; } + +static void dist_sawtooth(int *arr, int n, int m) +{ + int i; + for (i = 0; i < n; i++) + arr[i] = i % m; +} + +static void dist_rand(int *arr, int n, int m) +{ + int i; + uint32_t seed = 1; + for (i = 0; i < n; i++) + arr[i] = minstd_rand(&seed) % m; +} + +static void dist_stagger(int *arr, int n, int m) +{ + int i; + for (i = 0; i < n; i++) + arr[i] = (i * m + i) % n; +} + +static void dist_plateau(int *arr, int n, int m) +{ + int i; + for (i = 0; i < n; i++) + arr[i] = (i < m) ? i : m; +} + +static void dist_shuffle(int *arr, int n, int m) +{ + int i, j, k; + uint32_t seed = 1; + for (i = j = 0, k = 1; i < n; i++) + arr[i] = minstd_rand(&seed) % m ? (j += 2) : (k += 2); +} + +#define DIST(name) { #name, dist_##name } + +static struct dist { + const char *name; + void (*fn)(int *arr, int n, int m); +} dist[] = { + DIST(sawtooth), + DIST(rand), + DIST(stagger), + DIST(plateau), + DIST(shuffle), +}; + +static const struct dist *get_dist_by_name(const char *name) +{ + int i; + for (i = 0; i < ARRAY_SIZE(dist); i++) { + if (!strcmp(dist[i].name, name)) + return &dist[i]; + } + return NULL; +} + +static void mode_copy(int *arr, int n) +{ + /* nothing */ +} + +static void mode_reverse(int *arr, int n) +{ + int i, j; + for (i = 0, j = n - 1; i < j; i++, j--) + SWAP(arr[i], arr[j]); +} + +static void mode_reverse_1st_half(int *arr, int n) +{ + mode_reverse(arr, n / 2); +} + +static void mode_reverse_2nd_half(int *arr, int n) +{ + int half = n / 2; + mode_reverse(arr + half, n - half); +} + +static int compare_ints(const void *av, const void *bv) +{ + const int *ap = av, *bp = bv; + int a = *ap, b = *bp; + return (a > b) - (a < b); +} + +static void mode_sort(int *arr, int n) +{ + QSORT(arr, n, compare_ints); +} + +static void mode_dither(int *arr, int n) +{ + int i; + for (i = 0; i < n; i++) + arr[i] += i % 5; +} + +static void unriffle(int *arr, int n, int *tmp) +{ + int i, j; + COPY_ARRAY(tmp, arr, n); + for (i = j = 0; i < n; i += 2) + arr[j++] = tmp[i]; + for (i = 1; i < n; i += 2) + arr[j++] = tmp[i]; +} + +static void unriffle_recursively(int *arr, int n, int *tmp) +{ + if (n > 1) { + int half = n / 2; + unriffle(arr, n, tmp); + unriffle_recursively(arr, half, tmp); + unriffle_recursively(arr + half, n - half, tmp); + } +} + +static void mode_unriffle(int *arr, int n) +{ + int *tmp; + ALLOC_ARRAY(tmp, n); + unriffle_recursively(arr, n, tmp); + free(tmp); +} + +static unsigned int prev_pow2(unsigned int n) +{ + unsigned int pow2 = 1; + while (pow2 * 2 < n) + pow2 *= 2; + return pow2; +} + +static void unriffle_recursively_skewed(int *arr, int n, int *tmp) +{ + if (n > 1) { + int pow2 = prev_pow2(n); + int rest = n - pow2; + unriffle(arr + pow2 - rest, rest * 2, tmp); + unriffle_recursively_skewed(arr, pow2, tmp); + unriffle_recursively_skewed(arr + pow2, rest, tmp); + } +} + +static void mode_unriffle_skewed(int *arr, int n) +{ + int *tmp; + ALLOC_ARRAY(tmp, n); + unriffle_recursively_skewed(arr, n, tmp); + free(tmp); +} + +#define MODE(name) { #name, mode_##name } + +static struct mode { + const char *name; + void (*fn)(int *arr, int n); +} mode[] = { + MODE(copy), + MODE(reverse), + MODE(reverse_1st_half), + MODE(reverse_2nd_half), + MODE(sort), + MODE(dither), + MODE(unriffle), + MODE(unriffle_skewed), +}; + +static const struct mode *get_mode_by_name(const char *name) +{ + int i; + for (i = 0; i < ARRAY_SIZE(mode); i++) { + if (!strcmp(mode[i].name, name)) + return &mode[i]; + } + return NULL; +} + +static int generate(int argc, const char **argv) +{ + const struct dist *dist = NULL; + const struct mode *mode = NULL; + int i, n, m, *arr; + + if (argc != 4) + return 1; + + dist = get_dist_by_name(argv[0]); + mode = get_mode_by_name(argv[1]); + n = strtol(argv[2], NULL, 10); + m = strtol(argv[3], NULL, 10); + if (!dist || !mode) + return 1; + + ALLOC_ARRAY(arr, n); + dist->fn(arr, n, m); + mode->fn(arr, n); + for (i = 0; i < n; i++) + printf("%08x\n", arr[i]); + free(arr); + return 0; +} + +static struct stats { + int get_next, set_next, compare; +} stats; + +struct number { + int value, rank; + struct number *next; +}; + +static void *get_next_number(const void *a) +{ + stats.get_next++; + return ((const struct number *)a)->next; +} + +static void set_next_number(void *a, void *b) +{ + stats.set_next++; + ((struct number *)a)->next = b; +} + +static int compare_numbers(const void *av, const void *bv) +{ + const struct number *an = av, *bn = bv; + int a = an->value, b = bn->value; + stats.compare++; + return (a > b) - (a < b); +} + +static void clear_numbers(struct number *list) +{ + while (list) { + struct number *next = list->next; + free(list); + list = next; + } +} + +static int test(const struct dist *dist, const struct mode *mode, int n, int m) +{ + int *arr; + size_t i; + struct number *curr, *list, **tail; + int is_sorted = 1; + int is_stable = 1; + const char *verdict; + int result = -1; + + ALLOC_ARRAY(arr, n); + dist->fn(arr, n, m); + mode->fn(arr, n); + for (i = 0, tail = &list; i < n; i++) { + curr = xmalloc(sizeof(*curr)); + curr->value = arr[i]; + curr->rank = i; + *tail = curr; + tail = &curr->next; + } + *tail = NULL; + + stats.get_next = stats.set_next = stats.compare = 0; + list = llist_mergesort(list, get_next_number, set_next_number, + compare_numbers); + + QSORT(arr, n, compare_ints); + for (i = 0, curr = list; i < n && curr; i++, curr = curr->next) { + if (arr[i] != curr->value) + is_sorted = 0; + if (curr->next && curr->value == curr->next->value && + curr->rank >= curr->next->rank) + is_stable = 0; + } + if (i < n) { + verdict = "too short"; + } else if (curr) { + verdict = "too long"; + } else if (!is_sorted) { + verdict = "not sorted"; + } else if (!is_stable) { + verdict = "unstable"; + } else { + verdict = "OK"; + result = 0; + } + + printf("%-9s %-16s %8d %8d %8d %8d %8d %s\n", + dist->name, mode->name, n, m, stats.get_next, stats.set_next, + stats.compare, verdict); + + clear_numbers(list); + free(arr); + + return result; +} + +/* + * A version of the qsort certification program from "Engineering a Sort + * Function" by Bentley and McIlroy, Software—Practice and Experience, + * Volume 23, Issue 11, 1249–1265 (November 1993). + */ +static int run_tests(int argc, const char **argv) +{ + const char *argv_default[] = { "100", "1023", "1024", "1025" }; + if (!argc) + return run_tests(ARRAY_SIZE(argv_default), argv_default); + printf("%-9s %-16s %8s %8s %8s %8s %8s %s\n", + "distribut", "mode", "n", "m", "get_next", "set_next", + "compare", "verdict"); + while (argc--) { + int i, j, m, n = strtol(*argv++, NULL, 10); + for (i = 0; i < ARRAY_SIZE(dist); i++) { + for (j = 0; j < ARRAY_SIZE(mode); j++) { + for (m = 1; m < 2 * n; m *= 2) { + if (test(&dist[i], &mode[j], n, m)) + return 1; + } + } + } + } + return 0; +} + +int cmd__mergesort(int argc, const char **argv) +{ + int i; + const char *sep; + + if (argc == 6 && !strcmp(argv[1], "generate")) + return generate(argc - 2, argv + 2); + if (argc == 2 && !strcmp(argv[1], "sort")) + return sort_stdin(); + if (argc > 1 && !strcmp(argv[1], "test")) + return run_tests(argc - 2, argv + 2); + fprintf(stderr, "usage: test-tool mergesort generate <distribution> <mode> <n> <m>\n"); + fprintf(stderr, " or: test-tool mergesort sort\n"); + fprintf(stderr, " or: test-tool mergesort test [<n>...]\n"); + fprintf(stderr, "\n"); + for (i = 0, sep = "distributions: "; i < ARRAY_SIZE(dist); i++, sep = ", ") + fprintf(stderr, "%s%s", sep, dist[i].name); + fprintf(stderr, "\n"); + for (i = 0, sep = "modes: "; i < ARRAY_SIZE(mode); i++, sep = ", ") + fprintf(stderr, "%s%s", sep, mode[i].name); + fprintf(stderr, "\n"); + return 129; +} diff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c index 2051ce57db..a282b6ff13 100644 --- a/t/helper/test-parse-options.c +++ b/t/helper/test-parse-options.c @@ -134,7 +134,6 @@ 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", NULL, "means --quux"), OPT_NUMBER_CALLBACK(&integer, "set integer to NUM", number_callback), { OPTION_COUNTUP, '+', NULL, &boolean, NULL, "same as -b", diff --git a/t/helper/test-read-midx.c b/t/helper/test-read-midx.c index 7c2eb11a8e..9d6fa7a377 100644 --- a/t/helper/test-read-midx.c +++ b/t/helper/test-read-midx.c @@ -3,6 +3,7 @@ #include "midx.h" #include "repository.h" #include "object-store.h" +#include "pack-bitmap.h" static int read_midx_file(const char *object_dir, int show_objects) { @@ -60,12 +61,52 @@ static int read_midx_file(const char *object_dir, int show_objects) return 0; } +static int read_midx_checksum(const char *object_dir) +{ + struct multi_pack_index *m; + + setup_git_directory(); + m = load_multi_pack_index(object_dir, 1); + if (!m) + return 1; + printf("%s\n", hash_to_hex(get_midx_checksum(m))); + return 0; +} + +static int read_midx_preferred_pack(const char *object_dir) +{ + struct multi_pack_index *midx = NULL; + struct bitmap_index *bitmap = NULL; + + setup_git_directory(); + + midx = load_multi_pack_index(object_dir, 1); + if (!midx) + return 1; + + bitmap = prepare_bitmap_git(the_repository); + if (!bitmap) + return 1; + if (!bitmap_is_midx(bitmap)) { + free_bitmap_index(bitmap); + return 1; + } + + printf("%s\n", midx->pack_names[midx_preferred_pack(bitmap)]); + free_bitmap_index(bitmap); + return 0; +} + int cmd__read_midx(int argc, const char **argv) { if (!(argc == 2 || argc == 3)) - usage("read-midx [--show-objects] <object-dir>"); + usage("read-midx [--show-objects|--checksum|--preferred-pack] <object-dir>"); if (!strcmp(argv[1], "--show-objects")) return read_midx_file(argv[2], 1); + else if (!strcmp(argv[1], "--checksum")) + return read_midx_checksum(argv[2]); + else if (!strcmp(argv[1], "--preferred-pack")) + return read_midx_preferred_pack(argv[2]); return read_midx_file(argv[1], 0); } diff --git a/t/helper/test-run-command.c b/t/helper/test-run-command.c index 7ae03dc712..3c4fb86223 100644 --- a/t/helper/test-run-command.c +++ b/t/helper/test-run-command.c @@ -60,8 +60,10 @@ struct testsuite { int next; int quiet, immediate, verbose, verbose_log, trace, write_junit_xml; }; -#define TESTSUITE_INIT \ - { STRING_LIST_INIT_DUP, STRING_LIST_INIT_DUP, -1, 0, 0, 0, 0, 0, 0 } +#define TESTSUITE_INIT { \ + .tests = STRING_LIST_INIT_DUP, \ + .failed = STRING_LIST_INIT_DUP, \ +} static int next_test(struct child_process *cp, struct strbuf *err, void *cb, void **task_cb) @@ -142,9 +144,6 @@ static int testsuite(int argc, const char **argv) OPT_END() }; - memset(&suite, 0, sizeof(suite)); - suite.tests.strdup_strings = suite.failed.strdup_strings = 1; - argc = parse_options(argc, argv, NULL, options, testsuite_usage, PARSE_OPT_STOP_AT_NON_OPTION); diff --git a/t/helper/test-serve-v2.c b/t/helper/test-serve-v2.c index aee35e5aef..28e905afc3 100644 --- a/t/helper/test-serve-v2.c +++ b/t/helper/test-serve-v2.c @@ -10,12 +10,12 @@ static char const * const serve_usage[] = { int cmd__serve_v2(int argc, const char **argv) { - struct serve_options opts = SERVE_OPTIONS_INIT; - + int stateless_rpc = 0; + int advertise_capabilities = 0; struct option options[] = { - OPT_BOOL(0, "stateless-rpc", &opts.stateless_rpc, + OPT_BOOL(0, "stateless-rpc", &stateless_rpc, N_("quit after a single request/response exchange")), - OPT_BOOL(0, "advertise-capabilities", &opts.advertise_capabilities, + OPT_BOOL(0, "advertise-capabilities", &advertise_capabilities, N_("exit immediately after advertising capabilities")), OPT_END() }; @@ -25,7 +25,11 @@ int cmd__serve_v2(int argc, const char **argv) argc = parse_options(argc, argv, prefix, options, serve_usage, PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN); - serve(&opts); + + if (advertise_capabilities) + protocol_v2_advertise_capabilities(); + else + protocol_v2_serve_loop(stateless_rpc); return 0; } diff --git a/t/helper/test-simple-ipc.c b/t/helper/test-simple-ipc.c index 42040ef81b..28365ff85b 100644 --- a/t/helper/test-simple-ipc.c +++ b/t/helper/test-simple-ipc.c @@ -9,6 +9,7 @@ #include "parse-options.h" #include "thread-utils.h" #include "strvec.h" +#include "run-command.h" #ifndef SUPPORTS_SIMPLE_IPC int cmd__simple_ipc(int argc, const char **argv) @@ -112,7 +113,7 @@ static int app__slow_command(ipc_server_reply_cb *reply_cb, /* * The client sent a command followed by a (possibly very) large buffer. */ -static int app__sendbytes_command(const char *received, +static int app__sendbytes_command(const char *received, size_t received_len, ipc_server_reply_cb *reply_cb, struct ipc_server_reply_data *reply_data) { @@ -123,6 +124,13 @@ static int app__sendbytes_command(const char *received, int errs = 0; int ret; + /* + * The test is setup to send: + * "sendbytes" SP <n * char> + */ + if (received_len < strlen("sendbytes ")) + BUG("received_len is short in app__sendbytes_command"); + if (skip_prefix(received, "sendbytes ", &p)) len_ballast = strlen(p); @@ -160,7 +168,7 @@ static ipc_server_application_cb test_app_cb; * by this application. */ static int test_app_cb(void *application_data, - const char *command, + const char *command, size_t command_len, ipc_server_reply_cb *reply_cb, struct ipc_server_reply_data *reply_data) { @@ -173,7 +181,7 @@ static int test_app_cb(void *application_data, if (application_data != (void*)&my_app_data) BUG("application_cb: application_data pointer wrong"); - if (!strcmp(command, "quit")) { + if (command_len == 4 && !strncmp(command, "quit", 4)) { /* * The client sent a "quit" command. This is an async * request for the server to shutdown. @@ -193,22 +201,23 @@ static int test_app_cb(void *application_data, return SIMPLE_IPC_QUIT; } - if (!strcmp(command, "ping")) { + if (command_len == 4 && !strncmp(command, "ping", 4)) { const char *answer = "pong"; return reply_cb(reply_data, answer, strlen(answer)); } - if (!strcmp(command, "big")) + if (command_len == 3 && !strncmp(command, "big", 3)) return app__big_command(reply_cb, reply_data); - if (!strcmp(command, "chunk")) + if (command_len == 5 && !strncmp(command, "chunk", 5)) return app__chunk_command(reply_cb, reply_data); - if (!strcmp(command, "slow")) + if (command_len == 4 && !strncmp(command, "slow", 4)) return app__slow_command(reply_cb, reply_data); - if (starts_with(command, "sendbytes ")) - return app__sendbytes_command(command, reply_cb, reply_data); + if (command_len >= 10 && starts_with(command, "sendbytes ")) + return app__sendbytes_command(command, command_len, + reply_cb, reply_data); return app__unhandled_command(command, reply_cb, reply_data); } @@ -259,186 +268,72 @@ static int daemon__run_server(void) */ ret = ipc_server_run(cl_args.path, &opts, test_app_cb, (void*)&my_app_data); if (ret == -2) - error(_("socket/pipe already in use: '%s'"), cl_args.path); + error("socket/pipe already in use: '%s'", cl_args.path); else if (ret == -1) - error_errno(_("could not start server on: '%s'"), cl_args.path); + error_errno("could not start server on: '%s'", cl_args.path); return ret; } -#ifndef GIT_WINDOWS_NATIVE -/* - * This is adapted from `daemonize()`. Use `fork()` to directly create and - * run the daemon in a child process. - */ -static int spawn_server(pid_t *pid) -{ - struct ipc_server_opts opts = { - .nr_threads = cl_args.nr_threads, - }; - - *pid = fork(); +static start_bg_wait_cb bg_wait_cb; - switch (*pid) { - case 0: - if (setsid() == -1) - error_errno(_("setsid failed")); - close(0); - close(1); - close(2); - sanitize_stdfds(); +static int bg_wait_cb(const struct child_process *cp, void *cb_data) +{ + int s = ipc_get_active_state(cl_args.path); - return ipc_server_run(cl_args.path, &opts, test_app_cb, - (void*)&my_app_data); + switch (s) { + case IPC_STATE__LISTENING: + /* child is "ready" */ + return 0; - case -1: - return error_errno(_("could not spawn daemon in the background")); + case IPC_STATE__NOT_LISTENING: + case IPC_STATE__PATH_NOT_FOUND: + /* give child more time */ + return 1; default: - return 0; + case IPC_STATE__INVALID_PATH: + case IPC_STATE__OTHER_ERROR: + /* all the time in world won't help */ + return -1; } } -#else -/* - * Conceptually like `daemonize()` but different because Windows does not - * have `fork(2)`. Spawn a normal Windows child process but without the - * limitations of `start_command()` and `finish_command()`. - */ -static int spawn_server(pid_t *pid) -{ - char test_tool_exe[MAX_PATH]; - struct strvec args = STRVEC_INIT; - int in, out; - - GetModuleFileNameA(NULL, test_tool_exe, MAX_PATH); - - in = open("/dev/null", O_RDONLY); - out = open("/dev/null", O_WRONLY); - - strvec_push(&args, test_tool_exe); - strvec_push(&args, "simple-ipc"); - strvec_push(&args, "run-daemon"); - strvec_pushf(&args, "--name=%s", cl_args.path); - strvec_pushf(&args, "--threads=%d", cl_args.nr_threads); - *pid = mingw_spawnvpe(args.v[0], args.v, NULL, NULL, in, out, out); - close(in); - close(out); - - strvec_clear(&args); - - if (*pid < 0) - return error(_("could not spawn daemon in the background")); - - return 0; -} -#endif - -/* - * This is adapted from `wait_or_whine()`. Watch the child process and - * let it get started and begin listening for requests on the socket - * before reporting our success. - */ -static int wait_for_server_startup(pid_t pid_child) +static int daemon__start_server(void) { - int status; - pid_t pid_seen; - enum ipc_active_state s; - time_t time_limit, now; + struct child_process cp = CHILD_PROCESS_INIT; + enum start_bg_result sbgr; - time(&time_limit); - time_limit += cl_args.max_wait_sec; + strvec_push(&cp.args, "test-tool"); + strvec_push(&cp.args, "simple-ipc"); + strvec_push(&cp.args, "run-daemon"); + strvec_pushf(&cp.args, "--name=%s", cl_args.path); + strvec_pushf(&cp.args, "--threads=%d", cl_args.nr_threads); - for (;;) { - pid_seen = waitpid(pid_child, &status, WNOHANG); - - if (pid_seen == -1) - return error_errno(_("waitpid failed")); - - else if (pid_seen == 0) { - /* - * The child is still running (this should be - * the normal case). Try to connect to it on - * the socket and see if it is ready for - * business. - * - * If there is another daemon already running, - * our child will fail to start (possibly - * after a timeout on the lock), but we don't - * care (who responds) if the socket is live. - */ - s = ipc_get_active_state(cl_args.path); - if (s == IPC_STATE__LISTENING) - return 0; + cp.no_stdin = 1; + cp.no_stdout = 1; + cp.no_stderr = 1; - time(&now); - if (now > time_limit) - return error(_("daemon not online yet")); + sbgr = start_bg_command(&cp, bg_wait_cb, NULL, cl_args.max_wait_sec); - continue; - } + switch (sbgr) { + case SBGR_READY: + return 0; - else if (pid_seen == pid_child) { - /* - * The new child daemon process shutdown while - * it was starting up, so it is not listening - * on the socket. - * - * Try to ping the socket in the odd chance - * that another daemon started (or was already - * running) while our child was starting. - * - * Again, we don't care who services the socket. - */ - s = ipc_get_active_state(cl_args.path); - if (s == IPC_STATE__LISTENING) - return 0; + default: + case SBGR_ERROR: + case SBGR_CB_ERROR: + return error("daemon failed to start"); - /* - * We don't care about the WEXITSTATUS() nor - * any of the WIF*(status) values because - * `cmd__simple_ipc()` does the `!!result` - * trick on all function return values. - * - * So it is sufficient to just report the - * early shutdown as an error. - */ - return error(_("daemon failed to start")); - } + case SBGR_TIMEOUT: + return error("daemon not online yet"); - else - return error(_("waitpid is confused")); + case SBGR_DIED: + return error("daemon terminated"); } } /* - * This process will start a simple-ipc server in a background process and - * wait for it to become ready. This is like `daemonize()` but gives us - * more control and better error reporting (and makes it easier to write - * unit tests). - */ -static int daemon__start_server(void) -{ - pid_t pid_child; - int ret; - - /* - * Run the actual daemon in a background process. - */ - ret = spawn_server(&pid_child); - if (pid_child <= 0) - return ret; - - /* - * Let the parent wait for the child process to get started - * and begin listening for requests on the socket. - */ - ret = wait_for_server_startup(pid_child); - - return ret; -} - -/* * This process will run a quick probe to see if a simple-ipc server * is active on this path. * @@ -488,7 +383,9 @@ static int client__send_ipc(void) options.wait_if_busy = 1; options.wait_if_not_found = 0; - if (!ipc_client_send_command(cl_args.path, &options, command, &buf)) { + if (!ipc_client_send_command(cl_args.path, &options, + command, strlen(command), + &buf)) { if (buf.len) { printf("%s\n", buf.buf); fflush(stdout); @@ -538,7 +435,7 @@ static int client__stop_server(void) time(&now); if (now > time_limit) - return error(_("daemon has not shutdown yet")); + return error("daemon has not shutdown yet"); } } @@ -556,7 +453,9 @@ static int do_sendbytes(int bytecount, char byte, const char *path, strbuf_addstr(&buf_send, "sendbytes "); strbuf_addchars(&buf_send, byte, bytecount); - if (!ipc_client_send_command(path, options, buf_send.buf, &buf_resp)) { + if (!ipc_client_send_command(path, options, + buf_send.buf, buf_send.len, + &buf_resp)) { strbuf_rtrim(&buf_resp); printf("sent:%c%08d %s\n", byte, bytecount, buf_resp.buf); fflush(stdout); diff --git a/t/helper/test-submodule-nested-repo-config.c b/t/helper/test-submodule-nested-repo-config.c index e3f11ff5a7..dc1c14bde3 100644 --- a/t/helper/test-submodule-nested-repo-config.c +++ b/t/helper/test-submodule-nested-repo-config.c @@ -11,15 +11,13 @@ static void die_usage(const char **argv, const char *msg) int cmd__submodule_nested_repo_config(int argc, const char **argv) { struct repository subrepo; - const struct submodule *sub; if (argc < 3) die_usage(argv, "Wrong number of arguments."); setup_git_directory(); - sub = submodule_from_path(the_repository, null_oid(), argv[1]); - if (repo_submodule_init(&subrepo, the_repository, sub)) { + if (repo_submodule_init(&subrepo, the_repository, argv[1], null_oid())) { die_usage(argv, "Submodule not found."); } diff --git a/t/lib-bitmap.sh b/t/lib-bitmap.sh index fe3f98be24..21d0392dda 100644 --- a/t/lib-bitmap.sh +++ b/t/lib-bitmap.sh @@ -1,3 +1,6 @@ +# Helpers for scripts testing bitmap functionality; see t5310 for +# example usage. + # Compare a file containing rev-list bitmap traversal output to its non-bitmap # counterpart. You can't just use test_cmp for this, because the two produce # subtly different output: @@ -24,3 +27,240 @@ test_bitmap_traversal () { test_cmp "$1.normalized" "$2.normalized" && rm -f "$1.normalized" "$2.normalized" } + +# To ensure the logic for "maximal commits" is exercised, make +# the repository a bit more complicated. +# +# other second +# * * +# (99 commits) (99 commits) +# * * +# |\ /| +# | * octo-other octo-second * | +# |/|\_________ ____________/|\| +# | \ \/ __________/ | +# | | ________/\ / | +# * |/ * merge-right * +# | _|__________/ \____________ | +# |/ | \| +# (l1) * * merge-left * (r1) +# | / \________________________ | +# |/ \| +# (l2) * * (r2) +# \___________________________ | +# \| +# * (base) +# +# We only push bits down the first-parent history, which +# makes some of these commits unimportant! +# +# The important part for the maximal commit algorithm is how +# the bitmasks are extended. Assuming starting bit positions +# for second (bit 0) and other (bit 1), the bitmasks at the +# end should be: +# +# second: 1 (maximal, selected) +# other: 01 (maximal, selected) +# (base): 11 (maximal) +# +# This complicated history was important for a previous +# version of the walk that guarantees never walking a +# commit multiple times. That goal might be important +# again, so preserve this complicated case. For now, this +# test will guarantee that the bitmaps are computed +# correctly, even with the repeat calculations. +setup_bitmap_history() { + test_expect_success 'setup repo with moderate-sized history' ' + test_commit_bulk --id=file 10 && + git branch -M second && + git checkout -b other HEAD~5 && + test_commit_bulk --id=side 10 && + + # add complicated history setup, including merges and + # ambiguous merge-bases + + git checkout -b merge-left other~2 && + git merge second~2 -m "merge-left" && + + git checkout -b merge-right second~1 && + git merge other~1 -m "merge-right" && + + git checkout -b octo-second second && + git merge merge-left merge-right -m "octopus-second" && + + git checkout -b octo-other other && + git merge merge-left merge-right -m "octopus-other" && + + git checkout other && + git merge octo-other -m "pull octopus" && + + git checkout second && + git merge octo-second -m "pull octopus" && + + # Remove these branches so they are not selected + # as bitmap tips + git branch -D merge-left && + git branch -D merge-right && + git branch -D octo-other && + git branch -D octo-second && + + # add padding to make these merges less interesting + # and avoid having them selected for bitmaps + test_commit_bulk --id=file 100 && + git checkout other && + test_commit_bulk --id=side 100 && + git checkout second && + + bitmaptip=$(git rev-parse second) && + blob=$(echo tagged-blob | git hash-object -w --stdin) && + git tag tagged-blob $blob + ' +} + +rev_list_tests_head () { + test_expect_success "counting commits via bitmap ($state, $branch)" ' + git rev-list --count $branch >expect && + git rev-list --use-bitmap-index --count $branch >actual && + test_cmp expect actual + ' + + test_expect_success "counting partial commits via bitmap ($state, $branch)" ' + git rev-list --count $branch~5..$branch >expect && + git rev-list --use-bitmap-index --count $branch~5..$branch >actual && + test_cmp expect actual + ' + + test_expect_success "counting commits with limit ($state, $branch)" ' + git rev-list --count -n 1 $branch >expect && + git rev-list --use-bitmap-index --count -n 1 $branch >actual && + test_cmp expect actual + ' + + test_expect_success "counting non-linear history ($state, $branch)" ' + git rev-list --count other...second >expect && + git rev-list --use-bitmap-index --count other...second >actual && + test_cmp expect actual + ' + + test_expect_success "counting commits with limiting ($state, $branch)" ' + git rev-list --count $branch -- 1.t >expect && + git rev-list --use-bitmap-index --count $branch -- 1.t >actual && + test_cmp expect actual + ' + + test_expect_success "counting objects via bitmap ($state, $branch)" ' + git rev-list --count --objects $branch >expect && + git rev-list --use-bitmap-index --count --objects $branch >actual && + test_cmp expect actual + ' + + test_expect_success "enumerate commits ($state, $branch)" ' + git rev-list --use-bitmap-index $branch >actual && + git rev-list $branch >expect && + test_bitmap_traversal --no-confirm-bitmaps expect actual + ' + + test_expect_success "enumerate --objects ($state, $branch)" ' + git rev-list --objects --use-bitmap-index $branch >actual && + git rev-list --objects $branch >expect && + test_bitmap_traversal expect actual + ' + + test_expect_success "bitmap --objects handles non-commit objects ($state, $branch)" ' + git rev-list --objects --use-bitmap-index $branch tagged-blob >actual && + grep $blob actual + ' +} + +rev_list_tests () { + state=$1 + + for branch in "second" "other" + do + rev_list_tests_head + done +} + +basic_bitmap_tests () { + tip="$1" + test_expect_success 'rev-list --test-bitmap verifies bitmaps' " + git rev-list --test-bitmap "${tip:-HEAD}" + " + + rev_list_tests 'full bitmap' + + test_expect_success 'clone from bitmapped repository' ' + rm -fr clone.git && + git clone --no-local --bare . clone.git && + git rev-parse HEAD >expect && + git --git-dir=clone.git rev-parse HEAD >actual && + test_cmp expect actual + ' + + test_expect_success 'partial clone from bitmapped repository' ' + test_config uploadpack.allowfilter true && + rm -fr partial-clone.git && + git clone --no-local --bare --filter=blob:none . partial-clone.git && + ( + cd partial-clone.git && + pack=$(echo objects/pack/*.pack) && + git verify-pack -v "$pack" >have && + awk "/blob/ { print \$1 }" <have >blobs && + # we expect this single blob because of the direct ref + git rev-parse refs/tags/tagged-blob >expect && + test_cmp expect blobs + ) + ' + + test_expect_success 'setup further non-bitmapped commits' ' + test_commit_bulk --id=further 10 + ' + + rev_list_tests 'partial bitmap' + + test_expect_success 'fetch (partial bitmap)' ' + git --git-dir=clone.git fetch origin second:second && + git rev-parse HEAD >expect && + git --git-dir=clone.git rev-parse HEAD >actual && + test_cmp expect actual + ' + + test_expect_success 'enumerating progress counts pack-reused objects' ' + count=$(git rev-list --objects --all --count) && + git repack -adb && + + # check first with only reused objects; confirm that our + # progress showed the right number, and also that we did + # pack-reuse as expected. Check only the final "done" + # line of the meter (there may be an arbitrary number of + # intermediate lines ending with CR). + GIT_PROGRESS_DELAY=0 \ + git pack-objects --all --stdout --progress \ + </dev/null >/dev/null 2>stderr && + grep "Enumerating objects: $count, done" stderr && + grep "pack-reused $count" stderr && + + # now the same but with one non-reused object + git commit --allow-empty -m "an extra commit object" && + GIT_PROGRESS_DELAY=0 \ + git pack-objects --all --stdout --progress \ + </dev/null >/dev/null 2>stderr && + grep "Enumerating objects: $((count+1)), done" stderr && + grep "pack-reused $count" stderr + ' +} + +# have_delta <obj> <expected_base> +# +# Note that because this relies on cat-file, it might find _any_ copy of an +# object in the repository. The caller is responsible for making sure +# there's only one (e.g., via "repack -ad", or having just fetched a copy). +have_delta () { + echo $2 >expect && + echo $1 | git cat-file --batch-check="%(deltabase)" >actual && + test_cmp expect actual +} + +midx_checksum () { + test-tool read-midx --checksum "$1" +} diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf index afa91e38b0..180a41fe96 100644 --- a/t/lib-httpd/apache.conf +++ b/t/lib-httpd/apache.conf @@ -81,8 +81,6 @@ PassEnv GIT_TRACE PassEnv GIT_CONFIG_NOSYSTEM PassEnv GIT_TEST_SIDEBAND_ALL -SetEnvIf Git-Protocol ".*" GIT_PROTOCOL=$0 - Alias /dumb/ www/ Alias /auth/dumb/ www/auth/dumb/ @@ -117,6 +115,11 @@ Alias /auth/dumb/ www/auth/dumb/ SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH} SetEnv GIT_HTTP_EXPORT_ALL </LocationMatch> +<LocationMatch /smart_v0/> + SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH} + SetEnv GIT_HTTP_EXPORT_ALL + SetEnv GIT_PROTOCOL +</LocationMatch> ScriptAlias /smart/incomplete_length/git-upload-pack incomplete-length-upload-pack-v2-http.sh/ ScriptAlias /smart/incomplete_body/git-upload-pack incomplete-body-upload-pack-v2-http.sh/ ScriptAliasMatch /error_git_upload_pack/(.*)/git-upload-pack error.sh/ diff --git a/t/lib-midx.sh b/t/lib-midx.sh new file mode 100644 index 0000000000..1261994744 --- /dev/null +++ b/t/lib-midx.sh @@ -0,0 +1,8 @@ +# test_midx_consistent <objdir> +test_midx_consistent () { + ls $1/pack/pack-*.idx | xargs -n 1 basename | sort >expect && + test-tool read-midx $1 | grep ^pack-.*\.idx$ | sort >actual && + + test_cmp expect actual && + git multi-pack-index --object-dir=$1 verify +} diff --git a/t/lib-rebase.sh b/t/lib-rebase.sh index dc75b83451..ec6b9b107d 100644 --- a/t/lib-rebase.sh +++ b/t/lib-rebase.sh @@ -151,3 +151,59 @@ test_editor_unchanged () { EOF test_cmp expect actual } + +# Set up an editor for testing reword commands +# Checks that there are no uncommitted changes when rewording and that the +# todo-list is reread after each +set_reword_editor () { + >reword-actual && + >reword-oid && + + # Check rewording keeps the original authorship + GIT_AUTHOR_NAME="Reword Author" + GIT_AUTHOR_EMAIL="reword.author@example.com" + GIT_AUTHOR_DATE=@123456 + + write_script reword-sequence-editor.sh <<-\EOF && + todo="$(cat "$1")" && + echo "exec git log -1 --pretty=format:'%an <%ae> %at%n%B%n' \ + >>reword-actual" >"$1" && + printf "%s\n" "$todo" >>"$1" + EOF + + write_script reword-editor.sh <<-EOF && + # Save the oid of the first reworded commit so we can check rebase + # fast-forwards to it. Also check that we do not write .git/MERGE_MSG + # when fast-forwarding + if ! test -s reword-oid + then + git rev-parse HEAD >reword-oid && + if test -f .git/MERGE_MSG + then + echo 1>&2 "error: .git/MERGE_MSG exists" + exit 1 + fi + fi && + # There should be no uncommited changes + git diff --exit-code HEAD && + # The todo-list should be re-read after a reword + GIT_SEQUENCE_EDITOR="\"$PWD/reword-sequence-editor.sh\"" \ + git rebase --edit-todo && + echo edited >>"\$1" + EOF + + test_set_editor "$PWD/reword-editor.sh" +} + +# Check the results of a rebase after calling set_reword_editor +# Pass the commits that were reworded in the order that they were picked +# Expects the first pick to be a fast-forward +check_reworded_commits () { + test_cmp_rev "$(cat reword-oid)" "$1^{commit}" && + git log --format="%an <%ae> %at%n%B%nedited%n" --no-walk=unsorted "$@" \ + >reword-expected && + test_cmp reword-expected reword-actual && + git log --format="%an <%ae> %at%n%B" -n $# --first-parent --reverse \ + >reword-log && + test_cmp reword-expected reword-log +} diff --git a/t/lib-subtest.sh b/t/lib-subtest.sh new file mode 100644 index 0000000000..56ee927f0c --- /dev/null +++ b/t/lib-subtest.sh @@ -0,0 +1,95 @@ +write_sub_test_lib_test () { + name="$1" # stdin is the body of the test code + mkdir "$name" && + write_script "$name/$name.sh" "$TEST_SHELL_PATH" <<-EOF && + test_description='A test of test-lib.sh itself' + + # Point to the t/test-lib.sh, which isn't in ../ as usual + . "\$TEST_DIRECTORY"/test-lib.sh + EOF + cat >>"$name/$name.sh" +} + +_run_sub_test_lib_test_common () { + cmp_op="$1" want_code="$2" name="$3" # stdin is the body of the test code + shift 3 + + # intercept pseudo-options at the front of the argument list that we + # will not pass to child script + skip= + while test $# -gt 0 + do + case "$1" in + --skip=*) + skip=${1#--*=} + shift + ;; + *) + break + ;; + esac + done + + ( + cd "$name" && + + # Pretend we're not running under a test harness, whether we + # are or not. The test-lib output depends on the setting of + # this variable, so we need a stable setting under which to run + # the sub-test. + sane_unset HARNESS_ACTIVE && + + export TEST_DIRECTORY && + # The child test re-sources GIT-BUILD-OPTIONS and may thus + # override the test output directory. We thus pass it as an + # explicit override to the child. + TEST_OUTPUT_DIRECTORY_OVERRIDE=$(pwd) && + export TEST_OUTPUT_DIRECTORY_OVERRIDE && + GIT_SKIP_TESTS=$skip && + export GIT_SKIP_TESTS && + sane_unset GIT_TEST_FAIL_PREREQS && + ./"$name.sh" "$@" >out 2>err; + ret=$? && + test "$ret" "$cmp_op" "$want_code" + ) +} + +write_and_run_sub_test_lib_test () { + name="$1" descr="$2" # stdin is the body of the test code + write_sub_test_lib_test "$@" || return 1 + _run_sub_test_lib_test_common -eq 0 "$@" +} + +write_and_run_sub_test_lib_test_err () { + name="$1" descr="$2" # stdin is the body of the test code + write_sub_test_lib_test "$@" || return 1 + _run_sub_test_lib_test_common -eq 1 "$@" +} + +run_sub_test_lib_test () { + _run_sub_test_lib_test_common -eq 0 "$@" +} + +run_sub_test_lib_test_err () { + _run_sub_test_lib_test_common -eq 1 "$@" +} + +_check_sub_test_lib_test_common () { + name="$1" && + sed -e 's/^> //' -e 's/Z$//' >"$name"/expect.out && + test_cmp "$name"/expect.out "$name"/out +} + +check_sub_test_lib_test () { + name="$1" # stdin is the expected output from the test + _check_sub_test_lib_test_common "$name" && + test_must_be_empty "$name"/err +} + +check_sub_test_lib_test_err () { + name="$1" # stdin is the expected output from the test + _check_sub_test_lib_test_common "$name" && + # expected error output is in descriptor 3 + sed -e 's/^> //' -e 's/Z$//' <&3 >"$name"/expect.err && + test_cmp "$name"/expect.err "$name"/err +} diff --git a/t/perf/aggregate.perl b/t/perf/aggregate.perl index 82c0df4553..575d2000cc 100755 --- a/t/perf/aggregate.perl +++ b/t/perf/aggregate.perl @@ -17,8 +17,8 @@ sub get_times { my $rt = ((defined $1 ? $1 : 0.0)*60+$2)*60+$3; return ($rt, $4, $5); # size - } elsif ($line =~ /^\d+$/) { - return $&; + } elsif ($line =~ /^\s*(\d+)$/) { + return $1; } else { die "bad input line: $line"; } diff --git a/t/perf/lib-bitmap.sh b/t/perf/lib-bitmap.sh new file mode 100644 index 0000000000..63d3bc7cec --- /dev/null +++ b/t/perf/lib-bitmap.sh @@ -0,0 +1,69 @@ +# Helper functions for testing bitmap performance; see p5310. + +test_full_bitmap () { + test_perf 'simulated clone' ' + git pack-objects --stdout --all </dev/null >/dev/null + ' + + test_perf 'simulated fetch' ' + have=$(git rev-list HEAD~100 -1) && + { + echo HEAD && + echo ^$have + } | git pack-objects --revs --stdout >/dev/null + ' + + test_perf 'pack to file (bitmap)' ' + git pack-objects --use-bitmap-index --all pack1b </dev/null >/dev/null + ' + + test_perf 'rev-list (commits)' ' + git rev-list --all --use-bitmap-index >/dev/null + ' + + test_perf 'rev-list (objects)' ' + git rev-list --all --use-bitmap-index --objects >/dev/null + ' + + test_perf 'rev-list with tag negated via --not --all (objects)' ' + git rev-list perf-tag --not --all --use-bitmap-index --objects >/dev/null + ' + + test_perf 'rev-list with negative tag (objects)' ' + git rev-list HEAD --not perf-tag --use-bitmap-index --objects >/dev/null + ' + + test_perf 'rev-list count with blob:none' ' + git rev-list --use-bitmap-index --count --objects --all \ + --filter=blob:none >/dev/null + ' + + test_perf 'rev-list count with blob:limit=1k' ' + git rev-list --use-bitmap-index --count --objects --all \ + --filter=blob:limit=1k >/dev/null + ' + + test_perf 'rev-list count with tree:0' ' + git rev-list --use-bitmap-index --count --objects --all \ + --filter=tree:0 >/dev/null + ' + + test_perf 'simulated partial clone' ' + git pack-objects --stdout --all --filter=blob:none </dev/null >/dev/null + ' +} + +test_partial_bitmap () { + test_perf 'clone (partial bitmap)' ' + git pack-objects --stdout --all </dev/null >/dev/null + ' + + test_perf 'pack to file (partial bitmap)' ' + git pack-objects --use-bitmap-index --all pack2b </dev/null >/dev/null + ' + + test_perf 'rev-list with tree filter (partial bitmap)' ' + git rev-list --use-bitmap-index --count --objects --all \ + --filter=tree:0 >/dev/null + ' +} diff --git a/t/perf/p0071-sort.sh b/t/perf/p0071-sort.sh index 6e924f5fa3..ed366e2e12 100755 --- a/t/perf/p0071-sort.sh +++ b/t/perf/p0071-sort.sh @@ -11,16 +11,42 @@ test_expect_success 'setup' ' git cat-file --batch >unsorted ' -test_perf 'sort(1)' ' - sort <unsorted >expect +test_perf 'sort(1) unsorted' ' + sort <unsorted >sorted ' -test_perf 'string_list_sort()' ' - test-tool string-list sort <unsorted >actual +test_expect_success 'reverse' ' + sort -r <unsorted >reversed ' -test_expect_success 'string_list_sort() sorts like sort(1)' ' - test_cmp_bin expect actual -' +for file in sorted reversed +do + test_perf "sort(1) $file" " + sort <$file >actual + " +done + +for file in unsorted sorted reversed +do + + test_perf "string_list_sort() $file" " + test-tool string-list sort <$file >actual + " + + test_expect_success "string_list_sort() $file sorts like sort(1)" " + test_cmp_bin sorted actual + " +done + +for file in unsorted sorted reversed +do + test_perf "llist_mergesort() $file" " + test-tool mergesort sort <$file >actual + " + + test_expect_success "llist_mergesort() $file sorts like sort(1)" " + test_cmp_bin sorted actual + " +done test_done diff --git a/t/perf/p3400-rebase.sh b/t/perf/p3400-rebase.sh index 7a0bb29448..43d5a34e8c 100755 --- a/t/perf/p3400-rebase.sh +++ b/t/perf/p3400-rebase.sh @@ -18,7 +18,7 @@ test_expect_success 'setup rebasing on top of a lot of changes' ' test_tick && git commit -m commit$i unrelated-file$i && echo change$i >unrelated-file$i && - test_seq 1000 | tac >>unrelated-file$i && + test_seq 1000 | sort -nr >>unrelated-file$i && git add unrelated-file$i && test_tick && git commit -m commit$i-reverse unrelated-file$i || diff --git a/t/perf/p5310-pack-bitmaps.sh b/t/perf/p5310-pack-bitmaps.sh index 452be01056..7ad4f237bc 100755 --- a/t/perf/p5310-pack-bitmaps.sh +++ b/t/perf/p5310-pack-bitmaps.sh @@ -2,6 +2,7 @@ test_description='Tests pack performance using bitmaps' . ./perf-lib.sh +. "${TEST_DIRECTORY}/perf/lib-bitmap.sh" test_perf_large_repo @@ -25,56 +26,7 @@ test_perf 'repack to disk' ' git repack -ad ' -test_perf 'simulated clone' ' - git pack-objects --stdout --all </dev/null >/dev/null -' - -test_perf 'simulated fetch' ' - have=$(git rev-list HEAD~100 -1) && - { - echo HEAD && - echo ^$have - } | git pack-objects --revs --stdout >/dev/null -' - -test_perf 'pack to file (bitmap)' ' - git pack-objects --use-bitmap-index --all pack1b </dev/null >/dev/null -' - -test_perf 'rev-list (commits)' ' - git rev-list --all --use-bitmap-index >/dev/null -' - -test_perf 'rev-list (objects)' ' - git rev-list --all --use-bitmap-index --objects >/dev/null -' - -test_perf 'rev-list with tag negated via --not --all (objects)' ' - git rev-list perf-tag --not --all --use-bitmap-index --objects >/dev/null -' - -test_perf 'rev-list with negative tag (objects)' ' - git rev-list HEAD --not perf-tag --use-bitmap-index --objects >/dev/null -' - -test_perf 'rev-list count with blob:none' ' - git rev-list --use-bitmap-index --count --objects --all \ - --filter=blob:none >/dev/null -' - -test_perf 'rev-list count with blob:limit=1k' ' - git rev-list --use-bitmap-index --count --objects --all \ - --filter=blob:limit=1k >/dev/null -' - -test_perf 'rev-list count with tree:0' ' - git rev-list --use-bitmap-index --count --objects --all \ - --filter=tree:0 >/dev/null -' - -test_perf 'simulated partial clone' ' - git pack-objects --stdout --all --filter=blob:none </dev/null >/dev/null -' +test_full_bitmap test_expect_success 'create partial bitmap state' ' # pick a commit to represent the repo tip in the past @@ -97,17 +49,6 @@ test_expect_success 'create partial bitmap state' ' git update-ref HEAD $orig_tip ' -test_perf 'clone (partial bitmap)' ' - git pack-objects --stdout --all </dev/null >/dev/null -' - -test_perf 'pack to file (partial bitmap)' ' - git pack-objects --use-bitmap-index --all pack2b </dev/null >/dev/null -' - -test_perf 'rev-list with tree filter (partial bitmap)' ' - git rev-list --use-bitmap-index --count --objects --all \ - --filter=tree:0 >/dev/null -' +test_partial_bitmap test_done diff --git a/t/perf/p5326-multi-pack-bitmaps.sh b/t/perf/p5326-multi-pack-bitmaps.sh new file mode 100755 index 0000000000..f2fa228f16 --- /dev/null +++ b/t/perf/p5326-multi-pack-bitmaps.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +test_description='Tests performance using midx bitmaps' +. ./perf-lib.sh +. "${TEST_DIRECTORY}/perf/lib-bitmap.sh" + +test_perf_large_repo + +# we need to create the tag up front such that it is covered by the repack and +# thus by generated bitmaps. +test_expect_success 'create tags' ' + git tag --message="tag pointing to HEAD" perf-tag HEAD +' + +test_expect_success 'start with bitmapped pack' ' + git repack -adb +' + +test_perf 'setup multi-pack index' ' + git multi-pack-index write --bitmap +' + +test_expect_success 'drop pack bitmap' ' + rm -f .git/objects/pack/pack-*.bitmap +' + +test_full_bitmap + +test_expect_success 'create partial bitmap state' ' + # pick a commit to represent the repo tip in the past + cutoff=$(git rev-list HEAD~100 -1) && + orig_tip=$(git rev-parse HEAD) && + + # now pretend we have just one tip + rm -rf .git/logs .git/refs/* .git/packed-refs && + git update-ref HEAD $cutoff && + + # and then repack, which will leave us with a nice + # big bitmap pack of the "old" history, and all of + # the new history will be loose, as if it had been pushed + # up incrementally and exploded via unpack-objects + git repack -Ad && + git multi-pack-index write --bitmap && + + # and now restore our original tip, as if the pushes + # had happened + git update-ref HEAD $orig_tip +' + +test_partial_bitmap + +test_done diff --git a/t/perf/run b/t/perf/run index d19dec258a..55219aa405 100755 --- a/t/perf/run +++ b/t/perf/run @@ -74,7 +74,7 @@ set_git_test_installed () { mydir=$1 mydir_abs=$(cd $mydir && pwd) - mydir_abs_wrappers="$mydir_abs_wrappers/bin-wrappers" + mydir_abs_wrappers="$mydir_abs/bin-wrappers" if test -d "$mydir_abs_wrappers" then GIT_TEST_INSTALLED=$mydir_abs_wrappers diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index cb87768513..b007f0efef 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -19,6 +19,7 @@ modification *should* take notice and update the test vectors here. ' . ./test-lib.sh +. "$TEST_DIRECTORY"/lib-subtest.sh try_local_xy () { local x="local" y="alsolocal" && @@ -66,95 +67,8 @@ test_expect_success 'success is reported like this' ' : ' -_run_sub_test_lib_test_common () { - neg="$1" name="$2" descr="$3" # stdin is the body of the test code - shift 3 - - # intercept pseudo-options at the front of the argument list that we - # will not pass to child script - skip= - while test $# -gt 0 - do - case "$1" in - --skip=*) - skip=${1#--*=} - shift - ;; - *) - break - ;; - esac - done - - mkdir "$name" && - ( - # Pretend we're not running under a test harness, whether we - # are or not. The test-lib output depends on the setting of - # this variable, so we need a stable setting under which to run - # the sub-test. - sane_unset HARNESS_ACTIVE && - cd "$name" && - write_script "$name.sh" "$TEST_SHELL_PATH" <<-EOF && - test_description='$descr (run in sub test-lib) - - This is run in a sub test-lib so that we do not get incorrect - passing metrics - ' - - # Point to the t/test-lib.sh, which isn't in ../ as usual - . "\$TEST_DIRECTORY"/test-lib.sh - EOF - cat >>"$name.sh" && - export TEST_DIRECTORY && - # The child test re-sources GIT-BUILD-OPTIONS and may thus - # override the test output directory. We thus pass it as an - # explicit override to the child. - TEST_OUTPUT_DIRECTORY_OVERRIDE=$(pwd) && - export TEST_OUTPUT_DIRECTORY_OVERRIDE && - GIT_SKIP_TESTS=$skip && - export GIT_SKIP_TESTS && - sane_unset GIT_TEST_FAIL_PREREQS && - if test -z "$neg" - then - ./"$name.sh" "$@" >out 2>err - else - ! ./"$name.sh" "$@" >out 2>err - fi - ) -} - -run_sub_test_lib_test () { - _run_sub_test_lib_test_common '' "$@" -} - -run_sub_test_lib_test_err () { - _run_sub_test_lib_test_common '!' "$@" -} - -check_sub_test_lib_test () { - name="$1" # stdin is the expected output from the test - ( - cd "$name" && - test_must_be_empty err && - sed -e 's/^> //' -e 's/Z$//' >expect && - test_cmp expect out - ) -} - -check_sub_test_lib_test_err () { - name="$1" # stdin is the expected output from the test - # expected error output is in descriptor 3 - ( - cd "$name" && - sed -e 's/^> //' -e 's/Z$//' >expect.out && - test_cmp expect.out out && - sed -e 's/^> //' -e 's/Z$//' <&3 >expect.err && - test_cmp expect.err err - ) -} - -test_expect_success 'pretend we have a fully passing test suite' ' - run_sub_test_lib_test full-pass "3 passing tests" <<-\EOF && +test_expect_success 'subtest: 3 passing tests' ' + write_and_run_sub_test_lib_test full-pass <<-\EOF && for i in 1 2 3 do test_expect_success "passing test #$i" "true" @@ -170,9 +84,8 @@ test_expect_success 'pretend we have a fully passing test suite' ' EOF ' -test_expect_success 'pretend we have a partially passing test suite' ' - run_sub_test_lib_test_err \ - partial-pass "2/3 tests passing" <<-\EOF && +test_expect_success 'subtest: 2/3 tests passing' ' + write_and_run_sub_test_lib_test_err partial-pass <<-\EOF && test_expect_success "passing test #1" "true" test_expect_success "failing test #2" "false" test_expect_success "passing test #3" "true" @@ -188,8 +101,8 @@ test_expect_success 'pretend we have a partially passing test suite' ' EOF ' -test_expect_success 'pretend we have a known breakage' ' - run_sub_test_lib_test failing-todo "A failing TODO test" <<-\EOF && +test_expect_success 'subtest: a failing TODO test' ' + write_and_run_sub_test_lib_test failing-todo <<-\EOF && test_expect_success "passing test" "true" test_expect_failure "pretend we have a known breakage" "false" test_done @@ -203,8 +116,8 @@ test_expect_success 'pretend we have a known breakage' ' EOF ' -test_expect_success 'pretend we have fixed a known breakage' ' - run_sub_test_lib_test passing-todo "A passing TODO test" <<-\EOF && +test_expect_success 'subtest: a passing TODO test' ' + write_and_run_sub_test_lib_test passing-todo <<-\EOF && test_expect_failure "pretend we have fixed a known breakage" "true" test_done EOF @@ -215,9 +128,8 @@ test_expect_success 'pretend we have fixed a known breakage' ' EOF ' -test_expect_success 'pretend we have fixed one of two known breakages (run in sub test-lib)' ' - run_sub_test_lib_test partially-passing-todos \ - "2 TODO tests, one passing" <<-\EOF && +test_expect_success 'subtest: 2 TODO tests, one passin' ' + write_and_run_sub_test_lib_test partially-passing-todos <<-\EOF && test_expect_failure "pretend we have a known breakage" "false" test_expect_success "pretend we have a passing test" "true" test_expect_failure "pretend we have fixed another known breakage" "true" @@ -234,9 +146,8 @@ test_expect_success 'pretend we have fixed one of two known breakages (run in su EOF ' -test_expect_success 'pretend we have a pass, fail, and known breakage' ' - run_sub_test_lib_test_err \ - mixed-results1 "mixed results #1" <<-\EOF && +test_expect_success 'subtest: mixed results: pass, failure and a TODO test' ' + write_and_run_sub_test_lib_test_err mixed-results1 <<-\EOF && test_expect_success "passing test" "true" test_expect_success "failing test" "false" test_expect_failure "pretend we have a known breakage" "false" @@ -253,9 +164,8 @@ test_expect_success 'pretend we have a pass, fail, and known breakage' ' EOF ' -test_expect_success 'pretend we have a mix of all possible results' ' - run_sub_test_lib_test_err \ - mixed-results2 "mixed results #2" <<-\EOF && +test_expect_success 'subtest: mixed results: a mixture of all possible results' ' + write_and_run_sub_test_lib_test_err mixed-results2 <<-\EOF && test_expect_success "passing test" "true" test_expect_success "passing test" "true" test_expect_success "passing test" "true" @@ -289,9 +199,8 @@ test_expect_success 'pretend we have a mix of all possible results' ' EOF ' -test_expect_success 'test --verbose' ' - run_sub_test_lib_test_err \ - t1234-verbose "test verbose" --verbose <<-\EOF && +test_expect_success 'subtest: --verbose option' ' + write_and_run_sub_test_lib_test_err t1234-verbose --verbose <<-\EOF && test_expect_success "passing test" true test_expect_success "test with output" "echo foo" test_expect_success "failing test" false @@ -316,19 +225,14 @@ test_expect_success 'test --verbose' ' EOF ' -test_expect_success 'test --verbose-only' ' +test_expect_success 'subtest: --verbose-only option' ' run_sub_test_lib_test_err \ - t2345-verbose-only-2 "test verbose-only=2" \ - --verbose-only=2 <<-\EOF && - test_expect_success "passing test" true - test_expect_success "test with output" "echo foo" - test_expect_success "failing test" false - test_done - EOF - check_sub_test_lib_test t2345-verbose-only-2 <<-\EOF + t1234-verbose \ + --verbose-only=2 && + check_sub_test_lib_test t1234-verbose <<-\EOF > ok 1 - passing test > Z - > expecting success of 2345.2 '\''test with output'\'': echo foo + > expecting success of 1234.2 '\''test with output'\'': echo foo > foo > ok 2 - test with output > Z @@ -339,18 +243,11 @@ test_expect_success 'test --verbose-only' ' EOF ' -test_expect_success 'GIT_SKIP_TESTS' ' +test_expect_success 'subtest: skip one with GIT_SKIP_TESTS' ' ( - run_sub_test_lib_test git-skip-tests-basic \ - "GIT_SKIP_TESTS" \ - --skip="git.2" <<-\EOF && - for i in 1 2 3 - do - test_expect_success "passing test #$i" "true" - done - test_done - EOF - check_sub_test_lib_test git-skip-tests-basic <<-\EOF + run_sub_test_lib_test full-pass \ + --skip="full.2" && + check_sub_test_lib_test full-pass <<-\EOF > ok 1 - passing test #1 > ok 2 # skip passing test #2 (GIT_SKIP_TESTS) > ok 3 - passing test #3 @@ -360,10 +257,9 @@ test_expect_success 'GIT_SKIP_TESTS' ' ) ' -test_expect_success 'GIT_SKIP_TESTS several tests' ' +test_expect_success 'subtest: skip several with GIT_SKIP_TESTS' ' ( - run_sub_test_lib_test git-skip-tests-several \ - "GIT_SKIP_TESTS several tests" \ + write_and_run_sub_test_lib_test git-skip-tests-several \ --skip="git.2 git.5" <<-\EOF && for i in 1 2 3 4 5 6 do @@ -384,18 +280,11 @@ test_expect_success 'GIT_SKIP_TESTS several tests' ' ) ' -test_expect_success 'GIT_SKIP_TESTS sh pattern' ' +test_expect_success 'subtest: sh pattern skipping with GIT_SKIP_TESTS' ' ( - run_sub_test_lib_test git-skip-tests-sh-pattern \ - "GIT_SKIP_TESTS sh pattern" \ - --skip="git.[2-5]" <<-\EOF && - for i in 1 2 3 4 5 6 - do - test_expect_success "passing test #$i" "true" - done - test_done - EOF - check_sub_test_lib_test git-skip-tests-sh-pattern <<-\EOF + run_sub_test_lib_test git-skip-tests-several \ + --skip="git.[2-5]" && + check_sub_test_lib_test git-skip-tests-several <<-\EOF > ok 1 - passing test #1 > ok 2 # skip passing test #2 (GIT_SKIP_TESTS) > ok 3 # skip passing test #3 (GIT_SKIP_TESTS) @@ -408,35 +297,23 @@ test_expect_success 'GIT_SKIP_TESTS sh pattern' ' ) ' -test_expect_success 'GIT_SKIP_TESTS entire suite' ' +test_expect_success 'subtest: skip entire test suite with GIT_SKIP_TESTS' ' ( - run_sub_test_lib_test git-skip-tests-entire-suite \ - "GIT_SKIP_TESTS entire suite" \ - --skip="git" <<-\EOF && - for i in 1 2 3 - do - test_expect_success "passing test #$i" "true" - done - test_done - EOF - check_sub_test_lib_test git-skip-tests-entire-suite <<-\EOF + GIT_SKIP_TESTS="git" && export GIT_SKIP_TESTS && + run_sub_test_lib_test git-skip-tests-several \ + --skip="git" && + check_sub_test_lib_test git-skip-tests-several <<-\EOF > 1..0 # SKIP skip all tests in git EOF ) ' -test_expect_success 'GIT_SKIP_TESTS does not skip unmatched suite' ' +test_expect_success 'subtest: GIT_SKIP_TESTS does not skip unmatched suite' ' ( - run_sub_test_lib_test git-skip-tests-unmatched-suite \ - "GIT_SKIP_TESTS does not skip unmatched suite" \ - --skip="notgit" <<-\EOF && - for i in 1 2 3 - do - test_expect_success "passing test #$i" "true" - done - test_done - EOF - check_sub_test_lib_test git-skip-tests-unmatched-suite <<-\EOF + GIT_SKIP_TESTS="notgit" && export GIT_SKIP_TESTS && + run_sub_test_lib_test full-pass \ + --skip="notfull" && + check_sub_test_lib_test full-pass <<-\EOF > ok 1 - passing test #1 > ok 2 - passing test #2 > ok 3 - passing test #3 @@ -446,16 +323,9 @@ test_expect_success 'GIT_SKIP_TESTS does not skip unmatched suite' ' ) ' -test_expect_success '--run basic' ' - run_sub_test_lib_test run-basic \ - "--run basic" --run="1,3,5" <<-\EOF && - for i in 1 2 3 4 5 6 - do - test_expect_success "passing test #$i" "true" - done - test_done - EOF - check_sub_test_lib_test run-basic <<-\EOF +test_expect_success 'subtest: --run basic' ' + run_sub_test_lib_test git-skip-tests-several --run="1,3,5" && + check_sub_test_lib_test git-skip-tests-several <<-\EOF > ok 1 - passing test #1 > ok 2 # skip passing test #2 (--run) > ok 3 - passing test #3 @@ -467,16 +337,10 @@ test_expect_success '--run basic' ' EOF ' -test_expect_success '--run with a range' ' - run_sub_test_lib_test run-range \ - "--run with a range" --run="1-3" <<-\EOF && - for i in 1 2 3 4 5 6 - do - test_expect_success "passing test #$i" "true" - done - test_done - EOF - check_sub_test_lib_test run-range <<-\EOF +test_expect_success 'subtest: --run with a range' ' + run_sub_test_lib_test git-skip-tests-several \ + --run="1-3" && + check_sub_test_lib_test git-skip-tests-several <<-\EOF > ok 1 - passing test #1 > ok 2 - passing test #2 > ok 3 - passing test #3 @@ -488,16 +352,10 @@ test_expect_success '--run with a range' ' EOF ' -test_expect_success '--run with two ranges' ' - run_sub_test_lib_test run-two-ranges \ - "--run with two ranges" --run="1-2,5-6" <<-\EOF && - for i in 1 2 3 4 5 6 - do - test_expect_success "passing test #$i" "true" - done - test_done - EOF - check_sub_test_lib_test run-two-ranges <<-\EOF +test_expect_success 'subtest: --run with two ranges' ' + run_sub_test_lib_test git-skip-tests-several \ + --run="1-2,5-6" && + check_sub_test_lib_test git-skip-tests-several <<-\EOF > ok 1 - passing test #1 > ok 2 - passing test #2 > ok 3 # skip passing test #3 (--run) @@ -509,16 +367,10 @@ test_expect_success '--run with two ranges' ' EOF ' -test_expect_success '--run with a left open range' ' - run_sub_test_lib_test run-left-open-range \ - "--run with a left open range" --run="-3" <<-\EOF && - for i in 1 2 3 4 5 6 - do - test_expect_success "passing test #$i" "true" - done - test_done - EOF - check_sub_test_lib_test run-left-open-range <<-\EOF +test_expect_success 'subtest: --run with a left open range' ' + run_sub_test_lib_test git-skip-tests-several \ + --run="-3" && + check_sub_test_lib_test git-skip-tests-several <<-\EOF > ok 1 - passing test #1 > ok 2 - passing test #2 > ok 3 - passing test #3 @@ -530,16 +382,10 @@ test_expect_success '--run with a left open range' ' EOF ' -test_expect_success '--run with a right open range' ' - run_sub_test_lib_test run-right-open-range \ - "--run with a right open range" --run="4-" <<-\EOF && - for i in 1 2 3 4 5 6 - do - test_expect_success "passing test #$i" "true" - done - test_done - EOF - check_sub_test_lib_test run-right-open-range <<-\EOF +test_expect_success 'subtest: --run with a right open range' ' + run_sub_test_lib_test git-skip-tests-several \ + --run="4-" && + check_sub_test_lib_test git-skip-tests-several <<-\EOF > ok 1 # skip passing test #1 (--run) > ok 2 # skip passing test #2 (--run) > ok 3 # skip passing test #3 (--run) @@ -551,16 +397,10 @@ test_expect_success '--run with a right open range' ' EOF ' -test_expect_success '--run with basic negation' ' - run_sub_test_lib_test run-basic-neg \ - "--run with basic negation" --run="!3" <<-\EOF && - for i in 1 2 3 4 5 6 - do - test_expect_success "passing test #$i" "true" - done - test_done - EOF - check_sub_test_lib_test run-basic-neg <<-\EOF +test_expect_success 'subtest: --run with basic negation' ' + run_sub_test_lib_test git-skip-tests-several \ + --run="!3" && + check_sub_test_lib_test git-skip-tests-several <<-\EOF > ok 1 - passing test #1 > ok 2 - passing test #2 > ok 3 # skip passing test #3 (--run) @@ -572,16 +412,10 @@ test_expect_success '--run with basic negation' ' EOF ' -test_expect_success '--run with two negations' ' - run_sub_test_lib_test run-two-neg \ - "--run with two negations" --run="!3,!6" <<-\EOF && - for i in 1 2 3 4 5 6 - do - test_expect_success "passing test #$i" "true" - done - test_done - EOF - check_sub_test_lib_test run-two-neg <<-\EOF +test_expect_success 'subtest: --run with two negations' ' + run_sub_test_lib_test git-skip-tests-several \ + --run="!3,!6" && + check_sub_test_lib_test git-skip-tests-several <<-\EOF > ok 1 - passing test #1 > ok 2 - passing test #2 > ok 3 # skip passing test #3 (--run) @@ -593,16 +427,10 @@ test_expect_success '--run with two negations' ' EOF ' -test_expect_success '--run a range and negation' ' - run_sub_test_lib_test run-range-and-neg \ - "--run a range and negation" --run="-4,!2" <<-\EOF && - for i in 1 2 3 4 5 6 - do - test_expect_success "passing test #$i" "true" - done - test_done - EOF - check_sub_test_lib_test run-range-and-neg <<-\EOF +test_expect_success 'subtest: --run a range and negation' ' + run_sub_test_lib_test git-skip-tests-several \ + --run="-4,!2" && + check_sub_test_lib_test git-skip-tests-several <<-\EOF > ok 1 - passing test #1 > ok 2 # skip passing test #2 (--run) > ok 3 - passing test #3 @@ -614,16 +442,10 @@ test_expect_success '--run a range and negation' ' EOF ' -test_expect_success '--run range negation' ' - run_sub_test_lib_test run-range-neg \ - "--run range negation" --run="!1-3" <<-\EOF && - for i in 1 2 3 4 5 6 - do - test_expect_success "passing test #$i" "true" - done - test_done - EOF - check_sub_test_lib_test run-range-neg <<-\EOF +test_expect_success 'subtest: --run range negation' ' + run_sub_test_lib_test git-skip-tests-several \ + --run="!1-3" && + check_sub_test_lib_test git-skip-tests-several <<-\EOF > ok 1 # skip passing test #1 (--run) > ok 2 # skip passing test #2 (--run) > ok 3 # skip passing test #3 (--run) @@ -635,17 +457,10 @@ test_expect_success '--run range negation' ' EOF ' -test_expect_success '--run include, exclude and include' ' - run_sub_test_lib_test run-inc-neg-inc \ - "--run include, exclude and include" \ - --run="1-5,!1-3,2" <<-\EOF && - for i in 1 2 3 4 5 6 - do - test_expect_success "passing test #$i" "true" - done - test_done - EOF - check_sub_test_lib_test run-inc-neg-inc <<-\EOF +test_expect_success 'subtest: --run include, exclude and include' ' + run_sub_test_lib_test git-skip-tests-several \ + --run="1-5,!1-3,2" && + check_sub_test_lib_test git-skip-tests-several <<-\EOF > ok 1 # skip passing test #1 (--run) > ok 2 - passing test #2 > ok 3 # skip passing test #3 (--run) @@ -657,17 +472,10 @@ test_expect_success '--run include, exclude and include' ' EOF ' -test_expect_success '--run include, exclude and include, comma separated' ' - run_sub_test_lib_test run-inc-neg-inc-comma \ - "--run include, exclude and include, comma separated" \ - --run=1-5,!1-3,2 <<-\EOF && - for i in 1 2 3 4 5 6 - do - test_expect_success "passing test #$i" "true" - done - test_done - EOF - check_sub_test_lib_test run-inc-neg-inc-comma <<-\EOF +test_expect_success 'subtest: --run include, exclude and include, comma separated' ' + run_sub_test_lib_test git-skip-tests-several \ + --run=1-5,!1-3,2 && + check_sub_test_lib_test git-skip-tests-several <<-\EOF > ok 1 # skip passing test #1 (--run) > ok 2 - passing test #2 > ok 3 # skip passing test #3 (--run) @@ -679,17 +487,10 @@ test_expect_success '--run include, exclude and include, comma separated' ' EOF ' -test_expect_success '--run exclude and include' ' - run_sub_test_lib_test run-neg-inc \ - "--run exclude and include" \ - --run="!3-,5" <<-\EOF && - for i in 1 2 3 4 5 6 - do - test_expect_success "passing test #$i" "true" - done - test_done - EOF - check_sub_test_lib_test run-neg-inc <<-\EOF +test_expect_success 'subtest: --run exclude and include' ' + run_sub_test_lib_test git-skip-tests-several \ + --run="!3-,5" && + check_sub_test_lib_test git-skip-tests-several <<-\EOF > ok 1 - passing test #1 > ok 2 - passing test #2 > ok 3 # skip passing test #3 (--run) @@ -701,17 +502,10 @@ test_expect_success '--run exclude and include' ' EOF ' -test_expect_success '--run empty selectors' ' - run_sub_test_lib_test run-empty-sel \ - "--run empty selectors" \ - --run="1,,3,,,5" <<-\EOF && - for i in 1 2 3 4 5 6 - do - test_expect_success "passing test #$i" "true" - done - test_done - EOF - check_sub_test_lib_test run-empty-sel <<-\EOF +test_expect_success 'subtest: --run empty selectors' ' + run_sub_test_lib_test git-skip-tests-several \ + --run="1,,3,,,5" && + check_sub_test_lib_test git-skip-tests-several <<-\EOF > ok 1 - passing test #1 > ok 2 # skip passing test #2 (--run) > ok 3 - passing test #3 @@ -723,9 +517,8 @@ test_expect_success '--run empty selectors' ' EOF ' -test_expect_success '--run substring selector' ' - run_sub_test_lib_test run-substring-selector \ - "--run empty selectors" \ +test_expect_success 'subtest: --run substring selector' ' + write_and_run_sub_test_lib_test run-substring-selector \ --run="relevant" <<-\EOF && test_expect_success "relevant test" "true" for i in 1 2 3 4 5 6 @@ -747,9 +540,8 @@ test_expect_success '--run substring selector' ' EOF ' -test_expect_success '--run keyword selection' ' - run_sub_test_lib_test_err run-inv-range-start \ - "--run invalid range start" \ +test_expect_success 'subtest: --run keyword selection' ' + write_and_run_sub_test_lib_test_err run-inv-range-start \ --run="a-5" <<-\EOF && test_expect_success "passing test #1" "true" test_done @@ -762,14 +554,10 @@ test_expect_success '--run keyword selection' ' EOF_ERR ' -test_expect_success '--run invalid range end' ' - run_sub_test_lib_test_err run-inv-range-end \ - "--run invalid range end" \ - --run="1-z" <<-\EOF && - test_expect_success "passing test #1" "true" - test_done - EOF - check_sub_test_lib_test_err run-inv-range-end \ +test_expect_success 'subtest: --run invalid range end' ' + run_sub_test_lib_test_err run-inv-range-start \ + --run="1-z" && + check_sub_test_lib_test_err run-inv-range-start \ <<-\EOF_OUT 3<<-EOF_ERR > FATAL: Unexpected exit with code 1 EOF_OUT @@ -777,8 +565,8 @@ test_expect_success '--run invalid range end' ' EOF_ERR ' -test_expect_success 'tests respect prerequisites' ' - run_sub_test_lib_test prereqs "tests respect prereqs" <<-\EOF && +test_expect_success 'subtest: tests respect prerequisites' ' + write_and_run_sub_test_lib_test prereqs <<-\EOF && test_set_prereq HAVEIT test_expect_success HAVEIT "prereq is satisfied" "true" @@ -807,8 +595,8 @@ test_expect_success 'tests respect prerequisites' ' EOF ' -test_expect_success 'tests respect lazy prerequisites' ' - run_sub_test_lib_test lazy-prereqs "respect lazy prereqs" <<-\EOF && +test_expect_success 'subtest: tests respect lazy prerequisites' ' + write_and_run_sub_test_lib_test lazy-prereqs <<-\EOF && test_lazy_prereq LAZY_TRUE true test_expect_success LAZY_TRUE "lazy prereq is satisifed" "true" @@ -831,8 +619,8 @@ test_expect_success 'tests respect lazy prerequisites' ' EOF ' -test_expect_success 'nested lazy prerequisites' ' - run_sub_test_lib_test nested-lazy "nested lazy prereqs" <<-\EOF && +test_expect_success 'subtest: nested lazy prerequisites' ' + write_and_run_sub_test_lib_test nested-lazy <<-\EOF && test_lazy_prereq NESTED_INNER " >inner && @@ -857,9 +645,9 @@ test_expect_success 'nested lazy prerequisites' ' EOF ' -test_expect_success 'lazy prereqs do not turn off tracing' ' - run_sub_test_lib_test lazy-prereq-and-tracing \ - "lazy prereqs and -x" -v -x <<-\EOF && +test_expect_success 'subtest: lazy prereqs do not turn off tracing' ' + write_and_run_sub_test_lib_test lazy-prereq-and-tracing \ + -v -x <<-\EOF && test_lazy_prereq LAZY true test_expect_success lazy "test_have_prereq LAZY && echo trace" @@ -870,8 +658,8 @@ test_expect_success 'lazy prereqs do not turn off tracing' ' grep "echo trace" lazy-prereq-and-tracing/err ' -test_expect_success 'tests clean up after themselves' ' - run_sub_test_lib_test cleanup "test with cleanup" <<-\EOF && +test_expect_success 'subtest: tests clean up after themselves' ' + write_and_run_sub_test_lib_test cleanup <<-\EOF && clean=no test_expect_success "do cleanup" " test_when_finished clean=yes @@ -890,9 +678,9 @@ test_expect_success 'tests clean up after themselves' ' EOF ' -test_expect_success 'tests clean up even on failures' ' - run_sub_test_lib_test_err \ - failing-cleanup "Failing tests with cleanup commands" <<-\EOF && +test_expect_success 'subtest: tests clean up even on failures' ' + write_and_run_sub_test_lib_test_err \ + failing-cleanup <<-\EOF && test_expect_success "tests clean up even after a failure" " touch clean-after-failure && test_when_finished rm clean-after-failure && @@ -919,9 +707,9 @@ test_expect_success 'tests clean up even on failures' ' EOF ' -test_expect_success 'test_atexit is run' ' - run_sub_test_lib_test_err \ - atexit-cleanup "Run atexit commands" -i <<-\EOF && +test_expect_success 'subtest: test_atexit is run' ' + write_and_run_sub_test_lib_test_err \ + atexit-cleanup -i <<-\EOF && test_expect_success "tests clean up even after a failure" " > ../../clean-atexit && test_atexit rm ../../clean-atexit && @@ -1271,28 +1059,29 @@ P=$(test_oid root) test_expect_success 'git commit-tree records the correct tree in a commit' ' commit0=$(echo NO | git commit-tree $P) && - tree=$(git show --pretty=raw $commit0 | - sed -n -e "s/^tree //p" -e "/^author /q") && + git show --pretty=raw $commit0 >out && + tree=$(sed -n -e "s/^tree //p" -e "/^author /q" out) && test "z$tree" = "z$P" ' test_expect_success 'git commit-tree records the correct parent in a commit' ' commit1=$(echo NO | git commit-tree $P -p $commit0) && - parent=$(git show --pretty=raw $commit1 | - sed -n -e "s/^parent //p" -e "/^author /q") && + git show --pretty=raw $commit1 >out && + parent=$(sed -n -e "s/^parent //p" -e "/^author /q" out) && test "z$commit0" = "z$parent" ' test_expect_success 'git commit-tree omits duplicated parent in a commit' ' commit2=$(echo NO | git commit-tree $P -p $commit0 -p $commit0) && - parent=$(git show --pretty=raw $commit2 | - sed -n -e "s/^parent //p" -e "/^author /q" | - sort -u) && + git show --pretty=raw $commit2 >out && + cat >match.sed <<-\EOF && + s/^parent //p + /^author /q + EOF + parent=$(sed -n -f match.sed out | sort -u) && test "z$commit0" = "z$parent" && - numparent=$(git show --pretty=raw $commit2 | - sed -n -e "s/^parent //p" -e "/^author /q" | - wc -l) && - test $numparent = 1 + git show --pretty=raw $commit2 >out && + test_stdout_line_count = 1 sed -n -f match.sed out ' test_expect_success 'update-index D/F conflict' ' diff --git a/t/t0004-unwritable.sh b/t/t0004-unwritable.sh index e3137d638e..37d68ef03b 100755 --- a/t/t0004-unwritable.sh +++ b/t/t0004-unwritable.sh @@ -2,6 +2,7 @@ test_description='detect unwritable repository and fail correctly' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' @@ -21,7 +22,7 @@ test_expect_success POSIXPERM,SANITY 'write-tree should notice unwritable reposi test_must_fail git write-tree ' -test_expect_success POSIXPERM,SANITY 'commit should notice unwritable repository' ' +test_expect_success POSIXPERM,SANITY,!SANITIZE_LEAK 'commit should notice unwritable repository' ' test_when_finished "chmod 775 .git/objects .git/objects/??" && chmod a-w .git/objects .git/objects/?? && test_must_fail git commit -m second diff --git a/t/t0011-hashmap.sh b/t/t0011-hashmap.sh index 5343ffd3f9..e094975b13 100755 --- a/t/t0011-hashmap.sh +++ b/t/t0011-hashmap.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test hashmap and string hash functions' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_hashmap() { diff --git a/t/t0012-help.sh b/t/t0012-help.sh index 5679e29c62..91b68c74a1 100755 --- a/t/t0012-help.sh +++ b/t/t0012-help.sh @@ -34,6 +34,18 @@ test_expect_success 'basic help commands' ' git help -a >/dev/null ' +test_expect_success 'invalid usage' ' + test_expect_code 129 git help -g add && + test_expect_code 129 git help -a -c && + + test_expect_code 129 git help -g add && + test_expect_code 129 git help -a -g && + + test_expect_code 129 git help -g -c && + test_expect_code 129 git help --config-for-completion add && + test_expect_code 129 git help --config-sections-for-completion add +' + test_expect_success "works for commands and guides by default" ' configure_help && git help status && @@ -73,6 +85,59 @@ test_expect_success 'git help -g' ' test_i18ngrep "^ tutorial " help.output ' +test_expect_success 'git help fails for non-existing html pages' ' + configure_help && + mkdir html-empty && + test_must_fail git -c help.htmlpath=html-empty help status && + test_must_be_empty test-browser.log +' + +test_expect_success 'git help succeeds without git.html' ' + configure_help && + mkdir html-with-docs && + touch html-with-docs/git-status.html && + git -c help.htmlpath=html-with-docs help status && + echo "html-with-docs/git-status.html" >expect && + test_cmp expect test-browser.log +' + +test_expect_success 'git help -c' ' + git help -c >help.output && + cat >expect <<-\EOF && + + '\''git help config'\'' for more information + EOF + grep -v -E \ + -e "^[^.]+\.[^.]+$" \ + -e "^[^.]+\.[^.]+\.[^.]+$" \ + help.output >actual && + test_cmp expect actual +' + +test_expect_success 'git help --config-for-completion' ' + git help -c >human && + grep -E \ + -e "^[^.]+\.[^.]+$" \ + -e "^[^.]+\.[^.]+\.[^.]+$" human | + sed -e "s/\*.*//" -e "s/<.*//" | + sort -u >human.munged && + + git help --config-for-completion >vars && + test_cmp human.munged vars +' + +test_expect_success 'git help --config-sections-for-completion' ' + git help -c >human && + grep -E \ + -e "^[^.]+\.[^.]+$" \ + -e "^[^.]+\.[^.]+\.[^.]+$" human | + sed -e "s/\..*//" | + sort -u >human.munged && + + git help --config-sections-for-completion >sections && + test_cmp human.munged sections +' + test_expect_success 'generate builtin list' ' git --list-cmds=builtins >builtins ' diff --git a/t/t0016-oidmap.sh b/t/t0016-oidmap.sh index 31f8276ba8..0faef1f4f1 100755 --- a/t/t0016-oidmap.sh +++ b/t/t0016-oidmap.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test oidmap' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # This purposefully is very similar to t0011-hashmap.sh diff --git a/t/t0017-env-helper.sh b/t/t0017-env-helper.sh index 4a159f99e4..2e42fba956 100755 --- a/t/t0017-env-helper.sh +++ b/t/t0017-env-helper.sh @@ -2,6 +2,7 @@ test_description='test env--helper' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh diff --git a/t/t0018-advice.sh b/t/t0018-advice.sh index 39e5e4b34f..c13057a4ca 100755 --- a/t/t0018-advice.sh +++ b/t/t0018-advice.sh @@ -2,6 +2,7 @@ test_description='Test advise_if_enabled functionality' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'advice should be printed when config variable is unset' ' diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh index b5749f327d..33dfc9cd56 100755 --- a/t/t0021-conversion.sh +++ b/t/t0021-conversion.sh @@ -6,6 +6,7 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . ./test-lib.sh +. "$TEST_DIRECTORY"/lib-terminal.sh TEST_ROOT="$PWD" PATH=$TEST_ROOT:$PATH @@ -1061,4 +1062,74 @@ test_expect_success PERL,SYMLINKS,CASE_INSENSITIVE_FS \ ) ' +test_expect_success PERL 'setup for progress tests' ' + git init progress && + ( + cd progress && + git config filter.delay.process "rot13-filter.pl delay-progress.log clean smudge delay" && + git config filter.delay.required true && + + echo "*.a filter=delay" >.gitattributes && + touch test-delay10.a && + git add . && + git commit -m files + ) +' + +test_delayed_checkout_progress () { + if test "$1" = "!" + then + local expect_progress=N && + shift + else + local expect_progress= + fi && + + if test $# -lt 1 + then + BUG "no command given to test_delayed_checkout_progress" + fi && + + ( + cd progress && + GIT_PROGRESS_DELAY=0 && + export GIT_PROGRESS_DELAY && + rm -f *.a delay-progress.log && + + "$@" 2>err && + grep "IN: smudge test-delay10.a .* \\[DELAYED\\]" delay-progress.log && + if test "$expect_progress" = N + then + ! grep "Filtering content" err + else + grep "Filtering content" err + fi + ) +} + +for mode in pathspec branch +do + case "$mode" in + pathspec) opt='.' ;; + branch) opt='-f HEAD' ;; + esac + + test_expect_success PERL,TTY "delayed checkout shows progress by default on tty ($mode checkout)" ' + test_delayed_checkout_progress test_terminal git checkout $opt + ' + + test_expect_success PERL "delayed checkout ommits progress on non-tty ($mode checkout)" ' + test_delayed_checkout_progress ! git checkout $opt + ' + + test_expect_success PERL,TTY "delayed checkout ommits progress with --quiet ($mode checkout)" ' + test_delayed_checkout_progress ! test_terminal git checkout --quiet $opt + ' + + test_expect_success PERL,TTY "delayed checkout honors --[no]-progress ($mode checkout)" ' + test_delayed_checkout_progress ! test_terminal git checkout --no-progress $opt && + test_delayed_checkout_progress test_terminal git checkout --quiet --progress $opt + ' +done + test_done diff --git a/t/t0030-stripspace.sh b/t/t0030-stripspace.sh index 0c24a0f9a3..ae1ca380c1 100755 --- a/t/t0030-stripspace.sh +++ b/t/t0030-stripspace.sh @@ -5,6 +5,7 @@ test_description='git stripspace' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh t40='A quick brown fox jumps over the lazy do' diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index ad4746d899..da310ed29b 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -37,7 +37,6 @@ String options --list <str> add str to list Magic arguments - --quux means --quux -NUM set integer to NUM + same as -b --ambiguous positive ambiguity @@ -263,10 +262,6 @@ test_expect_success 'detect possible typos' ' test_cmp typo.err output.err ' -test_expect_success 'keep some options as arguments' ' - test-tool parse-options --expect="arg 00: --quux" --quux -' - cat >expect <<\EOF Callback: "four", 0 boolean: 5 diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh index de4960783f..34d1061f32 100755 --- a/t/t0060-path-utils.sh +++ b/t/t0060-path-utils.sh @@ -525,4 +525,30 @@ test_expect_success MINGW 'is_valid_path() on Windows' ' "PRN./abc" ' +test_lazy_prereq RUNTIME_PREFIX ' + test true = "$RUNTIME_PREFIX" +' + +test_lazy_prereq CAN_EXEC_IN_PWD ' + cp "$GIT_EXEC_PATH"/git$X ./ && + ./git rev-parse +' + +test_expect_success RUNTIME_PREFIX,CAN_EXEC_IN_PWD 'RUNTIME_PREFIX works' ' + mkdir -p pretend/bin pretend/libexec/git-core && + echo "echo HERE" | write_script pretend/libexec/git-core/git-here && + cp "$GIT_EXEC_PATH"/git$X pretend/bin/ && + GIT_EXEC_PATH= ./pretend/bin/git here >actual && + echo HERE >expect && + test_cmp expect actual' + +test_expect_success RUNTIME_PREFIX,CAN_EXEC_IN_PWD '%(prefix)/ works' ' + mkdir -p pretend/bin && + cp "$GIT_EXEC_PATH"/git$X pretend/bin/ && + git config yes.path "%(prefix)/yes" && + GIT_EXEC_PATH= ./pretend/bin/git config --path yes.path >actual && + echo "$(pwd)/pretend/yes" >expect && + test_cmp expect actual +' + test_done diff --git a/t/t0063-string-list.sh b/t/t0063-string-list.sh index c6ee9f66b1..46d4839194 100755 --- a/t/t0063-string-list.sh +++ b/t/t0063-string-list.sh @@ -5,6 +5,7 @@ test_description='Test string list functionality' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_split () { diff --git a/t/t0071-sort.sh b/t/t0071-sort.sh new file mode 100755 index 0000000000..a8ab174879 --- /dev/null +++ b/t/t0071-sort.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +test_description='verify sort functions' + +. ./test-lib.sh + +test_expect_success 'llist_mergesort()' ' + test-tool mergesort test +' + +test_done diff --git a/t/t0090-cache-tree.sh b/t/t0090-cache-tree.sh index 9bf66c9e68..9067572648 100755 --- a/t/t0090-cache-tree.sh +++ b/t/t0090-cache-tree.sh @@ -195,6 +195,7 @@ test_expect_success 'reset --hard gives cache-tree' ' test_expect_success 'reset --hard without index gives cache-tree' ' rm -f .git/index && + git clean -fd && git reset --hard && test_cache_tree ' diff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh index 526304ff95..eeedbfa919 100755 --- a/t/t0091-bugreport.sh +++ b/t/t0091-bugreport.sh @@ -2,6 +2,7 @@ test_description='git bugreport' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Headers "[System Info]" will be followed by a non-empty line if we put some diff --git a/t/t0210/scrub_normal.perl b/t/t0210/scrub_normal.perl index c65d1a815e..7cc4de392a 100644 --- a/t/t0210/scrub_normal.perl +++ b/t/t0210/scrub_normal.perl @@ -42,6 +42,12 @@ while (<>) { # so just omit it for testing purposes. # print "cmd_path _EXE_\n"; } + elsif ($line =~ m/^cmd_ancestry/) { + # 'cmd_ancestry' is not implemented everywhere, so for portability's + # sake, skip it when parsing normal. + # + # print "$line"; + } else { print "$line"; } diff --git a/t/t0211/scrub_perf.perl b/t/t0211/scrub_perf.perl index 351af7844e..d164b750ff 100644 --- a/t/t0211/scrub_perf.perl +++ b/t/t0211/scrub_perf.perl @@ -44,6 +44,11 @@ while (<>) { # $tokens[$col_rest] = "_EXE_"; goto SKIP_LINE; } + elsif ($tokens[$col_event] =~ m/cmd_ancestry/) { + # 'cmd_ancestry' is platform-specific and not implemented everywhere, + # so skip it. + goto SKIP_LINE; + } elsif ($tokens[$col_event] =~ m/child_exit/) { $tokens[$col_rest] =~ s/ pid:\d* / pid:_PID_ /; } diff --git a/t/t0212/parse_events.perl b/t/t0212/parse_events.perl index 6584bb5634..b6408560c0 100644 --- a/t/t0212/parse_events.perl +++ b/t/t0212/parse_events.perl @@ -132,7 +132,10 @@ while (<>) { # just omit it for testing purposes. # $processes->{$sid}->{'path'} = "_EXE_"; } - + elsif ($event eq 'cmd_ancestry') { + # 'cmd_ancestry' is platform-specific and not implemented everywhere, so + # just skip it for testing purposes. + } elsif ($event eq 'cmd_name') { $processes->{$sid}->{'name'} = $line->{'name'}; $processes->{$sid}->{'hierarchy'} = $line->{'hierarchy'}; diff --git a/t/t0301-credential-cache.sh b/t/t0301-credential-cache.sh index ebd5fa5249..698b7159f0 100755 --- a/t/t0301-credential-cache.sh +++ b/t/t0301-credential-cache.sh @@ -9,6 +9,21 @@ test -z "$NO_UNIX_SOCKETS" || { test_done } +uname_s=$(uname -s) +case $uname_s in +*MINGW*) + test_path_is_socket () { + # `test -S` cannot detect Win10's Unix sockets + test_path_exists "$1" + } + ;; +*) + test_path_is_socket () { + test -S "$1" + } + ;; +esac + # don't leave a stale daemon running test_atexit 'git credential-cache exit' @@ -21,7 +36,7 @@ test_expect_success 'socket defaults to ~/.cache/git/credential/socket' ' rmdir -p .cache/git/credential/ " && test_path_is_missing "$HOME/.git-credential-cache" && - test -S "$HOME/.cache/git/credential/socket" + test_path_is_socket "$HOME/.cache/git/credential/socket" ' XDG_CACHE_HOME="$HOME/xdg" @@ -31,7 +46,7 @@ helper_test cache test_expect_success "use custom XDG_CACHE_HOME if set and default sockets are not created" ' test_when_finished "git credential-cache exit" && - test -S "$XDG_CACHE_HOME/git/credential/socket" && + test_path_is_socket "$XDG_CACHE_HOME/git/credential/socket" && test_path_is_missing "$HOME/.git-credential-cache/socket" && test_path_is_missing "$HOME/.cache/git/credential/socket" ' @@ -48,7 +63,7 @@ test_expect_success 'credential-cache --socket option overrides default location username=store-user password=store-pass EOF - test -S "$HOME/dir/socket" + test_path_is_socket "$HOME/dir/socket" ' test_expect_success "use custom XDG_CACHE_HOME even if xdg socket exists" ' @@ -62,7 +77,7 @@ test_expect_success "use custom XDG_CACHE_HOME even if xdg socket exists" ' username=store-user password=store-pass EOF - test -S "$HOME/.cache/git/credential/socket" && + test_path_is_socket "$HOME/.cache/git/credential/socket" && XDG_CACHE_HOME="$HOME/xdg" && export XDG_CACHE_HOME && check approve cache <<-\EOF && @@ -71,7 +86,7 @@ test_expect_success "use custom XDG_CACHE_HOME even if xdg socket exists" ' username=store-user password=store-pass EOF - test -S "$XDG_CACHE_HOME/git/credential/socket" + test_path_is_socket "$XDG_CACHE_HOME/git/credential/socket" ' test_expect_success 'use user socket if user directory exists' ' @@ -79,14 +94,15 @@ test_expect_success 'use user socket if user directory exists' ' git credential-cache exit && rmdir \"\$HOME/.git-credential-cache/\" " && - mkdir -p -m 700 "$HOME/.git-credential-cache/" && + mkdir -p "$HOME/.git-credential-cache/" && + chmod 700 "$HOME/.git-credential-cache/" && check approve cache <<-\EOF && protocol=https host=example.com username=store-user password=store-pass EOF - test -S "$HOME/.git-credential-cache/socket" + test_path_is_socket "$HOME/.git-credential-cache/socket" ' test_expect_success SYMLINKS 'use user socket if user directory is a symlink to a directory' ' @@ -103,7 +119,7 @@ test_expect_success SYMLINKS 'use user socket if user directory is a symlink to username=store-user password=store-pass EOF - test -S "$HOME/.git-credential-cache/socket" + test_path_is_socket "$HOME/.git-credential-cache/socket" ' helper_test_timeout cache --timeout=1 diff --git a/t/t0410-partial-clone.sh b/t/t0410-partial-clone.sh index a211a66c67..bba679685f 100755 --- a/t/t0410-partial-clone.sh +++ b/t/t0410-partial-clone.sh @@ -4,6 +4,9 @@ test_description='partial clone' . ./test-lib.sh +# missing promisor objects cause repacks which write bitmaps to fail +GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 + delete_object () { rm $1/.git/objects/$(echo $2 | sed -e 's|^..|&/|') } @@ -536,7 +539,13 @@ test_expect_success 'gc does not repack promisor objects if there are none' ' repack_and_check () { rm -rf repo2 && cp -r repo repo2 && - git -C repo2 repack $1 -d && + if test x"$1" = "x--must-fail" + then + shift + test_must_fail git -C repo2 repack $1 -d + else + git -C repo2 repack $1 -d + fi && git -C repo2 fsck && git -C repo2 cat-file -e $2 && @@ -561,6 +570,7 @@ test_expect_success 'repack -d does not irreversibly delete promisor objects' ' printf "$THREE\n" | pack_as_from_promisor && delete_object repo "$ONE" && + repack_and_check --must-fail -ab "$TWO" "$THREE" && repack_and_check -a "$TWO" "$THREE" && repack_and_check -A "$TWO" "$THREE" && repack_and_check -l "$TWO" "$THREE" diff --git a/t/t1013-read-tree-submodule.sh b/t/t1013-read-tree-submodule.sh index b6df7444c0..bfc90d4cf2 100755 --- a/t/t1013-read-tree-submodule.sh +++ b/t/t1013-read-tree-submodule.sh @@ -6,7 +6,6 @@ test_description='read-tree can handle submodules' . "$TEST_DIRECTORY"/lib-submodule-update.sh KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS=1 -KNOWN_FAILURE_SUBMODULE_OVERWRITE_IGNORED_UNTRACKED=1 test_submodule_switch_recursing_with_args "read-tree -u -m" diff --git a/t/t1091-sparse-checkout-builtin.sh b/t/t1091-sparse-checkout-builtin.sh index 38fc8340f5..272ba1b566 100755 --- a/t/t1091-sparse-checkout-builtin.sh +++ b/t/t1091-sparse-checkout-builtin.sh @@ -206,16 +206,21 @@ test_expect_success 'sparse-checkout disable' ' ' test_expect_success 'sparse-index enabled and disabled' ' - git -C repo sparse-checkout init --cone --sparse-index && - test_cmp_config -C repo true index.sparse && - test-tool -C repo read-cache --table >cache && - grep " tree " cache && - - git -C repo sparse-checkout disable && - test-tool -C repo read-cache --table >cache && - ! grep " tree " cache && - git -C repo config --list >config && - ! grep index.sparse config + ( + sane_unset GIT_TEST_SPLIT_INDEX && + git -C repo update-index --no-split-index && + + git -C repo sparse-checkout init --cone --sparse-index && + test_cmp_config -C repo true index.sparse && + test-tool -C repo read-cache --table >cache && + grep " tree " cache && + + git -C repo sparse-checkout disable && + test-tool -C repo read-cache --table >cache && + ! grep " tree " cache && + git -C repo config --list >config && + ! grep index.sparse config + ) ' test_expect_success 'cone mode: init and set' ' @@ -406,7 +411,7 @@ test_expect_success 'sparse-checkout (init|set|disable) warns with unmerged stat git -C unmerged sparse-checkout disable ' -test_expect_success 'sparse-checkout reapply' ' +test_expect_failure 'sparse-checkout reapply' ' git clone repo tweak && echo dirty >tweak/deep/deeper2/a && @@ -438,6 +443,8 @@ test_expect_success 'sparse-checkout reapply' ' test_i18ngrep "warning.*The following paths are unmerged" err && test_path_is_file tweak/folder1/a && + # NEEDSWORK: We are asking to update a file outside of the + # sparse-checkout cone, but this is no longer allowed. git -C tweak add folder1/a && git -C tweak sparse-checkout reapply 2>err && test_must_be_empty err && @@ -642,4 +649,63 @@ test_expect_success MINGW 'cone mode replaces backslashes with slashes' ' check_files repo/deep a deeper1 ' +test_expect_success 'cone mode clears ignored subdirectories' ' + rm repo/.git/info/sparse-checkout && + + git -C repo sparse-checkout init --cone && + git -C repo sparse-checkout set deep/deeper1 && + + cat >repo/.gitignore <<-\EOF && + obj/ + *.o + EOF + + git -C repo add .gitignore && + git -C repo commit -m ".gitignore" && + + mkdir -p repo/obj repo/folder1/obj repo/deep/deeper2/obj && + for file in folder1/obj/a obj/a folder1/file.o folder1.o \ + deep/deeper2/obj/a deep/deeper2/file.o file.o + do + echo ignored >repo/$file || return 1 + done && + + git -C repo status --porcelain=v2 >out && + test_must_be_empty out && + + git -C repo sparse-checkout reapply && + test_path_is_missing repo/folder1 && + test_path_is_missing repo/deep/deeper2 && + test_path_is_dir repo/obj && + test_path_is_file repo/file.o && + + git -C repo status --porcelain=v2 >out && + test_must_be_empty out && + + git -C repo sparse-checkout set deep/deeper2 && + test_path_is_missing repo/deep/deeper1 && + test_path_is_dir repo/deep/deeper2 && + test_path_is_dir repo/obj && + test_path_is_file repo/file.o && + + >repo/deep/deeper2/ignored.o && + >repo/deep/deeper2/untracked && + + # When an untracked file is in the way, all untracked files + # (even ignored files) are preserved. + git -C repo sparse-checkout set folder1 2>err && + grep "contains untracked files" err && + test_path_is_file repo/deep/deeper2/ignored.o && + test_path_is_file repo/deep/deeper2/untracked && + + # The rest of the cone matches expectation + test_path_is_missing repo/deep/deeper1 && + test_path_is_dir repo/obj && + test_path_is_file repo/file.o && + + git -C repo status --porcelain=v2 >out && + echo "? deep/deeper2/untracked" >expect && + test_cmp expect out +' + test_done diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh index 91e30d6ec2..ca91c6a67f 100755 --- a/t/t1092-sparse-checkout-compatibility.sh +++ b/t/t1092-sparse-checkout-compatibility.sh @@ -47,7 +47,7 @@ test_expect_success 'setup' ' git checkout -b base && for dir in folder1 folder2 deep do - git checkout -b update-$dir && + git checkout -b update-$dir base && echo "updated $dir" >$dir/a && git commit -a -m "update $dir" || return 1 done && @@ -114,6 +114,16 @@ test_expect_success 'setup' ' git add . && git commit -m "file to dir" && + for side in left right + do + git checkout -b merge-$side base && + echo $side >>deep/deeper2/a && + echo $side >>folder1/a && + echo $side >>folder2/a && + git add . && + git commit -m "$side" || return 1 + done && + git checkout -b deepest base && echo "updated deepest" >deep/deeper1/deepest/a && git commit -a -m "update deepest" && @@ -177,6 +187,16 @@ test_sparse_match () { test_cmp sparse-checkout-err sparse-index-err } +test_sparse_unstaged () { + file=$1 && + for repo in sparse-checkout sparse-index + do + # Skip "unmerged" paths + git -C $repo diff --staged --diff-filter=u -- "$file" >diff && + test_must_be_empty diff || return 1 + done +} + test_expect_success 'sparse-index contents' ' init_repos && @@ -281,6 +301,20 @@ test_expect_success 'add, commit, checkout' ' test_all_match git checkout - ' +test_expect_success 'add outside sparse cone' ' + init_repos && + + run_on_sparse mkdir folder1 && + run_on_sparse ../edit-contents folder1/a && + run_on_sparse ../edit-contents folder1/newfile && + test_sparse_match test_must_fail git add folder1/a && + grep "Disable or modify the sparsity rules" sparse-checkout-err && + test_sparse_unstaged folder1/a && + test_sparse_match test_must_fail git add folder1/newfile && + grep "Disable or modify the sparsity rules" sparse-checkout-err && + test_sparse_unstaged folder1/newfile +' + test_expect_success 'commit including unstaged changes' ' init_repos && @@ -312,9 +346,6 @@ test_expect_success 'commit including unstaged changes' ' test_expect_success 'status/add: outside sparse cone' ' init_repos && - # adding a "missing" file outside the cone should fail - test_sparse_match test_must_fail git add folder1/a && - # folder1 is at HEAD, but outside the sparse cone run_on_sparse mkdir folder1 && cp initial-repo/folder1/a sparse-checkout/folder1/a && @@ -330,21 +361,29 @@ test_expect_success 'status/add: outside sparse cone' ' test_sparse_match git status --porcelain=v2 && - # This "git add folder1/a" fails with a warning - # in the sparse repos, differing from the full - # repo. This is intentional. + # Adding the path outside of the sparse-checkout cone should fail. test_sparse_match test_must_fail git add folder1/a && + grep "Disable or modify the sparsity rules" sparse-checkout-err && + test_sparse_unstaged folder1/a && test_sparse_match test_must_fail git add --refresh folder1/a && - test_all_match git status --porcelain=v2 && - - test_all_match git add . && + grep "Disable or modify the sparsity rules" sparse-checkout-err && + test_sparse_unstaged folder1/a && + test_sparse_match test_must_fail git add folder1/new && + grep "Disable or modify the sparsity rules" sparse-checkout-err && + test_sparse_unstaged folder1/new && + test_sparse_match git add --sparse folder1/a && + test_sparse_match git add --sparse folder1/new && + + test_all_match git add --sparse . && test_all_match git status --porcelain=v2 && test_all_match git commit -m folder1/new && + test_all_match git rev-parse HEAD^{tree} && run_on_all ../edit-contents folder1/newer && - test_all_match git add folder1/ && + test_all_match git add --sparse folder1/ && test_all_match git status --porcelain=v2 && - test_all_match git commit -m folder1/newer + test_all_match git commit -m folder1/newer && + test_all_match git rev-parse HEAD^{tree} ' test_expect_success 'checkout and reset --hard' ' @@ -472,16 +511,97 @@ test_expect_success 'checkout and reset (mixed) [sparse]' ' test_sparse_match git reset update-folder2 ' -test_expect_success 'merge' ' +test_expect_success 'merge, cherry-pick, and rebase' ' init_repos && - test_all_match git checkout -b merge update-deep && - test_all_match git merge -m "folder1" update-folder1 && - test_all_match git rev-parse HEAD^{tree} && - test_all_match git merge -m "folder2" update-folder2 && + for OPERATION in "merge -m merge" cherry-pick rebase + do + test_all_match git checkout -B temp update-deep && + test_all_match git $OPERATION update-folder1 && + test_all_match git rev-parse HEAD^{tree} && + test_all_match git $OPERATION update-folder2 && + test_all_match git rev-parse HEAD^{tree} || return 1 + done +' + +test_expect_success 'merge with conflict outside cone' ' + init_repos && + + test_all_match git checkout -b merge-tip merge-left && + test_all_match git status --porcelain=v2 && + test_all_match test_must_fail git merge -m merge merge-right && + test_all_match git status --porcelain=v2 && + + # Resolve the conflict in different ways: + # 1. Revert to the base + test_all_match git checkout base -- deep/deeper2/a && + test_all_match git status --porcelain=v2 && + + # 2. Add the file with conflict markers + test_sparse_match test_must_fail git add folder1/a && + grep "Disable or modify the sparsity rules" sparse-checkout-err && + test_sparse_unstaged folder1/a && + test_all_match git add --sparse folder1/a && + test_all_match git status --porcelain=v2 && + + # 3. Rename the file to another sparse filename and + # accept conflict markers as resolved content. + run_on_all mv folder2/a folder2/z && + test_sparse_match test_must_fail git add folder2 && + grep "Disable or modify the sparsity rules" sparse-checkout-err && + test_sparse_unstaged folder2/z && + test_all_match git add --sparse folder2 && + test_all_match git status --porcelain=v2 && + + test_all_match git merge --continue && + test_all_match git status --porcelain=v2 && test_all_match git rev-parse HEAD^{tree} ' +test_expect_success 'cherry-pick/rebase with conflict outside cone' ' + init_repos && + + for OPERATION in cherry-pick rebase + do + test_all_match git checkout -B tip && + test_all_match git reset --hard merge-left && + test_all_match git status --porcelain=v2 && + test_all_match test_must_fail git $OPERATION merge-right && + test_all_match git status --porcelain=v2 && + + # Resolve the conflict in different ways: + # 1. Revert to the base + test_all_match git checkout base -- deep/deeper2/a && + test_all_match git status --porcelain=v2 && + + # 2. Add the file with conflict markers + # NEEDSWORK: Even though the merge conflict removed the + # SKIP_WORKTREE bit from the index entry for folder1/a, we should + # warn that this is a problematic add. + test_sparse_match test_must_fail git add folder1/a && + grep "Disable or modify the sparsity rules" sparse-checkout-err && + test_sparse_unstaged folder1/a && + test_all_match git add --sparse folder1/a && + test_all_match git status --porcelain=v2 && + + # 3. Rename the file to another sparse filename and + # accept conflict markers as resolved content. + # NEEDSWORK: This mode now fails, because folder2/z is + # outside of the sparse-checkout cone and does not match an + # existing index entry with the SKIP_WORKTREE bit cleared. + run_on_all mv folder2/a folder2/z && + test_sparse_match test_must_fail git add folder2 && + grep "Disable or modify the sparsity rules" sparse-checkout-err && + test_sparse_unstaged folder2/z && + test_all_match git add --sparse folder2 && + test_all_match git status --porcelain=v2 && + + test_all_match git $OPERATION --continue && + test_all_match git status --porcelain=v2 && + test_all_match git rev-parse HEAD^{tree} || return 1 + done +' + test_expect_success 'merge with outside renames' ' init_repos && @@ -549,6 +669,7 @@ test_expect_success 'clean' ' test_expect_success 'submodule handling' ' init_repos && + test_sparse_match git sparse-checkout add modules && test_all_match mkdir modules && test_all_match touch modules/a && test_all_match git add modules && @@ -558,6 +679,7 @@ test_expect_success 'submodule handling' ' test_all_match git commit -m "add submodule" && # having a submodule prevents "modules" from collapse + test_sparse_match git sparse-checkout set deep/deeper1 && test-tool -C sparse-index read-cache --table >cache && grep "100644 blob .* modules/a" cache && grep "160000 commit $(git -C initial-repo rev-parse HEAD) modules/sub" cache @@ -575,8 +697,17 @@ test_expect_success 'sparse-index is expanded and converted back' ' ensure_not_expanded () { rm -f trace2.txt && echo >>sparse-index/untracked.txt && - GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \ - git -C sparse-index "$@" && + + if test "$1" = "!" + then + shift && + test_must_fail env \ + GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \ + git -C sparse-index "$@" || return 1 + else + GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \ + git -C sparse-index "$@" || return 1 + fi && test_region ! index ensure_full_index trace2.txt } @@ -598,7 +729,42 @@ test_expect_success 'sparse-index is not expanded' ' git -C sparse-index reset --hard && ensure_not_expanded checkout rename-out-to-out -- deep/deeper1 && git -C sparse-index reset --hard && - ensure_not_expanded restore -s rename-out-to-out -- deep/deeper1 + ensure_not_expanded restore -s rename-out-to-out -- deep/deeper1 && + + echo >>sparse-index/README.md && + ensure_not_expanded add -A && + echo >>sparse-index/extra.txt && + ensure_not_expanded add extra.txt && + echo >>sparse-index/untracked.txt && + ensure_not_expanded add . && + + ensure_not_expanded checkout -f update-deep && + test_config -C sparse-index pull.twohead ort && + ( + sane_unset GIT_TEST_MERGE_ALGORITHM && + for OPERATION in "merge -m merge" cherry-pick rebase + do + ensure_not_expanded merge -m merge update-folder1 && + ensure_not_expanded merge -m merge update-folder2 || return 1 + done + ) +' + +test_expect_success 'sparse-index is not expanded: merge conflict in cone' ' + init_repos && + + for side in right left + do + git -C sparse-index checkout -b expand-$side base && + echo $side >sparse-index/deep/a && + git -C sparse-index commit -a -m "$side" || return 1 + done && + + ( + sane_unset GIT_TEST_MERGE_ALGORITHM && + git -C sparse-index config pull.twohead ort && + ensure_not_expanded ! merge -m merged expand-right + ) ' # NEEDSWORK: a sparse-checkout behaves differently from a full checkout diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh index 4506cd435b..0d4f73acaa 100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -1598,6 +1598,40 @@ test_expect_success 'transaction cannot restart ongoing transaction' ' test_must_fail git show-ref --verify refs/heads/restart ' +test_expect_success PIPE 'transaction flushes status updates' ' + mkfifo in out && + (git update-ref --stdin <in >out &) && + + exec 9>in && + exec 8<out && + test_when_finished "exec 9>&-" && + test_when_finished "exec 8<&-" && + + echo "start" >&9 && + echo "start: ok" >expected && + read line <&8 && + echo "$line" >actual && + test_cmp expected actual && + + echo "create refs/heads/flush $A" >&9 && + + echo prepare >&9 && + echo "prepare: ok" >expected && + read line <&8 && + echo "$line" >actual && + test_cmp expected actual && + + # This must now fail given that we have locked the ref. + test_must_fail git update-ref refs/heads/flush $B 2>stderr && + grep "fatal: update_ref failed for ref ${SQ}refs/heads/flush${SQ}: cannot lock ref" stderr && + + echo commit >&9 && + echo "commit: ok" >expected && + read line <&8 && + echo "$line" >actual && + test_cmp expected actual +' + test_expect_success 'directory not created deleting packed ref' ' git branch d1/d2/r1 HEAD && git pack-refs --all && diff --git a/t/t1405-main-ref-store.sh b/t/t1405-main-ref-store.sh index a237d9880e..49718b7ea7 100755 --- a/t/t1405-main-ref-store.sh +++ b/t/t1405-main-ref-store.sh @@ -9,12 +9,18 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME RUN="test-tool ref-store main" -test_expect_success 'pack_refs(PACK_REFS_ALL | PACK_REFS_PRUNE)' ' - test_commit one && + +test_expect_success 'setup' ' + test_commit one +' + +test_expect_success REFFILES 'pack_refs(PACK_REFS_ALL | PACK_REFS_PRUNE)' ' N=`find .git/refs -type f | wc -l` && test "$N" != 0 && - $RUN pack-refs 3 && - N=`find .git/refs -type f | wc -l` + ALL_OR_PRUNE_FLAG=3 && + $RUN pack-refs ${ALL_OR_PRUNE_FLAG} && + N=`find .git/refs -type f` && + test -z "$N" ' test_expect_success 'create_symref(FOO, refs/heads/main)' ' @@ -98,12 +104,12 @@ test_expect_success 'reflog_exists(HEAD)' ' test_expect_success 'delete_reflog(HEAD)' ' $RUN delete-reflog HEAD && - ! test -f .git/logs/HEAD + test_must_fail git reflog exists HEAD ' test_expect_success 'create-reflog(HEAD)' ' $RUN create-reflog HEAD 1 && - test -f .git/logs/HEAD + git reflog exists HEAD ' test_expect_success 'delete_ref(refs/heads/foo)' ' diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh index 27b9080251..d42f067ff8 100755 --- a/t/t1410-reflog.sh +++ b/t/t1410-reflog.sh @@ -374,7 +374,9 @@ test_expect_failure 'reflog with non-commit entries displays all entries' ' test_line_count = 3 actual ' -test_expect_success 'reflog expire operates on symref not referrent' ' +# This test takes a lock on an individual ref; this is not supported in +# reftable. +test_expect_success REFFILES 'reflog expire operates on symref not referrent' ' git branch --create-reflog the_symref && git branch --create-reflog referrent && git update-ref referrent HEAD && diff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh index b1839e0877..fa3aeb80f2 100755 --- a/t/t1430-bad-ref-name.sh +++ b/t/t1430-bad-ref-name.sh @@ -170,7 +170,7 @@ test_expect_success 'for-each-ref emits warnings for broken names' ' ! grep -e "badname" output && ! grep -e "broken\.\.\.symref" output && test_i18ngrep "ignoring ref with broken name refs/heads/broken\.\.\.ref" error && - test_i18ngrep "ignoring broken ref refs/heads/badname" error && + test_i18ngrep ! "ignoring broken ref refs/heads/badname" error && test_i18ngrep "ignoring ref with broken name refs/heads/broken\.\.\.symref" error ' diff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh index b29563fc99..284fe18e72 100755 --- a/t/t1502-rev-parse-parseopt.sh +++ b/t/t1502-rev-parse-parseopt.sh @@ -282,4 +282,58 @@ test_expect_success 'test --parseopt --stuck-long and short option with unset op test_cmp expect output ' +test_expect_success 'test --parseopt help output: "wrapped" options normal "or:" lines' ' + sed -e "s/^|//" >spec <<-\EOF && + |cmd [--some-option] + | [--another-option] + |cmd [--yet-another-option] + |-- + |h,help show the help + EOF + + sed -e "s/^|//" >expect <<-\END_EXPECT && + |cat <<\EOF + |usage: cmd [--some-option] + | or: [--another-option] + | or: cmd [--yet-another-option] + | + | -h, --help show the help + | + |EOF + END_EXPECT + + test_must_fail git rev-parse --parseopt -- -h >out <spec >actual && + test_cmp expect actual +' + +test_expect_success 'test --parseopt help output: multi-line blurb after empty line' ' + sed -e "s/^|//" >spec <<-\EOF && + |cmd [--some-option] + | [--another-option] + | + |multi + |line + |blurb + |-- + |h,help show the help + EOF + + sed -e "s/^|//" >expect <<-\END_EXPECT && + |cat <<\EOF + |usage: cmd [--some-option] + | or: [--another-option] + | + | multi + | line + | blurb + | + | -h, --help show the help + | + |EOF + END_EXPECT + + test_must_fail git rev-parse --parseopt -- -h >out <spec >actual && + test_cmp expect actual +' + test_done diff --git a/t/t1503-rev-parse-verify.sh b/t/t1503-rev-parse-verify.sh index bf08102391..40958615eb 100755 --- a/t/t1503-rev-parse-verify.sh +++ b/t/t1503-rev-parse-verify.sh @@ -142,7 +142,7 @@ test_expect_success 'main@{n} for various n' ' test_must_fail git rev-parse --verify main@{$Np1} ' -test_expect_success SYMLINKS 'ref resolution not confused by broken symlinks' ' +test_expect_success SYMLINKS,REFFILES 'ref resolution not confused by broken symlinks' ' ln -s does-not-exist .git/refs/heads/broken && test_must_fail git rev-parse --verify broken ' diff --git a/t/t1600-index.sh b/t/t1600-index.sh index c9b9e718b8..46329c488b 100755 --- a/t/t1600-index.sh +++ b/t/t1600-index.sh @@ -4,6 +4,8 @@ test_description='index file specific tests' . ./test-lib.sh +sane_unset GIT_TEST_SPLIT_INDEX + test_expect_success 'setup' ' echo 1 >a ' @@ -13,7 +15,8 @@ test_expect_success 'bogus GIT_INDEX_VERSION issues warning' ' rm -f .git/index && GIT_INDEX_VERSION=2bogus && export GIT_INDEX_VERSION && - git add a 2>&1 | sed "s/[0-9]//" >actual.err && + git add a 2>err && + sed "s/[0-9]//" err >actual.err && sed -e "s/ Z$/ /" <<-\EOF >expect.err && warning: GIT_INDEX_VERSION set, but the value is invalid. Using version Z @@ -27,7 +30,8 @@ test_expect_success 'out of bounds GIT_INDEX_VERSION issues warning' ' rm -f .git/index && GIT_INDEX_VERSION=1 && export GIT_INDEX_VERSION && - git add a 2>&1 | sed "s/[0-9]//" >actual.err && + git add a 2>err && + sed "s/[0-9]//" err >actual.err && sed -e "s/ Z$/ /" <<-\EOF >expect.err && warning: GIT_INDEX_VERSION set, but the value is invalid. Using version Z @@ -50,7 +54,8 @@ test_expect_success 'out of bounds index.version issues warning' ' sane_unset GIT_INDEX_VERSION && rm -f .git/index && git config --add index.version 1 && - git add a 2>&1 | sed "s/[0-9]//" >actual.err && + git add a 2>err && + sed "s/[0-9]//" err >actual.err && sed -e "s/ Z$/ /" <<-\EOF >expect.err && warning: index.version set, but the value is invalid. Using version Z @@ -79,7 +84,7 @@ test_index_version () { else unset GIT_INDEX_VERSION fi && - git add a 2>&1 && + git add a && echo $EXPECTED_OUTPUT_VERSION >expect && test-tool index-version <.git/index >actual && test_cmp expect actual diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh index 986baa612e..decd2527ed 100755 --- a/t/t1700-split-index.sh +++ b/t/t1700-split-index.sh @@ -510,4 +510,38 @@ test_expect_success 'do not refresh null base index' ' ) ' +test_expect_success 'reading split index at alternate location' ' + git init reading-alternate-location && + ( + cd reading-alternate-location && + >file-in-alternate && + git update-index --split-index --add file-in-alternate + ) && + echo file-in-alternate >expect && + + # Should be able to find the shared index both right next to + # the specified split index file ... + GIT_INDEX_FILE=./reading-alternate-location/.git/index \ + git ls-files --cached >actual && + test_cmp expect actual && + + # ... and, for backwards compatibility, in the current GIT_DIR + # as well. + mv -v ./reading-alternate-location/.git/sharedindex.* .git && + GIT_INDEX_FILE=./reading-alternate-location/.git/index \ + git ls-files --cached >actual && + test_cmp expect actual +' + +test_expect_success 'GIT_TEST_SPLIT_INDEX works' ' + git init git-test-split-index && + ( + cd git-test-split-index && + >file && + GIT_TEST_SPLIT_INDEX=1 git update-index --add file && + ls -l .git/sharedindex.* >actual && + test_line_count = 1 actual + ) +' + test_done diff --git a/t/t2021-checkout-overwrite.sh b/t/t2021-checkout-overwrite.sh index 70d69263e6..660132ff8d 100755 --- a/t/t2021-checkout-overwrite.sh +++ b/t/t2021-checkout-overwrite.sh @@ -48,6 +48,7 @@ test_expect_success 'checkout commit with dir must not remove untracked a/b' ' test_expect_success SYMLINKS 'the symlink remained' ' + test_when_finished "rm a/b" && test -h a/b ' diff --git a/t/t2402-worktree-list.sh b/t/t2402-worktree-list.sh index fedcefe8de..4012bd67b0 100755 --- a/t/t2402-worktree-list.sh +++ b/t/t2402-worktree-list.sh @@ -230,7 +230,7 @@ test_expect_success 'broken main worktree still at the top' ' EOF cd linked && echo "worktree $(pwd)" >expected && - echo "ref: .broken" >../.git/HEAD && + (cd ../ && test-tool ref-store main create-symref HEAD .broken ) && git worktree list --porcelain >out && head -n 3 out >actual && test_cmp ../expected actual && diff --git a/t/t2500-untracked-overwriting.sh b/t/t2500-untracked-overwriting.sh new file mode 100755 index 0000000000..5c0bf4d21f --- /dev/null +++ b/t/t2500-untracked-overwriting.sh @@ -0,0 +1,244 @@ +#!/bin/sh + +test_description='Test handling of overwriting untracked files' + +. ./test-lib.sh + +test_setup_reset () { + git init reset_$1 && + ( + cd reset_$1 && + test_commit init && + + git branch stable && + git branch work && + + git checkout work && + test_commit foo && + + git checkout stable + ) +} + +test_expect_success 'reset --hard will nuke untracked files/dirs' ' + test_setup_reset hard && + ( + cd reset_hard && + git ls-tree -r stable && + git log --all --name-status --oneline && + git ls-tree -r work && + + mkdir foo.t && + echo precious >foo.t/file && + echo foo >expect && + + git reset --hard work && + + # check that untracked directory foo.t/ was nuked + test_path_is_file foo.t && + test_cmp expect foo.t + ) +' + +test_expect_success 'reset --merge will preserve untracked files/dirs' ' + test_setup_reset merge && + ( + cd reset_merge && + + mkdir foo.t && + echo precious >foo.t/file && + cp foo.t/file expect && + + test_must_fail git reset --merge work 2>error && + test_cmp expect foo.t/file && + grep "Updating .foo.t. would lose untracked files" error + ) +' + +test_expect_success 'reset --keep will preserve untracked files/dirs' ' + test_setup_reset keep && + ( + cd reset_keep && + + mkdir foo.t && + echo precious >foo.t/file && + cp foo.t/file expect && + + test_must_fail git reset --merge work 2>error && + test_cmp expect foo.t/file && + grep "Updating.*foo.t.*would lose untracked files" error + ) +' + +test_setup_checkout_m () { + git init checkout && + ( + cd checkout && + test_commit init && + + test_write_lines file has some >filler && + git add filler && + git commit -m filler && + + git branch stable && + + git switch -c work && + echo stuff >notes.txt && + test_write_lines file has some words >filler && + git add notes.txt filler && + git commit -m filler && + + git checkout stable + ) +} + +test_expect_success 'checkout -m does not nuke untracked file' ' + test_setup_checkout_m && + ( + cd checkout && + + # Tweak filler + test_write_lines this file has some >filler && + # Make an untracked file, save its contents in "expect" + echo precious >notes.txt && + cp notes.txt expect && + + test_must_fail git checkout -m work && + test_cmp expect notes.txt + ) +' + +test_setup_sequencing () { + git init sequencing_$1 && + ( + cd sequencing_$1 && + test_commit init && + + test_write_lines this file has some words >filler && + git add filler && + git commit -m filler && + + mkdir -p foo/bar && + test_commit foo/bar/baz && + + git branch simple && + git branch fooey && + + git checkout fooey && + git rm foo/bar/baz.t && + echo stuff >>filler && + git add -u && + git commit -m "changes" && + + git checkout simple && + echo items >>filler && + echo newstuff >>newfile && + git add filler newfile && + git commit -m another + ) +} + +test_expect_success 'git rebase --abort and untracked files' ' + test_setup_sequencing rebase_abort_and_untracked && + ( + cd sequencing_rebase_abort_and_untracked && + git checkout fooey && + test_must_fail git rebase simple && + + cat init.t && + git rm init.t && + echo precious >init.t && + cp init.t expect && + git status --porcelain && + test_must_fail git rebase --abort && + test_cmp expect init.t + ) +' + +test_expect_success 'git rebase fast forwarding and untracked files' ' + test_setup_sequencing rebase_fast_forward_and_untracked && + ( + cd sequencing_rebase_fast_forward_and_untracked && + git checkout init && + echo precious >filler && + cp filler expect && + test_must_fail git rebase init simple && + test_cmp expect filler + ) +' + +test_expect_failure 'git rebase --autostash and untracked files' ' + test_setup_sequencing rebase_autostash_and_untracked && + ( + cd sequencing_rebase_autostash_and_untracked && + git checkout simple && + git rm filler && + mkdir filler && + echo precious >filler/file && + cp filler/file expect && + git rebase --autostash init && + test_path_is_file filler/file + ) +' + +test_expect_failure 'git stash and untracked files' ' + test_setup_sequencing stash_and_untracked_files && + ( + cd sequencing_stash_and_untracked_files && + git checkout simple && + git rm filler && + mkdir filler && + echo precious >filler/file && + cp filler/file expect && + git status --porcelain && + git stash push && + git status --porcelain && + test_path_is_file filler/file + ) +' + +test_expect_success 'git am --abort and untracked dir vs. unmerged file' ' + test_setup_sequencing am_abort_and_untracked && + ( + cd sequencing_am_abort_and_untracked && + git format-patch -1 --stdout fooey >changes.mbox && + test_must_fail git am --3way changes.mbox && + + # Delete the conflicted file; we will stage and commit it later + rm filler && + + # Put an unrelated untracked directory there + mkdir filler && + echo foo >filler/file1 && + echo bar >filler/file2 && + + test_must_fail git am --abort 2>errors && + test_path_is_dir filler && + grep "Updating .filler. would lose untracked files in it" errors + ) +' + +test_expect_success 'git am --skip and untracked dir vs deleted file' ' + test_setup_sequencing am_skip_and_untracked && + ( + cd sequencing_am_skip_and_untracked && + git checkout fooey && + git format-patch -1 --stdout simple >changes.mbox && + test_must_fail git am --3way changes.mbox && + + # Delete newfile + rm newfile && + + # Put an unrelated untracked directory there + mkdir newfile && + echo foo >newfile/file1 && + echo bar >newfile/file2 && + + # Change our mind about resolutions, just skip this patch + test_must_fail git am --skip 2>errors && + test_path_is_dir newfile && + grep "Updating .newfile. would lose untracked files in it" errors + ) +' + +test_done diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index cc4b10236e..e575ffb4ff 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -1272,6 +1272,19 @@ test_expect_success 'attempt to delete a branch merged to its base' ' test_must_fail git branch -d my10 ' +test_expect_success 'branch --delete --force removes dangling branch' ' + git checkout main && + test_commit unstable && + hash=$(git rev-parse HEAD) && + objpath=$(echo $hash | sed -e "s|^..|.git/objects/&/|") && + git branch --no-track dangling && + mv $objpath $objpath.x && + test_when_finished "mv $objpath.x $objpath" && + git branch --delete --force dangling && + git for-each-ref refs/heads/dangling >actual && + test_must_be_empty actual +' + test_expect_success 'use --edit-description' ' write_script editor <<-\EOF && echo "New contents" >"$1" diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh index 5325b9f67a..6e94c6db7b 100755 --- a/t/t3203-branch-output.sh +++ b/t/t3203-branch-output.sh @@ -340,6 +340,10 @@ test_expect_success 'git branch --format option' ' test_cmp expect actual ' +test_expect_success 'git branch with --format=%(rest) must fail' ' + test_must_fail git branch --format="%(rest)" >actual +' + test_expect_success 'worktree colors correct' ' cat >expect <<-EOF && * <GREEN>(HEAD detached from fromtag)<RESET> diff --git a/t/t3320-notes-merge-worktrees.sh b/t/t3320-notes-merge-worktrees.sh index 052516e6c6..6b2d507f3e 100755 --- a/t/t3320-notes-merge-worktrees.sh +++ b/t/t3320-notes-merge-worktrees.sh @@ -46,8 +46,9 @@ test_expect_success 'create some new worktrees' ' test_expect_success 'merge z into y fails and sets NOTES_MERGE_REF' ' git config core.notesRef refs/notes/y && test_must_fail git notes merge z && - echo "ref: refs/notes/y" >expect && - test_cmp expect .git/NOTES_MERGE_REF + echo "refs/notes/y" >expect && + git symbolic-ref NOTES_MERGE_REF >actual && + test_cmp expect actual ' test_expect_success 'merge z into y while mid-merge in another workdir fails' ' @@ -57,7 +58,7 @@ test_expect_success 'merge z into y while mid-merge in another workdir fails' ' test_must_fail git notes merge z 2>err && test_i18ngrep "a notes merge into refs/notes/y is already in-progress at" err ) && - test_path_is_missing .git/worktrees/worktree/NOTES_MERGE_REF + test_must_fail git -C worktree symbolic-ref NOTES_MERGE_REF ' test_expect_success 'merge z into x while mid-merge on y succeeds' ' @@ -68,8 +69,9 @@ test_expect_success 'merge z into x while mid-merge on y succeeds' ' test_i18ngrep "Automatic notes merge failed" out && grep -v "A notes merge into refs/notes/x is already in-progress in" out ) && - echo "ref: refs/notes/x" >expect && - test_cmp expect .git/worktrees/worktree2/NOTES_MERGE_REF + echo "refs/notes/x" >expect && + git -C worktree2 symbolic-ref NOTES_MERGE_REF >actual && + test_cmp expect actual ' test_done diff --git a/t/t3403-rebase-skip.sh b/t/t3403-rebase-skip.sh index e26762d0b2..f6e4864497 100755 --- a/t/t3403-rebase-skip.sh +++ b/t/t3403-rebase-skip.sh @@ -20,6 +20,7 @@ test_expect_success setup ' git add hello && git commit -m "hello" && git branch skip-reference && + git tag hello && echo world >> hello && git commit -a -m "hello world" && @@ -36,7 +37,8 @@ test_expect_success setup ' test_tick && GIT_AUTHOR_NAME="Another Author" \ GIT_AUTHOR_EMAIL="another.author@example.com" \ - git commit --amend --no-edit -m amended-goodbye && + git commit --amend --no-edit -m amended-goodbye \ + --reset-author && test_tick && git tag amended-goodbye && @@ -51,7 +53,7 @@ test_expect_success setup ' ' test_expect_success 'rebase with git am -3 (default)' ' - test_must_fail git rebase main + test_must_fail git rebase --apply main ' test_expect_success 'rebase --skip can not be used with other options' ' @@ -95,6 +97,13 @@ test_expect_success 'moved back to branch correctly' ' test_debug 'gitk --all & sleep 1' +test_expect_success 'skipping final pick removes .git/MERGE_MSG' ' + test_must_fail git rebase --onto hello reverted-goodbye^ \ + reverted-goodbye && + git rebase --skip && + test_path_is_missing .git/MERGE_MSG +' + test_expect_success 'correct advice upon picking empty commit' ' test_when_finished "git rebase --abort" && test_must_fail git rebase -i --onto goodbye \ diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 66bcbbf952..12eb226957 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -297,6 +297,7 @@ test_expect_success 'abort with error when new base cannot be checked out' ' output && test_i18ngrep "file1" output && test_path_is_missing .git/rebase-merge && + rm file1 && git reset --hard HEAD^ ' @@ -351,82 +352,6 @@ test_expect_success 'retain authorship when squashing' ' git show HEAD | grep "^Author: Twerp Snog" ' -test_expect_success REBASE_P '-p handles "no changes" gracefully' ' - HEAD=$(git rev-parse HEAD) && - git rebase -i -p HEAD^ && - git update-index --refresh && - git diff-files --quiet && - git diff-index --quiet --cached HEAD -- && - test $HEAD = $(git rev-parse HEAD) -' - -test_expect_failure REBASE_P 'exchange two commits with -p' ' - git checkout H && - ( - set_fake_editor && - FAKE_LINES="2 1" git rebase -i -p HEAD~2 - ) && - test H = $(git cat-file commit HEAD^ | sed -ne \$p) && - test G = $(git cat-file commit HEAD | sed -ne \$p) -' - -test_expect_success REBASE_P 'preserve merges with -p' ' - git checkout -b to-be-preserved primary^ && - : > unrelated-file && - git add unrelated-file && - test_tick && - git commit -m "unrelated" && - git checkout -b another-branch primary && - echo B > file1 && - test_tick && - git commit -m J file1 && - test_tick && - git merge to-be-preserved && - echo C > file1 && - test_tick && - git commit -m K file1 && - echo D > file1 && - test_tick && - git commit -m L1 file1 && - git checkout HEAD^ && - echo 1 > unrelated-file && - test_tick && - git commit -m L2 unrelated-file && - test_tick && - git merge another-branch && - echo E > file1 && - test_tick && - git commit -m M file1 && - git checkout -b to-be-rebased && - test_tick && - git rebase -i -p --onto branch1 primary && - git update-index --refresh && - git diff-files --quiet && - git diff-index --quiet --cached HEAD -- && - test_cmp_rev HEAD~6 branch1 && - test_cmp_rev HEAD~4^2 to-be-preserved && - test_cmp_rev HEAD^^2^ HEAD^^^ && - test $(git show HEAD~5:file1) = B && - test $(git show HEAD~3:file1) = C && - test $(git show HEAD:file1) = E && - test $(git show HEAD:unrelated-file) = 1 -' - -test_expect_success REBASE_P 'edit ancestor with -p' ' - ( - set_fake_editor && - FAKE_LINES="1 2 edit 3 4" git rebase -i -p HEAD~3 - ) && - echo 2 > unrelated-file && - test_tick && - git commit -m L2-modified --amend unrelated-file && - git rebase --continue && - git update-index --refresh && - git diff-files --quiet && - git diff-index --quiet --cached HEAD -- && - test $(git show HEAD:unrelated-file) = 2 -' - test_expect_success '--continue tries to commit' ' git reset --hard D && test_tick && @@ -839,6 +764,19 @@ test_expect_success 'reword' ' git show HEAD~2 | grep "C changed" ' +test_expect_success 'no uncommited changes when rewording the todo list is reloaded' ' + git checkout E && + test_when_finished "git checkout @{-1}" && + ( + set_fake_editor && + GIT_SEQUENCE_EDITOR="\"$PWD/fake-editor.sh\"" && + export GIT_SEQUENCE_EDITOR && + set_reword_editor && + FAKE_LINES="reword 1 reword 2" git rebase -i C + ) && + check_reworded_commits D E +' + test_expect_success 'rebase -i can copy notes' ' git config notes.rewrite.rebase true && git config notes.rewriteRef "refs/notes/*" && diff --git a/t/t3407-rebase-abort.sh b/t/t3407-rebase-abort.sh index 7c381fbc89..ebbaed147a 100755 --- a/t/t3407-rebase-abort.sh +++ b/t/t3407-rebase-abort.sh @@ -7,77 +7,77 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . ./test-lib.sh -### Test that we handle space characters properly -work_dir="$(pwd)/test dir" - test_expect_success setup ' - mkdir -p "$work_dir" && - cd "$work_dir" && - git init && - echo a > a && - git add a && - git commit -m a && + test_commit a a a && git branch to-rebase && - echo b > a && - git commit -a -m b && - echo c > a && - git commit -a -m c && + test_commit --annotate b a b && + test_commit --annotate c a c && git checkout to-rebase && - echo d > a && - git commit -a -m "merge should fail on this" && - echo e > a && - git commit -a -m "merge should fail on this, too" && - git branch pre-rebase + test_commit "merge should fail on this" a d d && + test_commit --annotate "merge should fail on this, too" a e pre-rebase ' +# Check that HEAD is equal to "pre-rebase" and the current branch is +# "to-rebase" +check_head() { + test_cmp_rev HEAD pre-rebase^{commit} && + test "$(git symbolic-ref HEAD)" = refs/heads/to-rebase +} + testrebase() { type=$1 - dotest=$2 + state_dir=$2 test_expect_success "rebase$type --abort" ' - cd "$work_dir" && # Clean up the state from the previous one git reset --hard pre-rebase && test_must_fail git rebase$type main && - test_path_is_dir "$dotest" && + test_path_is_dir "$state_dir" && git rebase --abort && - test $(git rev-parse to-rebase) = $(git rev-parse pre-rebase) && - test ! -d "$dotest" + check_head && + test_path_is_missing "$state_dir" ' test_expect_success "rebase$type --abort after --skip" ' - cd "$work_dir" && # Clean up the state from the previous one git reset --hard pre-rebase && test_must_fail git rebase$type main && - test_path_is_dir "$dotest" && + test_path_is_dir "$state_dir" && test_must_fail git rebase --skip && - test $(git rev-parse HEAD) = $(git rev-parse main) && + test_cmp_rev HEAD main && git rebase --abort && - test $(git rev-parse to-rebase) = $(git rev-parse pre-rebase) && - test ! -d "$dotest" + check_head && + test_path_is_missing "$state_dir" ' test_expect_success "rebase$type --abort after --continue" ' - cd "$work_dir" && # Clean up the state from the previous one git reset --hard pre-rebase && test_must_fail git rebase$type main && - test_path_is_dir "$dotest" && + test_path_is_dir "$state_dir" && echo c > a && echo d >> a && git add a && test_must_fail git rebase --continue && - test $(git rev-parse HEAD) != $(git rev-parse main) && + test_cmp_rev ! HEAD main && + git rebase --abort && + check_head && + test_path_is_missing "$state_dir" + ' + + test_expect_success "rebase$type --abort when checking out a tag" ' + test_when_finished "git symbolic-ref HEAD refs/heads/to-rebase" && + git reset --hard a -- && + test_must_fail git rebase$type --onto b c pre-rebase && + test_cmp_rev HEAD b^{commit} && git rebase --abort && - test $(git rev-parse to-rebase) = $(git rev-parse pre-rebase) && - test ! -d "$dotest" + test_cmp_rev HEAD pre-rebase^{commit} && + ! git symbolic-ref HEAD ' test_expect_success "rebase$type --abort does not update reflog" ' - cd "$work_dir" && # Clean up the state from the previous one git reset --hard pre-rebase && git reflog show to-rebase > reflog_before && @@ -89,7 +89,6 @@ testrebase() { ' test_expect_success 'rebase --abort can not be used with other options' ' - cd "$work_dir" && # Clean up the state from the previous one git reset --hard pre-rebase && test_must_fail git rebase$type main && @@ -97,33 +96,21 @@ testrebase() { test_must_fail git rebase --abort -v && git rebase --abort ' + + test_expect_success "rebase$type --quit" ' + test_when_finished "git symbolic-ref HEAD refs/heads/to-rebase" && + # Clean up the state from the previous one + git reset --hard pre-rebase && + test_must_fail git rebase$type main && + test_path_is_dir $state_dir && + head_before=$(git rev-parse HEAD) && + git rebase --quit && + test_cmp_rev HEAD $head_before && + test_path_is_missing .git/rebase-apply + ' } testrebase " --apply" .git/rebase-apply testrebase " --merge" .git/rebase-merge -test_expect_success 'rebase --apply --quit' ' - cd "$work_dir" && - # Clean up the state from the previous one - git reset --hard pre-rebase && - test_must_fail git rebase --apply main && - test_path_is_dir .git/rebase-apply && - head_before=$(git rev-parse HEAD) && - git rebase --quit && - test $(git rev-parse HEAD) = $head_before && - test ! -d .git/rebase-apply -' - -test_expect_success 'rebase --merge --quit' ' - cd "$work_dir" && - # Clean up the state from the previous one - git reset --hard pre-rebase && - test_must_fail git rebase --merge main && - test_path_is_dir .git/rebase-merge && - head_before=$(git rev-parse HEAD) && - git rebase --quit && - test $(git rev-parse HEAD) = $head_before && - test ! -d .git/rebase-merge -' - test_done diff --git a/t/t3408-rebase-multi-line.sh b/t/t3408-rebase-multi-line.sh index ab0960e6d9..cde3562e3a 100755 --- a/t/t3408-rebase-multi-line.sh +++ b/t/t3408-rebase-multi-line.sh @@ -55,14 +55,4 @@ test_expect_success rebase ' test_cmp expect actual ' -test_expect_success REBASE_P rebasep ' - - git checkout side-merge && - git rebase -p side && - git cat-file commit HEAD | sed -e "1,/^\$/d" >actual && - git cat-file commit side-merge-original | sed -e "1,/^\$/d" >expect && - test_cmp expect actual - -' - test_done diff --git a/t/t3409-rebase-preserve-merges.sh b/t/t3409-rebase-preserve-merges.sh deleted file mode 100755 index ec8062a66a..0000000000 --- a/t/t3409-rebase-preserve-merges.sh +++ /dev/null @@ -1,130 +0,0 @@ -#!/bin/sh -# -# Copyright(C) 2008 Stephen Habermann & Andreas Ericsson -# -test_description='git rebase -p should preserve merges - -Run "git rebase -p" and check that merges are properly carried along -' -GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main -export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME - -. ./test-lib.sh - -if ! test_have_prereq REBASE_P; then - skip_all='skipping git rebase -p tests, as asked for' - test_done -fi - -GIT_AUTHOR_EMAIL=bogus_email_address -export GIT_AUTHOR_EMAIL - -# Clone 2 (conflicting merge): -# -# A1--A2--B3 <-- origin/main -# \ \ -# B1------M <-- topic -# \ -# B2 <-- origin/topic -# -# Clone 3 (no-ff merge): -# -# A1--A2--B3 <-- origin/main -# \ -# B1------M <-- topic -# \ / -# \--A3 <-- topic2 -# \ -# B2 <-- origin/topic -# -# Clone 4 (same as Clone 3) - -test_expect_success 'setup for merge-preserving rebase' \ - 'echo First > A && - git add A && - git commit -m "Add A1" && - git checkout -b topic && - echo Second > B && - git add B && - git commit -m "Add B1" && - git checkout -f main && - echo Third >> A && - git commit -a -m "Modify A2" && - echo Fifth > B && - git add B && - git commit -m "Add different B" && - - git clone ./. clone2 && - ( - cd clone2 && - git checkout -b topic origin/topic && - test_must_fail git merge origin/main && - echo Resolved >B && - git add B && - git commit -m "Merge origin/main into topic" - ) && - - git clone ./. clone3 && - ( - cd clone3 && - git checkout -b topic2 origin/topic && - echo Sixth > A && - git commit -a -m "Modify A3" && - git checkout -b topic origin/topic && - git merge --no-ff topic2 - ) && - - git clone ./. clone4 && - ( - cd clone4 && - git checkout -b topic2 origin/topic && - echo Sixth > A && - git commit -a -m "Modify A3" && - git checkout -b topic origin/topic && - git merge --no-ff topic2 - ) && - - git checkout topic && - echo Fourth >> B && - git commit -a -m "Modify B2" -' - -test_expect_success '--continue works after a conflict' ' - ( - cd clone2 && - git fetch && - test_must_fail git rebase -p origin/topic && - test 2 = $(git ls-files B | wc -l) && - echo Resolved again > B && - test_must_fail git rebase --continue && - grep "^@@@ " .git/rebase-merge/patch && - git add B && - git rebase --continue && - test 1 = $(git rev-list --all --pretty=oneline | grep "Modify A" | wc -l) && - test 1 = $(git rev-list --all --pretty=oneline | grep "Add different" | wc -l) && - test 1 = $(git rev-list --all --pretty=oneline | grep "Merge origin" | wc -l) - ) -' - -test_expect_success 'rebase -p preserves no-ff merges' ' - ( - cd clone3 && - git fetch && - git rebase -p origin/topic && - test 3 = $(git rev-list --all --pretty=oneline | grep "Modify A" | wc -l) && - test 1 = $(git rev-list --all --pretty=oneline | grep "Merge branch" | wc -l) - ) -' - -test_expect_success 'rebase -p ignores merge.log config' ' - ( - cd clone4 && - git fetch && - git -c merge.log=1 rebase -p origin/topic && - echo >expected && - git log --format="%b" -1 >current && - test_cmp expected current - ) -' - -test_done diff --git a/t/t3410-rebase-preserve-dropped-merges.sh b/t/t3410-rebase-preserve-dropped-merges.sh deleted file mode 100755 index 2e29866993..0000000000 --- a/t/t3410-rebase-preserve-dropped-merges.sh +++ /dev/null @@ -1,90 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2008 Stephen Haberman -# - -test_description='git rebase preserve merges - -This test runs git rebase with preserve merges and ensures commits -dropped by the --cherry-pick flag have their childrens parents -rewritten. -' -. ./test-lib.sh - -if ! test_have_prereq REBASE_P; then - skip_all='skipping git rebase -p tests, as asked for' - test_done -fi - -# set up two branches like this: -# -# A - B - C - D - E -# \ -# F - G - H -# \ -# I -# -# where B, D and G touch the same file. - -test_expect_success 'setup' ' - test_commit A file1 && - test_commit B file1 1 && - test_commit C file2 && - test_commit D file1 2 && - test_commit E file3 && - git checkout A && - test_commit F file4 && - test_commit G file1 3 && - test_commit H file5 && - git checkout F && - test_commit I file6 -' - -# A - B - C - D - E -# \ \ \ -# F - G - H -- L \ --> L -# \ | \ -# I -- G2 -- J -- K I -- K -# G2 = same changes as G -test_expect_success 'skip same-resolution merges with -p' ' - git checkout H && - test_must_fail git merge E && - test_commit L file1 23 && - git checkout I && - test_commit G2 file1 3 && - test_must_fail git merge E && - test_commit J file1 23 && - test_commit K file7 file7 && - git rebase -i -p L && - test $(git rev-parse HEAD^^) = $(git rev-parse L) && - test "23" = "$(cat file1)" && - test "I" = "$(cat file6)" && - test "file7" = "$(cat file7)" -' - -# A - B - C - D - E -# \ \ \ -# F - G - H -- L2 \ --> L2 -# \ | \ -# I -- G3 --- J2 -- K2 I -- G3 -- K2 -# G2 = different changes as G -test_expect_success 'keep different-resolution merges with -p' ' - git checkout H && - test_must_fail git merge E && - test_commit L2 file1 23 && - git checkout I && - test_commit G3 file1 4 && - test_must_fail git merge E && - test_commit J2 file1 24 && - test_commit K2 file7 file7 && - test_must_fail git rebase -i -p L2 && - echo 234 > file1 && - git add file1 && - git rebase --continue && - test $(git rev-parse HEAD^^^) = $(git rev-parse L2) && - test "234" = "$(cat file1)" && - test "I" = "$(cat file6)" && - test "file7" = "$(cat file7)" -' - -test_done diff --git a/t/t3411-rebase-preserve-around-merges.sh b/t/t3411-rebase-preserve-around-merges.sh deleted file mode 100755 index fb45e7bf7b..0000000000 --- a/t/t3411-rebase-preserve-around-merges.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2008 Stephen Haberman -# - -test_description='git rebase preserve merges - -This test runs git rebase with -p and tries to squash a commit from after -a merge to before the merge. -' -. ./test-lib.sh - -if ! test_have_prereq REBASE_P; then - skip_all='skipping git rebase -p tests, as asked for' - test_done -fi - -. "$TEST_DIRECTORY"/lib-rebase.sh - -set_fake_editor - -# set up two branches like this: -# -# A1 - B1 - D1 - E1 - F1 -# \ / -# -- C1 -- - -test_expect_success 'setup' ' - test_commit A1 && - test_commit B1 && - test_commit C1 && - git reset --hard B1 && - test_commit D1 && - test_merge E1 C1 && - test_commit F1 -' - -# Should result in: -# -# A1 - B1 - D2 - E2 -# \ / -# -- C1 -- -# -test_expect_success 'squash F1 into D1' ' - FAKE_LINES="1 squash 4 2 3" git rebase -i -p B1 && - test "$(git rev-parse HEAD^2)" = "$(git rev-parse C1)" && - test "$(git rev-parse HEAD~2)" = "$(git rev-parse B1)" && - git tag E2 -' - -# Start with: -# -# A1 - B1 - D2 - E2 -# \ -# G1 ---- L1 ---- M1 -# \ / -# H1 -- J1 -- K1 -# \ / -# -- I1 -- -# -# And rebase G1..M1 onto E2 - -test_expect_success 'rebase two levels of merge' ' - git checkout A1 && - test_commit G1 && - test_commit H1 && - test_commit I1 && - git checkout -b branch3 H1 && - test_commit J1 && - test_merge K1 I1 && - git checkout -b branch2 G1 && - test_commit L1 && - test_merge M1 K1 && - GIT_EDITOR=: git rebase -i -p E2 && - test "$(git rev-parse HEAD~3)" = "$(git rev-parse E2)" && - test "$(git rev-parse HEAD~2)" = "$(git rev-parse HEAD^2^2~2)" && - test "$(git rev-parse HEAD^2^1^1)" = "$(git rev-parse HEAD^2^2^1)" -' - -test_done diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh index fda62c65bd..19c6f4acbf 100755 --- a/t/t3412-rebase-root.sh +++ b/t/t3412-rebase-root.sh @@ -89,17 +89,6 @@ test_expect_success 'pre-rebase got correct input (4)' ' test "z$(cat .git/PRE-REBASE-INPUT)" = z--root,work4 ' -test_expect_success REBASE_P 'rebase -i -p with linear history' ' - git checkout -b work5 other && - git rebase -i -p --root --onto main && - git log --pretty=tformat:"%s" > rebased5 && - test_cmp expect rebased5 -' - -test_expect_success REBASE_P 'pre-rebase got correct input (5)' ' - test "z$(cat .git/PRE-REBASE-INPUT)" = z--root, -' - test_expect_success 'set up merge history' ' git checkout other^ && git checkout -b side && @@ -123,13 +112,6 @@ commit work6~4 1 EOF -test_expect_success REBASE_P 'rebase -i -p with merge' ' - git checkout -b work6 other && - git rebase -i -p --root --onto main && - log_with_names work6 > rebased6 && - test_cmp expect-side rebased6 -' - test_expect_success 'set up second root and merge' ' git symbolic-ref HEAD refs/heads/third && rm .git/index && @@ -158,13 +140,6 @@ commit work7~5 1 EOF -test_expect_success REBASE_P 'rebase -i -p with two roots' ' - git checkout -b work7 other && - git rebase -i -p --root --onto main && - log_with_names work7 > rebased7 && - test_cmp expect-third rebased7 -' - test_expect_success 'setup pre-rebase hook that fails' ' mkdir -p .git/hooks && cat >.git/hooks/pre-rebase <<EOF && @@ -264,21 +239,9 @@ commit conflict3~6 1 EOF -test_expect_success REBASE_P 'rebase -i -p --root with conflict (first part)' ' - git checkout -b conflict3 other && - test_must_fail git rebase -i -p --root --onto main && - git ls-files -u | grep "B$" -' - test_expect_success 'fix the conflict' ' echo 3 > B && git add B ' -test_expect_success REBASE_P 'rebase -i -p --root with conflict (second part)' ' - git rebase --continue && - log_with_names conflict3 >out && - test_cmp expect-conflict-p out -' - test_done diff --git a/t/t3414-rebase-preserve-onto.sh b/t/t3414-rebase-preserve-onto.sh deleted file mode 100755 index 72e04b5386..0000000000 --- a/t/t3414-rebase-preserve-onto.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2009 Greg Price -# - -test_description='git rebase -p should respect --onto - -In a rebase with --onto, we should rewrite all the commits that -aren'"'"'t on top of $ONTO, even if they are on top of $UPSTREAM. -' -. ./test-lib.sh - -if ! test_have_prereq REBASE_P; then - skip_all='skipping git rebase -p tests, as asked for' - test_done -fi - -. "$TEST_DIRECTORY"/lib-rebase.sh - -# Set up branches like this: -# A1---B1---E1---F1---G1 -# \ \ / -# \ \--C1---D1--/ -# H1 - -test_expect_success 'setup' ' - test_commit A1 && - test_commit B1 && - test_commit C1 && - test_commit D1 && - git reset --hard B1 && - test_commit E1 && - test_commit F1 && - test_merge G1 D1 && - git reset --hard A1 && - test_commit H1 -' - -# Now rebase merge G1 from both branches' base B1, both should move: -# A1---B1---E1---F1---G1 -# \ \ / -# \ \--C1---D1--/ -# \ -# H1---E2---F2---G2 -# \ / -# \--C2---D2--/ - -test_expect_success 'rebase from B1 onto H1' ' - git checkout G1 && - git rebase -p --onto H1 B1 && - test "$(git rev-parse HEAD^1^1^1)" = "$(git rev-parse H1)" && - test "$(git rev-parse HEAD^2^1^1)" = "$(git rev-parse H1)" -' - -# On the other hand if rebase from E1 which is within one branch, -# then the other branch stays: -# A1---B1---E1---F1---G1 -# \ \ / -# \ \--C1---D1--/ -# \ \ -# H1-----F3-----G3 - -test_expect_success 'rebase from E1 onto H1' ' - git checkout G1 && - git rebase -p --onto H1 E1 && - test "$(git rev-parse HEAD^1^1)" = "$(git rev-parse H1)" && - test "$(git rev-parse HEAD^2)" = "$(git rev-parse D1)" -' - -# And the same if we rebase from a commit in the second-parent branch. -# A1---B1---E1---F1----G1 -# \ \ \ / -# \ \--C1---D1-\-/ -# \ \ -# H1------D3------G4 - -test_expect_success 'rebase from C1 onto H1' ' - git checkout G1 && - git rev-list --first-parent --pretty=oneline C1..G1 && - git rebase -p --onto H1 C1 && - test "$(git rev-parse HEAD^2^1)" = "$(git rev-parse H1)" && - test "$(git rev-parse HEAD^1)" = "$(git rev-parse F1)" -' - -test_done diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh index f4c2ee02bc..22eca73aa3 100755 --- a/t/t3418-rebase-continue.sh +++ b/t/t3418-rebase-continue.sh @@ -21,7 +21,7 @@ test_expect_success 'setup' ' git checkout main ' -test_expect_success 'interactive rebase --continue works with touched file' ' +test_expect_success 'merge based rebase --continue with works with touched file' ' rm -fr .git/rebase-* && git reset --hard && git checkout main && @@ -31,12 +31,22 @@ test_expect_success 'interactive rebase --continue works with touched file' ' git rebase --continue ' -test_expect_success 'non-interactive rebase --continue works with touched file' ' +test_expect_success 'merge based rebase --continue removes .git/MERGE_MSG' ' + git checkout -f --detach topic && + + test_must_fail git rebase --onto main HEAD^ && + git read-tree --reset -u HEAD && + test_path_is_file .git/MERGE_MSG && + git rebase --continue && + test_path_is_missing .git/MERGE_MSG +' + +test_expect_success 'apply based rebase --continue works with touched file' ' rm -fr .git/rebase-* && git reset --hard && git checkout main && - test_must_fail git rebase --onto main main topic && + test_must_fail git rebase --apply --onto main main topic && echo "Resolved" >F2 && git add F2 && test-tool chmtime =-60 F1 && @@ -109,20 +119,6 @@ test_expect_success 'rebase -i --continue handles merge strategy and options' ' test -f funny.was.run ' -test_expect_success REBASE_P 'rebase passes merge strategy options correctly' ' - rm -fr .git/rebase-* && - git reset --hard commit-new-file-F3-on-topic-branch && - test_commit theirs-to-merge && - git reset --hard HEAD^ && - test_commit some-commit && - test_tick && - git merge --no-ff theirs-to-merge && - FAKE_LINES="1 edit 2 3" git rebase -i -f -p -m \ - -s recursive --strategy-option=theirs HEAD~2 && - test_commit force-change && - git rebase --continue -' - test_expect_success 'rebase -r passes merge strategy options correctly' ' rm -fr .git/rebase-* && git reset --hard commit-new-file-F3-on-topic-branch && @@ -254,11 +250,10 @@ test_rerere_autoupdate () { ' } -test_rerere_autoupdate +test_rerere_autoupdate --apply test_rerere_autoupdate -m GIT_SEQUENCE_EDITOR=: && export GIT_SEQUENCE_EDITOR test_rerere_autoupdate -i -test_have_prereq !REBASE_P || test_rerere_autoupdate --preserve-merges unset GIT_SEQUENCE_EDITOR test_expect_success 'the todo command "break" works' ' diff --git a/t/t3421-rebase-topology-linear.sh b/t/t3421-rebase-topology-linear.sh index 4a9204b4b6..62d86d557d 100755 --- a/t/t3421-rebase-topology-linear.sh +++ b/t/t3421-rebase-topology-linear.sh @@ -29,7 +29,6 @@ test_run_rebase () { test_run_rebase success --apply test_run_rebase success -m test_run_rebase success -i -test_have_prereq !REBASE_P || test_run_rebase success -p test_expect_success 'setup branches and remote tracking' ' git tag -l >tags && @@ -53,7 +52,6 @@ test_run_rebase () { test_run_rebase success --apply test_run_rebase success -m test_run_rebase success -i -test_have_prereq !REBASE_P || test_run_rebase success -p test_run_rebase () { result=$1 @@ -70,7 +68,6 @@ test_run_rebase success --apply test_run_rebase success --fork-point test_run_rebase success -m test_run_rebase success -i -test_have_prereq !REBASE_P || test_run_rebase failure -p test_run_rebase () { result=$1 @@ -87,7 +84,6 @@ test_run_rebase success --apply test_run_rebase success --fork-point test_run_rebase success -m test_run_rebase success -i -test_have_prereq !REBASE_P || test_run_rebase success -p test_run_rebase () { result=$1 @@ -102,7 +98,6 @@ test_run_rebase success --apply test_run_rebase success --fork-point test_run_rebase success -m test_run_rebase success -i -test_have_prereq !REBASE_P || test_run_rebase success -p # f # / @@ -142,7 +137,6 @@ test_run_rebase () { test_run_rebase success --apply test_run_rebase success -m test_run_rebase success -i -test_have_prereq !REBASE_P || test_run_rebase success -p test_run_rebase () { result=$1 @@ -157,7 +151,6 @@ test_run_rebase () { test_run_rebase success --apply test_run_rebase success -m test_run_rebase success -i -test_have_prereq !REBASE_P || test_run_rebase success -p test_run_rebase () { result=$1 @@ -172,7 +165,6 @@ test_run_rebase () { test_run_rebase success --apply test_run_rebase success -m test_run_rebase success -i -test_have_prereq !REBASE_P || test_run_rebase success -p test_run_rebase () { result=$1 @@ -187,7 +179,6 @@ test_run_rebase () { test_run_rebase success --apply test_run_rebase success -m test_run_rebase success -i -test_have_prereq !REBASE_P || test_run_rebase success -p # a---b---c---j! # \ @@ -215,7 +206,6 @@ test_run_rebase () { test_run_rebase failure --apply test_run_rebase success -m test_run_rebase success -i -test_have_prereq !REBASE_P || test_run_rebase failure -p test_run_rebase () { result=$1 @@ -229,7 +219,6 @@ test_run_rebase () { } test_run_rebase success -m test_run_rebase success -i -test_have_prereq !REBASE_P || test_run_rebase success -p test_run_rebase () { result=$1 @@ -243,7 +232,6 @@ test_run_rebase () { } test_run_rebase success -m test_run_rebase success -i -test_have_prereq !REBASE_P || test_run_rebase success -p test_run_rebase success --rebase-merges # m @@ -283,7 +271,6 @@ test_run_rebase () { test_run_rebase success --apply test_run_rebase success -m test_run_rebase success -i -test_have_prereq !REBASE_P || test_run_rebase success -p test_run_rebase () { result=$1 @@ -298,7 +285,6 @@ test_run_rebase () { test_run_rebase success --apply test_run_rebase success -m test_run_rebase success -i -test_have_prereq !REBASE_P || test_run_rebase failure -p test_run_rebase () { result=$1 @@ -313,7 +299,6 @@ test_run_rebase () { test_run_rebase success --apply test_run_rebase success -m test_run_rebase success -i -test_have_prereq !REBASE_P || test_run_rebase success -p test_run_rebase () { result=$1 @@ -329,7 +314,6 @@ test_run_rebase () { test_run_rebase success --apply test_run_rebase success -m test_run_rebase success -i -test_have_prereq !REBASE_P || test_run_rebase failure -p test_run_rebase () { result=$1 @@ -344,7 +328,6 @@ test_run_rebase () { test_run_rebase success --apply test_run_rebase success -m test_run_rebase success -i -test_have_prereq !REBASE_P || test_run_rebase failure -p test_run_rebase () { result=$1 @@ -358,7 +341,6 @@ test_run_rebase () { test_run_rebase success '' test_run_rebase success -m test_run_rebase success -i -test_have_prereq !REBASE_P || test_run_rebase failure -p test_run_rebase () { result=$1 @@ -373,6 +355,5 @@ test_run_rebase () { test_run_rebase success '' test_run_rebase success -m test_run_rebase success -i -test_have_prereq !REBASE_P || test_run_rebase success -p test_done diff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh index c8234062c6..eb0a3d9d48 100755 --- a/t/t3422-rebase-incompatible-options.sh +++ b/t/t3422-rebase-incompatible-options.sh @@ -63,15 +63,4 @@ test_rebase_am_only () { test_rebase_am_only --whitespace=fix test_rebase_am_only -C4 -test_expect_success REBASE_P '--preserve-merges incompatible with --signoff' ' - git checkout B^0 && - test_must_fail git rebase --preserve-merges --signoff A -' - -test_expect_success REBASE_P \ - '--preserve-merges incompatible with --rebase-merges' ' - git checkout B^0 && - test_must_fail git rebase --preserve-merges --rebase-merges A -' - test_done diff --git a/t/t3425-rebase-topology-merges.sh b/t/t3425-rebase-topology-merges.sh index e42faa44e7..63acc1ea4d 100755 --- a/t/t3425-rebase-topology-merges.sh +++ b/t/t3425-rebase-topology-merges.sh @@ -106,155 +106,4 @@ test_run_rebase success 'd n o e' --apply test_run_rebase success 'd n o e' -m test_run_rebase success 'd n o e' -i -if ! test_have_prereq REBASE_P; then - skip_all='skipping git rebase -p tests, as asked for' - test_done -fi - -test_expect_success "rebase -p is no-op in non-linear history" " - reset_rebase && - git rebase -p d w && - test_cmp_rev w HEAD -" - -test_expect_success "rebase -p is no-op when base inside second parent" " - reset_rebase && - git rebase -p e w && - test_cmp_rev w HEAD -" - -test_expect_failure "rebase -p --root on non-linear history is a no-op" " - reset_rebase && - git rebase -p --root w && - test_cmp_rev w HEAD -" - -test_expect_success "rebase -p re-creates merge from side branch" " - reset_rebase && - git rebase -p z w && - test_cmp_rev z HEAD^ && - test_cmp_rev w^2 HEAD^2 -" - -test_expect_success "rebase -p re-creates internal merge" " - reset_rebase && - git rebase -p c w && - test_cmp_rev c HEAD~4 && - test_cmp_rev HEAD^2^ HEAD~3 && - test_revision_subjects 'd n e o w' HEAD~3 HEAD~2 HEAD^2 HEAD^ HEAD -" - -test_expect_success "rebase -p can re-create two branches on onto" " - reset_rebase && - git rebase -p --onto c d w && - test_cmp_rev c HEAD~3 && - test_cmp_rev c HEAD^2^ && - test_revision_subjects 'n e o w' HEAD~2 HEAD^2 HEAD^ HEAD -" - -# f -# / -# a---b---c---g---h -# \ -# d---gp--i -# \ \ -# e-------u -# -# gp = cherry-picked g -# h = reverted g -test_expect_success 'setup of non-linear-history for patch-equivalence tests' ' - git checkout e && - test_merge u i -' - -test_expect_success "rebase -p re-creates history around dropped commit matching upstream" " - reset_rebase && - git rebase -p h u && - test_cmp_rev h HEAD~3 && - test_cmp_rev HEAD^2^ HEAD~2 && - test_revision_subjects 'd i e u' HEAD~2 HEAD^2 HEAD^ HEAD -" - -test_expect_success "rebase -p --onto in merged history drops patches in upstream" " - reset_rebase && - git rebase -p --onto f h u && - test_cmp_rev f HEAD~3 && - test_cmp_rev HEAD^2^ HEAD~2 && - test_revision_subjects 'd i e u' HEAD~2 HEAD^2 HEAD^ HEAD -" - -test_expect_success "rebase -p --onto in merged history does not drop patches in onto" " - reset_rebase && - git rebase -p --onto h f u && - test_cmp_rev h HEAD~3 && - test_cmp_rev HEAD^2~2 HEAD~2 && - test_revision_subjects 'd gp i e u' HEAD~2 HEAD^2^ HEAD^2 HEAD^ HEAD -" - -# a---b---c---g---h -# \ -# d---gp--s -# \ \ / -# \ X -# \ / \ -# e---t -# -# gp = cherry-picked g -# h = reverted g -test_expect_success 'setup of non-linear-history for dropping whole side' ' - git checkout gp && - test_merge s e && - git checkout e && - test_merge t gp -' - -test_expect_failure "rebase -p drops merge commit when entire first-parent side is dropped" " - reset_rebase && - git rebase -p h s && - test_cmp_rev h HEAD~2 && - test_linear_range 'd e' h.. -" - -test_expect_success "rebase -p drops merge commit when entire second-parent side is dropped" " - reset_rebase && - git rebase -p h t && - test_cmp_rev h HEAD~2 && - test_linear_range 'd e' h.. -" - -# a---b---c -# \ -# d---e -# \ \ -# n---r -# \ -# o -# -# r = tree-same with n -test_expect_success 'setup of non-linear-history for empty commits' ' - git checkout n && - git merge --no-commit e && - git reset n . && - git commit -m r && - git reset --hard && - git clean -f && - git tag r -' - -test_expect_success "rebase -p re-creates empty internal merge commit" " - reset_rebase && - git rebase -p c r && - test_cmp_rev c HEAD~3 && - test_cmp_rev HEAD^2^ HEAD~2 && - test_revision_subjects 'd e n r' HEAD~2 HEAD^2 HEAD^ HEAD -" - -test_expect_success "rebase -p re-creates empty merge commit" " - reset_rebase && - git rebase -p o r && - test_cmp_rev e HEAD^2 && - test_cmp_rev o HEAD^ && - test_revision_subjects 'r' HEAD -" - test_done diff --git a/t/t3427-rebase-subtree.sh b/t/t3427-rebase-subtree.sh index e78c7e3796..48b76f8232 100755 --- a/t/t3427-rebase-subtree.sh +++ b/t/t3427-rebase-subtree.sh @@ -36,11 +36,10 @@ commit_message() { # where the root commit adds three files: topic_1.t, topic_2.t and topic_3.t. # # This commit history is then rebased onto `topic_3` with the -# `-Xsubtree=files_subtree` option in three different ways: +# `-Xsubtree=files_subtree` option in two different ways: # -# 1. using `--preserve-merges` -# 2. using `--preserve-merges` and --keep-empty -# 3. without specifying a rebase backend +# 1. without specifying a rebase backend +# 2. using the `--rebase-merges` backend test_expect_success 'setup' ' test_commit README && @@ -69,25 +68,6 @@ test_expect_success 'setup' ' git commit -m "Empty commit" --allow-empty ' -# FAILURE: Does not preserve topic_4. -test_expect_failure REBASE_P 'Rebase -Xsubtree --preserve-merges --onto commit' ' - reset_rebase && - git checkout -b rebase-preserve-merges to-rebase && - git rebase -Xsubtree=files_subtree --preserve-merges --onto files-main main && - verbose test "$(commit_message HEAD~)" = "topic_4" && - verbose test "$(commit_message HEAD)" = "files_subtree/topic_5" -' - -# FAILURE: Does not preserve topic_4. -test_expect_failure REBASE_P 'Rebase -Xsubtree --keep-empty --preserve-merges --onto commit' ' - reset_rebase && - git checkout -b rebase-keep-empty to-rebase && - git rebase -Xsubtree=files_subtree --keep-empty --preserve-merges --onto files-main main && - verbose test "$(commit_message HEAD~2)" = "topic_4" && - verbose test "$(commit_message HEAD~)" = "files_subtree/topic_5" && - verbose test "$(commit_message HEAD)" = "Empty commit" -' - test_expect_success 'Rebase -Xsubtree --empty=ask --onto commit' ' reset_rebase && git checkout -b rebase-onto to-rebase && diff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh index 6748070df5..43c82d9a33 100755 --- a/t/t3430-rebase-merges.sh +++ b/t/t3430-rebase-merges.sh @@ -172,19 +172,39 @@ test_expect_success 'failed `merge <branch>` does not crash' ' grep "^Merge branch ${SQ}G${SQ}$" .git/rebase-merge/message ' -test_expect_success 'fast-forward merge -c still rewords' ' - git checkout -b fast-forward-merge-c H && +test_expect_success 'merge -c commits before rewording and reloads todo-list' ' + cat >script-from-scratch <<-\EOF && + merge -c E B + merge -c H G + EOF + + git checkout -b merge-c H && ( - set_fake_editor && - FAKE_COMMIT_MESSAGE=edited \ - GIT_SEQUENCE_EDITOR="echo merge -c H G >" \ - git rebase -ir @^ + set_reword_editor && + GIT_SEQUENCE_EDITOR="\"$PWD/replace-editor.sh\"" \ + git rebase -i -r D ) && - echo edited >expected && - git log --pretty=format:%B -1 >actual && - test_cmp expected actual + check_reworded_commits E H ' +test_expect_success 'merge -c rewords when a strategy is given' ' + git checkout -b merge-c-with-strategy H && + write_script git-merge-override <<-\EOF && + echo overridden$1 >G.t + git add G.t + EOF + + PATH="$PWD:$PATH" \ + GIT_SEQUENCE_EDITOR="echo merge -c H G >" \ + GIT_EDITOR="echo edited >>" \ + git rebase --no-ff -ir -s override -Xxopt E && + test_write_lines overridden--xopt >expect && + test_cmp expect G.t && + test_write_lines H "" edited "" >expect && + git log --format=%B -1 >actual && + test_cmp expect actual + +' test_expect_success 'with a branch tip that was cherry-picked already' ' git checkout -b already-upstream main && base="$(git rev-parse --verify HEAD)" && diff --git a/t/t3435-rebase-gpg-sign.sh b/t/t3435-rebase-gpg-sign.sh index ec10766858..5f8ba2c739 100755 --- a/t/t3435-rebase-gpg-sign.sh +++ b/t/t3435-rebase-gpg-sign.sh @@ -65,6 +65,7 @@ test_rebase_gpg_sign ! true -i --gpg-sign --no-gpg-sign test_rebase_gpg_sign false -i --no-gpg-sign --gpg-sign test_expect_failure 'rebase -p --no-gpg-sign override commit.gpgsign' ' + test_when_finished "git clean -f" && git reset --hard merged && git config commit.gpgsign true && git rebase -p --no-gpg-sign --onto=one fork-point main && diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh index 9d100cd188..4b5b607673 100755 --- a/t/t3501-revert-cherry-pick.sh +++ b/t/t3501-revert-cherry-pick.sh @@ -158,4 +158,20 @@ test_expect_success 'cherry-pick works with dirty renamed file' ' grep -q "^modified$" renamed ' +test_expect_success 'advice from failed revert' ' + test_commit --no-tag "add dream" dream dream && + dream_oid=$(git rev-parse --short HEAD) && + cat <<-EOF >expected && + error: could not revert $dream_oid... add dream + hint: After resolving the conflicts, mark them with + hint: "git add/rm <pathspec>", then run + hint: "git revert --continue". + hint: You can instead skip this commit with "git revert --skip". + hint: To abort and get back to the state before "git revert", + hint: run "git revert --abort". + EOF + test_commit --append --no-tag "double-add dream" dream dream && + test_must_fail git revert HEAD^ 2>actual && + test_cmp expected actual +' test_done diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh index 014001b8f3..979e843c65 100755 --- a/t/t3507-cherry-pick-conflict.sh +++ b/t/t3507-cherry-pick-conflict.sh @@ -47,20 +47,23 @@ test_expect_success 'failed cherry-pick does not advance HEAD' ' test "$head" = "$newhead" ' -test_expect_success 'advice from failed cherry-pick' " +test_expect_success 'advice from failed cherry-pick' ' pristine_detach initial && - picked=\$(git rev-parse --short picked) && + picked=$(git rev-parse --short picked) && cat <<-EOF >expected && - error: could not apply \$picked... picked - hint: after resolving the conflicts, mark the corrected paths - hint: with 'git add <paths>' or 'git rm <paths>' - hint: and commit the result with 'git commit' + error: could not apply $picked... picked + hint: After resolving the conflicts, mark them with + hint: "git add/rm <pathspec>", then run + hint: "git cherry-pick --continue". + hint: You can instead skip this commit with "git cherry-pick --skip". + hint: To abort and get back to the state before "git cherry-pick", + hint: run "git cherry-pick --abort". EOF test_must_fail git cherry-pick picked 2>actual && test_cmp expected actual -" +' test_expect_success 'advice from failed cherry-pick --no-commit' " pristine_detach initial && diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh index 49010aa946..3b0fa66c33 100755 --- a/t/t3510-cherry-pick-sequence.sh +++ b/t/t3510-cherry-pick-sequence.sh @@ -238,6 +238,7 @@ test_expect_success 'allow skipping commit but not abort for a new history' ' ' test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' ' + test_when_finished "rm unrelated" && pristine_detach initial && git rm --cached unrelated && git commit -m "untrack unrelated" && diff --git a/t/t3602-rm-sparse-checkout.sh b/t/t3602-rm-sparse-checkout.sh index e9e9a15c74..ecce497a9c 100755 --- a/t/t3602-rm-sparse-checkout.sh +++ b/t/t3602-rm-sparse-checkout.sh @@ -11,12 +11,15 @@ test_expect_success 'setup' " git commit -m files && cat >sparse_error_header <<-EOF && - The following pathspecs didn't match any eligible path, but they do match index - entries outside the current sparse checkout: + The following paths and/or pathspecs matched paths that exist + outside of your sparse-checkout definition, so will not be + updated in the index: EOF cat >sparse_hint <<-EOF && - hint: Disable or modify the sparsity rules if you intend to update such entries. + hint: If you intend to update such entries, try one of the following: + hint: * Use the --sparse option. + hint: * Disable or modify the sparsity rules. hint: Disable this message with \"git config advice.updateSparsePath false\" EOF @@ -37,9 +40,25 @@ done test_expect_success 'recursive rm does not remove sparse entries' ' git reset --hard && git sparse-checkout set sub/dir && - git rm -r sub && + test_must_fail git rm -r sub && + git rm --sparse -r sub && git status --porcelain -uno >actual && - echo "D sub/dir/e" >expected && + cat >expected <<-\EOF && + D sub/d + D sub/dir/e + EOF + test_cmp expected actual +' + +test_expect_success 'recursive rm --sparse removes sparse entries' ' + git reset --hard && + git sparse-checkout set "sub/dir" && + git rm --sparse -r sub && + git status --porcelain -uno >actual && + cat >expected <<-\EOF && + D sub/d + D sub/dir/e + EOF test_cmp expected actual ' @@ -75,4 +94,15 @@ test_expect_success 'do not warn about sparse entries with --ignore-unmatch' ' git ls-files --error-unmatch b ' +test_expect_success 'refuse to rm a non-skip-worktree path outside sparse cone' ' + git reset --hard && + git sparse-checkout set a && + git update-index --no-skip-worktree b && + test_must_fail git rm b 2>stderr && + test_cmp b_error_and_hint stderr && + git rm --sparse b 2>stderr && + test_must_be_empty stderr && + test_path_is_missing b +' + test_done diff --git a/t/t3705-add-sparse-checkout.sh b/t/t3705-add-sparse-checkout.sh index 2b1fd0d0ee..5b904988d4 100755 --- a/t/t3705-add-sparse-checkout.sh +++ b/t/t3705-add-sparse-checkout.sh @@ -19,6 +19,7 @@ setup_sparse_entry () { fi && git add sparse_entry && git update-index --skip-worktree sparse_entry && + git commit --allow-empty -m "ensure sparse_entry exists at HEAD" && SPARSE_ENTRY_BLOB=$(git rev-parse :sparse_entry) } @@ -36,14 +37,22 @@ setup_gitignore () { EOF } +test_sparse_entry_unstaged () { + git diff --staged -- sparse_entry >diff && + test_must_be_empty diff +} + test_expect_success 'setup' " cat >sparse_error_header <<-EOF && - The following pathspecs didn't match any eligible path, but they do match index - entries outside the current sparse checkout: + The following paths and/or pathspecs matched paths that exist + outside of your sparse-checkout definition, so will not be + updated in the index: EOF cat >sparse_hint <<-EOF && - hint: Disable or modify the sparsity rules if you intend to update such entries. + hint: If you intend to update such entries, try one of the following: + hint: * Use the --sparse option. + hint: * Disable or modify the sparsity rules. hint: Disable this message with \"git config advice.updateSparsePath false\" EOF @@ -55,6 +64,7 @@ test_expect_success 'git add does not remove sparse entries' ' setup_sparse_entry && rm sparse_entry && test_must_fail git add sparse_entry 2>stderr && + test_sparse_entry_unstaged && test_cmp error_and_hint stderr && test_sparse_entry_unchanged ' @@ -73,6 +83,7 @@ test_expect_success 'git add . does not remove sparse entries' ' rm sparse_entry && setup_gitignore && test_must_fail git add . 2>stderr && + test_sparse_entry_unstaged && cat sparse_error_header >expect && echo . >>expect && @@ -88,6 +99,7 @@ do setup_sparse_entry && echo modified >sparse_entry && test_must_fail git add $opt sparse_entry 2>stderr && + test_sparse_entry_unstaged && test_cmp error_and_hint stderr && test_sparse_entry_unchanged ' @@ -98,6 +110,7 @@ test_expect_success 'git add --refresh does not update sparse entries' ' git ls-files --debug sparse_entry | grep mtime >before && test-tool chmtime -60 sparse_entry && test_must_fail git add --refresh sparse_entry 2>stderr && + test_sparse_entry_unstaged && test_cmp error_and_hint stderr && git ls-files --debug sparse_entry | grep mtime >after && test_cmp before after @@ -106,6 +119,7 @@ test_expect_success 'git add --refresh does not update sparse entries' ' test_expect_success 'git add --chmod does not update sparse entries' ' setup_sparse_entry && test_must_fail git add --chmod=+x sparse_entry 2>stderr && + test_sparse_entry_unstaged && test_cmp error_and_hint stderr && test_sparse_entry_unchanged && ! test -x sparse_entry @@ -116,6 +130,7 @@ test_expect_success 'git add --renormalize does not update sparse entries' ' setup_sparse_entry "LINEONE\r\nLINETWO\r\n" && echo "sparse_entry text=auto" >.gitattributes && test_must_fail git add --renormalize sparse_entry 2>stderr && + test_sparse_entry_unstaged && test_cmp error_and_hint stderr && test_sparse_entry_unchanged ' @@ -124,6 +139,7 @@ test_expect_success 'git add --dry-run --ignore-missing warn on sparse path' ' setup_sparse_entry && rm sparse_entry && test_must_fail git add --dry-run --ignore-missing sparse_entry 2>stderr && + test_sparse_entry_unstaged && test_cmp error_and_hint stderr && test_sparse_entry_unchanged ' @@ -145,11 +161,57 @@ test_expect_success 'do not warn when pathspec matches dense entries' ' git ls-files --error-unmatch dense_entry ' +test_expect_success 'git add fails outside of sparse-checkout definition' ' + test_when_finished git sparse-checkout disable && + test_commit a && + git sparse-checkout init && + git sparse-checkout set a && + echo >>sparse_entry && + + git update-index --no-skip-worktree sparse_entry && + test_must_fail git add sparse_entry && + test_sparse_entry_unstaged && + + test_must_fail git add --chmod=+x sparse_entry && + test_sparse_entry_unstaged && + + test_must_fail git add --renormalize sparse_entry && + test_sparse_entry_unstaged && + + # Avoid munging CRLFs to avoid an error message + git -c core.autocrlf=input add --sparse sparse_entry 2>stderr && + test_must_be_empty stderr && + test-tool read-cache --table >actual && + grep "^100644 blob.*sparse_entry\$" actual && + + git add --sparse --chmod=+x sparse_entry 2>stderr && + test_must_be_empty stderr && + test-tool read-cache --table >actual && + grep "^100755 blob.*sparse_entry\$" actual && + + git reset && + + # This will print a message over stderr on Windows. + git add --sparse --renormalize sparse_entry && + git status --porcelain >actual && + grep "^M sparse_entry\$" actual +' + test_expect_success 'add obeys advice.updateSparsePath' ' setup_sparse_entry && test_must_fail git -c advice.updateSparsePath=false add sparse_entry 2>stderr && + test_sparse_entry_unstaged && test_cmp sparse_entry_error stderr ' +test_expect_success 'add allows sparse entries with --sparse' ' + git sparse-checkout set a && + echo modified >sparse_entry && + test_must_fail git add sparse_entry && + test_sparse_entry_unchanged && + git add --sparse sparse_entry 2>stderr && + test_must_be_empty stderr +' + test_done diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index 873aa56e35..f0a82be9de 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -1307,4 +1307,62 @@ test_expect_success 'stash -c stash.useBuiltin=false warning ' ' test_must_be_empty err ' +test_expect_success 'git stash succeeds despite directory/file change' ' + test_create_repo directory_file_switch_v1 && + ( + cd directory_file_switch_v1 && + test_commit init && + + test_write_lines this file has some words >filler && + git add filler && + git commit -m filler && + + git rm filler && + mkdir filler && + echo contents >filler/file && + git stash push + ) +' + +test_expect_success 'git stash can pop file -> directory saved changes' ' + test_create_repo directory_file_switch_v2 && + ( + cd directory_file_switch_v2 && + test_commit init && + + test_write_lines this file has some words >filler && + git add filler && + git commit -m filler && + + git rm filler && + mkdir filler && + echo contents >filler/file && + cp filler/file expect && + git stash push --include-untracked && + git stash apply --index && + test_cmp expect filler/file + ) +' + +test_expect_success 'git stash can pop directory -> file saved changes' ' + test_create_repo directory_file_switch_v3 && + ( + cd directory_file_switch_v3 && + test_commit init && + + mkdir filler && + test_write_lines some words >filler/file1 && + test_write_lines and stuff >filler/file2 && + git add filler && + git commit -m filler && + + git rm -rf filler && + echo contents >filler && + cp filler expect && + git stash push --include-untracked && + git stash apply --index && + test_cmp expect filler + ) +' + test_done diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index e561a8e485..28683d059d 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -65,7 +65,7 @@ test_expect_success setup ' export GIT_AUTHOR_DATE GIT_COMMITTER_DATE && git checkout master && - git pull -s ours . side && + git pull -s ours --no-rebase . side && GIT_AUTHOR_DATE="2006-06-26 00:05:00 +0000" && GIT_COMMITTER_DATE="2006-06-26 00:05:00 +0000" && diff --git a/t/t4018/java-class-member-function b/t/t4018/java-class-member-function index 298bc7a71b..3b95f68b3b 100644 --- a/t/t4018/java-class-member-function +++ b/t/t4018/java-class-member-function @@ -3,6 +3,10 @@ public class Beer int special; public static void main(String RIGHT[]) { + someMethodCall(); + someOtherMethod("17") + .doThat(); + // Whatever System.out.print("ChangeMe"); } } diff --git a/t/t4018/java-enum-constant b/t/t4018/java-enum-constant new file mode 100644 index 0000000000..a1931c8379 --- /dev/null +++ b/t/t4018/java-enum-constant @@ -0,0 +1,6 @@ +private enum RIGHT { + ONE, + TWO, + THREE, + ChangeMe +} diff --git a/t/t4018/java-method-return-generic-bounded b/t/t4018/java-method-return-generic-bounded new file mode 100644 index 0000000000..66dd78c379 --- /dev/null +++ b/t/t4018/java-method-return-generic-bounded @@ -0,0 +1,9 @@ +class MyExample { + public <T extends Bar & Foo<T>, R> Map<T, R[]> foo(String[] RIGHT) { + someMethodCall(); + someOtherMethod() + .doThat(); + // Whatever... + return (List<T>) Arrays.asList("ChangeMe"); + } +} diff --git a/t/t4018/java-method-return-generic-wildcard b/t/t4018/java-method-return-generic-wildcard new file mode 100644 index 0000000000..96e9e5f2c1 --- /dev/null +++ b/t/t4018/java-method-return-generic-wildcard @@ -0,0 +1,9 @@ +class MyExample { + public List<? extends Comparable> foo(String[] RIGHT) { + someMethodCall(); + someOtherMethod() + .doThat(); + // Whatever... + return Arrays.asList("ChangeMe"); + } +} diff --git a/t/t4018/java-nested-field b/t/t4018/java-nested-field new file mode 100644 index 0000000000..d92d3ec688 --- /dev/null +++ b/t/t4018/java-nested-field @@ -0,0 +1,6 @@ +class MyExample { + private static class RIGHT { + // change an inner class field + String inner = "ChangeMe"; + } +} diff --git a/t/t4018/php-enum b/t/t4018/php-enum new file mode 100644 index 0000000000..91a69c1a2b --- /dev/null +++ b/t/t4018/php-enum @@ -0,0 +1,4 @@ +enum RIGHT: string +{ + case Foo = 'ChangeMe'; +} diff --git a/t/t4045-diff-relative.sh b/t/t4045-diff-relative.sh index 61ba5f707f..fab351b48a 100755 --- a/t/t4045-diff-relative.sh +++ b/t/t4045-diff-relative.sh @@ -162,4 +162,57 @@ check_diff_relative_option subdir file2 true --no-relative --relative check_diff_relative_option . file2 false --no-relative --relative=subdir check_diff_relative_option . file2 true --no-relative --relative=subdir +test_expect_success 'setup diff --relative unmerged' ' + test_commit zero file0 && + test_commit base subdir/file0 && + git switch -c br1 && + test_commit one file0 && + test_commit sub1 subdir/file0 && + git switch -c br2 base && + test_commit two file0 && + git switch -c br3 && + test_commit sub3 subdir/file0 +' + +test_expect_success 'diff --relative without change in subdir' ' + git switch br2 && + test_when_finished "git merge --abort" && + test_must_fail git merge one && + git -C subdir diff --relative >out && + test_must_be_empty out && + git -C subdir diff --relative --name-only >out && + test_must_be_empty out +' + +test_expect_success 'diff --relative --name-only with change in subdir' ' + git switch br3 && + test_when_finished "git merge --abort" && + test_must_fail git merge sub1 && + test_write_lines file0 file0 >expected && + git -C subdir diff --relative --name-only >out && + test_cmp expected out +' + +test_expect_failure 'diff --relative with change in subdir' ' + git switch br3 && + br1_blob=$(git rev-parse --short --verify br1:subdir/file0) && + br3_blob=$(git rev-parse --short --verify br3:subdir/file0) && + test_when_finished "git merge --abort" && + test_must_fail git merge br1 && + cat >expected <<-EOF && + diff --cc file0 + index $br3_blob,$br1_blob..0000000 + --- a/file0 + +++ b/file0 + @@@ -1,1 -1,1 +1,5 @@@ + ++<<<<<<< HEAD + +sub3 + ++======= + + sub1 + ++>>>>>>> br1 + EOF + git -C subdir diff --relative >out && + test_cmp expected out +' + test_done diff --git a/t/t4060-diff-submodule-option-diff-format.sh b/t/t4060-diff-submodule-option-diff-format.sh index dc7b242697..d86e38abd8 100755 --- a/t/t4060-diff-submodule-option-diff-format.sh +++ b/t/t4060-diff-submodule-option-diff-format.sh @@ -361,7 +361,6 @@ test_expect_success 'typechanged submodule(submodule->blob)' ' rm -f sm1 && test_create_repo sm1 && head6=$(add_file sm1 foo6 foo7) -fullhead6=$(cd sm1; git rev-parse --verify HEAD) test_expect_success 'nonexistent commit' ' git diff-index -p --submodule=diff HEAD >actual && cat >expected <<-EOF && @@ -704,10 +703,26 @@ test_expect_success 'path filter' ' diff_cmp expected actual ' -commit_file sm2 +cat >.gitmodules <<-EOF +[submodule "sm2"] + path = sm2 + url = bogus_url +EOF +git add .gitmodules +commit_file sm2 .gitmodules + test_expect_success 'given commit' ' git diff-index -p --submodule=diff HEAD^ >actual && cat >expected <<-EOF && + diff --git a/.gitmodules b/.gitmodules + new file mode 100644 + index 1234567..89abcde + --- /dev/null + +++ b/.gitmodules + @@ -0,0 +1,3 @@ + +[submodule "sm2"] + +path = sm2 + +url = bogus_url Submodule sm1 $head7...0000000 (submodule deleted) Submodule sm2 0000000...$head9 (new submodule) diff --git a/sm2/foo8 b/sm2/foo8 @@ -729,15 +744,21 @@ test_expect_success 'given commit' ' ' test_expect_success 'setup .git file for sm2' ' - (cd sm2 && - REAL="$(pwd)/../.real" && - mv .git "$REAL" && - echo "gitdir: $REAL" >.git) + git submodule absorbgitdirs sm2 ' test_expect_success 'diff --submodule=diff with .git file' ' git diff --submodule=diff HEAD^ >actual && cat >expected <<-EOF && + diff --git a/.gitmodules b/.gitmodules + new file mode 100644 + index 1234567..89abcde + --- /dev/null + +++ b/.gitmodules + @@ -0,0 +1,3 @@ + +[submodule "sm2"] + +path = sm2 + +url = bogus_url Submodule sm1 $head7...0000000 (submodule deleted) Submodule sm2 0000000...$head9 (new submodule) diff --git a/sm2/foo8 b/sm2/foo8 @@ -758,9 +779,67 @@ test_expect_success 'diff --submodule=diff with .git file' ' diff_cmp expected actual ' +mv sm2 sm2-bak + +test_expect_success 'deleted submodule with .git file' ' + git diff-index -p --submodule=diff HEAD >actual && + cat >expected <<-EOF && + Submodule sm1 $head7...0000000 (submodule deleted) + Submodule sm2 $head9...0000000 (submodule deleted) + diff --git a/sm2/foo8 b/sm2/foo8 + deleted file mode 100644 + index 1234567..89abcde + --- a/sm2/foo8 + +++ /dev/null + @@ -1 +0,0 @@ + -foo8 + diff --git a/sm2/foo9 b/sm2/foo9 + deleted file mode 100644 + index 1234567..89abcde + --- a/sm2/foo9 + +++ /dev/null + @@ -1 +0,0 @@ + -foo9 + EOF + diff_cmp expected actual +' + +echo submodule-to-blob>sm2 + +test_expect_success 'typechanged(submodule->blob) submodule with .git file' ' + git diff-index -p --submodule=diff HEAD >actual && + cat >expected <<-EOF && + Submodule sm1 $head7...0000000 (submodule deleted) + Submodule sm2 $head9...0000000 (submodule deleted) + diff --git a/sm2/foo8 b/sm2/foo8 + deleted file mode 100644 + index 1234567..89abcde + --- a/sm2/foo8 + +++ /dev/null + @@ -1 +0,0 @@ + -foo8 + diff --git a/sm2/foo9 b/sm2/foo9 + deleted file mode 100644 + index 1234567..89abcde + --- a/sm2/foo9 + +++ /dev/null + @@ -1 +0,0 @@ + -foo9 + diff --git a/sm2 b/sm2 + new file mode 100644 + index 1234567..89abcde + --- /dev/null + +++ b/sm2 + @@ -0,0 +1 @@ + +submodule-to-blob + EOF + diff_cmp expected actual +' + +rm sm2 +mv sm2-bak sm2 + test_expect_success 'setup nested submodule' ' - git submodule add -f ./sm2 && - git commit -a -m "add sm2" && git -C sm2 submodule add ../sm2 nested && git -C sm2 commit -a -m "nested sub" && head10=$(git -C sm2 rev-parse --short --verify HEAD) @@ -791,6 +870,7 @@ test_expect_success 'diff --submodule=diff with moved nested submodule HEAD' ' test_expect_success 'diff --submodule=diff recurses into nested submodules' ' cat >expected <<-EOF && + Submodule sm1 $head7...0000000 (submodule deleted) Submodule sm2 contains modified content Submodule sm2 $head9..$head10: diff --git a/sm2/.gitmodules b/sm2/.gitmodules @@ -830,4 +910,67 @@ test_expect_success 'diff --submodule=diff recurses into nested submodules' ' diff_cmp expected actual ' +(cd sm2; commit_file nested) +commit_file sm2 +head12=$(cd sm2; git rev-parse --short --verify HEAD) + +mv sm2 sm2-bak + +test_expect_success 'diff --submodule=diff recurses into deleted nested submodules' ' + cat >expected <<-EOF && + Submodule sm1 $head7...0000000 (submodule deleted) + Submodule sm2 $head12...0000000 (submodule deleted) + diff --git a/sm2/.gitmodules b/sm2/.gitmodules + deleted file mode 100644 + index 3a816b8..0000000 + --- a/sm2/.gitmodules + +++ /dev/null + @@ -1,3 +0,0 @@ + -[submodule "nested"] + - path = nested + - url = ../sm2 + diff --git a/sm2/foo8 b/sm2/foo8 + deleted file mode 100644 + index db9916b..0000000 + --- a/sm2/foo8 + +++ /dev/null + @@ -1 +0,0 @@ + -foo8 + diff --git a/sm2/foo9 b/sm2/foo9 + deleted file mode 100644 + index 9c3b4f6..0000000 + --- a/sm2/foo9 + +++ /dev/null + @@ -1 +0,0 @@ + -foo9 + Submodule nested $head11...0000000 (submodule deleted) + diff --git a/sm2/nested/file b/sm2/nested/file + deleted file mode 100644 + index ca281f5..0000000 + --- a/sm2/nested/file + +++ /dev/null + @@ -1 +0,0 @@ + -nested content + diff --git a/sm2/nested/foo8 b/sm2/nested/foo8 + deleted file mode 100644 + index db9916b..0000000 + --- a/sm2/nested/foo8 + +++ /dev/null + @@ -1 +0,0 @@ + -foo8 + diff --git a/sm2/nested/foo9 b/sm2/nested/foo9 + deleted file mode 100644 + index 9c3b4f6..0000000 + --- a/sm2/nested/foo9 + +++ /dev/null + @@ -1 +0,0 @@ + -foo9 + EOF + git diff --submodule=diff >actual 2>err && + test_must_be_empty err && + diff_cmp expected actual +' + +mv sm2-bak sm2 + test_done diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh index fad6d3f542..d370ecfe0d 100755 --- a/t/t4103-apply-binary.sh +++ b/t/t4103-apply-binary.sh @@ -158,4 +158,27 @@ test_expect_success 'apply binary -p0 diff' ' test -z "$(git diff --name-status binary -- file3)" ' +test_expect_success 'reject truncated binary diff' ' + do_reset && + + # this length is calculated to get us very close to + # the 8192-byte strbuf we will use to read in the patch. + test-tool genrandom foo 6205 >file1 && + git diff --binary >patch && + + # truncate the patch at the second "literal" line, + # but exclude the trailing newline. We must use perl + # for this, since tools like "sed" cannot reliably + # produce output without the trailing newline. + perl -pe " + if (/^literal/ && \$count++ >= 1) { + chomp; + print; + exit 0; + } + " <patch >patch.trunc && + + do_reset && + test_must_fail git apply patch.trunc +' test_done diff --git a/t/t4108-apply-threeway.sh b/t/t4108-apply-threeway.sh index 65147efdea..cc3aa3314a 100755 --- a/t/t4108-apply-threeway.sh +++ b/t/t4108-apply-threeway.sh @@ -230,4 +230,49 @@ test_expect_success 'apply with --3way --cached and conflicts' ' test_cmp expect.diff actual.diff ' +test_expect_success 'apply binary file patch' ' + git reset --hard main && + cp "$TEST_DIRECTORY/test-binary-1.png" bin.png && + git add bin.png && + git commit -m "add binary file" && + + cp "$TEST_DIRECTORY/test-binary-2.png" bin.png && + + git diff --binary >bin.diff && + git reset --hard && + + # Apply must succeed. + git apply bin.diff +' + +test_expect_success 'apply binary file patch with 3way' ' + git reset --hard main && + cp "$TEST_DIRECTORY/test-binary-1.png" bin.png && + git add bin.png && + git commit -m "add binary file" && + + cp "$TEST_DIRECTORY/test-binary-2.png" bin.png && + + git diff --binary >bin.diff && + git reset --hard && + + # Apply must succeed. + git apply --3way --index bin.diff +' + +test_expect_success 'apply full-index patch with 3way' ' + git reset --hard main && + cp "$TEST_DIRECTORY/test-binary-1.png" bin.png && + git add bin.png && + git commit -m "add binary file" && + + cp "$TEST_DIRECTORY/test-binary-2.png" bin.png && + + git diff --full-index >bin.diff && + git reset --hard && + + # Apply must succeed. + git apply --3way --index bin.diff +' + test_done diff --git a/t/t4151-am-abort.sh b/t/t4151-am-abort.sh index 9d8d3c72e7..2374151662 100755 --- a/t/t4151-am-abort.sh +++ b/t/t4151-am-abort.sh @@ -23,7 +23,13 @@ test_expect_success setup ' test_tick && git commit -a -m $i || return 1 done && + git branch changes && git format-patch --no-numbered initial && + git checkout -b conflicting initial && + echo different >>file-1 && + echo whatever >new-file && + git add file-1 new-file && + git commit -m different && git checkout -b side initial && echo local change >file-2-expect ' @@ -191,4 +197,37 @@ test_expect_success 'am --abort leaves index stat info alone' ' git diff-files --exit-code --quiet ' +test_expect_success 'git am --abort return failed exit status when it fails' ' + test_when_finished "rm -rf file-2/ && git reset --hard && git am --abort" && + git checkout changes && + git format-patch -1 --stdout conflicting >changes.mbox && + test_must_fail git am --3way changes.mbox && + + git rm file-2 && + mkdir file-2 && + echo precious >file-2/somefile && + test_must_fail git am --abort && + test_path_is_dir file-2/ +' + +test_expect_success 'git am --abort cleans relevant files' ' + git checkout changes && + git format-patch -1 --stdout conflicting >changes.mbox && + test_must_fail git am --3way changes.mbox && + + test_path_is_file new-file && + echo further changes >>file-1 && + echo change other file >>file-2 && + + # Abort, and expect the files touched by am to be reverted + git am --abort && + + test_path_is_missing new-file && + + # Files not involved in am operation are left modified + git diff --name-only changes >actual && + test_write_lines file-2 >expect && + test_cmp expect actual +' + test_done diff --git a/t/t4210-log-i18n.sh b/t/t4210-log-i18n.sh index d2dfcf164e..0141f36e33 100755 --- a/t/t4210-log-i18n.sh +++ b/t/t4210-log-i18n.sh @@ -131,4 +131,11 @@ do fi done +test_expect_success 'log shows warning when conversion fails' ' + enc=this-encoding-does-not-exist && + git log -1 --encoding=$enc 2>err && + echo "warning: unable to reencode commit to ${SQ}${enc}${SQ}" >expect && + test_cmp expect err +' + test_done diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index 5c5e53f0be..e13a884207 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -34,6 +34,110 @@ test_expect_success 'setup' ' } >expect ' +test_expect_success 'setup pack-object <stdin' ' + git init pack-object-stdin && + test_commit -C pack-object-stdin one && + test_commit -C pack-object-stdin two + +' + +test_expect_success 'pack-object <stdin parsing: basic [|--revs]' ' + cat >in <<-EOF && + $(git -C pack-object-stdin rev-parse one) + EOF + + git -C pack-object-stdin pack-objects basic-stdin <in && + idx=$(echo pack-object-stdin/basic-stdin-*.idx) && + git show-index <"$idx" >actual && + test_line_count = 1 actual && + + git -C pack-object-stdin pack-objects --revs basic-stdin-revs <in && + idx=$(echo pack-object-stdin/basic-stdin-revs-*.idx) && + git show-index <"$idx" >actual && + test_line_count = 3 actual +' + +test_expect_success 'pack-object <stdin parsing: [|--revs] bad line' ' + cat >in <<-EOF && + $(git -C pack-object-stdin rev-parse one) + garbage + $(git -C pack-object-stdin rev-parse two) + EOF + + sed "s/^> //g" >err.expect <<-EOF && + fatal: expected object ID, got garbage: + > garbage + + EOF + test_must_fail git -C pack-object-stdin pack-objects bad-line-stdin <in 2>err.actual && + test_cmp err.expect err.actual && + + cat >err.expect <<-EOF && + fatal: bad revision '"'"'garbage'"'"' + EOF + test_must_fail git -C pack-object-stdin pack-objects --revs bad-line-stdin-revs <in 2>err.actual && + test_cmp err.expect err.actual +' + +test_expect_success 'pack-object <stdin parsing: [|--revs] empty line' ' + cat >in <<-EOF && + $(git -C pack-object-stdin rev-parse one) + + $(git -C pack-object-stdin rev-parse two) + EOF + + sed -e "s/^> //g" -e "s/Z$//g" >err.expect <<-EOF && + fatal: expected object ID, got garbage: + > Z + + EOF + test_must_fail git -C pack-object-stdin pack-objects empty-line-stdin <in 2>err.actual && + test_cmp err.expect err.actual && + + git -C pack-object-stdin pack-objects --revs empty-line-stdin-revs <in && + idx=$(echo pack-object-stdin/empty-line-stdin-revs-*.idx) && + git show-index <"$idx" >actual && + test_line_count = 3 actual +' + +test_expect_success 'pack-object <stdin parsing: [|--revs] with --stdin' ' + cat >in <<-EOF && + $(git -C pack-object-stdin rev-parse one) + $(git -C pack-object-stdin rev-parse two) + EOF + + # There is the "--stdin-packs is incompatible with --revs" + # test below, but we should make sure that the revision.c + # --stdin is not picked up + cat >err.expect <<-EOF && + fatal: disallowed abbreviated or ambiguous option '"'"'stdin'"'"' + EOF + test_must_fail git -C pack-object-stdin pack-objects stdin-with-stdin-option --stdin <in 2>err.actual && + test_cmp err.expect err.actual && + + test_must_fail git -C pack-object-stdin pack-objects --stdin --revs stdin-with-stdin-option-revs 2>err.actual <in && + test_cmp err.expect err.actual +' + +test_expect_success 'pack-object <stdin parsing: --stdin-packs handles garbage' ' + cat >in <<-EOF && + $(git -C pack-object-stdin rev-parse one) + $(git -C pack-object-stdin rev-parse two) + EOF + + # That we get "two" and not "one" has to do with OID + # ordering. It happens to be the same here under SHA-1 and + # SHA-256. See commentary in pack-objects.c + cat >err.expect <<-EOF && + fatal: could not find pack '"'"'$(git -C pack-object-stdin rev-parse two)'"'"' + EOF + test_must_fail git \ + -C pack-object-stdin \ + pack-objects stdin-with-stdin-option --stdin-packs \ + <in 2>err.actual && + test_cmp err.expect err.actual +' + # usage: check_deltas <stderr_from_pack_objects> <cmp_op> <nr_deltas> # e.g.: check_deltas stderr -gt 0 check_deltas() { diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh index 7cabb85ca6..8ae314af58 100755 --- a/t/t5304-prune.sh +++ b/t/t5304-prune.sh @@ -291,6 +291,7 @@ test_expect_success 'prune: handle HEAD reflog in multiple worktrees' ' cat ../expected >blob && git add blob && git commit -m "second commit in third" && + git clean -f && # Remove untracked left behind by deleting index git reset --hard HEAD^ ) && git prune --expire=now && diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh index b02838750e..673baa5c3c 100755 --- a/t/t5310-pack-bitmaps.sh +++ b/t/t5310-pack-bitmaps.sh @@ -8,6 +8,10 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . "$TEST_DIRECTORY"/lib-bundle.sh . "$TEST_DIRECTORY"/lib-bitmap.sh +# t5310 deals only with single-pack bitmaps, so don't write MIDX bitmaps in +# their place. +GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 + objpath () { echo ".git/objects/$(echo "$1" | sed -e 's|\(..\)|\1/|')" } @@ -25,93 +29,10 @@ has_any () { grep -Ff "$1" "$2" } -# To ensure the logic for "maximal commits" is exercised, make -# the repository a bit more complicated. -# -# other second -# * * -# (99 commits) (99 commits) -# * * -# |\ /| -# | * octo-other octo-second * | -# |/|\_________ ____________/|\| -# | \ \/ __________/ | -# | | ________/\ / | -# * |/ * merge-right * -# | _|__________/ \____________ | -# |/ | \| -# (l1) * * merge-left * (r1) -# | / \________________________ | -# |/ \| -# (l2) * * (r2) -# \___________________________ | -# \| -# * (base) -# -# We only push bits down the first-parent history, which -# makes some of these commits unimportant! -# -# The important part for the maximal commit algorithm is how -# the bitmasks are extended. Assuming starting bit positions -# for second (bit 0) and other (bit 1), the bitmasks at the -# end should be: -# -# second: 1 (maximal, selected) -# other: 01 (maximal, selected) -# (base): 11 (maximal) -# -# This complicated history was important for a previous -# version of the walk that guarantees never walking a -# commit multiple times. That goal might be important -# again, so preserve this complicated case. For now, this -# test will guarantee that the bitmaps are computed -# correctly, even with the repeat calculations. - -test_expect_success 'setup repo with moderate-sized history' ' - test_commit_bulk --id=file 10 && - git branch -M second && - git checkout -b other HEAD~5 && - test_commit_bulk --id=side 10 && - - # add complicated history setup, including merges and - # ambiguous merge-bases - - git checkout -b merge-left other~2 && - git merge second~2 -m "merge-left" && - - git checkout -b merge-right second~1 && - git merge other~1 -m "merge-right" && - - git checkout -b octo-second second && - git merge merge-left merge-right -m "octopus-second" && - - git checkout -b octo-other other && - git merge merge-left merge-right -m "octopus-other" && - - git checkout other && - git merge octo-other -m "pull octopus" && - - git checkout second && - git merge octo-second -m "pull octopus" && - - # Remove these branches so they are not selected - # as bitmap tips - git branch -D merge-left && - git branch -D merge-right && - git branch -D octo-other && - git branch -D octo-second && - - # add padding to make these merges less interesting - # and avoid having them selected for bitmaps - test_commit_bulk --id=file 100 && - git checkout other && - test_commit_bulk --id=side 100 && - git checkout second && - - bitmaptip=$(git rev-parse second) && - blob=$(echo tagged-blob | git hash-object -w --stdin) && - git tag tagged-blob $blob && - git config repack.writebitmaps true +setup_bitmap_history + +test_expect_success 'setup writing bitmaps during repack' ' + git config repack.writeBitmaps true ' test_expect_success 'full repack creates bitmaps' ' @@ -123,109 +44,7 @@ test_expect_success 'full repack creates bitmaps' ' grep "\"key\":\"num_maximal_commits\",\"value\":\"107\"" trace ' -test_expect_success 'rev-list --test-bitmap verifies bitmaps' ' - git rev-list --test-bitmap HEAD -' - -rev_list_tests_head () { - test_expect_success "counting commits via bitmap ($state, $branch)" ' - git rev-list --count $branch >expect && - git rev-list --use-bitmap-index --count $branch >actual && - test_cmp expect actual - ' - - test_expect_success "counting partial commits via bitmap ($state, $branch)" ' - git rev-list --count $branch~5..$branch >expect && - git rev-list --use-bitmap-index --count $branch~5..$branch >actual && - test_cmp expect actual - ' - - test_expect_success "counting commits with limit ($state, $branch)" ' - git rev-list --count -n 1 $branch >expect && - git rev-list --use-bitmap-index --count -n 1 $branch >actual && - test_cmp expect actual - ' - - test_expect_success "counting non-linear history ($state, $branch)" ' - git rev-list --count other...second >expect && - git rev-list --use-bitmap-index --count other...second >actual && - test_cmp expect actual - ' - - test_expect_success "counting commits with limiting ($state, $branch)" ' - git rev-list --count $branch -- 1.t >expect && - git rev-list --use-bitmap-index --count $branch -- 1.t >actual && - test_cmp expect actual - ' - - test_expect_success "counting objects via bitmap ($state, $branch)" ' - git rev-list --count --objects $branch >expect && - git rev-list --use-bitmap-index --count --objects $branch >actual && - test_cmp expect actual - ' - - test_expect_success "enumerate commits ($state, $branch)" ' - git rev-list --use-bitmap-index $branch >actual && - git rev-list $branch >expect && - test_bitmap_traversal --no-confirm-bitmaps expect actual - ' - - test_expect_success "enumerate --objects ($state, $branch)" ' - git rev-list --objects --use-bitmap-index $branch >actual && - git rev-list --objects $branch >expect && - test_bitmap_traversal expect actual - ' - - test_expect_success "bitmap --objects handles non-commit objects ($state, $branch)" ' - git rev-list --objects --use-bitmap-index $branch tagged-blob >actual && - grep $blob actual - ' -} - -rev_list_tests () { - state=$1 - - for branch in "second" "other" - do - rev_list_tests_head - done -} - -rev_list_tests 'full bitmap' - -test_expect_success 'clone from bitmapped repository' ' - git clone --no-local --bare . clone.git && - git rev-parse HEAD >expect && - git --git-dir=clone.git rev-parse HEAD >actual && - test_cmp expect actual -' - -test_expect_success 'partial clone from bitmapped repository' ' - test_config uploadpack.allowfilter true && - git clone --no-local --bare --filter=blob:none . partial-clone.git && - ( - cd partial-clone.git && - pack=$(echo objects/pack/*.pack) && - git verify-pack -v "$pack" >have && - awk "/blob/ { print \$1 }" <have >blobs && - # we expect this single blob because of the direct ref - git rev-parse refs/tags/tagged-blob >expect && - test_cmp expect blobs - ) -' - -test_expect_success 'setup further non-bitmapped commits' ' - test_commit_bulk --id=further 10 -' - -rev_list_tests 'partial bitmap' - -test_expect_success 'fetch (partial bitmap)' ' - git --git-dir=clone.git fetch origin second:second && - git rev-parse HEAD >expect && - git --git-dir=clone.git rev-parse HEAD >actual && - test_cmp expect actual -' +basic_bitmap_tests test_expect_success 'incremental repack fails when bitmaps are requested' ' test_commit more-1 && @@ -461,40 +280,6 @@ test_expect_success 'truncated bitmap fails gracefully (cache)' ' test_i18ngrep corrupted.bitmap.index stderr ' -test_expect_success 'enumerating progress counts pack-reused objects' ' - count=$(git rev-list --objects --all --count) && - git repack -adb && - - # check first with only reused objects; confirm that our progress - # showed the right number, and also that we did pack-reuse as expected. - # Check only the final "done" line of the meter (there may be an - # arbitrary number of intermediate lines ending with CR). - GIT_PROGRESS_DELAY=0 \ - git pack-objects --all --stdout --progress \ - </dev/null >/dev/null 2>stderr && - grep "Enumerating objects: $count, done" stderr && - grep "pack-reused $count" stderr && - - # now the same but with one non-reused object - git commit --allow-empty -m "an extra commit object" && - GIT_PROGRESS_DELAY=0 \ - git pack-objects --all --stdout --progress \ - </dev/null >/dev/null 2>stderr && - grep "Enumerating objects: $((count+1)), done" stderr && - grep "pack-reused $count" stderr -' - -# have_delta <obj> <expected_base> -# -# Note that because this relies on cat-file, it might find _any_ copy of an -# object in the repository. The caller is responsible for making sure -# there's only one (e.g., via "repack -ad", or having just fetched a copy). -have_delta () { - echo $2 >expect && - echo $1 | git cat-file --batch-check="%(deltabase)" >actual && - test_cmp expect actual -} - # Create a state of history with these properties: # # - refs that allow a client to fetch some new history, while sharing some old diff --git a/t/t5312-prune-corruption.sh b/t/t5312-prune-corruption.sh index 11423b3cb2..ea889c088a 100755 --- a/t/t5312-prune-corruption.sh +++ b/t/t5312-prune-corruption.sh @@ -7,6 +7,9 @@ if we see, for example, a ref with a bogus name, it is OK either to bail out or to proceed using it as a reachable tip, but it is _not_ OK to proceed as if it did not exist. Otherwise we might silently delete objects that cannot be recovered. + +Note that we do assert command failure in these cases, because that is +what currently happens. If that changes, these tests should be revisited. ' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME @@ -18,39 +21,58 @@ test_expect_success 'disable reflogs' ' git reflog expire --expire=all --all ' +create_bogus_ref () { + test_when_finished 'rm -f .git/refs/heads/bogus..name' && + echo $bogus >.git/refs/heads/bogus..name +} + test_expect_success 'create history reachable only from a bogus-named ref' ' test_tick && git commit --allow-empty -m main && base=$(git rev-parse HEAD) && test_tick && git commit --allow-empty -m bogus && bogus=$(git rev-parse HEAD) && git cat-file commit $bogus >saved && - echo $bogus >.git/refs/heads/bogus..name && git reset --hard HEAD^ ' test_expect_success 'pruning does not drop bogus object' ' test_when_finished "git hash-object -w -t commit saved" && - test_might_fail git prune --expire=now && - verbose git cat-file -e $bogus + create_bogus_ref && + test_must_fail git prune --expire=now && + git cat-file -e $bogus ' test_expect_success 'put bogus object into pack' ' git tag reachable $bogus && git repack -ad && git tag -d reachable && - verbose git cat-file -e $bogus + git cat-file -e $bogus +' + +test_expect_success 'non-destructive repack bails on bogus ref' ' + create_bogus_ref && + test_must_fail git repack -adk ' +test_expect_success 'GIT_REF_PARANOIA=0 overrides safety' ' + create_bogus_ref && + GIT_REF_PARANOIA=0 git repack -adk +' + + test_expect_success 'destructive repack keeps packed object' ' - test_might_fail git repack -Ad --unpack-unreachable=now && - verbose git cat-file -e $bogus && - test_might_fail git repack -ad && - verbose git cat-file -e $bogus + create_bogus_ref && + test_must_fail git repack -Ad --unpack-unreachable=now && + git cat-file -e $bogus && + test_must_fail git repack -ad && + git cat-file -e $bogus ' -# subsequent tests will have different corruptions -test_expect_success 'clean up bogus ref' ' - rm .git/refs/heads/bogus..name +test_expect_success 'destructive repack not confused by dangling symref' ' + test_when_finished "git symbolic-ref -d refs/heads/dangling" && + git symbolic-ref refs/heads/dangling refs/heads/does-not-exist && + git repack -ad && + test_must_fail git cat-file -e $bogus ' # We create two new objects here, "one" and "two". Our @@ -77,8 +99,8 @@ test_expect_success 'create history with missing tip commit' ' test_expect_success 'pruning with a corrupted tip does not drop history' ' test_when_finished "git hash-object -w -t commit saved" && - test_might_fail git prune --expire=now && - verbose git cat-file -e $recoverable + test_must_fail git prune --expire=now && + git cat-file -e $recoverable ' test_expect_success 'pack-refs does not silently delete broken loose ref' ' diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh index af88f805aa..295c5bd94d 100755 --- a/t/t5318-commit-graph.sh +++ b/t/t5318-commit-graph.sh @@ -5,6 +5,25 @@ test_description='commit graph' GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=0 +test_expect_success 'usage' ' + test_expect_code 129 git commit-graph write blah 2>err && + test_expect_code 129 git commit-graph write verify +' + +test_expect_success 'usage shown without sub-command' ' + test_expect_code 129 git commit-graph 2>err && + ! grep error: err +' + +test_expect_success 'usage shown with an error on unknown sub-command' ' + cat >expect <<-\EOF && + error: unrecognized subcommand: unknown + EOF + test_expect_code 129 git commit-graph unknown 2>stderr && + grep error stderr >actual && + test_cmp expect actual +' + test_expect_success 'setup full repo' ' mkdir full && cd "$TRASH_DIRECTORY/full" && diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh index 3d4d9f10c3..a3c72b68f7 100755 --- a/t/t5319-multi-pack-index.sh +++ b/t/t5319-multi-pack-index.sh @@ -168,18 +168,33 @@ test_expect_success 'write midx with two packs' ' compare_results_with_midx "two packs" +test_expect_success 'write midx with --stdin-packs' ' + rm -fr $objdir/pack/multi-pack-index && + + idx="$(find $objdir/pack -name "test-2-*.idx")" && + basename "$idx" >in && + + git multi-pack-index write --stdin-packs <in && + + test-tool read-midx $objdir | grep "\.idx$" >packs && + + test_cmp packs in +' + +compare_results_with_midx "mixed mode (one pack + extra)" + test_expect_success 'write progress off for redirected stderr' ' git multi-pack-index --object-dir=$objdir write 2>err && test_line_count = 0 err ' test_expect_success 'write force progress on for stderr' ' - GIT_PROGRESS_DELAY=0 git multi-pack-index --object-dir=$objdir --progress write 2>err && + GIT_PROGRESS_DELAY=0 git multi-pack-index --object-dir=$objdir write --progress 2>err && test_file_not_empty err ' test_expect_success 'write with the --no-progress option' ' - GIT_PROGRESS_DELAY=0 git multi-pack-index --object-dir=$objdir --no-progress write 2>err && + GIT_PROGRESS_DELAY=0 git multi-pack-index --object-dir=$objdir write --no-progress 2>err && test_line_count = 0 err ' @@ -201,6 +216,34 @@ test_expect_success 'write midx with twelve packs' ' compare_results_with_midx "twelve packs" +test_expect_success 'multi-pack-index *.rev cleanup with --object-dir' ' + git init repo && + git clone -s repo alternate && + + test_when_finished "rm -rf repo alternate" && + + ( + cd repo && + test_commit base && + git repack -d + ) && + + ours="alternate/.git/objects/pack/multi-pack-index-123.rev" && + theirs="repo/.git/objects/pack/multi-pack-index-abc.rev" && + touch "$ours" "$theirs" && + + ( + cd alternate && + git multi-pack-index --object-dir ../repo/.git/objects write + ) && + + # writing a midx in "repo" should not remove the .rev file in the + # alternate + test_path_is_file repo/.git/objects/pack/multi-pack-index && + test_path_is_file $ours && + test_path_is_missing $theirs +' + test_expect_success 'warn on improper hash version' ' git init --object-format=sha1 sha1 && ( @@ -277,6 +320,23 @@ test_expect_success 'midx picks objects from preferred pack' ' ) ' +test_expect_success 'preferred packs must be non-empty' ' + test_when_finished rm -rf preferred.git && + git init preferred.git && + ( + cd preferred.git && + + test_commit base && + git repack -ad && + + empty="$(git pack-objects $objdir/pack/pack </dev/null)" && + + test_must_fail git multi-pack-index write \ + --preferred-pack=pack-$empty.pack 2>err && + grep "with no objects" err + ) +' + test_expect_success 'verify multi-pack-index success' ' git multi-pack-index verify --object-dir=$objdir ' @@ -429,12 +489,12 @@ test_expect_success 'repack progress off for redirected stderr' ' ' test_expect_success 'repack force progress on for stderr' ' - GIT_PROGRESS_DELAY=0 git multi-pack-index --object-dir=$objdir --progress repack 2>err && + GIT_PROGRESS_DELAY=0 git multi-pack-index --object-dir=$objdir repack --progress 2>err && test_file_not_empty err ' test_expect_success 'repack with the --no-progress option' ' - GIT_PROGRESS_DELAY=0 git multi-pack-index --object-dir=$objdir --no-progress repack 2>err && + GIT_PROGRESS_DELAY=0 git multi-pack-index --object-dir=$objdir repack --no-progress 2>err && test_line_count = 0 err ' @@ -487,7 +547,8 @@ test_expect_success 'repack preserves multi-pack-index when creating packs' ' compare_results_with_midx "after repack" test_expect_success 'multi-pack-index and pack-bitmap' ' - git -c repack.writeBitmaps=true repack -ad && + GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \ + git -c repack.writeBitmaps=true repack -ad && git multi-pack-index write && git rev-list --test-bitmap HEAD ' @@ -537,7 +598,15 @@ test_expect_success 'force some 64-bit offsets with pack-objects' ' idx64=objects64/pack/test-64-$pack64.idx && chmod u+w $idx64 && corrupt_data $idx64 $(test_oid idxoff) "\02" && - midx64=$(git multi-pack-index --object-dir=objects64 write) && + # objects64 is not a real repository, but can serve as an alternate + # anyway so we can write a MIDX into it + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + ( cd ../objects64 && pwd ) >.git/objects/info/alternates && + midx64=$(git multi-pack-index --object-dir=../objects64 write) + ) && midx_read_expect 1 63 5 objects64 " large-offsets" ' @@ -618,7 +687,7 @@ test_expect_success 'expire progress off for redirected stderr' ' test_expect_success 'expire force progress on for stderr' ' ( cd dup && - GIT_PROGRESS_DELAY=0 git multi-pack-index --progress expire 2>err && + GIT_PROGRESS_DELAY=0 git multi-pack-index expire --progress 2>err && test_file_not_empty err ) ' @@ -626,7 +695,7 @@ test_expect_success 'expire force progress on for stderr' ' test_expect_success 'expire with the --no-progress option' ' ( cd dup && - GIT_PROGRESS_DELAY=0 git multi-pack-index --no-progress expire 2>err && + GIT_PROGRESS_DELAY=0 git multi-pack-index expire --no-progress 2>err && test_line_count = 0 err ) ' @@ -842,4 +911,9 @@ test_expect_success 'usage shown without sub-command' ' ! test_i18ngrep "unrecognized subcommand" err ' +test_expect_success 'complains when run outside of a repository' ' + nongit test_must_fail git multi-pack-index write 2>err && + grep "not a git repository" err +' + test_done diff --git a/t/t5323-pack-redundant.sh b/t/t5323-pack-redundant.sh index 8b01793845..8dbbcc5e51 100755 --- a/t/t5323-pack-redundant.sh +++ b/t/t5323-pack-redundant.sh @@ -114,9 +114,9 @@ test_expect_success 'setup main repo' ' create_commits_in "$main_repo" A B C D E F G H I J K L M N O P Q R ' -test_expect_success 'master: pack-redundant works with no packfile' ' +test_expect_success 'main: pack-redundant works with no packfile' ' ( - cd "$master_repo" && + cd "$main_repo" && cat >expect <<-EOF && fatal: Zero packs found! EOF diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh new file mode 100755 index 0000000000..e187f90f29 --- /dev/null +++ b/t/t5326-multi-pack-bitmaps.sh @@ -0,0 +1,398 @@ +#!/bin/sh + +test_description='exercise basic multi-pack bitmap functionality' +. ./test-lib.sh +. "${TEST_DIRECTORY}/lib-bitmap.sh" + +# We'll be writing our own midx and bitmaps, so avoid getting confused by the +# automatic ones. +GIT_TEST_MULTI_PACK_INDEX=0 +GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 + +objdir=.git/objects +midx=$objdir/pack/multi-pack-index + +# midx_pack_source <obj> +midx_pack_source () { + test-tool read-midx --show-objects .git/objects | grep "^$1 " | cut -f2 +} + +setup_bitmap_history + +test_expect_success 'enable core.multiPackIndex' ' + git config core.multiPackIndex true +' + +test_expect_success 'create single-pack midx with bitmaps' ' + git repack -ad && + git multi-pack-index write --bitmap && + test_path_is_file $midx && + test_path_is_file $midx-$(midx_checksum $objdir).bitmap && + test_path_is_file $midx-$(midx_checksum $objdir).rev +' + +basic_bitmap_tests + +test_expect_success 'create new additional packs' ' + for i in $(test_seq 1 16) + do + test_commit "$i" && + git repack -d || return 1 + done && + + git checkout -b other2 HEAD~8 && + for i in $(test_seq 1 8) + do + test_commit "side-$i" && + git repack -d || return 1 + done && + git checkout second +' + +test_expect_success 'create multi-pack midx with bitmaps' ' + git multi-pack-index write --bitmap && + + ls $objdir/pack/pack-*.pack >packs && + test_line_count = 25 packs && + + test_path_is_file $midx && + test_path_is_file $midx-$(midx_checksum $objdir).bitmap && + test_path_is_file $midx-$(midx_checksum $objdir).rev +' + +basic_bitmap_tests + +test_expect_success '--no-bitmap is respected when bitmaps exist' ' + git multi-pack-index write --bitmap && + + test_commit respect--no-bitmap && + git repack -d && + + test_path_is_file $midx && + test_path_is_file $midx-$(midx_checksum $objdir).bitmap && + test_path_is_file $midx-$(midx_checksum $objdir).rev && + + git multi-pack-index write --no-bitmap && + + test_path_is_file $midx && + test_path_is_missing $midx-$(midx_checksum $objdir).bitmap && + test_path_is_missing $midx-$(midx_checksum $objdir).rev +' + +test_expect_success 'setup midx with base from later pack' ' + # Write a and b so that "a" is a delta on top of base "b", since Git + # prefers to delete contents out of a base rather than add to a shorter + # object. + test_seq 1 128 >a && + test_seq 1 130 >b && + + git add a b && + git commit -m "initial commit" && + + a=$(git rev-parse HEAD:a) && + b=$(git rev-parse HEAD:b) && + + # In the first pack, "a" is stored as a delta to "b". + p1=$(git pack-objects .git/objects/pack/pack <<-EOF + $a + $b + EOF + ) && + + # In the second pack, "a" is missing, and "b" is not a delta nor base to + # any other object. + p2=$(git pack-objects .git/objects/pack/pack <<-EOF + $b + $(git rev-parse HEAD) + $(git rev-parse HEAD^{tree}) + EOF + ) && + + git prune-packed && + # Use the second pack as the preferred source, so that "b" occurs + # earlier in the MIDX object order, rendering "a" unusable for pack + # reuse. + git multi-pack-index write --bitmap --preferred-pack=pack-$p2.idx && + + have_delta $a $b && + test $(midx_pack_source $a) != $(midx_pack_source $b) +' + +rev_list_tests 'full bitmap with backwards delta' + +test_expect_success 'clone with bitmaps enabled' ' + git clone --no-local --bare . clone-reverse-delta.git && + test_when_finished "rm -fr clone-reverse-delta.git" && + + git rev-parse HEAD >expect && + git --git-dir=clone-reverse-delta.git rev-parse HEAD >actual && + test_cmp expect actual +' + +bitmap_reuse_tests() { + from=$1 + to=$2 + + test_expect_success "setup pack reuse tests ($from -> $to)" ' + rm -fr repo && + git init repo && + ( + cd repo && + test_commit_bulk 16 && + git tag old-tip && + + git config core.multiPackIndex true && + if test "MIDX" = "$from" + then + git repack -Ad && + git multi-pack-index write --bitmap + else + git repack -Adb + fi + ) + ' + + test_expect_success "build bitmap from existing ($from -> $to)" ' + ( + cd repo && + test_commit_bulk --id=further 16 && + git tag new-tip && + + if test "MIDX" = "$to" + then + git repack -d && + git multi-pack-index write --bitmap + else + git repack -Adb + fi + ) + ' + + test_expect_success "verify resulting bitmaps ($from -> $to)" ' + ( + cd repo && + git for-each-ref && + git rev-list --test-bitmap refs/tags/old-tip && + git rev-list --test-bitmap refs/tags/new-tip + ) + ' +} + +bitmap_reuse_tests 'pack' 'MIDX' +bitmap_reuse_tests 'MIDX' 'pack' +bitmap_reuse_tests 'MIDX' 'MIDX' + +test_expect_success 'missing object closure fails gracefully' ' + rm -fr repo && + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + + test_commit loose && + test_commit packed && + + # Do not pass "--revs"; we want a pack without the "loose" + # commit. + git pack-objects $objdir/pack/pack <<-EOF && + $(git rev-parse packed) + EOF + + test_must_fail git multi-pack-index write --bitmap 2>err && + grep "doesn.t have full closure" err && + test_path_is_missing $midx + ) +' + +test_expect_success 'setup partial bitmaps' ' + test_commit packed && + git repack && + test_commit loose && + git multi-pack-index write --bitmap 2>err && + test_path_is_file $midx && + test_path_is_file $midx-$(midx_checksum $objdir).bitmap && + test_path_is_file $midx-$(midx_checksum $objdir).rev +' + +basic_bitmap_tests HEAD~ + +test_expect_success 'removing a MIDX clears stale bitmaps' ' + rm -fr repo && + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + test_commit base && + git repack && + git multi-pack-index write --bitmap && + + # Write a MIDX and bitmap; remove the MIDX but leave the bitmap. + stale_bitmap=$midx-$(midx_checksum $objdir).bitmap && + stale_rev=$midx-$(midx_checksum $objdir).rev && + rm $midx && + + # Then write a new MIDX. + test_commit new && + git repack && + git multi-pack-index write --bitmap && + + test_path_is_file $midx && + test_path_is_file $midx-$(midx_checksum $objdir).bitmap && + test_path_is_file $midx-$(midx_checksum $objdir).rev && + test_path_is_missing $stale_bitmap && + test_path_is_missing $stale_rev + ) +' + +test_expect_success 'pack.preferBitmapTips' ' + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + + test_commit_bulk --message="%s" 103 && + + git log --format="%H" >commits.raw && + sort <commits.raw >commits && + + git log --format="create refs/tags/%s %H" HEAD >refs && + git update-ref --stdin <refs && + + git multi-pack-index write --bitmap && + test_path_is_file $midx && + test_path_is_file $midx-$(midx_checksum $objdir).bitmap && + test_path_is_file $midx-$(midx_checksum $objdir).rev && + + test-tool bitmap list-commits | sort >bitmaps && + comm -13 bitmaps commits >before && + test_line_count = 1 before && + + perl -ne "printf(\"create refs/tags/include/%d \", $.); print" \ + <before | git update-ref --stdin && + + rm -fr $midx-$(midx_checksum $objdir).bitmap && + rm -fr $midx-$(midx_checksum $objdir).rev && + rm -fr $midx && + + git -c pack.preferBitmapTips=refs/tags/include \ + multi-pack-index write --bitmap && + test-tool bitmap list-commits | sort >bitmaps && + comm -13 bitmaps commits >after && + + ! test_cmp before after + ) +' + +test_expect_success 'writing a bitmap with --refs-snapshot' ' + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + + test_commit one && + test_commit two && + + git rev-parse one >snapshot && + + git repack -ad && + + # First, write a MIDX which see both refs/tags/one and + # refs/tags/two (causing both of those commits to receive + # bitmaps). + git multi-pack-index write --bitmap && + + test_path_is_file $midx && + test_path_is_file $midx-$(midx_checksum $objdir).bitmap && + + test-tool bitmap list-commits | sort >bitmaps && + grep "$(git rev-parse one)" bitmaps && + grep "$(git rev-parse two)" bitmaps && + + rm -fr $midx-$(midx_checksum $objdir).bitmap && + rm -fr $midx-$(midx_checksum $objdir).rev && + rm -fr $midx && + + # Then again, but with a refs snapshot which only sees + # refs/tags/one. + git multi-pack-index write --bitmap --refs-snapshot=snapshot && + + test_path_is_file $midx && + test_path_is_file $midx-$(midx_checksum $objdir).bitmap && + + test-tool bitmap list-commits | sort >bitmaps && + grep "$(git rev-parse one)" bitmaps && + ! grep "$(git rev-parse two)" bitmaps + ) +' + +test_expect_success 'write a bitmap with --refs-snapshot (preferred tips)' ' + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + + test_commit_bulk --message="%s" 103 && + + git log --format="%H" >commits.raw && + sort <commits.raw >commits && + + git log --format="create refs/tags/%s %H" HEAD >refs && + git update-ref --stdin <refs && + + git multi-pack-index write --bitmap && + test_path_is_file $midx && + test_path_is_file $midx-$(midx_checksum $objdir).bitmap && + + test-tool bitmap list-commits | sort >bitmaps && + comm -13 bitmaps commits >before && + test_line_count = 1 before && + + ( + grep -vf before commits.raw && + # mark missing commits as preferred + sed "s/^/+/" before + ) >snapshot && + + rm -fr $midx-$(midx_checksum $objdir).bitmap && + rm -fr $midx-$(midx_checksum $objdir).rev && + rm -fr $midx && + + git multi-pack-index write --bitmap --refs-snapshot=snapshot && + test-tool bitmap list-commits | sort >bitmaps && + comm -13 bitmaps commits >after && + + ! test_cmp before after + ) +' + +test_expect_success 'hash-cache values are propagated from pack bitmaps' ' + rm -fr repo && + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + + test_commit base && + test_commit base2 && + git repack -adb && + + test-tool bitmap dump-hashes >pack.raw && + test_file_not_empty pack.raw && + sort pack.raw >pack.hashes && + + test_commit new && + git repack && + git multi-pack-index write --bitmap && + + test-tool bitmap dump-hashes >midx.raw && + sort midx.raw >midx.hashes && + + # ensure that every namehash in the pack bitmap can be found in + # the midx bitmap (i.e., that there are no oid-namehash pairs + # unique to the pack bitmap). + comm -23 pack.hashes midx.hashes >dropped.hashes && + test_must_be_empty dropped.hashes + ) +' + +test_done diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index e83b2a6506..a0faf0dd94 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -1214,6 +1214,19 @@ test_expect_success '--negotiation-tip understands abbreviated SHA-1' ' check_negotiation_tip ' +test_expect_success '--negotiation-tip rejects missing OIDs' ' + setup_negotiation_tip server server 0 && + test_must_fail git -C client fetch \ + --negotiation-tip=alpha_1 \ + --negotiation-tip=$(test_oid zero) \ + origin alpha_s beta_s 2>err && + cat >fatal-expect <<-EOF && + fatal: the object $(test_oid zero) does not exist +EOF + grep fatal: err >fatal-actual && + test_cmp fatal-expect fatal-actual +' + . "$TEST_DIRECTORY"/lib-httpd.sh start_httpd diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 0916f76302..8212ca56dc 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -201,6 +201,7 @@ test_expect_success 'push with negotiation' ' # Without negotiation mk_empty testrepo && git push testrepo $the_first_commit:refs/remotes/origin/first_commit && + test_commit -C testrepo unrelated_commit && git -C testrepo config receive.hideRefs refs/remotes/origin/first_commit && echo now pushing without negotiation && GIT_TRACE2_EVENT="$(pwd)/event" git -c protocol.version=2 push testrepo refs/heads/main:refs/remotes/origin/main && @@ -210,6 +211,7 @@ test_expect_success 'push with negotiation' ' rm event && mk_empty testrepo && git push testrepo $the_first_commit:refs/remotes/origin/first_commit && + test_commit -C testrepo unrelated_commit && git -C testrepo config receive.hideRefs refs/remotes/origin/first_commit && GIT_TRACE2_EVENT="$(pwd)/event" git -c protocol.version=2 -c push.negotiate=1 push testrepo refs/heads/main:refs/remotes/origin/main && grep_wrote 2 event # 1 commit, 1 tree @@ -219,6 +221,7 @@ test_expect_success 'push with negotiation proceeds anyway even if negotiation f rm event && mk_empty testrepo && git push testrepo $the_first_commit:refs/remotes/origin/first_commit && + test_commit -C testrepo unrelated_commit && git -C testrepo config receive.hideRefs refs/remotes/origin/first_commit && GIT_TEST_PROTOCOL_VERSION=0 GIT_TRACE2_EVENT="$(pwd)/event" \ git -c push.negotiate=1 push testrepo refs/heads/main:refs/remotes/origin/main 2>err && @@ -659,10 +662,10 @@ test_expect_success 'push does not update local refs on failure' ' test_expect_success 'allow deleting an invalid remote ref' ' - mk_test testrepo heads/main && + mk_test testrepo heads/branch && rm -f testrepo/.git/objects/??/* && - git push testrepo :refs/heads/main && - (cd testrepo && test_must_fail git rev-parse --verify refs/heads/main) + git push testrepo :refs/heads/branch && + (cd testrepo && test_must_fail git rev-parse --verify refs/heads/branch) ' @@ -703,25 +706,26 @@ test_expect_success 'pushing valid refs triggers post-receive and post-update ho ' test_expect_success 'deleting dangling ref triggers hooks with correct args' ' - mk_test_with_hooks testrepo heads/main && + mk_test_with_hooks testrepo heads/branch && + orig=$(git -C testrepo rev-parse refs/heads/branch) && rm -f testrepo/.git/objects/??/* && - git push testrepo :refs/heads/main && + git push testrepo :refs/heads/branch && ( cd testrepo/.git && cat >pre-receive.expect <<-EOF && - $ZERO_OID $ZERO_OID refs/heads/main + $orig $ZERO_OID refs/heads/branch EOF cat >update.expect <<-EOF && - refs/heads/main $ZERO_OID $ZERO_OID + refs/heads/branch $orig $ZERO_OID EOF cat >post-receive.expect <<-EOF && - $ZERO_OID $ZERO_OID refs/heads/main + $orig $ZERO_OID refs/heads/branch EOF cat >post-update.expect <<-EOF && - refs/heads/main + refs/heads/branch EOF test_cmp pre-receive.expect pre-receive.actual && @@ -1767,5 +1771,4 @@ test_expect_success 'denyCurrentBranch and worktrees' ' git -C cloned push origin HEAD:new-wt && test_must_fail git -C cloned push --delete origin new-wt ' - test_done diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh index e2c0c51022..93ecfcdd24 100755 --- a/t/t5520-pull.sh +++ b/t/t5520-pull.sh @@ -136,12 +136,12 @@ test_expect_success 'the default remote . should not break explicit pull' ' git reset --hard HEAD^ && echo file >expect && test_cmp expect file && - git pull . second && + git pull --no-rebase . second && echo modified >expect && test_cmp expect file && git reflog -1 >reflog.actual && sed "s/^[0-9a-f][0-9a-f]*/OBJID/" reflog.actual >reflog.fuzzy && - echo "OBJID HEAD@{0}: pull . second: Fast-forward" >reflog.expected && + echo "OBJID HEAD@{0}: pull --no-rebase . second: Fast-forward" >reflog.expected && test_cmp reflog.expected reflog.fuzzy ' @@ -226,7 +226,7 @@ test_expect_success 'fail if the index has unresolved entries' ' test_commit modified2 file && git ls-files -u >unmerged && test_must_be_empty unmerged && - test_must_fail git pull . second && + test_must_fail git pull --no-rebase . second && git ls-files -u >unmerged && test_file_not_empty unmerged && cp file expected && @@ -409,37 +409,37 @@ test_expect_success 'pull --rebase --no-autostash & rebase.autostash unset' ' test_expect_success 'pull succeeds with dirty working directory and merge.autostash set' ' test_config merge.autostash true && - test_pull_autostash 2 + test_pull_autostash 2 --no-rebase ' test_expect_success 'pull --autostash & merge.autostash=true' ' test_config merge.autostash true && - test_pull_autostash 2 --autostash + test_pull_autostash 2 --autostash --no-rebase ' test_expect_success 'pull --autostash & merge.autostash=false' ' test_config merge.autostash false && - test_pull_autostash 2 --autostash + test_pull_autostash 2 --autostash --no-rebase ' test_expect_success 'pull --autostash & merge.autostash unset' ' test_unconfig merge.autostash && - test_pull_autostash 2 --autostash + test_pull_autostash 2 --autostash --no-rebase ' test_expect_success 'pull --no-autostash & merge.autostash=true' ' test_config merge.autostash true && - test_pull_autostash_fail --no-autostash + test_pull_autostash_fail --no-autostash --no-rebase ' test_expect_success 'pull --no-autostash & merge.autostash=false' ' test_config merge.autostash false && - test_pull_autostash_fail --no-autostash + test_pull_autostash_fail --no-autostash --no-rebase ' test_expect_success 'pull --no-autostash & merge.autostash unset' ' test_unconfig merge.autostash && - test_pull_autostash_fail --no-autostash + test_pull_autostash_fail --no-autostash --no-rebase ' test_expect_success 'pull.rebase' ' @@ -546,15 +546,6 @@ test_expect_success 'pull.rebase=1 is treated as true and flattens keep-merge' ' test_cmp expect actual ' -test_expect_success REBASE_P \ - 'pull.rebase=preserve rebases and merges keep-merge' ' - git reset --hard before-preserve-rebase && - test_config pull.rebase preserve && - git pull . copy && - test_cmp_rev HEAD^^ copy && - test_cmp_rev HEAD^2 keep-merge -' - test_expect_success 'pull.rebase=interactive' ' write_script "$TRASH_DIRECTORY/fake-editor" <<-\EOF && echo I was here >fake.out && @@ -598,7 +589,7 @@ test_expect_success '--rebase=false create a new merge commit' ' test_expect_success '--rebase=true rebases and flattens keep-merge' ' git reset --hard before-preserve-rebase && - test_config pull.rebase preserve && + test_config pull.rebase merges && git pull --rebase=true . copy && test_cmp_rev HEAD^^ copy && echo file3 >expect && @@ -606,23 +597,14 @@ test_expect_success '--rebase=true rebases and flattens keep-merge' ' test_cmp expect actual ' -test_expect_success REBASE_P \ - '--rebase=preserve rebases and merges keep-merge' ' - git reset --hard before-preserve-rebase && - test_config pull.rebase true && - git pull --rebase=preserve . copy && - test_cmp_rev HEAD^^ copy && - test_cmp_rev HEAD^2 keep-merge -' - test_expect_success '--rebase=invalid fails' ' git reset --hard before-preserve-rebase && test_must_fail git pull --rebase=invalid . copy ' -test_expect_success '--rebase overrides pull.rebase=preserve and flattens keep-merge' ' +test_expect_success '--rebase overrides pull.rebase=merges and flattens keep-merge' ' git reset --hard before-preserve-rebase && - test_config pull.rebase preserve && + test_config pull.rebase merges && git pull --rebase . copy && test_cmp_rev HEAD^^ copy && echo file3 >expect && diff --git a/t/t5521-pull-options.sh b/t/t5521-pull-options.sh index 63a688bdbf..7601c919fd 100755 --- a/t/t5521-pull-options.sh +++ b/t/t5521-pull-options.sh @@ -113,7 +113,7 @@ test_expect_success 'git pull --force' ' git pull two && test_commit A && git branch -f origin && - git pull --all --force + git pull --no-rebase --all --force ) ' @@ -179,7 +179,7 @@ test_expect_success 'git pull --allow-unrelated-histories' ' ( cd dst && test_must_fail git pull ../src side && - git pull --allow-unrelated-histories ../src side + git pull --no-rebase --allow-unrelated-histories ../src side ) ' diff --git a/t/t5524-pull-msg.sh b/t/t5524-pull-msg.sh index c278adaa5a..b2be3605f5 100755 --- a/t/t5524-pull-msg.sh +++ b/t/t5524-pull-msg.sh @@ -28,7 +28,7 @@ test_expect_success setup ' test_expect_success pull ' ( cd cloned && - git pull --log && + git pull --no-rebase --log && git log -2 && git cat-file commit HEAD >result && grep Dollar result @@ -41,7 +41,7 @@ test_expect_success '--log=1 limits shortlog length' ' git reset --hard HEAD^ && test "$(cat afile)" = original && test "$(cat bfile)" = added && - git pull --log=1 && + git pull --no-rebase --log=1 && git log -3 && git cat-file commit HEAD >result && grep Dollar result && diff --git a/t/t5549-fetch-push-http.sh b/t/t5549-fetch-push-http.sh new file mode 100755 index 0000000000..2cdebcb735 --- /dev/null +++ b/t/t5549-fetch-push-http.sh @@ -0,0 +1,72 @@ +#!/bin/sh + +test_description='fetch/push functionality using the HTTP protocol' + +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-httpd.sh +start_httpd + +SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" +URI="$HTTPD_URL/smart/server" + +grep_wrote () { + object_count=$1 + file_name=$2 + grep 'write_pack_file/wrote.*"value":"'$1'"' $2 +} + +setup_client_and_server () { + git init client && + test_when_finished 'rm -rf client' && + test_commit -C client first_commit && + test_commit -C client second_commit && + + git init "$SERVER" && + test_when_finished 'rm -rf "$SERVER"' && + test_config -C "$SERVER" http.receivepack true && + test_commit -C "$SERVER" unrelated_commit && + git -C client push "$URI" first_commit:refs/remotes/origin/first_commit && + git -C "$SERVER" config receive.hideRefs refs/remotes/origin/first_commit +} + +test_expect_success 'push without negotiation (for comparing object counts with the next test)' ' + setup_client_and_server && + + GIT_TRACE2_EVENT="$(pwd)/event" git -C client -c protocol.version=2 \ + push "$URI" refs/heads/main:refs/remotes/origin/main && + test_when_finished "rm -f event" && + grep_wrote 6 event # 2 commits, 2 trees, 2 blobs +' + +test_expect_success 'push with negotiation' ' + setup_client_and_server && + + GIT_TRACE2_EVENT="$(pwd)/event" git -C client -c protocol.version=2 -c push.negotiate=1 \ + push "$URI" refs/heads/main:refs/remotes/origin/main && + test_when_finished "rm -f event" && + grep_wrote 3 event # 1 commit, 1 tree, 1 blob +' + +test_expect_success 'push with negotiation proceeds anyway even if negotiation fails' ' + setup_client_and_server && + + # Use protocol v0 to make negotiation fail (because protocol v0 does + # not support the "wait-for-done" capability, which is required for + # push negotiation) + GIT_TEST_PROTOCOL_VERSION=0 GIT_TRACE2_EVENT="$(pwd)/event" git -C client -c push.negotiate=1 \ + push "$URI" refs/heads/main:refs/remotes/origin/main 2>err && + test_when_finished "rm -f event" && + grep_wrote 6 event && # 2 commits, 2 trees, 2 blobs + + cat >warning-expect <<-EOF && + warning: --negotiate-only requires protocol v2 + warning: push negotiation failed; proceeding anyway with push +EOF + grep warning: err >warning-actual && + test_cmp warning-expect warning-actual +' + +test_done diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh index 4f87d90c5b..f92c79c132 100755 --- a/t/t5551-http-fetch-smart.sh +++ b/t/t5551-http-fetch-smart.sh @@ -196,8 +196,8 @@ test_expect_success 'GIT_TRACE_CURL redacts auth details' ' # Ensure that there is no "Basic" followed by a base64 string, but that # the auth details are redacted - ! grep "Authorization: Basic [0-9a-zA-Z+/]" trace && - grep "Authorization: Basic <redacted>" trace + ! grep -i "Authorization: Basic [0-9a-zA-Z+/]" trace && + grep -i "Authorization: Basic <redacted>" trace ' test_expect_success 'GIT_CURL_VERBOSE redacts auth details' ' @@ -208,8 +208,8 @@ test_expect_success 'GIT_CURL_VERBOSE redacts auth details' ' # Ensure that there is no "Basic" followed by a base64 string, but that # the auth details are redacted - ! grep "Authorization: Basic [0-9a-zA-Z+/]" trace && - grep "Authorization: Basic <redacted>" trace + ! grep -i "Authorization: Basic [0-9a-zA-Z+/]" trace && + grep -i "Authorization: Basic <redacted>" trace ' test_expect_success 'GIT_TRACE_CURL does not redact auth details if GIT_TRACE_REDACT=0' ' @@ -219,7 +219,7 @@ test_expect_success 'GIT_TRACE_CURL does not redact auth details if GIT_TRACE_RE git clone --bare "$HTTPD_URL/auth/smart/repo.git" redact-auth && expect_askpass both user@host && - grep "Authorization: Basic [0-9a-zA-Z+/]" trace + grep -i "Authorization: Basic [0-9a-zA-Z+/]" trace ' test_expect_success 'disable dumb http on server' ' @@ -474,10 +474,10 @@ test_expect_success 'cookies are redacted by default' ' GIT_TRACE_CURL=true \ git -c "http.cookieFile=$(pwd)/cookies" clone \ $HTTPD_URL/smart/repo.git clone 2>err && - grep "Cookie:.*Foo=<redacted>" err && - grep "Cookie:.*Bar=<redacted>" err && - ! grep "Cookie:.*Foo=1" err && - ! grep "Cookie:.*Bar=2" err + grep -i "Cookie:.*Foo=<redacted>" err && + grep -i "Cookie:.*Bar=<redacted>" err && + ! grep -i "Cookie:.*Foo=1" err && + ! grep -i "Cookie:.*Bar=2" err ' test_expect_success 'empty values of cookies are also redacted' ' @@ -486,7 +486,7 @@ test_expect_success 'empty values of cookies are also redacted' ' GIT_TRACE_CURL=true \ git -c "http.cookieFile=$(pwd)/cookies" clone \ $HTTPD_URL/smart/repo.git clone 2>err && - grep "Cookie:.*Foo=<redacted>" err + grep -i "Cookie:.*Foo=<redacted>" err ' test_expect_success 'GIT_TRACE_REDACT=0 disables cookie redaction' ' @@ -496,8 +496,8 @@ test_expect_success 'GIT_TRACE_REDACT=0 disables cookie redaction' ' GIT_TRACE_REDACT=0 GIT_TRACE_CURL=true \ git -c "http.cookieFile=$(pwd)/cookies" clone \ $HTTPD_URL/smart/repo.git clone 2>err && - grep "Cookie:.*Foo=1" err && - grep "Cookie:.*Bar=2" err + grep -i "Cookie:.*Foo=1" err && + grep -i "Cookie:.*Bar=2" err ' test_expect_success 'GIT_TRACE_CURL_NO_DATA prevents data from being traced' ' @@ -558,4 +558,13 @@ test_expect_success 'http auth forgets bogus credentials' ' expect_askpass both user@host ' +test_expect_success 'client falls back from v2 to v0 to match server' ' + GIT_TRACE_PACKET=$PWD/trace \ + GIT_TEST_PROTOCOL_VERSION=2 \ + git clone $HTTPD_URL/smart_v0/repo.git repo-v0 && + # check for v0; there the HEAD symref is communicated in the capability + # line; v2 uses a different syntax on each ref advertisement line + grep symref=HEAD:refs/heads/ trace +' + test_done diff --git a/t/t5553-set-upstream.sh b/t/t5553-set-upstream.sh index b1d614ce18..9c12c0f8c3 100755 --- a/t/t5553-set-upstream.sh +++ b/t/t5553-set-upstream.sh @@ -108,27 +108,27 @@ test_expect_success 'setup commit on main and other pull' ' test_expect_success 'pull --set-upstream upstream main sets branch main but not other' ' clear_config main other && - git pull --set-upstream upstream main && + git pull --no-rebase --set-upstream upstream main && check_config main upstream refs/heads/main && check_config_missing other ' test_expect_success 'pull --set-upstream main:other2 does not set the branch other2' ' clear_config other2 && - git pull --set-upstream upstream main:other2 && + git pull --no-rebase --set-upstream upstream main:other2 && check_config_missing other2 ' test_expect_success 'pull --set-upstream upstream other sets branch main' ' clear_config main other && - git pull --set-upstream upstream other && + git pull --no-rebase --set-upstream upstream other && check_config main upstream refs/heads/other && check_config_missing other ' test_expect_success 'pull --set-upstream upstream tag does not set the tag' ' clear_config three && - git pull --tags --set-upstream upstream three && + git pull --no-rebase --tags --set-upstream upstream three && check_config_missing three ' @@ -144,16 +144,16 @@ test_expect_success 'pull --set-upstream http://nosuchdomain.example.com fails w test_expect_success 'pull --set-upstream upstream HEAD sets branch HEAD' ' clear_config main other && - git pull --set-upstream upstream HEAD && + git pull --no-rebase --set-upstream upstream HEAD && check_config main upstream HEAD && git checkout other && - git pull --set-upstream upstream HEAD && + git pull --no-rebase --set-upstream upstream HEAD && check_config other upstream HEAD ' test_expect_success 'pull --set-upstream upstream with more than one branch does nothing' ' clear_config main three && - git pull --set-upstream upstream main three && + git pull --no-rebase --set-upstream upstream main three && check_config_missing main && check_config_missing three ' diff --git a/t/t5555-http-smart-common.sh b/t/t5555-http-smart-common.sh new file mode 100755 index 0000000000..49faf5e283 --- /dev/null +++ b/t/t5555-http-smart-common.sh @@ -0,0 +1,161 @@ +#!/bin/sh + +test_description='test functionality common to smart fetch & push' + +. ./test-lib.sh + +test_expect_success 'setup' ' + test_commit --no-tag initial +' + +test_expect_success 'git upload-pack --http-backend-info-refs and --advertise-refs are aliased' ' + git upload-pack --http-backend-info-refs . >expected 2>err.expected && + git upload-pack --advertise-refs . >actual 2>err.actual && + test_cmp err.expected err.actual && + test_cmp expected actual +' + +test_expect_success 'git receive-pack --http-backend-info-refs and --advertise-refs are aliased' ' + git receive-pack --http-backend-info-refs . >expected 2>err.expected && + git receive-pack --advertise-refs . >actual 2>err.actual && + test_cmp err.expected err.actual && + test_cmp expected actual +' + +test_expect_success 'git upload-pack --advertise-refs' ' + cat >expect <<-EOF && + $(git rev-parse HEAD) HEAD + $(git rev-parse HEAD) $(git symbolic-ref HEAD) + 0000 + EOF + + # We only care about GIT_PROTOCOL, not GIT_TEST_PROTOCOL_VERSION + sane_unset GIT_PROTOCOL && + GIT_TEST_PROTOCOL_VERSION=2 \ + git upload-pack --advertise-refs . >out 2>err && + + test-tool pkt-line unpack <out >actual && + test_must_be_empty err && + test_cmp actual expect && + + # The --advertise-refs alias works + git upload-pack --advertise-refs . >out 2>err && + + test-tool pkt-line unpack <out >actual && + test_must_be_empty err && + test_cmp actual expect +' + +test_expect_success 'git upload-pack --advertise-refs: v0' ' + # With no specified protocol + cat >expect <<-EOF && + $(git rev-parse HEAD) HEAD + $(git rev-parse HEAD) $(git symbolic-ref HEAD) + 0000 + EOF + + git upload-pack --advertise-refs . >out 2>err && + test-tool pkt-line unpack <out >actual && + test_must_be_empty err && + test_cmp actual expect && + + # With explicit v0 + GIT_PROTOCOL=version=0 \ + git upload-pack --advertise-refs . >out 2>err && + test-tool pkt-line unpack <out >actual 2>err && + test_must_be_empty err && + test_cmp actual expect + +' + +test_expect_success 'git receive-pack --advertise-refs: v0' ' + # With no specified protocol + cat >expect <<-EOF && + $(git rev-parse HEAD) $(git symbolic-ref HEAD) + 0000 + EOF + + git receive-pack --advertise-refs . >out 2>err && + test-tool pkt-line unpack <out >actual && + test_must_be_empty err && + test_cmp actual expect && + + # With explicit v0 + GIT_PROTOCOL=version=0 \ + git receive-pack --advertise-refs . >out 2>err && + test-tool pkt-line unpack <out >actual 2>err && + test_must_be_empty err && + test_cmp actual expect + +' + +test_expect_success 'git upload-pack --advertise-refs: v1' ' + # With no specified protocol + cat >expect <<-EOF && + version 1 + $(git rev-parse HEAD) HEAD + $(git rev-parse HEAD) $(git symbolic-ref HEAD) + 0000 + EOF + + GIT_PROTOCOL=version=1 \ + git upload-pack --advertise-refs . >out && + + test-tool pkt-line unpack <out >actual 2>err && + test_must_be_empty err && + test_cmp actual expect +' + +test_expect_success 'git receive-pack --advertise-refs: v1' ' + # With no specified protocol + cat >expect <<-EOF && + version 1 + $(git rev-parse HEAD) $(git symbolic-ref HEAD) + 0000 + EOF + + GIT_PROTOCOL=version=1 \ + git receive-pack --advertise-refs . >out && + + test-tool pkt-line unpack <out >actual 2>err && + test_must_be_empty err && + test_cmp actual expect +' + +test_expect_success 'git upload-pack --advertise-refs: v2' ' + cat >expect <<-EOF && + version 2 + agent=FAKE + ls-refs=unborn + fetch=shallow wait-for-done + server-option + object-format=$(test_oid algo) + object-info + 0000 + EOF + + GIT_PROTOCOL=version=2 \ + GIT_USER_AGENT=FAKE \ + git upload-pack --advertise-refs . >out 2>err && + + test-tool pkt-line unpack <out >actual && + test_must_be_empty err && + test_cmp actual expect +' + +test_expect_success 'git receive-pack --advertise-refs: v2' ' + # There is no v2 yet for receive-pack, implicit v0 + cat >expect <<-EOF && + $(git rev-parse HEAD) $(git symbolic-ref HEAD) + 0000 + EOF + + GIT_PROTOCOL=version=2 \ + git receive-pack --advertise-refs . >out 2>err && + + test-tool pkt-line unpack <out >actual && + test_must_be_empty err && + test_cmp actual expect +' + +test_done diff --git a/t/t5562/invoke-with-content-length.pl b/t/t5562/invoke-with-content-length.pl index 0943474af2..718dd9b49d 100644 --- a/t/t5562/invoke-with-content-length.pl +++ b/t/t5562/invoke-with-content-length.pl @@ -13,11 +13,6 @@ my $body_data; defined read($body_fh, $body_data, $body_size) or die "Cannot read $body_filename: $!"; close($body_fh); -my $exited = 0; -$SIG{"CHLD"} = sub { - $exited = 1; -}; - # write data my $pid = open(my $out, "|-", @command); { @@ -29,8 +24,13 @@ my $pid = open(my $out, "|-", @command); } print $out $body_data or die "Cannot write data: $!"; -sleep 60; # is interrupted by SIGCHLD -if (!$exited) { - close($out); +$SIG{ALRM} = sub { + kill 'KILL', $pid; die "Command did not exit after reading whole body"; +}; +alarm 60; + +my $ret = waitpid($pid, 0); +if ($ret != $pid) { + die "confusing return from waitpid: $ret"; } diff --git a/t/t5582-fetch-negative-refspec.sh b/t/t5582-fetch-negative-refspec.sh index e5d2e79ad3..7a80e47c2b 100755 --- a/t/t5582-fetch-negative-refspec.sh +++ b/t/t5582-fetch-negative-refspec.sh @@ -105,7 +105,6 @@ test_expect_success "fetch with negative pattern refspec does not expand prefix" ' test_expect_success "fetch with negative refspec avoids duplicate conflict" ' - cd "$D" && ( cd one && git branch dups/a && diff --git a/t/t5600-clone-fail-cleanup.sh b/t/t5600-clone-fail-cleanup.sh index 5bf10261d3..34b3df4027 100755 --- a/t/t5600-clone-fail-cleanup.sh +++ b/t/t5600-clone-fail-cleanup.sh @@ -35,7 +35,9 @@ test_expect_success 'create a repo to clone' ' ' test_expect_success 'create objects in repo for later corruption' ' - test_commit -C foo file + test_commit -C foo file && + git -C foo checkout --detach && + test_commit -C foo detached ' # source repository given to git clone should be relative to the diff --git a/t/t5604-clone-reference.sh b/t/t5604-clone-reference.sh index e845d621f6..24340e6d56 100755 --- a/t/t5604-clone-reference.sh +++ b/t/t5604-clone-reference.sh @@ -87,7 +87,7 @@ test_expect_success 'updating origin' ' ' test_expect_success 'pulling changes from origin' ' - git -C C pull origin + git -C C pull --no-rebase origin ' # the 2 local objects are commit and tree from the merge @@ -96,7 +96,7 @@ test_expect_success 'that alternate to origin gets used' ' ' test_expect_success 'pulling changes from origin' ' - git -C D pull origin + git -C D pull --no-rebase origin ' # the 5 local objects are expected; file3 blob, commit in A to add it diff --git a/t/t5606-clone-options.sh b/t/t5606-clone-options.sh index 3a595c0f82..d822153e4d 100755 --- a/t/t5606-clone-options.sh +++ b/t/t5606-clone-options.sh @@ -16,6 +16,18 @@ test_expect_success 'setup' ' ' +test_expect_success 'submodule.stickyRecursiveClone flag manipulates submodule.recurse value' ' + + test_config_global submodule.stickyRecursiveClone true && + git clone --recurse-submodules parent clone_recurse_true && + test_cmp_config -C clone_recurse_true true submodule.recurse && + + test_config_global submodule.stickyRecursiveClone false && + git clone --recurse-submodules parent clone_recurse_false && + test_expect_code 1 git -C clone_recurse_false config --get submodule.recurse + +' + test_expect_success 'clone -o' ' git clone -o foo parent clone-o && diff --git a/t/t5607-clone-bundle.sh b/t/t5607-clone-bundle.sh index ed0d911e95..51705aa86a 100755 --- a/t/t5607-clone-bundle.sh +++ b/t/t5607-clone-bundle.sh @@ -91,7 +91,8 @@ test_expect_success 'ridiculously long subject in boundary' ' git fetch long-subject-bundle.bdl && - if ! test_have_prereq SHA1 + algo=$(test_oid algo) && + if test "$algo" != sha1 then echo "@object-format=sha256" fi >expect && @@ -100,7 +101,7 @@ test_expect_success 'ridiculously long subject in boundary' ' $(git rev-parse HEAD) HEAD EOF - if test_have_prereq SHA1 + if test "$algo" = sha1 then head -n 3 long-subject-bundle.bdl else diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh index 930721f053..aa1827d841 100755 --- a/t/t5701-git-serve.sh +++ b/t/t5701-git-serve.sh @@ -72,6 +72,37 @@ test_expect_success 'request invalid command' ' test_i18ngrep "invalid command" err ' +test_expect_success 'request capability as command' ' + test-tool pkt-line pack >in <<-EOF && + command=agent + object-format=$(test_oid algo) + 0000 + EOF + test_must_fail test-tool serve-v2 --stateless-rpc 2>err <in && + grep invalid.command.*agent err +' + +test_expect_success 'request command as capability' ' + test-tool pkt-line pack >in <<-EOF && + command=ls-refs + object-format=$(test_oid algo) + fetch + 0000 + EOF + test_must_fail test-tool serve-v2 --stateless-rpc 2>err <in && + grep unknown.capability err +' + +test_expect_success 'requested command is command=value' ' + test-tool pkt-line pack >in <<-EOF && + command=ls-refs=whatever + object-format=$(test_oid algo) + 0000 + EOF + test_must_fail test-tool serve-v2 --stateless-rpc 2>err <in && + grep invalid.command.*ls-refs=whatever err +' + test_expect_success 'wrong object-format' ' test-tool pkt-line pack >in <<-EOF && command=fetch @@ -116,6 +147,19 @@ test_expect_success 'basics of ls-refs' ' test_cmp expect actual ' +test_expect_success 'ls-refs complains about unknown options' ' + test-tool pkt-line pack >in <<-EOF && + command=ls-refs + object-format=$(test_oid algo) + 0001 + no-such-arg + 0000 + EOF + + test_must_fail test-tool serve-v2 --stateless-rpc 2>err <in && + grep unexpected.line.*no-such-arg err +' + test_expect_success 'basic ref-prefixes' ' test-tool pkt-line pack >in <<-EOF && command=ls-refs @@ -158,6 +202,37 @@ test_expect_success 'refs/heads prefix' ' test_cmp expect actual ' +test_expect_success 'ignore very large set of prefixes' ' + # generate a large number of ref-prefixes that we expect + # to match nothing; the value here exceeds TOO_MANY_PREFIXES + # from ls-refs.c. + { + echo command=ls-refs && + echo object-format=$(test_oid algo) && + echo 0001 && + perl -le "print \"ref-prefix refs/heads/\$_\" for (1..65536)" && + echo 0000 + } | + test-tool pkt-line pack >in && + + # and then confirm that we see unmatched prefixes anyway (i.e., + # that the prefix was not applied). + cat >expect <<-EOF && + $(git rev-parse HEAD) HEAD + $(git rev-parse refs/heads/dev) refs/heads/dev + $(git rev-parse refs/heads/main) refs/heads/main + $(git rev-parse refs/heads/release) refs/heads/release + $(git rev-parse refs/tags/annotated-tag) refs/tags/annotated-tag + $(git rev-parse refs/tags/one) refs/tags/one + $(git rev-parse refs/tags/two) refs/tags/two + 0000 + EOF + + test-tool serve-v2 --stateless-rpc <in >out && + test-tool pkt-line unpack <out >actual && + test_cmp expect actual +' + test_expect_success 'peel parameter' ' test-tool pkt-line pack >in <<-EOF && command=ls-refs diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh index 78de1ff2ad..d527cf6c49 100755 --- a/t/t5702-protocol-v2.sh +++ b/t/t5702-protocol-v2.sh @@ -27,9 +27,9 @@ test_expect_success 'list refs with git:// using protocol v2' ' ls-remote --symref "$GIT_DAEMON_URL/parent" >actual && # Client requested to use protocol v2 - grep "git> .*\\\0\\\0version=2\\\0$" log && + grep "ls-remote> .*\\\0\\\0version=2\\\0$" log && # Server responded using protocol v2 - grep "git< version 2" log && + grep "ls-remote< version 2" log && git ls-remote --symref "$GIT_DAEMON_URL/parent" >expect && test_cmp expect actual @@ -151,7 +151,7 @@ test_expect_success 'list refs with file:// using protocol v2' ' ls-remote --symref "file://$(pwd)/file_parent" >actual && # Server responded using protocol v2 - grep "git< version 2" log && + grep "ls-remote< version 2" log && git ls-remote --symref "file://$(pwd)/file_parent" >expect && test_cmp expect actual @@ -237,6 +237,19 @@ test_expect_success '...but not if explicitly forbidden by config' ' ! grep "refs/heads/mydefaultbranch" file_empty_child/.git/HEAD ' +test_expect_success 'bare clone propagates empty default branch' ' + test_when_finished "rm -rf file_empty_parent file_empty_child.git" && + + GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= \ + git -c init.defaultBranch=mydefaultbranch init file_empty_parent && + + GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= \ + git -c init.defaultBranch=main -c protocol.version=2 \ + clone --bare \ + "file://$(pwd)/file_empty_parent" file_empty_child.git && + grep "refs/heads/mydefaultbranch" file_empty_child.git/HEAD +' + test_expect_success 'fetch with file:// using protocol v2' ' test_when_finished "rm -f log" && diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh index e9e471621d..220098523a 100755 --- a/t/t5703-upload-pack-ref-in-want.sh +++ b/t/t5703-upload-pack-ref-in-want.sh @@ -40,6 +40,30 @@ write_command () { fi } +# Write a complete fetch command to stdout, suitable for use with `test-tool +# pkt-line`. "want-ref", "want", and "have" lines are read from stdin. +# +# Examples: +# +# write_fetch_command <<-EOF +# want-ref refs/heads/main +# have $(git rev-parse a) +# EOF +# +# write_fetch_command <<-EOF +# want $(git rev-parse b) +# have $(git rev-parse a) +# EOF +# +write_fetch_command () { + write_command fetch && + echo "0001" && + echo "no-progress" && + cat && + echo "done" && + echo "0000" +} + # c(o/foo) d(o/bar) # \ / # b e(baz) f(main) @@ -77,15 +101,11 @@ test_expect_success 'config controls ref-in-want advertisement' ' ' test_expect_success 'invalid want-ref line' ' - test-tool pkt-line pack >in <<-EOF && - $(write_command fetch) - 0001 - no-progress + write_fetch_command >pkt <<-EOF && want-ref refs/heads/non-existent - done - 0000 EOF + test-tool pkt-line pack <pkt >in && test_must_fail test-tool serve-v2 --stateless-rpc 2>out <in && grep "unknown ref" out ' @@ -97,16 +117,11 @@ test_expect_success 'basic want-ref' ' EOF git rev-parse f >expected_commits && - oid=$(git rev-parse a) && - test-tool pkt-line pack >in <<-EOF && - $(write_command fetch) - 0001 - no-progress + write_fetch_command >pkt <<-EOF && want-ref refs/heads/main - have $oid - done - 0000 + have $(git rev-parse a) EOF + test-tool pkt-line pack <pkt >in && test-tool serve-v2 --stateless-rpc >out <in && check_output @@ -121,17 +136,12 @@ test_expect_success 'multiple want-ref lines' ' EOF git rev-parse c d >expected_commits && - oid=$(git rev-parse b) && - test-tool pkt-line pack >in <<-EOF && - $(write_command fetch) - 0001 - no-progress + write_fetch_command >pkt <<-EOF && want-ref refs/heads/o/foo want-ref refs/heads/o/bar - have $oid - done - 0000 + have $(git rev-parse b) EOF + test-tool pkt-line pack <pkt >in && test-tool serve-v2 --stateless-rpc >out <in && check_output @@ -144,16 +154,12 @@ test_expect_success 'mix want and want-ref' ' EOF git rev-parse e f >expected_commits && - test-tool pkt-line pack >in <<-EOF && - $(write_command fetch) - 0001 - no-progress + write_fetch_command >pkt <<-EOF && want-ref refs/heads/main want $(git rev-parse e) have $(git rev-parse a) - done - 0000 EOF + test-tool pkt-line pack <pkt >in && test-tool serve-v2 --stateless-rpc >out <in && check_output @@ -166,16 +172,11 @@ test_expect_success 'want-ref with ref we already have commit for' ' EOF >expected_commits && - oid=$(git rev-parse c) && - test-tool pkt-line pack >in <<-EOF && - $(write_command fetch) - 0001 - no-progress + write_fetch_command >pkt <<-EOF && want-ref refs/heads/o/foo - have $oid - done - 0000 + have $(git rev-parse c) EOF + test-tool pkt-line pack <pkt >in && test-tool serve-v2 --stateless-rpc >out <in && check_output @@ -298,6 +299,141 @@ test_expect_success 'fetching with wildcard that matches multiple refs' ' grep "want-ref refs/heads/o/bar" log ' +REPO="$(pwd)/repo-ns" + +test_expect_success 'setup namespaced repo' ' + ( + git init -b main "$REPO" && + cd "$REPO" && + test_commit a && + test_commit b && + git checkout a && + test_commit c && + git checkout a && + test_commit d && + git update-ref refs/heads/ns-no b && + git update-ref refs/namespaces/ns/refs/heads/ns-yes c && + git update-ref refs/namespaces/ns/refs/heads/hidden d + ) && + git -C "$REPO" config uploadpack.allowRefInWant true +' + +test_expect_success 'with namespace: want-ref is considered relative to namespace' ' + wanted_ref=refs/heads/ns-yes && + + oid=$(git -C "$REPO" rev-parse "refs/namespaces/ns/$wanted_ref") && + cat >expected_refs <<-EOF && + $oid $wanted_ref + EOF + cat >expected_commits <<-EOF && + $oid + $(git -C "$REPO" rev-parse a) + EOF + + write_fetch_command >pkt <<-EOF && + want-ref $wanted_ref + EOF + test-tool pkt-line pack <pkt >in && + + GIT_NAMESPACE=ns test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in && + check_output +' + +test_expect_success 'with namespace: want-ref outside namespace is unknown' ' + wanted_ref=refs/heads/ns-no && + + write_fetch_command >pkt <<-EOF && + want-ref $wanted_ref + EOF + test-tool pkt-line pack <pkt >in && + + test_must_fail env GIT_NAMESPACE=ns \ + test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in && + grep "unknown ref" out +' + +# Cross-check refs/heads/ns-no indeed exists +test_expect_success 'without namespace: want-ref outside namespace succeeds' ' + wanted_ref=refs/heads/ns-no && + + oid=$(git -C "$REPO" rev-parse $wanted_ref) && + cat >expected_refs <<-EOF && + $oid $wanted_ref + EOF + cat >expected_commits <<-EOF && + $oid + $(git -C "$REPO" rev-parse a) + EOF + + write_fetch_command >pkt <<-EOF && + want-ref $wanted_ref + EOF + test-tool pkt-line pack <pkt >in && + + test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in && + check_output +' + +test_expect_success 'with namespace: hideRefs is matched, relative to namespace' ' + wanted_ref=refs/heads/hidden && + git -C "$REPO" config transfer.hideRefs $wanted_ref && + + write_fetch_command >pkt <<-EOF && + want-ref $wanted_ref + EOF + test-tool pkt-line pack <pkt >in && + + test_must_fail env GIT_NAMESPACE=ns \ + test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in && + grep "unknown ref" out +' + +# Cross-check refs/heads/hidden indeed exists +test_expect_success 'with namespace: want-ref succeeds if hideRefs is removed' ' + wanted_ref=refs/heads/hidden && + git -C "$REPO" config --unset transfer.hideRefs $wanted_ref && + + oid=$(git -C "$REPO" rev-parse "refs/namespaces/ns/$wanted_ref") && + cat >expected_refs <<-EOF && + $oid $wanted_ref + EOF + cat >expected_commits <<-EOF && + $oid + $(git -C "$REPO" rev-parse a) + EOF + + write_fetch_command >pkt <<-EOF && + want-ref $wanted_ref + EOF + test-tool pkt-line pack <pkt >in && + + GIT_NAMESPACE=ns test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in && + check_output +' + +test_expect_success 'without namespace: relative hideRefs does not match' ' + wanted_ref=refs/namespaces/ns/refs/heads/hidden && + git -C "$REPO" config transfer.hideRefs refs/heads/hidden && + + oid=$(git -C "$REPO" rev-parse $wanted_ref) && + cat >expected_refs <<-EOF && + $oid $wanted_ref + EOF + cat >expected_commits <<-EOF && + $oid + $(git -C "$REPO" rev-parse a) + EOF + + write_fetch_command >pkt <<-EOF && + want-ref $wanted_ref + EOF + test-tool pkt-line pack <pkt >in && + + test-tool -C "$REPO" serve-v2 --stateless-rpc >out <in && + check_output +' + + . "$TEST_DIRECTORY"/lib-httpd.sh start_httpd diff --git a/t/t5704-protocol-violations.sh b/t/t5704-protocol-violations.sh index 5c941949b9..bc393d7c31 100755 --- a/t/t5704-protocol-violations.sh +++ b/t/t5704-protocol-violations.sh @@ -32,4 +32,19 @@ test_expect_success 'extra delim packet in v2 fetch args' ' test_i18ngrep "expected flush after fetch arguments" err ' +test_expect_success 'bogus symref in v0 capabilities' ' + test_commit foo && + oid=$(git rev-parse HEAD) && + dst=refs/heads/foo && + { + printf "%s HEAD\0symref object-format=%s symref=HEAD:%s\n" \ + "$oid" "$GIT_DEFAULT_HASH" "$dst" | + test-tool pkt-line pack-raw-stdin && + printf "0000" + } >input && + git ls-remote --symref --upload-pack="cat input; read junk;:" . >actual && + printf "ref: %s\tHEAD\n%s\tHEAD\n" "$dst" "$oid" >expect && + test_cmp expect actual +' + test_done diff --git a/t/t5705-session-id-in-capabilities.sh b/t/t5705-session-id-in-capabilities.sh index f1d189d5bc..eb8c79aafd 100755 --- a/t/t5705-session-id-in-capabilities.sh +++ b/t/t5705-session-id-in-capabilities.sh @@ -73,6 +73,17 @@ do grep \"key\":\"server-sid\" tr2-client-events && grep \"key\":\"client-sid\" tr2-server-events ' + + test_expect_success "client & server log negotiated version (v${PROTO})" ' + test_when_finished "rm -rf local tr2-client-events tr2-server-events" && + cp -r "$LOCAL_PRISTINE" local && + GIT_TRACE2_EVENT="$(pwd)/tr2-client-events" \ + git -c protocol.version=$PROTO -C local fetch \ + --upload-pack "GIT_TRACE2_EVENT=\"$(pwd)/tr2-server-events\" git-upload-pack" \ + origin && + grep \"key\":\"negotiated-version\",\"value\":\"$PROTO\" tr2-client-events && + grep \"key\":\"negotiated-version\",\"value\":\"$PROTO\" tr2-server-events + ' done test_done diff --git a/t/t6000-rev-list-misc.sh b/t/t6000-rev-list-misc.sh index 12def7bcbf..ef849e5bc8 100755 --- a/t/t6000-rev-list-misc.sh +++ b/t/t6000-rev-list-misc.sh @@ -169,4 +169,35 @@ test_expect_success 'rev-list --count --objects' ' test_line_count = $count actual ' +test_expect_success 'rev-list --unsorted-input results in different sorting' ' + git rev-list --unsorted-input HEAD HEAD~ >first && + git rev-list --unsorted-input HEAD~ HEAD >second && + ! test_cmp first second && + sort first >first.sorted && + sort second >second.sorted && + test_cmp first.sorted second.sorted +' + +test_expect_success 'rev-list --unsorted-input incompatible with --no-walk' ' + cat >expect <<-EOF && + fatal: --no-walk is incompatible with --unsorted-input + EOF + test_must_fail git rev-list --unsorted-input --no-walk HEAD 2>error && + test_cmp expect error && + test_must_fail git rev-list --unsorted-input --no-walk=sorted HEAD 2>error && + test_cmp expect error && + test_must_fail git rev-list --unsorted-input --no-walk=unsorted HEAD 2>error && + test_cmp expect error && + + cat >expect <<-EOF && + fatal: --unsorted-input is incompatible with --no-walk + EOF + test_must_fail git rev-list --no-walk --unsorted-input HEAD 2>error && + test_cmp expect error && + test_must_fail git rev-list --no-walk=sorted --unsorted-input HEAD 2>error && + test_cmp expect error && + test_must_fail git rev-list --no-walk=unsorted --unsorted-input HEAD 2>error && + test_cmp expect error +' + test_done diff --git a/t/t6001-rev-list-graft.sh b/t/t6001-rev-list-graft.sh index 90d93f77fa..7294147334 100755 --- a/t/t6001-rev-list-graft.sh +++ b/t/t6001-rev-list-graft.sh @@ -23,7 +23,8 @@ test_expect_success setup ' git commit -a -m "Third in one history." && A2=$(git rev-parse --verify HEAD) && - rm -f .git/refs/heads/main .git/index && + git update-ref -d refs/heads/main && + rm -f .git/index && echo >fileA fileA again && echo >subdir/fileB fileB again && diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh index a1baf4e451..1be85d064e 100755 --- a/t/t6030-bisect-porcelain.sh +++ b/t/t6030-bisect-porcelain.sh @@ -962,4 +962,22 @@ test_expect_success 'bisect handles annotated tags' ' grep "$bad is the first bad commit" output ' +test_expect_success 'bisect run fails with exit code equals or greater than 128' ' + write_script test_script.sh <<-\EOF && + exit 128 + EOF + test_must_fail git bisect run ./test_script.sh && + write_script test_script.sh <<-\EOF && + exit 255 + EOF + test_must_fail git bisect run ./test_script.sh +' + +test_expect_success 'bisect visualize with a filename with dash and space' ' + echo "My test line" >>"./-hello 2" && + git add -- "./-hello 2" && + git commit --quiet -m "Add test line" -- "./-hello 2" && + git bisect visualize -p -- "-hello 2" +' + test_done diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh index e33d512ec1..2500acc2ef 100755 --- a/t/t6050-replace.sh +++ b/t/t6050-replace.sh @@ -132,7 +132,7 @@ tagger T A Gger <> 0 +0000 EOF test_expect_success 'tag replaced commit' ' - git mktag <tag.sig >.git/refs/tags/mytag + git update-ref refs/tags/mytag $(git mktag <tag.sig) ' test_expect_success '"git fsck" works' ' diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh index 1a501ee09e..bae2419150 100755 --- a/t/t6120-describe.sh +++ b/t/t6120-describe.sh @@ -107,7 +107,8 @@ test_expect_success 'describe --contains defaults to HEAD without commit-ish' ' check_describe tags/A --all A^0 test_expect_success 'renaming tag A to Q locally produces a warning' " - mv .git/refs/tags/A .git/refs/tags/Q && + git update-ref refs/tags/Q $(git rev-parse refs/tags/A) && + git update-ref -d refs/tags/A && git describe HEAD 2>err >out && cat >expected <<-\EOF && warning: tag 'Q' is externally known as 'A' @@ -135,7 +136,8 @@ test_expect_success 'abbrev=0 will not break misplaced tag (2)' ' ' test_expect_success 'rename tag Q back to A' ' - mv .git/refs/tags/Q .git/refs/tags/A + git update-ref refs/tags/A $(git rev-parse refs/tags/Q) && + git update-ref -d refs/tags/Q ' test_expect_success 'pack tag refs' 'git pack-refs' diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh index 9e0214076b..80679d5e12 100755 --- a/t/t6300-for-each-ref.sh +++ b/t/t6300-for-each-ref.sh @@ -59,18 +59,25 @@ test_atom() { # Automatically test "contents:size" atom after testing "contents" if test "$2" = "contents" then - case $(git cat-file -t "$ref") in - tag) - # We cannot use $3 as it expects sanitize_pgp to run - expect=$(git cat-file tag $ref | tail -n +6 | wc -c) ;; - tree | blob) - expect='' ;; - commit) - expect=$(printf '%s' "$3" | wc -c) ;; - esac - # Leave $expect unquoted to lose possible leading whitespaces - echo $expect >expected + # for commit leg, $3 is changed there + expect=$(printf '%s' "$3" | wc -c) test_expect_${4:-success} $PREREQ "basic atom: $1 contents:size" ' + type=$(git cat-file -t "$ref") && + case $type in + tag) + # We cannot use $3 as it expects sanitize_pgp to run + git cat-file tag $ref >out && + expect=$(tail -n +6 out | wc -c) && + rm -f out ;; + tree | blob) + expect="" ;; + commit) + : "use the calculated expect" ;; + *) + BUG "unknown object type" ;; + esac && + # Leave $expect unquoted to lose possible leading whitespaces + echo $expect >expected && git for-each-ref --format="%(contents:size)" "$ref" >actual && test_cmp expected actual ' @@ -130,6 +137,8 @@ test_atom head parent:short=10 '' test_atom head numparent 0 test_atom head object '' test_atom head type '' +test_atom head raw "$(git cat-file commit refs/heads/main) +" test_atom head '*objectname' '' test_atom head '*objecttype' '' test_atom head author 'A U Thor <author@example.com> 1151968724 +0200' @@ -221,6 +230,15 @@ test_atom tag contents 'Tagging at 1151968727 ' test_atom tag HEAD ' ' +test_expect_success 'basic atom: refs/tags/testtag *raw' ' + git cat-file commit refs/tags/testtag^{} >expected && + git for-each-ref --format="%(*raw)" refs/tags/testtag >actual && + sanitize_pgp <expected >expected.clean && + echo >>expected.clean && + sanitize_pgp <actual >actual.clean && + test_cmp expected.clean actual.clean +' + test_expect_success 'Check invalid atoms names are errors' ' test_must_fail git for-each-ref --format="%(INVALID)" refs/heads ' @@ -686,6 +704,15 @@ test_atom refs/tags/signed-empty contents:body '' test_atom refs/tags/signed-empty contents:signature "$sig" test_atom refs/tags/signed-empty contents "$sig" +test_expect_success GPG 'basic atom: refs/tags/signed-empty raw' ' + git cat-file tag refs/tags/signed-empty >expected && + git for-each-ref --format="%(raw)" refs/tags/signed-empty >actual && + sanitize_pgp <expected >expected.clean && + echo >>expected.clean && + sanitize_pgp <actual >actual.clean && + test_cmp expected.clean actual.clean +' + test_atom refs/tags/signed-short subject 'subject line' test_atom refs/tags/signed-short subject:sanitize 'subject-line' test_atom refs/tags/signed-short contents:subject 'subject line' @@ -695,6 +722,15 @@ test_atom refs/tags/signed-short contents:signature "$sig" test_atom refs/tags/signed-short contents "subject line $sig" +test_expect_success GPG 'basic atom: refs/tags/signed-short raw' ' + git cat-file tag refs/tags/signed-short >expected && + git for-each-ref --format="%(raw)" refs/tags/signed-short >actual && + sanitize_pgp <expected >expected.clean && + echo >>expected.clean && + sanitize_pgp <actual >actual.clean && + test_cmp expected.clean actual.clean +' + test_atom refs/tags/signed-long subject 'subject line' test_atom refs/tags/signed-long subject:sanitize 'subject-line' test_atom refs/tags/signed-long contents:subject 'subject line' @@ -708,6 +744,15 @@ test_atom refs/tags/signed-long contents "subject line body contents $sig" +test_expect_success GPG 'basic atom: refs/tags/signed-long raw' ' + git cat-file tag refs/tags/signed-long >expected && + git for-each-ref --format="%(raw)" refs/tags/signed-long >actual && + sanitize_pgp <expected >expected.clean && + echo >>expected.clean && + sanitize_pgp <actual >actual.clean && + test_cmp expected.clean actual.clean +' + test_expect_success 'set up refs pointing to tree and blob' ' git update-ref refs/mytrees/first refs/heads/main^{tree} && git update-ref refs/myblobs/first refs/heads/main:one @@ -720,6 +765,16 @@ test_atom refs/mytrees/first contents:body "" test_atom refs/mytrees/first contents:signature "" test_atom refs/mytrees/first contents "" +test_expect_success 'basic atom: refs/mytrees/first raw' ' + git cat-file tree refs/mytrees/first >expected && + echo >>expected && + git for-each-ref --format="%(raw)" refs/mytrees/first >actual && + test_cmp expected actual && + git cat-file -s refs/mytrees/first >expected && + git for-each-ref --format="%(raw:size)" refs/mytrees/first >actual && + test_cmp expected actual +' + test_atom refs/myblobs/first subject "" test_atom refs/myblobs/first contents:subject "" test_atom refs/myblobs/first body "" @@ -727,6 +782,189 @@ test_atom refs/myblobs/first contents:body "" test_atom refs/myblobs/first contents:signature "" test_atom refs/myblobs/first contents "" +test_expect_success 'basic atom: refs/myblobs/first raw' ' + git cat-file blob refs/myblobs/first >expected && + echo >>expected && + git for-each-ref --format="%(raw)" refs/myblobs/first >actual && + test_cmp expected actual && + git cat-file -s refs/myblobs/first >expected && + git for-each-ref --format="%(raw:size)" refs/myblobs/first >actual && + test_cmp expected actual +' + +test_expect_success 'set up refs pointing to binary blob' ' + printf "a\0b\0c" >blob1 && + printf "a\0c\0b" >blob2 && + printf "\0a\0b\0c" >blob3 && + printf "abc" >blob4 && + printf "\0 \0 \0 " >blob5 && + printf "\0 \0a\0 " >blob6 && + printf " " >blob7 && + >blob8 && + obj=$(git hash-object -w blob1) && + git update-ref refs/myblobs/blob1 "$obj" && + obj=$(git hash-object -w blob2) && + git update-ref refs/myblobs/blob2 "$obj" && + obj=$(git hash-object -w blob3) && + git update-ref refs/myblobs/blob3 "$obj" && + obj=$(git hash-object -w blob4) && + git update-ref refs/myblobs/blob4 "$obj" && + obj=$(git hash-object -w blob5) && + git update-ref refs/myblobs/blob5 "$obj" && + obj=$(git hash-object -w blob6) && + git update-ref refs/myblobs/blob6 "$obj" && + obj=$(git hash-object -w blob7) && + git update-ref refs/myblobs/blob7 "$obj" && + obj=$(git hash-object -w blob8) && + git update-ref refs/myblobs/blob8 "$obj" +' + +test_expect_success 'Verify sorts with raw' ' + cat >expected <<-EOF && + refs/myblobs/blob8 + refs/myblobs/blob5 + refs/myblobs/blob6 + refs/myblobs/blob3 + refs/myblobs/blob7 + refs/mytrees/first + refs/myblobs/first + refs/myblobs/blob1 + refs/myblobs/blob2 + refs/myblobs/blob4 + refs/heads/main + EOF + git for-each-ref --format="%(refname)" --sort=raw \ + refs/heads/main refs/myblobs/ refs/mytrees/first >actual && + test_cmp expected actual +' + +test_expect_success 'Verify sorts with raw:size' ' + cat >expected <<-EOF && + refs/myblobs/blob8 + refs/myblobs/first + refs/myblobs/blob7 + refs/heads/main + refs/myblobs/blob4 + refs/myblobs/blob1 + refs/myblobs/blob2 + refs/myblobs/blob3 + refs/myblobs/blob5 + refs/myblobs/blob6 + refs/mytrees/first + EOF + git for-each-ref --format="%(refname)" --sort=raw:size \ + refs/heads/main refs/myblobs/ refs/mytrees/first >actual && + test_cmp expected actual +' + +test_expect_success 'validate raw atom with %(if:equals)' ' + cat >expected <<-EOF && + not equals + not equals + not equals + not equals + not equals + not equals + refs/myblobs/blob4 + not equals + not equals + not equals + not equals + not equals + EOF + git for-each-ref --format="%(if:equals=abc)%(raw)%(then)%(refname)%(else)not equals%(end)" \ + refs/myblobs/ refs/heads/ >actual && + test_cmp expected actual +' + +test_expect_success 'validate raw atom with %(if:notequals)' ' + cat >expected <<-EOF && + refs/heads/ambiguous + refs/heads/main + refs/heads/newtag + refs/myblobs/blob1 + refs/myblobs/blob2 + refs/myblobs/blob3 + equals + refs/myblobs/blob5 + refs/myblobs/blob6 + refs/myblobs/blob7 + refs/myblobs/blob8 + refs/myblobs/first + EOF + git for-each-ref --format="%(if:notequals=abc)%(raw)%(then)%(refname)%(else)equals%(end)" \ + refs/myblobs/ refs/heads/ >actual && + test_cmp expected actual +' + +test_expect_success 'empty raw refs with %(if)' ' + cat >expected <<-EOF && + refs/myblobs/blob1 not empty + refs/myblobs/blob2 not empty + refs/myblobs/blob3 not empty + refs/myblobs/blob4 not empty + refs/myblobs/blob5 not empty + refs/myblobs/blob6 not empty + refs/myblobs/blob7 empty + refs/myblobs/blob8 empty + refs/myblobs/first not empty + EOF + git for-each-ref --format="%(refname) %(if)%(raw)%(then)not empty%(else)empty%(end)" \ + refs/myblobs/ >actual && + test_cmp expected actual +' + +test_expect_success '%(raw) with --python must fail' ' + test_must_fail git for-each-ref --format="%(raw)" --python +' + +test_expect_success '%(raw) with --tcl must fail' ' + test_must_fail git for-each-ref --format="%(raw)" --tcl +' + +test_expect_success '%(raw) with --perl' ' + git for-each-ref --format="\$name= %(raw); +print \"\$name\"" refs/myblobs/blob1 --perl | perl >actual && + cmp blob1 actual && + git for-each-ref --format="\$name= %(raw); +print \"\$name\"" refs/myblobs/blob3 --perl | perl >actual && + cmp blob3 actual && + git for-each-ref --format="\$name= %(raw); +print \"\$name\"" refs/myblobs/blob8 --perl | perl >actual && + cmp blob8 actual && + git for-each-ref --format="\$name= %(raw); +print \"\$name\"" refs/myblobs/first --perl | perl >actual && + cmp one actual && + git cat-file tree refs/mytrees/first > expected && + git for-each-ref --format="\$name= %(raw); +print \"\$name\"" refs/mytrees/first --perl | perl >actual && + cmp expected actual +' + +test_expect_success '%(raw) with --shell must fail' ' + test_must_fail git for-each-ref --format="%(raw)" --shell +' + +test_expect_success '%(raw) with --shell and --sort=raw must fail' ' + test_must_fail git for-each-ref --format="%(raw)" --sort=raw --shell +' + +test_expect_success '%(raw:size) with --shell' ' + git for-each-ref --format="%(raw:size)" | while read line + do + echo "'\''$line'\''" >>expect + done && + git for-each-ref --format="%(raw:size)" --shell >actual && + test_cmp expect actual +' + +test_expect_success 'for-each-ref --format compare with cat-file --batch' ' + git rev-parse refs/mytrees/first | git cat-file --batch >expected && + git for-each-ref --format="%(objectname) %(objecttype) %(objectsize) +%(raw)" refs/mytrees/first >actual && + test_cmp expected actual +' + test_expect_success 'set up multiple-sort tags' ' for when in 100000 200000 do @@ -980,6 +1218,10 @@ test_expect_success 'basic atom: head contents:trailers' ' test_cmp expect actual.clean ' +test_expect_success 'basic atom: rest must fail' ' + test_must_fail git for-each-ref --format="%(rest)" refs/heads/main +' + test_expect_success 'trailer parsing not fooled by --- line' ' git commit --allow-empty -F - <<-\EOF && this is the subject diff --git a/t/t6402-merge-rename.sh b/t/t6402-merge-rename.sh index 3da2896e3b..3a32b1a45c 100755 --- a/t/t6402-merge-rename.sh +++ b/t/t6402-merge-rename.sh @@ -103,7 +103,7 @@ test_expect_success 'setup' ' test_expect_success 'pull renaming branch into unrenaming one' \ ' git show-branch && - test_expect_code 1 git pull . white && + test_expect_code 1 git pull --no-rebase . white && git ls-files -s && test_stdout_line_count = 3 git ls-files -u B && test_stdout_line_count = 1 git ls-files -s N && @@ -119,7 +119,7 @@ test_expect_success 'pull renaming branch into another renaming one' \ rm -f B && git reset --hard && git checkout red && - test_expect_code 1 git pull . white && + test_expect_code 1 git pull --no-rebase . white && test_stdout_line_count = 3 git ls-files -u B && test_stdout_line_count = 1 git ls-files -s N && sed -ne "/^g/{ @@ -133,7 +133,7 @@ test_expect_success 'pull unrenaming branch into renaming one' \ ' git reset --hard && git show-branch && - test_expect_code 1 git pull . main && + test_expect_code 1 git pull --no-rebase . main && test_stdout_line_count = 3 git ls-files -u B && test_stdout_line_count = 1 git ls-files -s N && sed -ne "/^g/{ @@ -147,7 +147,7 @@ test_expect_success 'pull conflicting renames' \ ' git reset --hard && git show-branch && - test_expect_code 1 git pull . blue && + test_expect_code 1 git pull --no-rebase . blue && test_stdout_line_count = 1 git ls-files -u A && test_stdout_line_count = 1 git ls-files -u B && test_stdout_line_count = 1 git ls-files -u C && @@ -163,7 +163,7 @@ test_expect_success 'interference with untracked working tree file' ' git reset --hard && git show-branch && echo >A this file should not matter && - test_expect_code 1 git pull . white && + test_expect_code 1 git pull --no-rebase . white && test_path_is_file A ' @@ -173,7 +173,7 @@ test_expect_success 'interference with untracked working tree file' ' git show-branch && rm -f A && echo >A this file should not matter && - test_expect_code 1 git pull . red && + test_expect_code 1 git pull --no-rebase . red && test_path_is_file A ' @@ -183,7 +183,7 @@ test_expect_success 'interference with untracked working tree file' ' git checkout -f main && git tag -f anchor && git show-branch && - git pull . yellow && + git pull --no-rebase . yellow && test_path_is_missing M && git reset --hard anchor ' @@ -210,7 +210,7 @@ test_expect_success 'updated working tree file should prevent the merge' ' echo >>M one line addition && cat M >M.saved && git update-index M && - test_expect_code 128 git pull . yellow && + test_expect_code 128 git pull --no-rebase . yellow && test_cmp M M.saved && rm -f M.saved ' @@ -222,7 +222,7 @@ test_expect_success 'interference with untracked working tree file' ' git tag -f anchor && git show-branch && echo >M this file should not matter && - git pull . main && + git pull --no-rebase . main && test_path_is_file M && ! { git ls-files -s | diff --git a/t/t6409-merge-subtree.sh b/t/t6409-merge-subtree.sh index d406b2343c..ba7890ec52 100755 --- a/t/t6409-merge-subtree.sh +++ b/t/t6409-merge-subtree.sh @@ -100,7 +100,7 @@ test_expect_success 'merge update' ' git checkout -b topic_2 && git commit -m "update git-gui" && cd ../git && - git pull -s subtree gui topic_2 && + git pull --no-rebase -s subtree gui topic_2 && git ls-files -s >actual && ( echo "100644 $o3 0 git-gui/git-gui.sh" && @@ -129,7 +129,7 @@ test_expect_success 'initial ambiguous subtree' ' test_expect_success 'merge using explicit' ' cd ../git && git reset --hard topic_2 && - git pull -Xsubtree=git-gui gui topic_2 && + git pull --no-rebase -Xsubtree=git-gui gui topic_2 && git ls-files -s >actual && ( echo "100644 $o3 0 git-gui/git-gui.sh" && @@ -142,7 +142,7 @@ test_expect_success 'merge using explicit' ' test_expect_success 'merge2 using explicit' ' cd ../git && git reset --hard topic_2 && - git pull -Xsubtree=git-gui2 gui topic_2 && + git pull --no-rebase -Xsubtree=git-gui2 gui topic_2 && git ls-files -s >actual && ( echo "100644 $o1 0 git-gui/git-gui.sh" && diff --git a/t/t6415-merge-dir-to-symlink.sh b/t/t6415-merge-dir-to-symlink.sh index 2ce104aca7..2655e295f5 100755 --- a/t/t6415-merge-dir-to-symlink.sh +++ b/t/t6415-merge-dir-to-symlink.sh @@ -25,7 +25,8 @@ test_expect_success 'checkout does not clobber untracked symlink' ' git reset --hard main && git rm --cached a/b && git commit -m "untracked symlink remains" && - test_must_fail git checkout start^0 + test_must_fail git checkout start^0 && + git clean -fd # Do not leave the untracked symlink in the way ' test_expect_success 'a/b-2/c/d is kept when clobbering symlink b' ' @@ -34,7 +35,8 @@ test_expect_success 'a/b-2/c/d is kept when clobbering symlink b' ' git rm --cached a/b && git commit -m "untracked symlink remains" && git checkout -f start^0 && - test_path_is_file a/b-2/c/d + test_path_is_file a/b-2/c/d && + git clean -fd # Do not leave the untracked symlink in the way ' test_expect_success 'checkout should not have deleted a/b-2/c/d' ' diff --git a/t/t6417-merge-ours-theirs.sh b/t/t6417-merge-ours-theirs.sh index ac9aee9a66..ec065d6a65 100755 --- a/t/t6417-merge-ours-theirs.sh +++ b/t/t6417-merge-ours-theirs.sh @@ -69,11 +69,11 @@ test_expect_success 'binary file with -Xours/-Xtheirs' ' ' test_expect_success 'pull passes -X to underlying merge' ' - git reset --hard main && git pull -s recursive -Xours . side && - git reset --hard main && git pull -s recursive -X ours . side && - git reset --hard main && git pull -s recursive -Xtheirs . side && - git reset --hard main && git pull -s recursive -X theirs . side && - git reset --hard main && test_must_fail git pull -s recursive -X bork . side + git reset --hard main && git pull --no-rebase -s recursive -Xours . side && + git reset --hard main && git pull --no-rebase -s recursive -X ours . side && + git reset --hard main && git pull --no-rebase -s recursive -Xtheirs . side && + git reset --hard main && git pull --no-rebase -s recursive -X theirs . side && + git reset --hard main && test_must_fail git pull --no-rebase -s recursive -X bork . side ' test_expect_success SYMLINKS 'symlink with -Xours/-Xtheirs' ' diff --git a/t/t6424-merge-unrelated-index-changes.sh b/t/t6424-merge-unrelated-index-changes.sh index 5e3779ebc9..89dd544f38 100755 --- a/t/t6424-merge-unrelated-index-changes.sh +++ b/t/t6424-merge-unrelated-index-changes.sh @@ -132,6 +132,7 @@ test_expect_success 'merge-recursive, when index==head but head!=HEAD' ' # Make index match B git diff C B -- | git apply --cached && + test_when_finished "git clean -fd" && # Do not leave untracked around # Merge B & F, with B as "head" git merge-recursive A -- B F > out && test_i18ngrep "Already up to date" out diff --git a/t/t6430-merge-recursive.sh b/t/t6430-merge-recursive.sh index ffcc01fe65..a0efe7cb6d 100755 --- a/t/t6430-merge-recursive.sh +++ b/t/t6430-merge-recursive.sh @@ -718,7 +718,9 @@ test_expect_success 'merge-recursive remembers the names of all base trees' ' # merge-recursive prints in reverse order, but we do not care sort <trees >expect && sed -n "s/^virtual //p" out | sort >actual && - test_cmp expect actual + test_cmp expect actual && + + git clean -fd ' test_expect_success 'merge-recursive internal merge resolves to the sameness' ' diff --git a/t/t6436-merge-overwrite.sh b/t/t6436-merge-overwrite.sh index 84b4aacf49..c0b7bd7c3f 100755 --- a/t/t6436-merge-overwrite.sh +++ b/t/t6436-merge-overwrite.sh @@ -68,7 +68,8 @@ test_expect_success 'will not overwrite removed file' ' git commit -m "rm c1.c" && cp important c1.c && test_must_fail git merge c1a && - test_cmp important c1.c + test_cmp important c1.c && + rm c1.c # Do not leave untracked file in way of future tests ' test_expect_success 'will not overwrite re-added file' ' diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh index 10c7ae7f09..c2021267f2 100755 --- a/t/t6500-gc.sh +++ b/t/t6500-gc.sh @@ -241,7 +241,7 @@ test_expect_success 'background auto gc respects lock for all operations' ' # create a ref whose loose presence we can use to detect a pack-refs run git update-ref refs/heads/should-be-loose HEAD && - test_path_is_file .git/refs/heads/should-be-loose && + (ls -1 .git/refs/heads .git/reftable >expect || true) && # now fake a concurrent gc that holds the lock; we can use our # shell pid so that it looks valid. @@ -258,7 +258,8 @@ test_expect_success 'background auto gc respects lock for all operations' ' # our gc should exit zero without doing anything run_and_wait_for_auto_gc && - test_path_is_file .git/refs/heads/should-be-loose + (ls -1 .git/refs/heads .git/reftable >actual || true) && + test_cmp expect actual ' # DO NOT leave a detached auto gc process running near the end of the diff --git a/t/t7002-mv-sparse-checkout.sh b/t/t7002-mv-sparse-checkout.sh new file mode 100755 index 0000000000..545748949a --- /dev/null +++ b/t/t7002-mv-sparse-checkout.sh @@ -0,0 +1,189 @@ +#!/bin/sh + +test_description='git mv in sparse working trees' + +. ./test-lib.sh + +test_expect_success 'setup' " + mkdir -p sub/dir sub/dir2 && + touch a b c sub/d sub/dir/e sub/dir2/e && + git add -A && + git commit -m files && + + cat >sparse_error_header <<-EOF && + The following paths and/or pathspecs matched paths that exist + outside of your sparse-checkout definition, so will not be + updated in the index: + EOF + + cat >sparse_hint <<-EOF + hint: If you intend to update such entries, try one of the following: + hint: * Use the --sparse option. + hint: * Disable or modify the sparsity rules. + hint: Disable this message with \"git config advice.updateSparsePath false\" + EOF +" + +test_expect_success 'mv refuses to move sparse-to-sparse' ' + test_when_finished rm -f e && + git reset --hard && + git sparse-checkout set a && + touch b && + test_must_fail git mv b e 2>stderr && + cat sparse_error_header >expect && + echo b >>expect && + echo e >>expect && + cat sparse_hint >>expect && + test_cmp expect stderr && + git mv --sparse b e 2>stderr && + test_must_be_empty stderr +' + +test_expect_success 'mv refuses to move sparse-to-sparse, ignores failure' ' + test_when_finished rm -f b c e && + git reset --hard && + git sparse-checkout set a && + + # tracked-to-untracked + touch b && + git mv -k b e 2>stderr && + test_path_exists b && + test_path_is_missing e && + cat sparse_error_header >expect && + echo b >>expect && + echo e >>expect && + cat sparse_hint >>expect && + test_cmp expect stderr && + + git mv --sparse b e 2>stderr && + test_must_be_empty stderr && + test_path_is_missing b && + test_path_exists e && + + # tracked-to-tracked + git reset --hard && + touch b && + git mv -k b c 2>stderr && + test_path_exists b && + test_path_is_missing c && + cat sparse_error_header >expect && + echo b >>expect && + echo c >>expect && + cat sparse_hint >>expect && + test_cmp expect stderr && + + git mv --sparse b c 2>stderr && + test_must_be_empty stderr && + test_path_is_missing b && + test_path_exists c +' + +test_expect_success 'mv refuses to move non-sparse-to-sparse' ' + test_when_finished rm -f b c e && + git reset --hard && + git sparse-checkout set a && + + # tracked-to-untracked + test_must_fail git mv a e 2>stderr && + test_path_exists a && + test_path_is_missing e && + cat sparse_error_header >expect && + echo e >>expect && + cat sparse_hint >>expect && + test_cmp expect stderr && + git mv --sparse a e 2>stderr && + test_must_be_empty stderr && + test_path_is_missing a && + test_path_exists e && + + # tracked-to-tracked + rm e && + git reset --hard && + test_must_fail git mv a c 2>stderr && + test_path_exists a && + test_path_is_missing c && + cat sparse_error_header >expect && + echo c >>expect && + cat sparse_hint >>expect && + test_cmp expect stderr && + git mv --sparse a c 2>stderr && + test_must_be_empty stderr && + test_path_is_missing a && + test_path_exists c +' + +test_expect_success 'mv refuses to move sparse-to-non-sparse' ' + test_when_finished rm -f b c e && + git reset --hard && + git sparse-checkout set a e && + + # tracked-to-untracked + touch b && + test_must_fail git mv b e 2>stderr && + cat sparse_error_header >expect && + echo b >>expect && + cat sparse_hint >>expect && + test_cmp expect stderr && + git mv --sparse b e 2>stderr && + test_must_be_empty stderr +' + +test_expect_success 'recursive mv refuses to move (possible) sparse' ' + test_when_finished rm -rf b c e sub2 && + git reset --hard && + # Without cone mode, "sub" and "sub2" do not match + git sparse-checkout set sub/dir sub2/dir && + + # Add contained contents to ensure we avoid non-existence errors + mkdir sub/dir2 && + touch sub/d sub/dir2/e && + + test_must_fail git mv sub sub2 2>stderr && + cat sparse_error_header >expect && + cat >>expect <<-\EOF && + sub/d + sub2/d + sub/dir/e + sub2/dir/e + sub/dir2/e + sub2/dir2/e + EOF + cat sparse_hint >>expect && + test_cmp expect stderr && + git mv --sparse sub sub2 2>stderr && + test_must_be_empty stderr && + git commit -m "moved sub to sub2" && + git rev-parse HEAD~1:sub >expect && + git rev-parse HEAD:sub2 >actual && + test_cmp expect actual && + git reset --hard HEAD~1 +' + +test_expect_success 'recursive mv refuses to move sparse' ' + git reset --hard && + # Use cone mode so "sub/" matches the sparse-checkout patterns + git sparse-checkout init --cone && + git sparse-checkout set sub/dir sub2/dir && + + # Add contained contents to ensure we avoid non-existence errors + mkdir sub/dir2 && + touch sub/dir2/e && + + test_must_fail git mv sub sub2 2>stderr && + cat sparse_error_header >expect && + cat >>expect <<-\EOF && + sub/dir2/e + sub2/dir2/e + EOF + cat sparse_hint >>expect && + test_cmp expect stderr && + git mv --sparse sub sub2 2>stderr && + test_must_be_empty stderr && + git commit -m "moved sub to sub2" && + git rev-parse HEAD~1:sub >expect && + git rev-parse HEAD:sub2 >actual && + test_cmp expect actual && + git reset --hard HEAD~1 +' + +test_done diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 2f72c5c688..082be85dff 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -1998,6 +1998,10 @@ test_expect_success '--format should list tags as per format given' ' test_cmp expect actual ' +test_expect_success 'git tag -l with --format="%(rest)" must fail' ' + test_must_fail git tag -l --format="%(rest)" "v1*" +' + test_expect_success "set up color tests" ' echo "<RED>v1.0<RESET>" >expect.color && echo "v1.0" >expect.bare && diff --git a/t/t7030-verify-tag.sh b/t/t7030-verify-tag.sh index 3cefde9602..10faa64515 100755 --- a/t/t7030-verify-tag.sh +++ b/t/t7030-verify-tag.sh @@ -194,6 +194,10 @@ test_expect_success GPG 'verifying tag with --format' ' test_cmp expect actual ' +test_expect_success GPG 'verifying tag with --format="%(rest)" must fail' ' + test_must_fail git verify-tag --format="%(rest)" "fourth-signed" +' + test_expect_success GPG 'verifying a forged tag with --format should fail silently' ' test_must_fail git verify-tag --format="tagname : %(tag)" $(cat forged1.tag) >actual-forged && test_must_be_empty actual-forged diff --git a/t/t7064-wtstatus-pv2.sh b/t/t7064-wtstatus-pv2.sh index 4613882caf..eeb0534163 100755 --- a/t/t7064-wtstatus-pv2.sh +++ b/t/t7064-wtstatus-pv2.sh @@ -373,10 +373,7 @@ test_expect_success 'verify upstream fields in branch header' ' ## Test upstream-gone case. Fake this by pointing ## origin/initial-branch at a non-existing commit. - OLD=$(git rev-parse origin/initial-branch) && - NEW=$ZERO_OID && - mv .git/packed-refs .git/old-packed-refs && - sed "s/$OLD/$NEW/g" <.git/old-packed-refs >.git/packed-refs && + git update-ref -d refs/remotes/origin/initial-branch && HUF=$(git rev-parse HEAD) && diff --git a/t/t7112-reset-submodule.sh b/t/t7112-reset-submodule.sh index 19830d9036..a3e2413bc3 100755 --- a/t/t7112-reset-submodule.sh +++ b/t/t7112-reset-submodule.sh @@ -6,7 +6,6 @@ test_description='reset can handle submodules' . "$TEST_DIRECTORY"/lib-submodule-update.sh KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS=1 -KNOWN_FAILURE_SUBMODULE_OVERWRITE_IGNORED_UNTRACKED=1 test_submodule_switch_recursing_with_args "reset --keep" diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 7f6e23a4bb..b7ba1c3268 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -585,6 +585,7 @@ test_expect_success 'checkout --conflict=diff3' ' ' test_expect_success 'failing checkout -b should not break working tree' ' + git clean -fd && # Remove untracked files in the way git reset --hard main && git symbolic-ref HEAD refs/heads/main && test_must_fail git checkout -b renamer side^ && diff --git a/t/t7500-commit-template-squash-signoff.sh b/t/t7500-commit-template-squash-signoff.sh index 54c2082acb..8dd0f98812 100755 --- a/t/t7500-commit-template-squash-signoff.sh +++ b/t/t7500-commit-template-squash-signoff.sh @@ -270,7 +270,7 @@ EOF test_expect_success 'commit --fixup provides correct one-line commit message' ' commit_for_rebase_autosquash_setup && - git commit --fixup HEAD~1 && + EDITOR="echo ignored >>" git commit --fixup HEAD~1 && commit_msg_is "fixup! target message subject line" ' @@ -281,6 +281,13 @@ test_expect_success 'commit --fixup -m"something" -m"extra"' ' extra" ' +test_expect_success 'commit --fixup --edit' ' + commit_for_rebase_autosquash_setup && + EDITOR="printf \"something\nextra\" >>" git commit --fixup HEAD~1 --edit && + commit_msg_is "fixup! target message subject linesomething +extra" +' + get_commit_msg () { rev="$1" && git log -1 --pretty=format:"%B" "$rev" diff --git a/t/t7505-prepare-commit-msg-hook.sh b/t/t7505-prepare-commit-msg-hook.sh index 7a8194ce72..2a07c70867 100755 --- a/t/t7505-prepare-commit-msg-hook.sh +++ b/t/t7505-prepare-commit-msg-hook.sh @@ -250,7 +250,6 @@ test_rebase () { } test_rebase success -test_have_prereq !REBASE_P || test_rebase success -p test_expect_success 'with hook (cherry-pick)' ' test_when_finished "git checkout -f main" && diff --git a/t/t7517-per-repo-email.sh b/t/t7517-per-repo-email.sh index 405420ae4d..163ae80468 100755 --- a/t/t7517-per-repo-email.sh +++ b/t/t7517-per-repo-email.sh @@ -75,19 +75,6 @@ test_expect_success 'noop interactive rebase does not care about ident' ' git rebase -i HEAD^ ' -test_expect_success REBASE_P \ - 'fast-forward rebase does not care about ident (preserve)' ' - git checkout -B tmp side-without-commit && - git rebase -p main -' - -test_expect_success REBASE_P \ - 'non-fast-forward rebase refuses to write commits (preserve)' ' - test_when_finished "git rebase --abort || true" && - git checkout -B tmp side-with-commit && - test_must_fail git rebase -p main -' - test_expect_success 'author.name overrides user.name' ' test_config user.name user && test_config user.email user@example.com && diff --git a/t/t7519-status-fsmonitor.sh b/t/t7519-status-fsmonitor.sh index deea88d443..f488d930df 100755 --- a/t/t7519-status-fsmonitor.sh +++ b/t/t7519-status-fsmonitor.sh @@ -389,47 +389,55 @@ test_expect_success 'status succeeds after staging/unstaging' ' # If "!" is supplied, then we verify that we do not call ensure_full_index # during a call to 'git status'. Otherwise, we verify that we _do_ call it. check_sparse_index_behavior () { - git status --porcelain=v2 >expect && - git sparse-checkout init --cone --sparse-index && - git sparse-checkout set dir1 dir2 && + git -C full status --porcelain=v2 >expect && GIT_TRACE2_EVENT="$(pwd)/trace2.txt" GIT_TRACE2_EVENT_NESTING=10 \ - git status --porcelain=v2 >actual && + git -C sparse status --porcelain=v2 >actual && test_region $1 index ensure_full_index trace2.txt && test_region fsm_hook query trace2.txt && test_cmp expect actual && - rm trace2.txt && - git sparse-checkout disable + rm trace2.txt } test_expect_success 'status succeeds with sparse index' ' - git reset --hard && - - test_config core.fsmonitor "$TEST_DIRECTORY/t7519/fsmonitor-all" && - check_sparse_index_behavior ! && - - write_script .git/hooks/fsmonitor-test<<-\EOF && - printf "last_update_token\0" - EOF - git config core.fsmonitor .git/hooks/fsmonitor-test && - check_sparse_index_behavior ! && + ( + sane_unset GIT_TEST_SPLIT_INDEX && - write_script .git/hooks/fsmonitor-test<<-\EOF && - printf "last_update_token\0" - printf "dir1/modified\0" - EOF - check_sparse_index_behavior ! && + git clone . full && + git clone --sparse . sparse && + git -C sparse sparse-checkout init --cone --sparse-index && + git -C sparse sparse-checkout set dir1 dir2 && - cp -r dir1 dir1a && - git add dir1a && - git commit -m "add dir1a" && + write_script .git/hooks/fsmonitor-test <<-\EOF && + printf "last_update_token\0" + EOF + git -C full config core.fsmonitor ../.git/hooks/fsmonitor-test && + git -C sparse config core.fsmonitor ../.git/hooks/fsmonitor-test && + check_sparse_index_behavior ! && - # This one modifies outside the sparse-checkout definition - # and hence we expect to expand the sparse-index. - write_script .git/hooks/fsmonitor-test<<-\EOF && - printf "last_update_token\0" - printf "dir1a/modified\0" - EOF - check_sparse_index_behavior + write_script .git/hooks/fsmonitor-test <<-\EOF && + printf "last_update_token\0" + printf "dir1/modified\0" + EOF + check_sparse_index_behavior ! && + + git -C sparse sparse-checkout add dir1a && + + for repo in full sparse + do + cp -r $repo/dir1 $repo/dir1a && + git -C $repo add dir1a && + git -C $repo commit -m "add dir1a" || return 1 + done && + git -C sparse sparse-checkout set dir1 dir2 && + + # This one modifies outside the sparse-checkout definition + # and hence we expect to expand the sparse-index. + write_script .git/hooks/fsmonitor-test <<-\EOF && + printf "last_update_token\0" + printf "dir1a/modified\0" + EOF + check_sparse_index_behavior + ) ' test_done diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh index 2ef39d3088..c773e30b3f 100755 --- a/t/t7600-merge.sh +++ b/t/t7600-merge.sh @@ -717,6 +717,7 @@ test_expect_success 'failed fast-forward merge with --autostash' ' git reset --hard c0 && git merge-file file file.orig file.5 && cp file.5 other && + test_when_finished "rm other" && test_must_fail git merge --autostash c1 2>err && test_i18ngrep "Applied autostash." err && test_cmp file.5 file diff --git a/t/t7601-merge-pull-config.sh b/t/t7601-merge-pull-config.sh index 52e8ccc933..1f652f433e 100755 --- a/t/t7601-merge-pull-config.sh +++ b/t/t7601-merge-pull-config.sh @@ -27,120 +27,324 @@ test_expect_success 'setup' ' git tag c3 ' -test_expect_success 'pull.rebase not set' ' +test_expect_success 'pull.rebase not set, ff possible' ' git reset --hard c0 && git pull . c1 2>err && - test_i18ngrep ! "Pulling without specifying how to reconcile" err + test_i18ngrep ! "You have divergent branches" err ' test_expect_success 'pull.rebase not set and pull.ff=true' ' git reset --hard c0 && test_config pull.ff true && git pull . c1 2>err && - test_i18ngrep ! "Pulling without specifying how to reconcile" err + test_i18ngrep ! "You have divergent branches" err ' test_expect_success 'pull.rebase not set and pull.ff=false' ' git reset --hard c0 && test_config pull.ff false && git pull . c1 2>err && - test_i18ngrep ! "Pulling without specifying how to reconcile" err + test_i18ngrep ! "You have divergent branches" err ' test_expect_success 'pull.rebase not set and pull.ff=only' ' git reset --hard c0 && test_config pull.ff only && git pull . c1 2>err && - test_i18ngrep ! "Pulling without specifying how to reconcile" err + test_i18ngrep ! "You have divergent branches" err ' test_expect_success 'pull.rebase not set and --rebase given' ' git reset --hard c0 && git pull --rebase . c1 2>err && - test_i18ngrep ! "Pulling without specifying how to reconcile" err + test_i18ngrep ! "You have divergent branches" err ' test_expect_success 'pull.rebase not set and --no-rebase given' ' git reset --hard c0 && git pull --no-rebase . c1 2>err && - test_i18ngrep ! "Pulling without specifying how to reconcile" err + test_i18ngrep ! "You have divergent branches" err ' test_expect_success 'pull.rebase not set and --ff given' ' git reset --hard c0 && git pull --ff . c1 2>err && - test_i18ngrep ! "Pulling without specifying how to reconcile" err + test_i18ngrep ! "You have divergent branches" err ' test_expect_success 'pull.rebase not set and --no-ff given' ' git reset --hard c0 && git pull --no-ff . c1 2>err && - test_i18ngrep ! "Pulling without specifying how to reconcile" err + test_i18ngrep ! "You have divergent branches" err ' test_expect_success 'pull.rebase not set and --ff-only given' ' git reset --hard c0 && git pull --ff-only . c1 2>err && - test_i18ngrep ! "Pulling without specifying how to reconcile" err + test_i18ngrep ! "You have divergent branches" err ' test_expect_success 'pull.rebase not set (not-fast-forward)' ' git reset --hard c2 && - git -c color.advice=always pull . c1 2>err && + test_must_fail git -c color.advice=always pull . c1 2>err && test_decode_color <err >decoded && test_i18ngrep "<YELLOW>hint: " decoded && - test_i18ngrep "Pulling without specifying how to reconcile" decoded + test_i18ngrep "You have divergent branches" decoded ' test_expect_success 'pull.rebase not set and pull.ff=true (not-fast-forward)' ' git reset --hard c2 && test_config pull.ff true && git pull . c1 2>err && - test_i18ngrep ! "Pulling without specifying how to reconcile" err + test_i18ngrep ! "You have divergent branches" err ' test_expect_success 'pull.rebase not set and pull.ff=false (not-fast-forward)' ' git reset --hard c2 && test_config pull.ff false && git pull . c1 2>err && - test_i18ngrep ! "Pulling without specifying how to reconcile" err + test_i18ngrep ! "You have divergent branches" err ' test_expect_success 'pull.rebase not set and pull.ff=only (not-fast-forward)' ' git reset --hard c2 && test_config pull.ff only && test_must_fail git pull . c1 2>err && - test_i18ngrep ! "Pulling without specifying how to reconcile" err + test_i18ngrep ! "You have divergent branches" err ' test_expect_success 'pull.rebase not set and --rebase given (not-fast-forward)' ' git reset --hard c2 && git pull --rebase . c1 2>err && - test_i18ngrep ! "Pulling without specifying how to reconcile" err + test_i18ngrep ! "You have divergent branches" err ' test_expect_success 'pull.rebase not set and --no-rebase given (not-fast-forward)' ' git reset --hard c2 && git pull --no-rebase . c1 2>err && - test_i18ngrep ! "Pulling without specifying how to reconcile" err + test_i18ngrep ! "You have divergent branches" err ' test_expect_success 'pull.rebase not set and --ff given (not-fast-forward)' ' git reset --hard c2 && git pull --ff . c1 2>err && - test_i18ngrep ! "Pulling without specifying how to reconcile" err + test_i18ngrep ! "You have divergent branches" err ' test_expect_success 'pull.rebase not set and --no-ff given (not-fast-forward)' ' git reset --hard c2 && git pull --no-ff . c1 2>err && - test_i18ngrep ! "Pulling without specifying how to reconcile" err + test_i18ngrep ! "You have divergent branches" err ' test_expect_success 'pull.rebase not set and --ff-only given (not-fast-forward)' ' git reset --hard c2 && test_must_fail git pull --ff-only . c1 2>err && - test_i18ngrep ! "Pulling without specifying how to reconcile" err + test_i18ngrep ! "You have divergent branches" err +' + +test_does_rebase () { + git reset --hard c2 && + git "$@" . c1 && + # Check that we actually did a rebase + git rev-list --count HEAD >actual && + git rev-list --merges --count HEAD >>actual && + test_write_lines 3 0 >expect && + test_cmp expect actual && + rm actual expect +} + +# Prefers merge over fast-forward +test_does_merge_when_ff_possible () { + git reset --hard c0 && + git "$@" . c1 && + # Check that we actually did a merge + git rev-list --count HEAD >actual && + git rev-list --merges --count HEAD >>actual && + test_write_lines 3 1 >expect && + test_cmp expect actual && + rm actual expect +} + +# Prefers fast-forward over merge or rebase +test_does_fast_forward () { + git reset --hard c0 && + git "$@" . c1 && + + # Check that we did not get any merges + git rev-list --count HEAD >actual && + git rev-list --merges --count HEAD >>actual && + test_write_lines 2 0 >expect && + test_cmp expect actual && + + # Check that we ended up at c1 + git rev-parse HEAD >actual && + git rev-parse c1^{commit} >expect && + test_cmp actual expect && + + # Remove temporary files + rm actual expect +} + +# Doesn't fail when fast-forward not possible; does a merge +test_falls_back_to_full_merge () { + git reset --hard c2 && + git "$@" . c1 && + # Check that we actually did a merge + git rev-list --count HEAD >actual && + git rev-list --merges --count HEAD >>actual && + test_write_lines 4 1 >expect && + test_cmp expect actual && + rm actual expect +} + +# Attempts fast forward, which is impossible, and bails +test_attempts_fast_forward () { + git reset --hard c2 && + test_must_fail git "$@" . c1 2>err && + test_i18ngrep "Not possible to fast-forward, aborting" err +} + +# +# Group 1: Interaction of --ff-only with --[no-]rebase +# (And related interaction of pull.ff=only with pull.rebase) +# +test_expect_success '--ff-only overrides --rebase' ' + test_attempts_fast_forward pull --rebase --ff-only +' + +test_expect_success '--ff-only overrides --rebase even if first' ' + test_attempts_fast_forward pull --ff-only --rebase +' + +test_expect_success '--ff-only overrides --no-rebase' ' + test_attempts_fast_forward pull --ff-only --no-rebase +' + +test_expect_success 'pull.ff=only overrides pull.rebase=true' ' + test_attempts_fast_forward -c pull.ff=only -c pull.rebase=true pull +' + +test_expect_success 'pull.ff=only overrides pull.rebase=false' ' + test_attempts_fast_forward -c pull.ff=only -c pull.rebase=false pull +' + +# Group 2: --rebase=[!false] overrides --no-ff and --ff +# (And related interaction of pull.rebase=!false and pull.ff=!only) +test_expect_success '--rebase overrides --no-ff' ' + test_does_rebase pull --rebase --no-ff +' + +test_expect_success '--rebase overrides --ff' ' + test_does_rebase pull --rebase --ff +' + +test_expect_success '--rebase fast-forwards when possible' ' + test_does_fast_forward pull --rebase --ff +' + +test_expect_success 'pull.rebase=true overrides pull.ff=false' ' + test_does_rebase -c pull.rebase=true -c pull.ff=false pull +' + +test_expect_success 'pull.rebase=true overrides pull.ff=true' ' + test_does_rebase -c pull.rebase=true -c pull.ff=true pull +' + +# Group 3: command line flags take precedence over config +test_expect_success '--ff-only takes precedence over pull.rebase=true' ' + test_attempts_fast_forward -c pull.rebase=true pull --ff-only +' + +test_expect_success '--ff-only takes precedence over pull.rebase=false' ' + test_attempts_fast_forward -c pull.rebase=false pull --ff-only +' + +test_expect_success '--no-rebase takes precedence over pull.ff=only' ' + test_falls_back_to_full_merge -c pull.ff=only pull --no-rebase +' + +test_expect_success '--rebase takes precedence over pull.ff=only' ' + test_does_rebase -c pull.ff=only pull --rebase +' + +test_expect_success '--rebase overrides pull.ff=true' ' + test_does_rebase -c pull.ff=true pull --rebase +' + +test_expect_success '--rebase overrides pull.ff=false' ' + test_does_rebase -c pull.ff=false pull --rebase +' + +test_expect_success '--rebase overrides pull.ff unset' ' + test_does_rebase pull --rebase +' + +# Group 4: --no-rebase heeds pull.ff=!only or explict --ff or --no-ff + +test_expect_success '--no-rebase works with --no-ff' ' + test_does_merge_when_ff_possible pull --no-rebase --no-ff +' + +test_expect_success '--no-rebase works with --ff' ' + test_does_fast_forward pull --no-rebase --ff +' + +test_expect_success '--no-rebase does ff if pull.ff unset' ' + test_does_fast_forward pull --no-rebase +' + +test_expect_success '--no-rebase heeds pull.ff=true' ' + test_does_fast_forward -c pull.ff=true pull --no-rebase +' + +test_expect_success '--no-rebase heeds pull.ff=false' ' + test_does_merge_when_ff_possible -c pull.ff=false pull --no-rebase +' + +# Group 5: pull.rebase=!false in combination with --no-ff or --ff +test_expect_success 'pull.rebase=true and --no-ff' ' + test_does_rebase -c pull.rebase=true pull --no-ff +' + +test_expect_success 'pull.rebase=true and --ff' ' + test_does_rebase -c pull.rebase=true pull --ff +' + +test_expect_success 'pull.rebase=false and --no-ff' ' + test_does_merge_when_ff_possible -c pull.rebase=false pull --no-ff +' + +test_expect_success 'pull.rebase=false and --ff, ff possible' ' + test_does_fast_forward -c pull.rebase=false pull --ff +' + +test_expect_success 'pull.rebase=false and --ff, ff not possible' ' + test_falls_back_to_full_merge -c pull.rebase=false pull --ff +' + +# End of groupings for conflicting merge vs. rebase flags/options + +test_expect_success 'Multiple heads warns about inability to fast forward' ' + git reset --hard c1 && + test_must_fail git pull . c2 c3 2>err && + test_i18ngrep "You have divergent branches" err +' + +test_expect_success 'Multiple can never be fast forwarded' ' + git reset --hard c0 && + test_must_fail git -c pull.ff=only pull . c1 c2 c3 2>err && + test_i18ngrep ! "You have divergent branches" err && + # In addition to calling out "cannot fast-forward", we very much + # want the "multiple branches" piece to be called out to users. + test_i18ngrep "Cannot fast-forward to multiple branches" err +' + +test_expect_success 'Cannot rebase with multiple heads' ' + git reset --hard c0 && + test_must_fail git -c pull.rebase=true pull . c1 c2 c3 2>err && + test_i18ngrep ! "You have divergent branches" err && + test_i18ngrep "Cannot rebase onto multiple branches." err ' test_expect_success 'merge c1 with c2' ' diff --git a/t/t7603-merge-reduce-heads.sh b/t/t7603-merge-reduce-heads.sh index 98948955ae..27cd94ad6f 100755 --- a/t/t7603-merge-reduce-heads.sh +++ b/t/t7603-merge-reduce-heads.sh @@ -68,7 +68,7 @@ test_expect_success 'merge c1 with c2, c3, c4, c5' ' test_expect_success 'pull c2, c3, c4, c5 into c1' ' git reset --hard c1 && - git pull . c2 c3 c4 c5 && + git pull --no-rebase . c2 c3 c4 c5 && test "$(git rev-parse c1)" != "$(git rev-parse HEAD)" && test "$(git rev-parse c1)" = "$(git rev-parse HEAD^1)" && test "$(git rev-parse c2)" = "$(git rev-parse HEAD^2)" && diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh index 25b235c063..0260ad6f0e 100755 --- a/t/t7700-repack.sh +++ b/t/t7700-repack.sh @@ -3,6 +3,8 @@ test_description='git repack works correctly' . ./test-lib.sh +. "${TEST_DIRECTORY}/lib-bitmap.sh" +. "${TEST_DIRECTORY}/lib-midx.sh" commit_and_pack () { test_commit "$@" 1>&2 && @@ -63,13 +65,14 @@ test_expect_success 'objects in packs marked .keep are not repacked' ' test_expect_success 'writing bitmaps via command-line can duplicate .keep objects' ' # build on $oid, $packid, and .keep state from previous - git repack -Adbl && + GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 git repack -Adbl && test_has_duplicate_object true ' test_expect_success 'writing bitmaps via config can duplicate .keep objects' ' # build on $oid, $packid, and .keep state from previous - git -c repack.writebitmaps=true repack -Adl && + GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \ + git -c repack.writebitmaps=true repack -Adl && test_has_duplicate_object true ' @@ -189,7 +192,9 @@ test_expect_success 'repack --keep-pack' ' test_expect_success 'bitmaps are created by default in bare repos' ' git clone --bare .git bare.git && - git -C bare.git repack -ad && + rm -f bare.git/objects/pack/*.bitmap && + GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \ + git -C bare.git repack -ad && bitmap=$(ls bare.git/objects/pack/*.bitmap) && test_path_is_file "$bitmap" ' @@ -200,7 +205,8 @@ test_expect_success 'incremental repack does not complain' ' ' test_expect_success 'bitmaps can be disabled on bare repos' ' - git -c repack.writeBitmaps=false -C bare.git repack -ad && + GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \ + git -c repack.writeBitmaps=false -C bare.git repack -ad && bitmap=$(ls bare.git/objects/pack/*.bitmap || :) && test -z "$bitmap" ' @@ -211,7 +217,8 @@ test_expect_success 'no bitmaps created if .keep files present' ' keep=${pack%.pack}.keep && test_when_finished "rm -f \"\$keep\"" && >"$keep" && - git -C bare.git repack -ad 2>stderr && + GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \ + git -C bare.git repack -ad 2>stderr && test_must_be_empty stderr && find bare.git/objects/pack/ -type f -name "*.bitmap" >actual && test_must_be_empty actual @@ -222,10 +229,147 @@ test_expect_success 'auto-bitmaps do not complain if unavailable' ' blob=$(test-tool genrandom big $((1024*1024)) | git -C bare.git hash-object -w --stdin) && git -C bare.git update-ref refs/tags/big $blob && - git -C bare.git repack -ad 2>stderr && + GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \ + git -C bare.git repack -ad 2>stderr && test_must_be_empty stderr && find bare.git/objects/pack -type f -name "*.bitmap" >actual && test_must_be_empty actual ' +objdir=.git/objects +midx=$objdir/pack/multi-pack-index + +test_expect_success 'setup for --write-midx tests' ' + git init midx && + ( + cd midx && + git config core.multiPackIndex true && + + test_commit base + ) +' + +test_expect_success '--write-midx unchanged' ' + ( + cd midx && + GIT_TEST_MULTI_PACK_INDEX=0 git repack && + test_path_is_missing $midx && + test_path_is_missing $midx-*.bitmap && + + GIT_TEST_MULTI_PACK_INDEX=0 git repack --write-midx && + + test_path_is_file $midx && + test_path_is_missing $midx-*.bitmap && + test_midx_consistent $objdir + ) +' + +test_expect_success '--write-midx with a new pack' ' + ( + cd midx && + test_commit loose && + + GIT_TEST_MULTI_PACK_INDEX=0 git repack --write-midx && + + test_path_is_file $midx && + test_path_is_missing $midx-*.bitmap && + test_midx_consistent $objdir + ) +' + +test_expect_success '--write-midx with -b' ' + ( + cd midx && + GIT_TEST_MULTI_PACK_INDEX=0 git repack -mb && + + test_path_is_file $midx && + test_path_is_file $midx-*.bitmap && + test_midx_consistent $objdir + ) +' + +test_expect_success '--write-midx with -d' ' + ( + cd midx && + test_commit repack && + + GIT_TEST_MULTI_PACK_INDEX=0 git repack -Ad --write-midx && + + test_path_is_file $midx && + test_path_is_missing $midx-*.bitmap && + test_midx_consistent $objdir + ) +' + +test_expect_success 'cleans up MIDX when appropriate' ' + ( + cd midx && + + test_commit repack-2 && + GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adb --write-midx && + + checksum=$(midx_checksum $objdir) && + test_path_is_file $midx && + test_path_is_file $midx-$checksum.bitmap && + test_path_is_file $midx-$checksum.rev && + + test_commit repack-3 && + GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adb --write-midx && + + test_path_is_file $midx && + test_path_is_missing $midx-$checksum.bitmap && + test_path_is_missing $midx-$checksum.rev && + test_path_is_file $midx-$(midx_checksum $objdir).bitmap && + test_path_is_file $midx-$(midx_checksum $objdir).rev && + + test_commit repack-4 && + GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adb && + + find $objdir/pack -type f -name "multi-pack-index*" >files && + test_must_be_empty files + ) +' + +test_expect_success '--write-midx with preferred bitmap tips' ' + git init midx-preferred-tips && + test_when_finished "rm -fr midx-preferred-tips" && + ( + cd midx-preferred-tips && + + test_commit_bulk --message="%s" 103 && + + git log --format="%H" >commits.raw && + sort <commits.raw >commits && + + git log --format="create refs/tags/%s/%s %H" HEAD >refs && + git update-ref --stdin <refs && + + git repack --write-midx --write-bitmap-index && + test_path_is_file $midx && + test_path_is_file $midx-$(midx_checksum $objdir).bitmap && + + test-tool bitmap list-commits | sort >bitmaps && + comm -13 bitmaps commits >before && + test_line_count = 1 before && + + rm -fr $midx-$(midx_checksum $objdir).bitmap && + rm -fr $midx-$(midx_checksum $objdir).rev && + rm -fr $midx && + + # instead of constructing the snapshot ourselves (c.f., the test + # "write a bitmap with --refs-snapshot (preferred tips)" in + # t5326), mark the missing commit as preferred by adding it to + # the pack.preferBitmapTips configuration. + git for-each-ref --format="%(refname:rstrip=1)" \ + --points-at="$(cat before)" >missing && + git config pack.preferBitmapTips "$(cat missing)" && + git repack --write-midx --write-bitmap-index && + + test-tool bitmap list-commits | sort >bitmaps && + comm -13 bitmaps commits >after && + + ! test_cmp before after + ) +' + test_done diff --git a/t/t7703-repack-geometric.sh b/t/t7703-repack-geometric.sh index 5ccaa440e0..bdbbcbf1ec 100755 --- a/t/t7703-repack-geometric.sh +++ b/t/t7703-repack-geometric.sh @@ -15,7 +15,7 @@ test_expect_success '--geometric with no packs' ' ( cd geometric && - git repack --geometric 2 >out && + git repack --write-midx --geometric 2 >out && test_i18ngrep "Nothing new to pack" out ) ' @@ -180,4 +180,26 @@ test_expect_success '--geometric ignores kept packs' ' ) ' +test_expect_success '--geometric chooses largest MIDX preferred pack' ' + git init geometric && + test_when_finished "rm -fr geometric" && + ( + cd geometric && + + # These packs already form a geometric progression. + test_commit_bulk --start=1 1 && # 3 objects + test_commit_bulk --start=2 2 && # 6 objects + ls $objdir/pack/pack-*.idx >before && + test_commit_bulk --start=4 4 && # 12 objects + ls $objdir/pack/pack-*.idx >after && + + git repack --geometric 2 -dbm && + + comm -3 before after | xargs -n 1 basename >expect && + test-tool read-midx --preferred-pack $objdir >actual && + + test_cmp expect actual + ) +' + test_done diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh index a173f564bc..096456292c 100755 --- a/t/t7800-difftool.sh +++ b/t/t7800-difftool.sh @@ -453,6 +453,13 @@ run_dir_diff_test 'difftool --dir-diff' ' grep "^file$" output ' +run_dir_diff_test 'difftool --dir-diff avoids repeated slashes in TMPDIR' ' + TMPDIR="${TMPDIR:-/tmp}////" \ + git difftool --dir-diff $symlinks --extcmd echo branch >output && + grep -v // output >actual && + test_line_count = 1 actual +' + run_dir_diff_test 'difftool --dir-diff ignores --prompt' ' git difftool --dir-diff $symlinks --prompt --extcmd ls branch >output && grep "^sub$" output && @@ -674,7 +681,6 @@ test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' ' rm c && ln -s d c && cat >expect <<-EOF && - b c c @@ -710,7 +716,6 @@ test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' ' # Deleted symlinks rm -f c && cat >expect <<-EOF && - b c EOF @@ -723,6 +728,71 @@ test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' ' test_cmp expect actual ' +test_expect_success SYMLINKS 'difftool --dir-diff writes symlinks as raw text' ' + # Start out on a branch called "branch-init". + git init -b branch-init symlink-files && + ( + cd symlink-files && + # This test ensures that symlinks are written as raw text. + # The "cat" tools output link and file contents. + git config difftool.cat-left-link.cmd "cat \"\$LOCAL/link\"" && + git config difftool.cat-left-a.cmd "cat \"\$LOCAL/file-a\"" && + git config difftool.cat-right-link.cmd "cat \"\$REMOTE/link\"" && + git config difftool.cat-right-b.cmd "cat \"\$REMOTE/file-b\"" && + + # Record the empty initial state so that we can come back here + # later and not have to consider the any cases where difftool + # will create symlinks back into the worktree. + test_tick && + git commit --allow-empty -m init && + + # Create a file called "file-a" with a symlink pointing to it. + git switch -c branch-a && + echo a >file-a && + ln -s file-a link && + git add file-a link && + test_tick && + git commit -m link-to-file-a && + + # Create a file called "file-b" and point the symlink to it. + git switch -c branch-b && + echo b >file-b && + rm link && + ln -s file-b link && + git add file-b link && + git rm file-a && + test_tick && + git commit -m link-to-file-b && + + # Checkout the initial branch so that the --symlinks behavior is + # not activated. The two directories should be completely + # independent with no symlinks pointing back here. + git switch branch-init && + + # The left link must be "file-a" and "file-a" must contain "a". + echo file-a >expect && + git difftool --symlinks --dir-diff --tool cat-left-link \ + branch-a branch-b >actual && + test_cmp expect actual && + + echo a >expect && + git difftool --symlinks --dir-diff --tool cat-left-a \ + branch-a branch-b >actual && + test_cmp expect actual && + + # The right link must be "file-b" and "file-b" must contain "b". + echo file-b >expect && + git difftool --symlinks --dir-diff --tool cat-right-link \ + branch-a branch-b >actual && + test_cmp expect actual && + + echo b >expect && + git difftool --symlinks --dir-diff --tool cat-right-b \ + branch-a branch-b >actual && + test_cmp expect actual + ) +' + test_expect_success 'add -N and difftool -d' ' test_when_finished git reset --hard && diff --git a/t/t7814-grep-recurse-submodules.sh b/t/t7814-grep-recurse-submodules.sh index 828cb3ba58..058e5d0c96 100755 --- a/t/t7814-grep-recurse-submodules.sh +++ b/t/t7814-grep-recurse-submodules.sh @@ -8,6 +8,9 @@ submodules. . ./test-lib.sh +GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=1 +export GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB + test_expect_success 'setup directory structure and submodule' ' echo "(1|2)d(3|4)" >a && mkdir b && @@ -438,4 +441,107 @@ test_expect_success 'grep --recurse-submodules with --cached ignores worktree mo test_must_fail git grep --recurse-submodules --cached "A modified line in submodule" >actual 2>&1 && test_must_be_empty actual ' + +test_expect_failure 'grep --textconv: superproject .gitattributes does not affect submodules' ' + reset_and_clean && + test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" && + echo "a diff=d2x" >.gitattributes && + + cat >expect <<-\EOF && + a:(1|2)x(3|4) + EOF + git grep --textconv --recurse-submodules x >actual && + test_cmp expect actual +' + +test_expect_failure 'grep --textconv: superproject .gitattributes (from index) does not affect submodules' ' + reset_and_clean && + test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" && + echo "a diff=d2x" >.gitattributes && + git add .gitattributes && + rm .gitattributes && + + cat >expect <<-\EOF && + a:(1|2)x(3|4) + EOF + git grep --textconv --recurse-submodules x >actual && + test_cmp expect actual +' + +test_expect_failure 'grep --textconv: superproject .git/info/attributes does not affect submodules' ' + reset_and_clean && + test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" && + super_attr="$(git rev-parse --git-path info/attributes)" && + test_when_finished "rm -f \"$super_attr\"" && + echo "a diff=d2x" >"$super_attr" && + + cat >expect <<-\EOF && + a:(1|2)x(3|4) + EOF + git grep --textconv --recurse-submodules x >actual && + test_cmp expect actual +' + +# Note: what currently prevents this test from passing is not that the +# .gitattributes file from "./submodule" is being ignored, but that it is being +# propagated to the nested "./submodule/sub" files. +# +test_expect_failure 'grep --textconv correctly reads submodule .gitattributes' ' + reset_and_clean && + test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" && + echo "a diff=d2x" >submodule/.gitattributes && + + cat >expect <<-\EOF && + submodule/a:(1|2)x(3|4) + EOF + git grep --textconv --recurse-submodules x >actual && + test_cmp expect actual +' + +test_expect_failure 'grep --textconv correctly reads submodule .gitattributes (from index)' ' + reset_and_clean && + test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" && + echo "a diff=d2x" >submodule/.gitattributes && + git -C submodule add .gitattributes && + rm submodule/.gitattributes && + + cat >expect <<-\EOF && + submodule/a:(1|2)x(3|4) + EOF + git grep --textconv --recurse-submodules x >actual && + test_cmp expect actual +' + +test_expect_failure 'grep --textconv correctly reads submodule .git/info/attributes' ' + reset_and_clean && + test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" && + + submodule_attr="$(git -C submodule rev-parse --path-format=absolute --git-path info/attributes)" && + test_when_finished "rm -f \"$submodule_attr\"" && + echo "a diff=d2x" >"$submodule_attr" && + + cat >expect <<-\EOF && + submodule/a:(1|2)x(3|4) + EOF + git grep --textconv --recurse-submodules x >actual && + test_cmp expect actual +' + +test_expect_failure 'grep saves textconv cache in the appropriate repository' ' + reset_and_clean && + test_config_global diff.d2x_cached.textconv "sed -e \"s/d/x/\"" && + test_config_global diff.d2x_cached.cachetextconv true && + echo "a diff=d2x_cached" >submodule/.gitattributes && + + # We only read/write to the textconv cache when grepping from an OID, + # as the working tree file might have modifications. + git grep --textconv --cached --recurse-submodules x && + + super_textconv_cache="$(git rev-parse --git-path refs/notes/textconv/d2x_cached)" && + sub_textconv_cache="$(git -C submodule rev-parse \ + --path-format=absolute --git-path refs/notes/textconv/d2x_cached)" && + test_path_is_missing "$super_textconv_cache" && + test_path_is_file "$sub_textconv_cache" +' + test_done diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh index 58f46c77e6..9b9f11a8e7 100755 --- a/t/t7900-maintenance.sh +++ b/t/t7900-maintenance.sh @@ -20,6 +20,17 @@ test_xmllint () { fi } +test_lazy_prereq SYSTEMD_ANALYZE ' + systemd-analyze verify /lib/systemd/system/basic.target +' + +test_systemd_analyze_verify () { + if test_have_prereq SYSTEMD_ANALYZE + then + systemd-analyze verify "$@" + fi +} + test_expect_success 'help text' ' test_expect_code 129 git maintenance -h 2>err && test_i18ngrep "usage: git maintenance <subcommand>" err && @@ -265,7 +276,7 @@ test_expect_success 'incremental-repack task' ' # Delete refs that have not been repacked in these packs. git for-each-ref --format="delete %(refname)" \ - refs/prefetch refs/tags >refs && + refs/prefetch refs/tags refs/remotes >refs && git update-ref --stdin <refs && # Replace the object directory with this pack layout. @@ -274,6 +285,10 @@ test_expect_success 'incremental-repack task' ' ls $packDir/*.pack >packs-before && test_line_count = 3 packs-before && + # make sure we do not have any broken refs that were + # missed in the deletion above + git for-each-ref && + # the job repacks the two into a new pack, but does not # delete the old ones. git maintenance run --task=incremental-repack && @@ -492,8 +507,21 @@ test_expect_success !MINGW 'register and unregister with regex metacharacters' ' maintenance.repo "$(pwd)/$META" ' +test_expect_success 'start --scheduler=<scheduler>' ' + test_expect_code 129 git maintenance start --scheduler=foo 2>err && + test_i18ngrep "unrecognized --scheduler argument" err && + + test_expect_code 129 git maintenance start --no-scheduler 2>err && + test_i18ngrep "unknown option" err && + + test_expect_code 128 \ + env GIT_TEST_MAINT_SCHEDULER="launchctl:true,schtasks:true" \ + git maintenance start --scheduler=crontab 2>err && + test_i18ngrep "fatal: crontab scheduler is not available" err +' + test_expect_success 'start from empty cron table' ' - GIT_TEST_MAINT_SCHEDULER="crontab:test-tool crontab cron.txt" git maintenance start && + GIT_TEST_MAINT_SCHEDULER="crontab:test-tool crontab cron.txt" git maintenance start --scheduler=crontab && # start registers the repo git config --get --global --fixed-value maintenance.repo "$(pwd)" && @@ -516,7 +544,7 @@ test_expect_success 'stop from existing schedule' ' test_expect_success 'start preserves existing schedule' ' echo "Important information!" >cron.txt && - GIT_TEST_MAINT_SCHEDULER="crontab:test-tool crontab cron.txt" git maintenance start && + GIT_TEST_MAINT_SCHEDULER="crontab:test-tool crontab cron.txt" git maintenance start --scheduler=crontab && grep "Important information!" cron.txt ' @@ -545,7 +573,7 @@ test_expect_success 'start and stop macOS maintenance' ' EOF rm -f args && - GIT_TEST_MAINT_SCHEDULER=launchctl:./print-args git maintenance start && + GIT_TEST_MAINT_SCHEDULER=launchctl:./print-args git maintenance start --scheduler=launchctl && # start registers the repo git config --get --global --fixed-value maintenance.repo "$(pwd)" && @@ -582,6 +610,23 @@ test_expect_success 'start and stop macOS maintenance' ' test_line_count = 0 actual ' +test_expect_success 'use launchctl list to prevent extra work' ' + # ensure we are registered + GIT_TEST_MAINT_SCHEDULER=launchctl:./print-args git maintenance start --scheduler=launchctl && + + # do it again on a fresh args file + rm -f args && + GIT_TEST_MAINT_SCHEDULER=launchctl:./print-args git maintenance start --scheduler=launchctl && + + ls "$HOME/Library/LaunchAgents" >actual && + cat >expect <<-\EOF && + list org.git-scm.git.hourly + list org.git-scm.git.daily + list org.git-scm.git.weekly + EOF + test_cmp expect args +' + test_expect_success 'start and stop Windows maintenance' ' write_script print-args <<-\EOF && echo $* >>args @@ -596,7 +641,7 @@ test_expect_success 'start and stop Windows maintenance' ' EOF rm -f args && - GIT_TEST_MAINT_SCHEDULER="schtasks:./print-args" git maintenance start && + GIT_TEST_MAINT_SCHEDULER="schtasks:./print-args" git maintenance start --scheduler=schtasks && # start registers the repo git config --get --global --fixed-value maintenance.repo "$(pwd)" && @@ -619,6 +664,83 @@ test_expect_success 'start and stop Windows maintenance' ' test_cmp expect args ' +test_expect_success 'start and stop Linux/systemd maintenance' ' + write_script print-args <<-\EOF && + printf "%s\n" "$*" >>args + EOF + + XDG_CONFIG_HOME="$PWD" && + export XDG_CONFIG_HOME && + rm -f args && + GIT_TEST_MAINT_SCHEDULER="systemctl:./print-args" git maintenance start --scheduler=systemd-timer && + + # start registers the repo + git config --get --global --fixed-value maintenance.repo "$(pwd)" && + + test_systemd_analyze_verify "systemd/user/git-maintenance@.service" && + + printf -- "--user enable --now git-maintenance@%s.timer\n" hourly daily weekly >expect && + test_cmp expect args && + + rm -f args && + GIT_TEST_MAINT_SCHEDULER="systemctl:./print-args" git maintenance stop && + + # stop does not unregister the repo + git config --get --global --fixed-value maintenance.repo "$(pwd)" && + + test_path_is_missing "systemd/user/git-maintenance@.timer" && + test_path_is_missing "systemd/user/git-maintenance@.service" && + + printf -- "--user disable --now git-maintenance@%s.timer\n" hourly daily weekly >expect && + test_cmp expect args +' + +test_expect_success 'start and stop when several schedulers are available' ' + write_script print-args <<-\EOF && + printf "%s\n" "$*" | sed "s:gui/[0-9][0-9]*:gui/[UID]:; s:\(schtasks /create .* /xml\).*:\1:;" >>args + EOF + + rm -f args && + GIT_TEST_MAINT_SCHEDULER="systemctl:./print-args systemctl,launchctl:./print-args launchctl,schtasks:./print-args schtasks" git maintenance start --scheduler=systemd-timer && + printf "launchctl bootout gui/[UID] $pfx/Library/LaunchAgents/org.git-scm.git.%s.plist\n" \ + hourly daily weekly >expect && + printf "schtasks /delete /tn Git Maintenance (%s) /f\n" \ + hourly daily weekly >>expect && + printf -- "systemctl --user enable --now git-maintenance@%s.timer\n" hourly daily weekly >>expect && + test_cmp expect args && + + rm -f args && + GIT_TEST_MAINT_SCHEDULER="systemctl:./print-args systemctl,launchctl:./print-args launchctl,schtasks:./print-args schtasks" git maintenance start --scheduler=launchctl && + printf -- "systemctl --user disable --now git-maintenance@%s.timer\n" hourly daily weekly >expect && + printf "schtasks /delete /tn Git Maintenance (%s) /f\n" \ + hourly daily weekly >>expect && + for frequency in hourly daily weekly + do + PLIST="$pfx/Library/LaunchAgents/org.git-scm.git.$frequency.plist" && + echo "launchctl bootout gui/[UID] $PLIST" >>expect && + echo "launchctl bootstrap gui/[UID] $PLIST" >>expect || return 1 + done && + test_cmp expect args && + + rm -f args && + GIT_TEST_MAINT_SCHEDULER="systemctl:./print-args systemctl,launchctl:./print-args launchctl,schtasks:./print-args schtasks" git maintenance start --scheduler=schtasks && + printf -- "systemctl --user disable --now git-maintenance@%s.timer\n" hourly daily weekly >expect && + printf "launchctl bootout gui/[UID] $pfx/Library/LaunchAgents/org.git-scm.git.%s.plist\n" \ + hourly daily weekly >>expect && + printf "schtasks /create /tn Git Maintenance (%s) /f /xml\n" \ + hourly daily weekly >>expect && + test_cmp expect args && + + rm -f args && + GIT_TEST_MAINT_SCHEDULER="systemctl:./print-args systemctl,launchctl:./print-args launchctl,schtasks:./print-args schtasks" git maintenance stop && + printf -- "systemctl --user disable --now git-maintenance@%s.timer\n" hourly daily weekly >expect && + printf "launchctl bootout gui/[UID] $pfx/Library/LaunchAgents/org.git-scm.git.%s.plist\n" \ + hourly daily weekly >>expect && + printf "schtasks /delete /tn Git Maintenance (%s) /f\n" \ + hourly daily weekly >>expect && + test_cmp expect args +' + test_expect_success 'register preserves existing strategy' ' git config maintenance.strategy none && git maintenance register && diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 57fc10e7f8..aa0c20499b 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -1533,6 +1533,21 @@ test_expect_success $PREREQ 'sendemail.8bitEncoding works' ' test_cmp content-type-decl actual ' +test_expect_success $PREREQ 'sendemail.8bitEncoding in .git/config overrides --global .gitconfig' ' + clean_fake_sendmail && + git config sendemail.assume8bitEncoding UTF-8 && + test_when_finished "rm -rf home" && + mkdir home && + git config -f home/.gitconfig sendemail.assume8bitEncoding "bogus too" && + echo bogus | + env HOME="$(pwd)/home" DEBUG=1 \ + git send-email --from=author@example.com --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + email-using-8bit >stdout && + egrep "Content|MIME" msgtxt1 >actual && + test_cmp content-type-decl actual +' + test_expect_success $PREREQ '--8bit-encoding overrides sendemail.8bitEncoding' ' clean_fake_sendmail && git config sendemail.assume8bitEncoding "bogus too" && @@ -2198,7 +2213,7 @@ test_expect_success $PREREQ 'leading and trailing whitespaces are removed' ' test_expect_success $PREREQ 'test using command name with --sendmail-cmd' ' clean_fake_sendmail && - PATH="$(pwd):$PATH" \ + PATH="$PWD:$PATH" \ git send-email \ --from="Example <nobody@example.com>" \ --to=nobody@example.com \ @@ -2227,6 +2242,51 @@ test_expect_success $PREREQ 'test shell expression with --sendmail-cmd' ' test_path_is_file commandline1 ' +test_expect_success $PREREQ 'set up in-reply-to/references patches' ' + cat >has-reply.patch <<-\EOF && + From: A U Thor <author@example.com> + Subject: patch with in-reply-to + Message-ID: <patch.with.in.reply.to@example.com> + In-Reply-To: <replied.to@example.com> + References: <replied.to@example.com> + + This is the body. + EOF + cat >no-reply.patch <<-\EOF + From: A U Thor <author@example.com> + Subject: patch without in-reply-to + Message-ID: <patch.without.in.reply.to@example.com> + + This is the body. + EOF +' + +test_expect_success $PREREQ 'patch reply headers correct with --no-thread' ' + clean_fake_sendmail && + git send-email \ + --no-thread \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + has-reply.patch no-reply.patch && + grep "In-Reply-To: <replied.to@example.com>" msgtxt1 && + grep "References: <replied.to@example.com>" msgtxt1 && + ! grep replied.to@example.com msgtxt2 +' + +test_expect_success $PREREQ 'cmdline in-reply-to used with --no-thread' ' + clean_fake_sendmail && + git send-email \ + --no-thread \ + --in-reply-to="<cmdline.reply@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + has-reply.patch no-reply.patch && + grep "In-Reply-To: <cmdline.reply@example.com>" msgtxt1 && + grep "References: <cmdline.reply@example.com>" msgtxt1 && + grep "In-Reply-To: <cmdline.reply@example.com>" msgtxt2 && + grep "References: <cmdline.reply@example.com>" msgtxt2 +' + test_expect_success $PREREQ 'invoke hook' ' mkdir -p .git/hooks && diff --git a/t/t9002-column.sh b/t/t9002-column.sh index 89983527b6..6d3dbde3fe 100755 --- a/t/t9002-column.sh +++ b/t/t9002-column.sh @@ -42,6 +42,24 @@ EOF test_cmp expected actual ' +test_expect_success '--nl' ' + cat >expected <<\EOF && +oneZ +twoZ +threeZ +fourZ +fiveZ +sixZ +sevenZ +eightZ +nineZ +tenZ +elevenZ +EOF + git column --nl="Z$LF" --mode=plain <lista >actual && + test_cmp expected actual +' + test_expect_success '80 columns' ' cat >expected <<\EOF && one two three four five six seven eight nine ten eleven diff --git a/t/t9351-fast-export-anonymize.sh b/t/t9351-fast-export-anonymize.sh index 1c6e6fcdaf..77047e250d 100755 --- a/t/t9351-fast-export-anonymize.sh +++ b/t/t9351-fast-export-anonymize.sh @@ -18,7 +18,8 @@ test_expect_success 'setup simple repo' ' git update-index --add --cacheinfo 160000,$fake_commit,link1 && git update-index --add --cacheinfo 160000,$fake_commit,link2 && git commit -m "add gitlink" && - git tag -m "annotated tag" mytag + git tag -m "annotated tag" mytag && + git tag -m "annotated tag with long message" longtag ' test_expect_success 'export anonymized stream' ' @@ -55,7 +56,8 @@ test_expect_success 'stream retains other as refname' ' test_expect_success 'stream omits other refnames' ' ! grep main stream && - ! grep mytag stream + ! grep mytag stream && + ! grep longtag stream ' test_expect_success 'stream omits identities' ' @@ -118,9 +120,9 @@ test_expect_success 'identical gitlinks got identical oid' ' test_line_count = 1 commits ' -test_expect_success 'tag points to branch tip' ' +test_expect_success 'all tags point to branch tip' ' git rev-parse $other_branch >expect && - git for-each-ref --format="%(*objectname)" | grep . >actual && + git for-each-ref --format="%(*objectname)" | grep . | uniq >actual && test_cmp expect actual ' diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh index 2d29d486ee..17f988edd2 100755 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@ -36,6 +36,13 @@ CVSWORK="$PWD/cvswork" CVS_SERVER=git-cvsserver export CVSROOT CVS_SERVER +if perl -e 'exit(1) if not defined crypt("", "cv")' +then + PWDHASH='lac2ItudM3.KM' +else + PWDHASH='$2b$10$t8fGvE/a9eLmfOLzsZme2uOa2QtoMYwIxq9wZA6aBKtF1Yb7FJIzi' +fi + rm -rf "$CVSWORK" "$SERVERDIR" test_expect_success 'setup' ' git config push.default matching && @@ -54,7 +61,7 @@ test_expect_success 'setup' ' GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true && GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log" && GIT_DIR="$SERVERDIR" git config gitcvs.authdb "$SERVERDIR/auth.db" && - echo cvsuser:cvGVEarMLnhlA > "$SERVERDIR/auth.db" + echo "cvsuser:$PWDHASH" >"$SERVERDIR/auth.db" ' # note that cvs doesn't accept absolute pathnames diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 11573936d5..5decc3b269 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -540,6 +540,15 @@ test_expect_success '__gitcomp - expand/narrow all negative options' ' EOF ' +test_expect_success '__gitcomp - equal skip' ' + test_gitcomp "--option=" "--option=" <<-\EOF && + + EOF + test_gitcomp "option=" "option=" <<-\EOF + + EOF +' + test_expect_success '__gitcomp - doesnt fail because of invalid variable name' ' __gitcomp "$invalid_variable_name" ' @@ -2380,6 +2389,12 @@ test_expect_success 'git clone --config= - value' ' EOF ' +test_expect_success 'options with value' ' + test_completion "git merge -X diff-algorithm=" <<-\EOF + + EOF +' + test_expect_success 'sourcing the completion script clears cached commands' ' __git_compute_all_commands && verbose test -n "$__git_all_commands" && diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index e28411bb75..eef2262a36 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -137,33 +137,110 @@ test_tick () { # Stop execution and start a shell. This is useful for debugging tests. # # Be sure to remove all invocations of this command before submitting. +# WARNING: the shell invoked by this helper does not have the same environment +# as the one running the tests (shell variables and functions are not +# available, and the options below further modify the environment). As such, +# commands copied from a test script might behave differently than when +# running the test. +# +# Usage: test_pause [options] +# -t +# Use your original TERM instead of test-lib.sh's "dumb". +# This usually restores color output in the invoked shell. +# -s +# Invoke $SHELL instead of $TEST_SHELL_PATH. +# -h +# Use your original HOME instead of test-lib.sh's "$TRASH_DIRECTORY". +# This allows you to use your regular shell environment and Git aliases. +# CAUTION: running commands copied from a test script into the paused shell +# might result in files in your HOME being overwritten. +# -a +# Shortcut for -t -s -h test_pause () { - "$SHELL_PATH" <&6 >&5 2>&7 + PAUSE_TERM=$TERM && + PAUSE_SHELL=$TEST_SHELL_PATH && + PAUSE_HOME=$HOME && + while test $# != 0 + do + case "$1" in + -t) + PAUSE_TERM="$USER_TERM" + ;; + -s) + PAUSE_SHELL="$SHELL" + ;; + -h) + PAUSE_HOME="$USER_HOME" + ;; + -a) + PAUSE_TERM="$USER_TERM" + PAUSE_SHELL="$SHELL" + PAUSE_HOME="$USER_HOME" + ;; + *) + break + ;; + esac + shift + done && + TERM="$PAUSE_TERM" HOME="$PAUSE_HOME" "$PAUSE_SHELL" <&6 >&5 2>&7 } # Wrap git with a debugger. Adding this to a command can make it easier # to understand what is going on in a failing test. # +# Usage: debug [options] <git command> +# -d <debugger> +# --debugger=<debugger> +# Use <debugger> instead of GDB +# -t +# Use your original TERM instead of test-lib.sh's "dumb". +# This usually restores color output in the debugger. +# WARNING: the command being debugged might behave differently than when +# running the test. +# # Examples: # debug git checkout master # debug --debugger=nemiver git $ARGS # debug -d "valgrind --tool=memcheck --track-origins=yes" git $ARGS debug () { - case "$1" in - -d) - GIT_DEBUGGER="$2" && - shift 2 - ;; - --debugger=*) - GIT_DEBUGGER="${1#*=}" && - shift 1 - ;; - *) - GIT_DEBUGGER=1 - ;; - esac && - GIT_DEBUGGER="${GIT_DEBUGGER}" "$@" <&6 >&5 2>&7 + GIT_DEBUGGER=1 && + DEBUG_TERM=$TERM && + while test $# != 0 + do + case "$1" in + -t) + DEBUG_TERM="$USER_TERM" + ;; + -d) + GIT_DEBUGGER="$2" && + shift + ;; + --debugger=*) + GIT_DEBUGGER="${1#*=}" + ;; + *) + break + ;; + esac + shift + done && + + dotfiles=".gdbinit .lldbinit" + + for dotfile in $dotfiles + do + dotfile="$USER_HOME/$dotfile" && + test -f "$dotfile" && cp "$dotfile" "$HOME" || : + done && + + TERM="$DEBUG_TERM" GIT_DEBUGGER="${GIT_DEBUGGER}" "$@" <&6 >&5 2>&7 && + + for dotfile in $dotfiles + do + rm -f "$HOME/$dotfile" + done } # Usage: test_commit [options] <message> [<file> [<contents> [<tag>]]] diff --git a/t/test-lib.sh b/t/test-lib.sh index abcfbed6d6..151da80c56 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -534,7 +534,7 @@ SQ=\' # when case-folding filenames u200c=$(printf '\342\200\214') -export _x05 _x35 _x40 _z40 LF u200c EMPTY_TREE EMPTY_BLOB ZERO_OID OID_REGEX +export _x05 _x35 LF u200c EMPTY_TREE EMPTY_BLOB ZERO_OID OID_REGEX # Each test should start with something like this, after copyright notices: # @@ -585,8 +585,9 @@ else } fi +USER_TERM="$TERM" TERM=dumb -export TERM +export TERM USER_TERM error () { say_color error "error: $*" @@ -1343,7 +1344,8 @@ fi GIT_TEMPLATE_DIR="$GIT_BUILD_DIR"/templates/blt GIT_CONFIG_NOSYSTEM=1 GIT_ATTR_NOSYSTEM=1 -export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_ATTR_NOSYSTEM +GIT_CEILING_DIRECTORIES="$TRASH_DIRECTORY/.." +export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_ATTR_NOSYSTEM GIT_CEILING_DIRECTORIES if test -z "$GIT_TEST_CMP" then @@ -1379,10 +1381,31 @@ then test_done fi +# skip non-whitelisted tests when compiled with SANITIZE=leak +if test -n "$SANITIZE_LEAK" +then + if test_bool_env GIT_TEST_PASSING_SANITIZE_LEAK false + then + # We need to see it in "git env--helper" (via + # test_bool_env) + export TEST_PASSES_SANITIZE_LEAK + + if ! test_bool_env TEST_PASSES_SANITIZE_LEAK false + then + skip_all="skipping $this_test under GIT_TEST_PASSING_SANITIZE_LEAK=true" + test_done + fi + fi +elif test_bool_env GIT_TEST_PASSING_SANITIZE_LEAK false +then + error "GIT_TEST_PASSING_SANITIZE_LEAK=true has no effect except when compiled with SANITIZE=leak" +fi + # Last-minute variable setup +USER_HOME="$HOME" HOME="$TRASH_DIRECTORY" GNUPGHOME="$HOME/gnupg-home-not-used" -export HOME GNUPGHOME +export HOME GNUPGHOME USER_HOME # Test repository rm -fr "$TRASH_DIRECTORY" || { @@ -1422,10 +1445,9 @@ then fi # Convenience -# A regexp to match 5, 35 and 40 hexdigits +# A regexp to match 5 and 35 hexdigits _x05='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' _x35="$_x05$_x05$_x05$_x05$_x05$_x05$_x05" -_x40="$_x35$_x05" test_oid_init @@ -1434,7 +1456,6 @@ OID_REGEX=$(echo $ZERO_OID | sed -e 's/0/[0-9a-f]/g') OIDPATH_REGEX=$(test_oid_to_path $ZERO_OID | sed -e 's/0/[0-9a-f]/g') EMPTY_TREE=$(test_oid empty_tree) EMPTY_BLOB=$(test_oid empty_blob) -_z40=$ZERO_OID # Provide an implementation of the 'yes' utility; the upper bound # limit is there to help Windows that cannot stop this loop from @@ -1533,6 +1554,7 @@ test -z "$NO_PYTHON" && test_set_prereq PYTHON test -n "$USE_LIBPCRE2" && test_set_prereq PCRE test -n "$USE_LIBPCRE2" && test_set_prereq LIBPCRE2 test -z "$NO_GETTEXT" && test_set_prereq GETTEXT +test -n "$SANITIZE_LEAK" && test_set_prereq SANITIZE_LEAK if test -z "$GIT_TEST_CHECK_CACHE_TREE" then @@ -1708,10 +1730,6 @@ test_lazy_prereq SHA1 ' esac ' -test_lazy_prereq REBASE_P ' - test -z "$GIT_TEST_SKIP_REBASE_P" -' - # Ensure that no test accidentally triggers a Git command # that runs the actual maintenance scheduler, affecting a user's # system permanently. |