diff options
Diffstat (limited to 't')
166 files changed, 6081 insertions, 968 deletions
diff --git a/t/Makefile b/t/Makefile index 18e2b28b26..d613935f14 100644 --- a/t/Makefile +++ b/t/Makefile @@ -52,7 +52,8 @@ clean-except-prove-cache: clean: clean-except-prove-cache $(RM) .prove -test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax +test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax \ + test-lint-filenames test-lint-duplicates: @dups=`echo $(T) | tr ' ' '\n' | sed 's/-.*//' | sort | uniq -d` && \ @@ -67,6 +68,14 @@ test-lint-executable: test-lint-shell-syntax: @'$(PERL_PATH_SQ)' check-non-portable-shell.pl $(T) $(THELPERS) +test-lint-filenames: + @# We do *not* pass a glob to ls-files but use grep instead, to catch + @# non-ASCII characters (which are quoted within double-quotes) + @bad="$$(git -c core.quotepath=true ls-files 2>/dev/null | \ + grep '["*:<>?\\|]')"; \ + test -z "$$bad" || { \ + echo >&2 "non-portable file name(s): $$bad"; exit 1; } + aggregate-results-and-cleanup: $(T) $(MAKE) aggregate-results $(MAKE) clean diff --git a/t/helper/.gitignore b/t/helper/.gitignore new file mode 100644 index 0000000000..d6e8b36798 --- /dev/null +++ b/t/helper/.gitignore @@ -0,0 +1,33 @@ +/test-chmtime +/test-ctype +/test-config +/test-date +/test-delta +/test-dump-cache-tree +/test-dump-split-index +/test-dump-untracked-cache +/test-fake-ssh +/test-scrap-cache-tree +/test-genrandom +/test-hashmap +/test-index-version +/test-line-buffer +/test-match-trees +/test-mergesort +/test-mktemp +/test-parse-options +/test-path-utils +/test-prio-queue +/test-read-cache +/test-regex +/test-revision-walking +/test-run-command +/test-sha1 +/test-sha1-array +/test-sigchain +/test-string-list +/test-submodule-config +/test-subprocess +/test-svn-fe +/test-urlmatch-normalization +/test-wildmatch diff --git a/t/helper/test-chmtime.c b/t/helper/test-chmtime.c new file mode 100644 index 0000000000..e760256406 --- /dev/null +++ b/t/helper/test-chmtime.c @@ -0,0 +1,119 @@ +/* + * This program can either change modification time of the given + * file(s) or just print it. The program does not change atime or + * ctime (their values are explicitly preserved). + * + * The mtime can be changed to an absolute value: + * + * test-chmtime =<seconds> file... + * + * Relative to the current time as returned by time(3): + * + * test-chmtime =+<seconds> (or =-<seconds>) file... + * + * Or relative to the current mtime of the file: + * + * test-chmtime <seconds> file... + * test-chmtime +<seconds> (or -<seconds>) file... + * + * Examples: + * + * To just print the mtime use --verbose and set the file mtime offset to 0: + * + * test-chmtime -v +0 file + * + * To set the mtime to current time: + * + * test-chmtime =+0 file + * + */ +#include "git-compat-util.h" +#include <utime.h> + +static const char usage_str[] = "-v|--verbose (+|=|=+|=-|-)<seconds> <file>..."; + +static int timespec_arg(const char *arg, long int *set_time, int *set_eq) +{ + char *test; + const char *timespec = arg; + *set_eq = (*timespec == '=') ? 1 : 0; + if (*set_eq) { + timespec++; + if (*timespec == '+') { + *set_eq = 2; /* relative "in the future" */ + timespec++; + } + } + *set_time = strtol(timespec, &test, 10); + if (*test) { + fprintf(stderr, "Not a base-10 integer: %s\n", arg + 1); + return 0; + } + if ((*set_eq && *set_time < 0) || *set_eq == 2) { + time_t now = time(NULL); + *set_time += now; + } + return 1; +} + +int cmd_main(int argc, const char **argv) +{ + static int verbose; + + int i = 1; + /* no mtime change by default */ + int set_eq = 0; + long int set_time = 0; + + if (argc < 3) + goto usage; + + if (strcmp(argv[i], "--verbose") == 0 || strcmp(argv[i], "-v") == 0) { + verbose = 1; + ++i; + } + if (timespec_arg(argv[i], &set_time, &set_eq)) + ++i; + else + goto usage; + + for (; i < argc; i++) { + struct stat sb; + struct utimbuf utb; + + if (stat(argv[i], &sb) < 0) { + fprintf(stderr, "Failed to stat %s: %s\n", + argv[i], strerror(errno)); + return 1; + } + +#ifdef GIT_WINDOWS_NATIVE + if (!(sb.st_mode & S_IWUSR) && + chmod(argv[i], sb.st_mode | S_IWUSR)) { + fprintf(stderr, "Could not make user-writable %s: %s", + argv[i], strerror(errno)); + return 1; + } +#endif + + utb.actime = sb.st_atime; + utb.modtime = set_eq ? set_time : sb.st_mtime + set_time; + + if (verbose) { + uintmax_t mtime = utb.modtime < 0 ? 0: utb.modtime; + printf("%"PRIuMAX"\t%s\n", mtime, argv[i]); + } + + if (utb.modtime != sb.st_mtime && utime(argv[i], &utb) < 0) { + fprintf(stderr, "Failed to modify time on %s: %s\n", + argv[i], strerror(errno)); + return 1; + } + } + + return 0; + +usage: + fprintf(stderr, "usage: %s %s\n", argv[0], usage_str); + return 1; +} diff --git a/t/helper/test-config.c b/t/helper/test-config.c new file mode 100644 index 0000000000..d143cd7222 --- /dev/null +++ b/t/helper/test-config.c @@ -0,0 +1,152 @@ +#include "cache.h" +#include "string-list.h" + +/* + * This program exposes the C API of the configuration mechanism + * as a set of simple commands in order to facilitate testing. + * + * Reads stdin and prints result of command to stdout: + * + * get_value -> prints the value with highest priority for the entered key + * + * get_value_multi -> prints all values for the entered key in increasing order + * of priority + * + * get_int -> print integer value for the entered key or die + * + * get_bool -> print bool value for the entered key or die + * + * get_string -> print string value for the entered key or die + * + * configset_get_value -> returns value with the highest priority for the entered key + * from a config_set constructed from files entered as arguments. + * + * configset_get_value_multi -> returns value_list for the entered key sorted in + * ascending order of priority from a config_set + * constructed from files entered as arguments. + * + * Examples: + * + * To print the value with highest priority for key "foo.bAr Baz.rock": + * test-config get_value "foo.bAr Baz.rock" + * + */ + + +int cmd_main(int argc, const char **argv) +{ + int i, val; + const char *v; + const struct string_list *strptr; + struct config_set cs; + git_configset_init(&cs); + + if (argc < 2) { + fprintf(stderr, "Please, provide a command name on the command-line\n"); + goto exit1; + } else if (argc == 3 && !strcmp(argv[1], "get_value")) { + if (!git_config_get_value(argv[2], &v)) { + if (!v) + printf("(NULL)\n"); + else + printf("%s\n", v); + goto exit0; + } else { + printf("Value not found for \"%s\"\n", argv[2]); + goto exit1; + } + } else if (argc == 3 && !strcmp(argv[1], "get_value_multi")) { + strptr = git_config_get_value_multi(argv[2]); + if (strptr) { + for (i = 0; i < strptr->nr; i++) { + v = strptr->items[i].string; + if (!v) + printf("(NULL)\n"); + else + printf("%s\n", v); + } + goto exit0; + } else { + printf("Value not found for \"%s\"\n", argv[2]); + goto exit1; + } + } else if (argc == 3 && !strcmp(argv[1], "get_int")) { + if (!git_config_get_int(argv[2], &val)) { + printf("%d\n", val); + goto exit0; + } else { + printf("Value not found for \"%s\"\n", argv[2]); + goto exit1; + } + } else if (argc == 3 && !strcmp(argv[1], "get_bool")) { + if (!git_config_get_bool(argv[2], &val)) { + printf("%d\n", val); + goto exit0; + } else { + printf("Value not found for \"%s\"\n", argv[2]); + goto exit1; + } + } else if (argc == 3 && !strcmp(argv[1], "get_string")) { + if (!git_config_get_string_const(argv[2], &v)) { + printf("%s\n", v); + goto exit0; + } else { + printf("Value not found for \"%s\"\n", argv[2]); + goto exit1; + } + } else if (!strcmp(argv[1], "configset_get_value")) { + for (i = 3; i < argc; i++) { + int err; + if ((err = git_configset_add_file(&cs, argv[i]))) { + fprintf(stderr, "Error (%d) reading configuration file %s.\n", err, argv[i]); + goto exit2; + } + } + if (!git_configset_get_value(&cs, argv[2], &v)) { + if (!v) + printf("(NULL)\n"); + else + printf("%s\n", v); + goto exit0; + } else { + printf("Value not found for \"%s\"\n", argv[2]); + goto exit1; + } + } else if (!strcmp(argv[1], "configset_get_value_multi")) { + for (i = 3; i < argc; i++) { + int err; + if ((err = git_configset_add_file(&cs, argv[i]))) { + fprintf(stderr, "Error (%d) reading configuration file %s.\n", err, argv[i]); + goto exit2; + } + } + strptr = git_configset_get_value_multi(&cs, argv[2]); + if (strptr) { + for (i = 0; i < strptr->nr; i++) { + v = strptr->items[i].string; + if (!v) + printf("(NULL)\n"); + else + printf("%s\n", v); + } + goto exit0; + } else { + printf("Value not found for \"%s\"\n", argv[2]); + goto exit1; + } + } + + die("%s: Please check the syntax and the function name", argv[0]); + +exit0: + git_configset_clear(&cs); + return 0; + +exit1: + git_configset_clear(&cs); + return 1; + +exit2: + git_configset_clear(&cs); + return 2; +} diff --git a/t/helper/test-ctype.c b/t/helper/test-ctype.c new file mode 100644 index 0000000000..bb72c47df5 --- /dev/null +++ b/t/helper/test-ctype.c @@ -0,0 +1,42 @@ +#include "cache.h" + +static int rc; + +static void report_error(const char *class, int ch) +{ + printf("%s classifies char %d (0x%02x) wrongly\n", class, ch, ch); + rc = 1; +} + +static int is_in(const char *s, int ch) +{ + /* We can't find NUL using strchr. It's classless anyway. */ + if (ch == '\0') + return 0; + return !!strchr(s, ch); +} + +#define TEST_CLASS(t,s) { \ + int i; \ + for (i = 0; i < 256; i++) { \ + if (is_in(s, i) != t(i)) \ + report_error(#t, i); \ + } \ +} + +#define DIGIT "0123456789" +#define LOWER "abcdefghijklmnopqrstuvwxyz" +#define UPPER "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + +int cmd_main(int argc, const char **argv) +{ + TEST_CLASS(isdigit, DIGIT); + TEST_CLASS(isspace, " \n\r\t"); + TEST_CLASS(isalpha, LOWER UPPER); + TEST_CLASS(isalnum, LOWER UPPER DIGIT); + TEST_CLASS(is_glob_special, "*?[\\"); + TEST_CLASS(is_regex_special, "$()*+.?[\\^{|"); + TEST_CLASS(is_pathspec_magic, "!\"#%&',-/:;<=>@_`~"); + + return rc; +} diff --git a/t/helper/test-date.c b/t/helper/test-date.c new file mode 100644 index 0000000000..506054bcd5 --- /dev/null +++ b/t/helper/test-date.c @@ -0,0 +1,99 @@ +#include "cache.h" + +static const char *usage_msg = "\n" +" test-date relative [time_t]...\n" +" test-date show:<format> [time_t]...\n" +" test-date parse [date]...\n" +" test-date approxidate [date]...\n"; + +static void show_relative_dates(const char **argv, struct timeval *now) +{ + struct strbuf buf = STRBUF_INIT; + + for (; *argv; argv++) { + time_t t = atoi(*argv); + show_date_relative(t, 0, now, &buf); + printf("%s -> %s\n", *argv, buf.buf); + } + strbuf_release(&buf); +} + +static void show_dates(const char **argv, const char *format) +{ + struct date_mode mode; + + parse_date_format(format, &mode); + for (; *argv; argv++) { + char *arg; + time_t t; + int tz; + + /* + * Do not use our normal timestamp parsing here, as the point + * is to test the formatting code in isolation. + */ + t = strtol(*argv, &arg, 10); + while (*arg == ' ') + arg++; + tz = atoi(arg); + + printf("%s -> %s\n", *argv, show_date(t, tz, &mode)); + } +} + +static void parse_dates(const char **argv, struct timeval *now) +{ + struct strbuf result = STRBUF_INIT; + + for (; *argv; argv++) { + unsigned long t; + int tz; + + strbuf_reset(&result); + parse_date(*argv, &result); + if (sscanf(result.buf, "%lu %d", &t, &tz) == 2) + printf("%s -> %s\n", + *argv, show_date(t, tz, DATE_MODE(ISO8601))); + else + printf("%s -> bad\n", *argv); + } + strbuf_release(&result); +} + +static void parse_approxidate(const char **argv, struct timeval *now) +{ + for (; *argv; argv++) { + time_t t; + t = approxidate_relative(*argv, now); + printf("%s -> %s\n", *argv, show_date(t, 0, DATE_MODE(ISO8601))); + } +} + +int cmd_main(int argc, const char **argv) +{ + struct timeval now; + const char *x; + + x = getenv("TEST_DATE_NOW"); + if (x) { + now.tv_sec = atoi(x); + now.tv_usec = 0; + } + else + gettimeofday(&now, NULL); + + argv++; + if (!*argv) + usage(usage_msg); + if (!strcmp(*argv, "relative")) + show_relative_dates(argv+1, &now); + else if (skip_prefix(*argv, "show:", &x)) + show_dates(argv+1, x); + else if (!strcmp(*argv, "parse")) + parse_dates(argv+1, &now); + else if (!strcmp(*argv, "approxidate")) + parse_approxidate(argv+1, &now); + else + usage(usage_msg); + return 0; +} diff --git a/t/helper/test-delta.c b/t/helper/test-delta.c new file mode 100644 index 0000000000..59937dc1be --- /dev/null +++ b/t/helper/test-delta.c @@ -0,0 +1,78 @@ +/* + * test-delta.c: test code to exercise diff-delta.c and patch-delta.c + * + * (C) 2005 Nicolas Pitre <nico@fluxnic.net> + * + * This code is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "git-compat-util.h" +#include "delta.h" +#include "cache.h" + +static const char usage_str[] = + "test-delta (-d|-p) <from_file> <data_file> <out_file>"; + +int cmd_main(int argc, const char **argv) +{ + int fd; + struct stat st; + void *from_buf, *data_buf, *out_buf; + unsigned long from_size, data_size, out_size; + + if (argc != 5 || (strcmp(argv[1], "-d") && strcmp(argv[1], "-p"))) { + fprintf(stderr, "usage: %s\n", usage_str); + return 1; + } + + fd = open(argv[2], O_RDONLY); + if (fd < 0 || fstat(fd, &st)) { + perror(argv[2]); + return 1; + } + from_size = st.st_size; + from_buf = mmap(NULL, from_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (from_buf == MAP_FAILED) { + perror(argv[2]); + close(fd); + return 1; + } + close(fd); + + fd = open(argv[3], O_RDONLY); + if (fd < 0 || fstat(fd, &st)) { + perror(argv[3]); + return 1; + } + data_size = st.st_size; + data_buf = mmap(NULL, data_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (data_buf == MAP_FAILED) { + perror(argv[3]); + close(fd); + return 1; + } + close(fd); + + if (argv[1][1] == 'd') + out_buf = diff_delta(from_buf, from_size, + data_buf, data_size, + &out_size, 0); + else + out_buf = patch_delta(from_buf, from_size, + data_buf, data_size, + &out_size); + if (!out_buf) { + fprintf(stderr, "delta operation failed (returned NULL)\n"); + return 1; + } + + fd = open (argv[4], O_WRONLY|O_CREAT|O_TRUNC, 0666); + if (fd < 0 || write_in_full(fd, out_buf, out_size) != out_size) { + perror(argv[4]); + return 1; + } + + return 0; +} diff --git a/t/helper/test-dump-cache-tree.c b/t/helper/test-dump-cache-tree.c new file mode 100644 index 0000000000..44f3290258 --- /dev/null +++ b/t/helper/test-dump-cache-tree.c @@ -0,0 +1,67 @@ +#include "cache.h" +#include "tree.h" +#include "cache-tree.h" + + +static void dump_one(struct cache_tree *it, const char *pfx, const char *x) +{ + if (it->entry_count < 0) + printf("%-40s %s%s (%d subtrees)\n", + "invalid", x, pfx, it->subtree_nr); + else + printf("%s %s%s (%d entries, %d subtrees)\n", + sha1_to_hex(it->sha1), x, pfx, + it->entry_count, it->subtree_nr); +} + +static int dump_cache_tree(struct cache_tree *it, + struct cache_tree *ref, + const char *pfx) +{ + int i; + int errs = 0; + + if (!it || !ref) + /* missing in either */ + return 0; + + if (it->entry_count < 0) { + /* invalid */ + dump_one(it, pfx, ""); + dump_one(ref, pfx, "#(ref) "); + } + else { + dump_one(it, pfx, ""); + if (hashcmp(it->sha1, ref->sha1) || + ref->entry_count != it->entry_count || + ref->subtree_nr != it->subtree_nr) { + /* claims to be valid but is lying */ + dump_one(ref, pfx, "#(ref) "); + errs = 1; + } + } + + for (i = 0; i < it->subtree_nr; i++) { + char path[PATH_MAX]; + struct cache_tree_sub *down = it->down[i]; + struct cache_tree_sub *rdwn; + + rdwn = cache_tree_sub(ref, down->name); + xsnprintf(path, sizeof(path), "%s%.*s/", pfx, down->namelen, down->name); + if (dump_cache_tree(down->cache_tree, rdwn->cache_tree, path)) + errs = 1; + } + return errs; +} + +int cmd_main(int ac, const char **av) +{ + struct index_state istate; + struct cache_tree *another = cache_tree(); + if (read_cache() < 0) + die("unable to read index file"); + istate = the_index; + istate.cache_tree = another; + cache_tree_update(&istate, WRITE_TREE_DRY_RUN); + return dump_cache_tree(active_cache_tree, another, ""); +} diff --git a/t/helper/test-dump-split-index.c b/t/helper/test-dump-split-index.c new file mode 100644 index 0000000000..d1689248b4 --- /dev/null +++ b/t/helper/test-dump-split-index.c @@ -0,0 +1,36 @@ +#include "cache.h" +#include "split-index.h" +#include "ewah/ewok.h" + +static void show_bit(size_t pos, void *data) +{ + printf(" %d", (int)pos); +} + +int cmd_main(int ac, const char **av) +{ + struct split_index *si; + int i; + + do_read_index(&the_index, av[1], 1); + printf("own %s\n", sha1_to_hex(the_index.sha1)); + si = the_index.split_index; + if (!si) { + printf("not a split index\n"); + return 0; + } + printf("base %s\n", sha1_to_hex(si->base_sha1)); + for (i = 0; i < the_index.cache_nr; i++) { + struct cache_entry *ce = the_index.cache[i]; + printf("%06o %s %d\t%s\n", ce->ce_mode, + sha1_to_hex(ce->sha1), ce_stage(ce), ce->name); + } + printf("replacements:"); + if (si->replace_bitmap) + ewah_each_bit(si->replace_bitmap, show_bit, NULL); + printf("\ndeletions:"); + if (si->delete_bitmap) + ewah_each_bit(si->delete_bitmap, show_bit, NULL); + printf("\n"); + return 0; +} diff --git a/t/helper/test-dump-untracked-cache.c b/t/helper/test-dump-untracked-cache.c new file mode 100644 index 0000000000..50112cc858 --- /dev/null +++ b/t/helper/test-dump-untracked-cache.c @@ -0,0 +1,66 @@ +#include "cache.h" +#include "dir.h" + +static int compare_untracked(const void *a_, const void *b_) +{ + const char *const *a = a_; + const char *const *b = b_; + return strcmp(*a, *b); +} + +static int compare_dir(const void *a_, const void *b_) +{ + const struct untracked_cache_dir *const *a = a_; + const struct untracked_cache_dir *const *b = b_; + return strcmp((*a)->name, (*b)->name); +} + +static void dump(struct untracked_cache_dir *ucd, struct strbuf *base) +{ + int i, len; + qsort(ucd->untracked, ucd->untracked_nr, sizeof(*ucd->untracked), + compare_untracked); + qsort(ucd->dirs, ucd->dirs_nr, sizeof(*ucd->dirs), + compare_dir); + len = base->len; + strbuf_addf(base, "%s/", ucd->name); + printf("%s %s", base->buf, + sha1_to_hex(ucd->exclude_sha1)); + if (ucd->recurse) + fputs(" recurse", stdout); + if (ucd->check_only) + fputs(" check_only", stdout); + if (ucd->valid) + fputs(" valid", stdout); + printf("\n"); + for (i = 0; i < ucd->untracked_nr; i++) + printf("%s\n", ucd->untracked[i]); + for (i = 0; i < ucd->dirs_nr; i++) + dump(ucd->dirs[i], base); + strbuf_setlen(base, len); +} + +int cmd_main(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; + + setup_git_directory(); + if (read_cache() < 0) + die("unable to read index file"); + uc = the_index.untracked; + if (!uc) { + printf("no untracked cache\n"); + return 0; + } + printf("info/exclude %s\n", sha1_to_hex(uc->ss_info_exclude.sha1)); + printf("core.excludesfile %s\n", sha1_to_hex(uc->ss_excludes_file.sha1)); + printf("exclude_per_dir %s\n", uc->exclude_per_dir); + printf("flags %08x\n", uc->dir_flags); + if (uc->root) + dump(uc->root, &base); + return 0; +} diff --git a/t/helper/test-fake-ssh.c b/t/helper/test-fake-ssh.c new file mode 100644 index 0000000000..12beee99ad --- /dev/null +++ b/t/helper/test-fake-ssh.c @@ -0,0 +1,30 @@ +#include "git-compat-util.h" +#include "run-command.h" +#include "strbuf.h" + +int cmd_main(int argc, const char **argv) +{ + const char *trash_directory = getenv("TRASH_DIRECTORY"); + struct strbuf buf = STRBUF_INIT; + FILE *f; + int i; + const char *child_argv[] = { NULL, NULL }; + + /* First, print all parameters into $TRASH_DIRECTORY/ssh-output */ + if (!trash_directory) + die("Need a TRASH_DIRECTORY!"); + strbuf_addf(&buf, "%s/ssh-output", trash_directory); + f = fopen(buf.buf, "w"); + if (!f) + die("Could not write to %s", buf.buf); + for (i = 0; i < argc; i++) + fprintf(f, "%s%s", i > 0 ? " " : "", i > 0 ? argv[i] : "ssh:"); + fprintf(f, "\n"); + fclose(f); + + /* Now, evaluate the *last* parameter */ + if (argc < 2) + return 0; + child_argv[0] = argv[argc - 1]; + return run_command_v_opt(child_argv, RUN_USING_SHELL); +} diff --git a/t/helper/test-genrandom.c b/t/helper/test-genrandom.c new file mode 100644 index 0000000000..8d11d22d98 --- /dev/null +++ b/t/helper/test-genrandom.c @@ -0,0 +1,33 @@ +/* + * Simple random data generator used to create reproducible test files. + * This is inspired from POSIX.1-2001 implementation example for rand(). + * Copyright (C) 2007 by Nicolas Pitre, licensed under the GPL version 2. + */ + +#include "git-compat-util.h" + +int cmd_main(int argc, const char **argv) +{ + unsigned long count, next = 0; + unsigned char *c; + + if (argc < 2 || argc > 3) { + fprintf(stderr, "usage: %s <seed_string> [<size>]\n", argv[0]); + return 1; + } + + c = (unsigned char *) argv[1]; + do { + next = next * 11 + *c; + } while (*c++); + + count = (argc == 3) ? strtoul(argv[2], NULL, 0) : -1L; + + while (count--) { + next = next * 1103515245 + 12345; + if (putchar((next >> 16) & 0xff) == EOF) + return -1; + } + + return 0; +} diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c new file mode 100644 index 0000000000..7aa9440e27 --- /dev/null +++ b/t/helper/test-hashmap.c @@ -0,0 +1,264 @@ +#include "git-compat-util.h" +#include "hashmap.h" + +struct test_entry +{ + struct hashmap_entry ent; + /* key and value as two \0-terminated strings */ + char key[FLEX_ARRAY]; +}; + +static const char *get_value(const struct test_entry *e) +{ + return e->key + strlen(e->key) + 1; +} + +static int test_entry_cmp(const struct test_entry *e1, + const struct test_entry *e2, const char* key) +{ + return strcmp(e1->key, key ? key : e2->key); +} + +static int test_entry_cmp_icase(const struct test_entry *e1, + const struct test_entry *e2, const char* key) +{ + return strcasecmp(e1->key, key ? key : e2->key); +} + +static struct test_entry *alloc_test_entry(int hash, char *key, int klen, + char *value, int vlen) +{ + struct test_entry *entry = malloc(sizeof(struct test_entry) + klen + + vlen + 2); + hashmap_entry_init(entry, hash); + memcpy(entry->key, key, klen + 1); + memcpy(entry->key + klen + 1, value, vlen + 1); + return entry; +} + +#define HASH_METHOD_FNV 0 +#define HASH_METHOD_I 1 +#define HASH_METHOD_IDIV10 2 +#define HASH_METHOD_0 3 +#define HASH_METHOD_X2 4 +#define TEST_SPARSE 8 +#define TEST_ADD 16 +#define TEST_SIZE 100000 + +static unsigned int hash(unsigned int method, unsigned int i, const char *key) +{ + unsigned int hash = 0; + switch (method & 3) + { + case HASH_METHOD_FNV: + hash = strhash(key); + break; + case HASH_METHOD_I: + hash = i; + break; + case HASH_METHOD_IDIV10: + hash = i / 10; + break; + case HASH_METHOD_0: + hash = 0; + break; + } + + if (method & HASH_METHOD_X2) + hash = 2 * hash; + return hash; +} + +/* + * Test performance of hashmap.[ch] + * Usage: time echo "perfhashmap method rounds" | test-hashmap + */ +static void perf_hashmap(unsigned int method, unsigned int rounds) +{ + struct hashmap map; + char buf[16]; + struct test_entry **entries; + unsigned int *hashes; + unsigned int i, j; + + entries = malloc(TEST_SIZE * sizeof(struct test_entry *)); + hashes = malloc(TEST_SIZE * sizeof(int)); + for (i = 0; i < TEST_SIZE; i++) { + snprintf(buf, sizeof(buf), "%i", i); + entries[i] = alloc_test_entry(0, buf, strlen(buf), "", 0); + hashes[i] = hash(method, i, entries[i]->key); + } + + if (method & TEST_ADD) { + /* test adding to the map */ + for (j = 0; j < rounds; j++) { + hashmap_init(&map, (hashmap_cmp_fn) test_entry_cmp, 0); + + /* add entries */ + for (i = 0; i < TEST_SIZE; i++) { + hashmap_entry_init(entries[i], hashes[i]); + hashmap_add(&map, entries[i]); + } + + hashmap_free(&map, 0); + } + } else { + /* test map lookups */ + hashmap_init(&map, (hashmap_cmp_fn) test_entry_cmp, 0); + + /* fill the map (sparsely if specified) */ + j = (method & TEST_SPARSE) ? TEST_SIZE / 10 : TEST_SIZE; + for (i = 0; i < j; i++) { + hashmap_entry_init(entries[i], hashes[i]); + hashmap_add(&map, entries[i]); + } + + for (j = 0; j < rounds; j++) { + for (i = 0; i < TEST_SIZE; i++) { + hashmap_get_from_hash(&map, hashes[i], + entries[i]->key); + } + } + + hashmap_free(&map, 0); + } +} + +#define DELIM " \t\r\n" + +/* + * Read stdin line by line and print result of commands to stdout: + * + * hash key -> strhash(key) memhash(key) strihash(key) memihash(key) + * put key value -> NULL / old value + * get key -> NULL / value + * remove key -> NULL / old value + * iterate -> key1 value1\nkey2 value2\n... + * size -> tablesize numentries + * + * perfhashmap method rounds -> test hashmap.[ch] performance + */ +int cmd_main(int argc, const char **argv) +{ + char line[1024]; + struct hashmap map; + int icase; + + /* init hash map */ + icase = argc > 1 && !strcmp("ignorecase", argv[1]); + hashmap_init(&map, (hashmap_cmp_fn) (icase ? test_entry_cmp_icase + : test_entry_cmp), 0); + + /* process commands from stdin */ + while (fgets(line, sizeof(line), stdin)) { + char *cmd, *p1 = NULL, *p2 = NULL; + int l1 = 0, l2 = 0, hash = 0; + struct test_entry *entry; + + /* break line into command and up to two parameters */ + cmd = strtok(line, DELIM); + /* ignore empty lines */ + if (!cmd || *cmd == '#') + continue; + + p1 = strtok(NULL, DELIM); + if (p1) { + l1 = strlen(p1); + hash = icase ? strihash(p1) : strhash(p1); + p2 = strtok(NULL, DELIM); + if (p2) + l2 = strlen(p2); + } + + if (!strcmp("hash", cmd) && l1) { + + /* print results of different hash functions */ + printf("%u %u %u %u\n", strhash(p1), memhash(p1, l1), + strihash(p1), memihash(p1, l1)); + + } else if (!strcmp("add", cmd) && l1 && l2) { + + /* create entry with key = p1, value = p2 */ + entry = alloc_test_entry(hash, p1, l1, p2, l2); + + /* add to hashmap */ + hashmap_add(&map, entry); + + } else if (!strcmp("put", cmd) && l1 && l2) { + + /* create entry with key = p1, value = p2 */ + entry = alloc_test_entry(hash, p1, l1, p2, l2); + + /* add / replace entry */ + entry = hashmap_put(&map, entry); + + /* print and free replaced entry, if any */ + puts(entry ? get_value(entry) : "NULL"); + free(entry); + + } else if (!strcmp("get", cmd) && l1) { + + /* lookup entry in hashmap */ + entry = hashmap_get_from_hash(&map, hash, p1); + + /* print result */ + if (!entry) + puts("NULL"); + while (entry) { + puts(get_value(entry)); + entry = hashmap_get_next(&map, entry); + } + + } else if (!strcmp("remove", cmd) && l1) { + + /* setup static key */ + struct hashmap_entry key; + hashmap_entry_init(&key, hash); + + /* remove entry from hashmap */ + entry = hashmap_remove(&map, &key, p1); + + /* print result and free entry*/ + puts(entry ? get_value(entry) : "NULL"); + free(entry); + + } else if (!strcmp("iterate", cmd)) { + + struct hashmap_iter iter; + hashmap_iter_init(&map, &iter); + while ((entry = hashmap_iter_next(&iter))) + printf("%s %s\n", entry->key, get_value(entry)); + + } else if (!strcmp("size", cmd)) { + + /* print table sizes */ + printf("%u %u\n", map.tablesize, map.size); + + } else if (!strcmp("intern", cmd) && l1) { + + /* test that strintern works */ + const char *i1 = strintern(p1); + const char *i2 = strintern(p1); + if (strcmp(i1, p1)) + printf("strintern(%s) returns %s\n", p1, i1); + else if (i1 == p1) + printf("strintern(%s) returns input pointer\n", p1); + else if (i1 != i2) + printf("strintern(%s) != strintern(%s)", i1, i2); + else + printf("%s\n", i1); + + } else if (!strcmp("perfhashmap", cmd) && l1 && l2) { + + perf_hashmap(atoi(p1), atoi(p2)); + + } else { + + printf("Unknown command %s\n", cmd); + + } + } + + hashmap_free(&map, 1); + return 0; +} diff --git a/t/helper/test-index-version.c b/t/helper/test-index-version.c new file mode 100644 index 0000000000..f569f6b7ef --- /dev/null +++ b/t/helper/test-index-version.c @@ -0,0 +1,14 @@ +#include "cache.h" + +int cmd_main(int argc, const char **argv) +{ + struct cache_header hdr; + int version; + + memset(&hdr,0,sizeof(hdr)); + if (read(0, &hdr, sizeof(hdr)) != sizeof(hdr)) + return 0; + version = ntohl(hdr.hdr_version); + printf("%d\n", version); + return 0; +} diff --git a/t/helper/test-line-buffer.c b/t/helper/test-line-buffer.c new file mode 100644 index 0000000000..81575fe2ab --- /dev/null +++ b/t/helper/test-line-buffer.c @@ -0,0 +1,91 @@ +/* + * test-line-buffer.c: code to exercise the svn importer's input helper + */ + +#include "git-compat-util.h" +#include "strbuf.h" +#include "vcs-svn/line_buffer.h" + +static uint32_t strtouint32(const char *s) +{ + char *end; + uintmax_t n = strtoumax(s, &end, 10); + if (*s == '\0' || *end != '\0') + die("invalid count: %s", s); + return (uint32_t) n; +} + +static void handle_command(const char *command, const char *arg, struct line_buffer *buf) +{ + switch (*command) { + case 'b': + if (starts_with(command, "binary ")) { + struct strbuf sb = STRBUF_INIT; + strbuf_addch(&sb, '>'); + buffer_read_binary(buf, &sb, strtouint32(arg)); + fwrite(sb.buf, 1, sb.len, stdout); + strbuf_release(&sb); + return; + } + case 'c': + if (starts_with(command, "copy ")) { + buffer_copy_bytes(buf, strtouint32(arg)); + return; + } + case 's': + if (starts_with(command, "skip ")) { + buffer_skip_bytes(buf, strtouint32(arg)); + return; + } + default: + die("unrecognized command: %s", command); + } +} + +static void handle_line(const char *line, struct line_buffer *stdin_buf) +{ + const char *arg = strchr(line, ' '); + if (!arg) + die("no argument in line: %s", line); + handle_command(line, arg + 1, stdin_buf); +} + +int cmd_main(int argc, const char **argv) +{ + struct line_buffer stdin_buf = LINE_BUFFER_INIT; + struct line_buffer file_buf = LINE_BUFFER_INIT; + struct line_buffer *input = &stdin_buf; + const char *filename; + char *s; + + if (argc == 1) + filename = NULL; + else if (argc == 2) + filename = argv[1]; + else + usage("test-line-buffer [file | &fd] < script"); + + if (buffer_init(&stdin_buf, NULL)) + die_errno("open error"); + if (filename) { + if (*filename == '&') { + if (buffer_fdinit(&file_buf, strtouint32(filename + 1))) + die_errno("error opening fd %s", filename + 1); + } else { + if (buffer_init(&file_buf, filename)) + die_errno("error opening %s", filename); + } + input = &file_buf; + } + + while ((s = buffer_read_line(&stdin_buf))) + handle_line(s, input); + + if (filename && buffer_deinit(&file_buf)) + die("error reading from %s", filename); + if (buffer_deinit(&stdin_buf)) + die("input error"); + if (ferror(stdout)) + die("output error"); + return 0; +} diff --git a/t/helper/test-match-trees.c b/t/helper/test-match-trees.c new file mode 100644 index 0000000000..e939502863 --- /dev/null +++ b/t/helper/test-match-trees.c @@ -0,0 +1,26 @@ +#include "cache.h" +#include "tree.h" + +int cmd_main(int ac, const char **av) +{ + struct object_id hash1, hash2, shifted; + struct tree *one, *two; + + setup_git_directory(); + + if (get_oid(av[1], &hash1)) + die("cannot parse %s as an object name", av[1]); + if (get_oid(av[2], &hash2)) + die("cannot parse %s as an object name", av[2]); + one = parse_tree_indirect(hash1.hash); + if (!one) + die("not a tree-ish %s", av[1]); + two = parse_tree_indirect(hash2.hash); + if (!two) + die("not a tree-ish %s", av[2]); + + shift_tree(&one->object.oid, &two->object.oid, &shifted, -1); + printf("shifted: %s\n", oid_to_hex(&shifted)); + + exit(0); +} diff --git a/t/helper/test-mergesort.c b/t/helper/test-mergesort.c new file mode 100644 index 0000000000..335cf6b626 --- /dev/null +++ b/t/helper/test-mergesort.c @@ -0,0 +1,52 @@ +#include "cache.h" +#include "mergesort.h" + +struct line { + char *text; + struct line *next; +}; + +static void *get_next(const void *a) +{ + return ((const struct line *)a)->next; +} + +static void set_next(void *a, void *b) +{ + ((struct line *)a)->next = b; +} + +static int compare_strings(const void *a, const void *b) +{ + const struct line *x = a, *y = b; + return strcmp(x->text, y->text); +} + +int cmd_main(int argc, const char **argv) +{ + struct line *line, *p = NULL, *lines = NULL; + struct strbuf sb = STRBUF_INIT; + + for (;;) { + if (strbuf_getwholeline(&sb, stdin, '\n')) + break; + line = xmalloc(sizeof(struct line)); + line->text = strbuf_detach(&sb, NULL); + if (p) { + line->next = p->next; + p->next = line; + } else { + line->next = NULL; + lines = line; + } + p = line; + } + + lines = llist_mergesort(lines, get_next, set_next, compare_strings); + + while (lines) { + printf("%s", lines->text); + lines = lines->next; + } + return 0; +} diff --git a/t/helper/test-mktemp.c b/t/helper/test-mktemp.c new file mode 100644 index 0000000000..89d9b2f7be --- /dev/null +++ b/t/helper/test-mktemp.c @@ -0,0 +1,14 @@ +/* + * test-mktemp.c: code to exercise the creation of temporary files + */ +#include "git-compat-util.h" + +int cmd_main(int argc, const char **argv) +{ + if (argc != 2) + usage("Expected 1 parameter defining the temporary file template"); + + xmkstemp(xstrdup(argv[1])); + + return 0; +} diff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c new file mode 100644 index 0000000000..d51d29251e --- /dev/null +++ b/t/helper/test-parse-options.c @@ -0,0 +1,179 @@ +#include "cache.h" +#include "parse-options.h" +#include "string-list.h" + +static int boolean = 0; +static int integer = 0; +static unsigned long magnitude = 0; +static unsigned long timestamp; +static int abbrev = 7; +static int verbose = -1; /* unspecified */ +static int dry_run = 0, quiet = 0; +static char *string = NULL; +static char *file = NULL; +static int ambiguous; +static struct string_list list; + +static struct { + int called; + const char *arg; + int unset; +} length_cb; + +static int length_callback(const struct option *opt, const char *arg, int unset) +{ + length_cb.called = 1; + length_cb.arg = arg; + length_cb.unset = unset; + + if (unset) + return 1; /* do not support unset */ + + *(int *)opt->value = strlen(arg); + return 0; +} + +static int number_callback(const struct option *opt, const char *arg, int unset) +{ + *(int *)opt->value = strtol(arg, NULL, 10); + return 0; +} + +static int collect_expect(const struct option *opt, const char *arg, int unset) +{ + struct string_list *expect; + struct string_list_item *item; + struct strbuf label = STRBUF_INIT; + const char *colon; + + if (!arg || unset) + die("malformed --expect option"); + + expect = (struct string_list *)opt->value; + colon = strchr(arg, ':'); + if (!colon) + die("malformed --expect option, lacking a colon"); + strbuf_add(&label, arg, colon - arg); + item = string_list_insert(expect, strbuf_detach(&label, NULL)); + if (item->util) + die("malformed --expect option, duplicate %s", label.buf); + item->util = (void *)arg; + return 0; +} + +__attribute__((format (printf,3,4))) +static void show(struct string_list *expect, int *status, const char *fmt, ...) +{ + struct string_list_item *item; + struct strbuf buf = STRBUF_INIT; + va_list args; + + va_start(args, fmt); + strbuf_vaddf(&buf, fmt, args); + va_end(args); + + if (!expect->nr) + printf("%s\n", buf.buf); + else { + char *colon = strchr(buf.buf, ':'); + if (!colon) + die("malformed output format, output lacking colon: %s", fmt); + *colon = '\0'; + item = string_list_lookup(expect, buf.buf); + *colon = ':'; + if (!item) + ; /* not among entries being checked */ + else { + if (strcmp((const char *)item->util, buf.buf)) { + printf("-%s\n", (char *)item->util); + printf("+%s\n", buf.buf); + *status = 1; + } + } + } + strbuf_release(&buf); +} + +int cmd_main(int argc, const char **argv) +{ + const char *prefix = "prefix/"; + const char *usage[] = { + "test-parse-options <options>", + NULL + }; + struct string_list expect = STRING_LIST_INIT_NODUP; + struct option options[] = { + OPT_BOOL(0, "yes", &boolean, "get a boolean"), + OPT_BOOL('D', "no-doubt", &boolean, "begins with 'no-'"), + { OPTION_SET_INT, 'B', "no-fear", &boolean, NULL, + "be brave", PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 }, + OPT_COUNTUP('b', "boolean", &boolean, "increment by one"), + OPT_BIT('4', "or4", &boolean, + "bitwise-or boolean with ...0100", 4), + OPT_NEGBIT(0, "neg-or4", &boolean, "same as --no-or4", 4), + OPT_GROUP(""), + OPT_INTEGER('i', "integer", &integer, "get a integer"), + OPT_INTEGER('j', NULL, &integer, "get a integer, too"), + OPT_MAGNITUDE('m', "magnitude", &magnitude, "get a magnitude"), + OPT_SET_INT(0, "set23", &integer, "set integer to 23", 23), + OPT_DATE('t', NULL, ×tamp, "get timestamp of <time>"), + OPT_CALLBACK('L', "length", &integer, "str", + "get length of <str>", length_callback), + OPT_FILENAME('F', "file", &file, "set file to <file>"), + OPT_GROUP("String options"), + OPT_STRING('s', "string", &string, "string", "get a string"), + OPT_STRING(0, "string2", &string, "str", "get another string"), + OPT_STRING(0, "st", &string, "st", "get another string (pervert ordering)"), + OPT_STRING('o', NULL, &string, "str", "get another string"), + OPT_NOOP_NOARG(0, "obsolete"), + OPT_STRING_LIST(0, "list", &list, "str", "add str to list"), + OPT_GROUP("Magic arguments"), + OPT_ARGUMENT("quux", "means --quux"), + OPT_NUMBER_CALLBACK(&integer, "set integer to NUM", + number_callback), + { OPTION_COUNTUP, '+', NULL, &boolean, NULL, "same as -b", + PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH }, + { OPTION_COUNTUP, 0, "ambiguous", &ambiguous, NULL, + "positive ambiguity", PARSE_OPT_NOARG | PARSE_OPT_NONEG }, + { OPTION_COUNTUP, 0, "no-ambiguous", &ambiguous, NULL, + "negative ambiguity", PARSE_OPT_NOARG | PARSE_OPT_NONEG }, + OPT_GROUP("Standard options"), + OPT__ABBREV(&abbrev), + OPT__VERBOSE(&verbose, "be verbose"), + OPT__DRY_RUN(&dry_run, "dry run"), + OPT__QUIET(&quiet, "be quiet"), + OPT_CALLBACK(0, "expect", &expect, "string", + "expected output in the variable dump", + collect_expect), + OPT_END(), + }; + int i; + int ret = 0; + + argc = parse_options(argc, (const char **)argv, prefix, options, usage, 0); + + if (length_cb.called) { + const char *arg = length_cb.arg; + int unset = length_cb.unset; + show(&expect, &ret, "Callback: \"%s\", %d", + (arg ? arg : "not set"), unset); + } + show(&expect, &ret, "boolean: %d", boolean); + show(&expect, &ret, "integer: %d", integer); + show(&expect, &ret, "magnitude: %lu", magnitude); + show(&expect, &ret, "timestamp: %lu", timestamp); + show(&expect, &ret, "string: %s", string ? string : "(not set)"); + show(&expect, &ret, "abbrev: %d", abbrev); + show(&expect, &ret, "verbose: %d", verbose); + show(&expect, &ret, "quiet: %d", quiet); + show(&expect, &ret, "dry run: %s", dry_run ? "yes" : "no"); + show(&expect, &ret, "file: %s", file ? file : "(not set)"); + + for (i = 0; i < list.nr; i++) + show(&expect, &ret, "list: %s", list.items[i].string); + + for (i = 0; i < argc; i++) + show(&expect, &ret, "arg %02d: %s", i, argv[i]); + + return ret; +} diff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c new file mode 100644 index 0000000000..1ebe0f750c --- /dev/null +++ b/t/helper/test-path-utils.c @@ -0,0 +1,262 @@ +#include "cache.h" +#include "string-list.h" + +/* + * A "string_list_each_func_t" function that normalizes an entry from + * GIT_CEILING_DIRECTORIES. If the path is unusable for some reason, + * die with an explanation. + */ +static int normalize_ceiling_entry(struct string_list_item *item, void *unused) +{ + char *ceil = item->string; + + if (!*ceil) + die("Empty path is not supported"); + if (!is_absolute_path(ceil)) + die("Path \"%s\" is not absolute", ceil); + if (normalize_path_copy(ceil, ceil) < 0) + die("Path \"%s\" could not be normalized", ceil); + return 1; +} + +static void normalize_argv_string(const char **var, const char *input) +{ + if (!strcmp(input, "<null>")) + *var = NULL; + else if (!strcmp(input, "<empty>")) + *var = ""; + else + *var = input; + + if (*var && (**var == '<' || **var == '(')) + die("Bad value: %s\n", input); +} + +struct test_data { + const char *from; /* input: transform from this ... */ + const char *to; /* output: ... to this. */ + const char *alternative; /* output: ... or this. */ +}; + +static int test_function(struct test_data *data, char *(*func)(char *input), + const char *funcname) +{ + int failed = 0, i; + char buffer[1024]; + char *to; + + for (i = 0; data[i].to; i++) { + if (!data[i].from) + to = func(NULL); + else { + xsnprintf(buffer, sizeof(buffer), "%s", data[i].from); + to = func(buffer); + } + if (!strcmp(to, data[i].to)) + continue; + if (!data[i].alternative) + error("FAIL: %s(%s) => '%s' != '%s'\n", + funcname, data[i].from, to, data[i].to); + else if (!strcmp(to, data[i].alternative)) + continue; + else + error("FAIL: %s(%s) => '%s' != '%s', '%s'\n", + funcname, data[i].from, to, data[i].to, + data[i].alternative); + failed = 1; + } + return failed; +} + +static struct test_data basename_data[] = { + /* --- POSIX type paths --- */ + { NULL, "." }, + { "", "." }, + { ".", "." }, + { "..", ".." }, + { "/", "/" }, + { "//", "/", "//" }, + { "///", "/", "//" }, + { "////", "/", "//" }, + { "usr", "usr" }, + { "/usr", "usr" }, + { "/usr/", "usr" }, + { "/usr//", "usr" }, + { "/usr/lib", "lib" }, + { "usr/lib", "lib" }, + { "usr/lib///", "lib" }, + +#if defined(__MINGW32__) || defined(_MSC_VER) + /* --- win32 type paths --- */ + { "\\usr", "usr" }, + { "\\usr\\", "usr" }, + { "\\usr\\\\", "usr" }, + { "\\usr\\lib", "lib" }, + { "usr\\lib", "lib" }, + { "usr\\lib\\\\\\", "lib" }, + { "C:/usr", "usr" }, + { "C:/usr", "usr" }, + { "C:/usr/", "usr" }, + { "C:/usr//", "usr" }, + { "C:/usr/lib", "lib" }, + { "C:usr/lib", "lib" }, + { "C:usr/lib///", "lib" }, + { "C:", "." }, + { "C:a", "a" }, + { "C:/", "/" }, + { "C:///", "/" }, + { "\\", "\\", "/" }, + { "\\\\", "\\", "/" }, + { "\\\\\\", "\\", "/" }, +#endif + { NULL, NULL } +}; + +static struct test_data dirname_data[] = { + /* --- POSIX type paths --- */ + { NULL, "." }, + { "", "." }, + { ".", "." }, + { "..", "." }, + { "/", "/" }, + { "//", "/", "//" }, + { "///", "/", "//" }, + { "////", "/", "//" }, + { "usr", "." }, + { "/usr", "/" }, + { "/usr/", "/" }, + { "/usr//", "/" }, + { "/usr/lib", "/usr" }, + { "usr/lib", "usr" }, + { "usr/lib///", "usr" }, + +#if defined(__MINGW32__) || defined(_MSC_VER) + /* --- win32 type paths --- */ + { "\\", "\\" }, + { "\\\\", "\\\\" }, + { "\\usr", "\\" }, + { "\\usr\\", "\\" }, + { "\\usr\\\\", "\\" }, + { "\\usr\\lib", "\\usr" }, + { "usr\\lib", "usr" }, + { "usr\\lib\\\\\\", "usr" }, + { "C:a", "C:." }, + { "C:/", "C:/" }, + { "C:///", "C:/" }, + { "C:/usr", "C:/" }, + { "C:/usr/", "C:/" }, + { "C:/usr//", "C:/" }, + { "C:/usr/lib", "C:/usr" }, + { "C:usr/lib", "C:usr" }, + { "C:usr/lib///", "C:usr" }, + { "\\\\\\", "\\" }, + { "\\\\\\\\", "\\" }, + { "C:", "C:.", "." }, +#endif + { NULL, NULL } +}; + +int cmd_main(int argc, const char **argv) +{ + if (argc == 3 && !strcmp(argv[1], "normalize_path_copy")) { + char *buf = xmallocz(strlen(argv[2])); + int rv = normalize_path_copy(buf, argv[2]); + if (rv) + buf = "++failed++"; + puts(buf); + return 0; + } + + if (argc >= 2 && !strcmp(argv[1], "real_path")) { + while (argc > 2) { + puts(real_path(argv[2])); + argc--; + argv++; + } + return 0; + } + + if (argc >= 2 && !strcmp(argv[1], "absolute_path")) { + while (argc > 2) { + puts(absolute_path(argv[2])); + argc--; + argv++; + } + return 0; + } + + if (argc == 4 && !strcmp(argv[1], "longest_ancestor_length")) { + int len; + struct string_list ceiling_dirs = STRING_LIST_INIT_DUP; + char *path = xstrdup(argv[2]); + + /* + * We have to normalize the arguments because under + * Windows, bash mangles arguments that look like + * absolute POSIX paths or colon-separate lists of + * absolute POSIX paths into DOS paths (e.g., + * "/foo:/foo/bar" might be converted to + * "D:\Src\msysgit\foo;D:\Src\msysgit\foo\bar"), + * whereas longest_ancestor_length() requires paths + * that use forward slashes. + */ + if (normalize_path_copy(path, path)) + die("Path \"%s\" could not be normalized", argv[2]); + string_list_split(&ceiling_dirs, argv[3], PATH_SEP, -1); + filter_string_list(&ceiling_dirs, 0, + normalize_ceiling_entry, NULL); + len = longest_ancestor_length(path, &ceiling_dirs); + string_list_clear(&ceiling_dirs, 0); + free(path); + printf("%d\n", len); + return 0; + } + + if (argc >= 4 && !strcmp(argv[1], "prefix_path")) { + const char *prefix = argv[2]; + int prefix_len = strlen(prefix); + int nongit_ok; + setup_git_directory_gently(&nongit_ok); + while (argc > 3) { + puts(prefix_path(prefix, prefix_len, argv[3])); + argc--; + argv++; + } + return 0; + } + + if (argc == 4 && !strcmp(argv[1], "strip_path_suffix")) { + char *prefix = strip_path_suffix(argv[2], argv[3]); + printf("%s\n", prefix ? prefix : "(null)"); + return 0; + } + + if (argc == 3 && !strcmp(argv[1], "print_path")) { + puts(argv[2]); + return 0; + } + + if (argc == 4 && !strcmp(argv[1], "relative_path")) { + struct strbuf sb = STRBUF_INIT; + const char *in, *prefix, *rel; + normalize_argv_string(&in, argv[2]); + normalize_argv_string(&prefix, argv[3]); + rel = relative_path(in, prefix, &sb); + if (!rel) + puts("(null)"); + else + puts(strlen(rel) > 0 ? rel : "(empty)"); + strbuf_release(&sb); + return 0; + } + + if (argc == 2 && !strcmp(argv[1], "basename")) + return test_function(basename_data, basename, argv[1]); + + if (argc == 2 && !strcmp(argv[1], "dirname")) + return test_function(dirname_data, dirname, argv[1]); + + fprintf(stderr, "%s: unknown function name: %s\n", argv[0], + argv[1] ? argv[1] : "(there was none)"); + return 1; +} diff --git a/t/helper/test-prio-queue.c b/t/helper/test-prio-queue.c new file mode 100644 index 0000000000..ae58fff359 --- /dev/null +++ b/t/helper/test-prio-queue.c @@ -0,0 +1,39 @@ +#include "cache.h" +#include "prio-queue.h" + +static int intcmp(const void *va, const void *vb, void *data) +{ + const int *a = va, *b = vb; + return *a - *b; +} + +static void show(int *v) +{ + if (!v) + printf("NULL\n"); + else + printf("%d\n", *v); + free(v); +} + +int cmd_main(int argc, const char **argv) +{ + struct prio_queue pq = { intcmp }; + + while (*++argv) { + if (!strcmp(*argv, "get")) + show(prio_queue_get(&pq)); + else if (!strcmp(*argv, "dump")) { + int *v; + while ((v = prio_queue_get(&pq))) + show(v); + } + else { + int *v = malloc(sizeof(*v)); + *v = atoi(*argv); + prio_queue_put(&pq, v); + } + } + + return 0; +} diff --git a/t/helper/test-read-cache.c b/t/helper/test-read-cache.c new file mode 100644 index 0000000000..2a7990efc3 --- /dev/null +++ b/t/helper/test-read-cache.c @@ -0,0 +1,13 @@ +#include "cache.h" + +int cmd_main(int argc, const char **argv) +{ + int i, cnt = 1; + if (argc == 2) + cnt = strtol(argv[1], NULL, 0); + for (i = 0; i < cnt; i++) { + read_cache(); + discard_cache(); + } + return 0; +} diff --git a/t/helper/test-regex.c b/t/helper/test-regex.c new file mode 100644 index 0000000000..b5ea8a97c5 --- /dev/null +++ b/t/helper/test-regex.c @@ -0,0 +1,75 @@ +#include "git-compat-util.h" +#include "gettext.h" + +struct reg_flag { + const char *name; + int flag; +}; + +static struct reg_flag reg_flags[] = { + { "EXTENDED", REG_EXTENDED }, + { "NEWLINE", REG_NEWLINE }, + { "ICASE", REG_ICASE }, + { "NOTBOL", REG_NOTBOL }, +#ifdef REG_STARTEND + { "STARTEND", REG_STARTEND }, +#endif + { NULL, 0 } +}; + +static int test_regex_bug(void) +{ + char *pat = "[^={} \t]+"; + char *str = "={}\nfred"; + regex_t r; + regmatch_t m[1]; + + if (regcomp(&r, pat, REG_EXTENDED | REG_NEWLINE)) + die("failed regcomp() for pattern '%s'", pat); + if (regexec(&r, str, 1, m, 0)) + die("no match of pattern '%s' to string '%s'", pat, str); + + /* http://sourceware.org/bugzilla/show_bug.cgi?id=3957 */ + if (m[0].rm_so == 3) /* matches '\n' when it should not */ + die("regex bug confirmed: re-build git with NO_REGEX=1"); + + return 0; +} + +int cmd_main(int argc, const char **argv) +{ + const char *pat; + const char *str; + int flags = 0; + regex_t r; + regmatch_t m[1]; + + if (argc == 2 && !strcmp(argv[1], "--bug")) + return test_regex_bug(); + else if (argc < 3) + usage("test-regex --bug\n" + "test-regex <pattern> <string> [<options>]"); + + argv++; + pat = *argv++; + str = *argv++; + while (*argv) { + struct reg_flag *rf; + for (rf = reg_flags; rf->name; rf++) + if (!strcmp(*argv, rf->name)) { + flags |= rf->flag; + break; + } + if (!rf->name) + die("do not recognize %s", *argv); + argv++; + } + git_setup_gettext(); + + if (regcomp(&r, pat, flags)) + die("failed regcomp() for pattern '%s'", pat); + if (regexec(&r, str, 1, m, 0)) + return 1; + + return 0; +} diff --git a/t/helper/test-revision-walking.c b/t/helper/test-revision-walking.c new file mode 100644 index 0000000000..b8e6fe1d00 --- /dev/null +++ b/t/helper/test-revision-walking.c @@ -0,0 +1,68 @@ +/* + * test-revision-walking.c: test revision walking API. + * + * (C) 2012 Heiko Voigt <hvoigt@hvoigt.net> + * + * This code is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "cache.h" +#include "commit.h" +#include "diff.h" +#include "revision.h" + +static void print_commit(struct commit *commit) +{ + struct strbuf sb = STRBUF_INIT; + struct pretty_print_context ctx = {0}; + ctx.date_mode.type = DATE_NORMAL; + format_commit_message(commit, " %m %s", &sb, &ctx); + printf("%s\n", sb.buf); + strbuf_release(&sb); +} + +static int run_revision_walk(void) +{ + struct rev_info rev; + struct commit *commit; + const char *argv[] = {NULL, "--all", NULL}; + int argc = ARRAY_SIZE(argv) - 1; + int got_revision = 0; + + init_revisions(&rev, NULL); + setup_revisions(argc, argv, &rev, NULL); + if (prepare_revision_walk(&rev)) + die("revision walk setup failed"); + + while ((commit = get_revision(&rev)) != NULL) { + print_commit(commit); + got_revision = 1; + } + + reset_revision_walk(); + return got_revision; +} + +int cmd_main(int argc, const char **argv) +{ + if (argc < 2) + return 1; + + setup_git_directory(); + + if (!strcmp(argv[1], "run-twice")) { + printf("1st\n"); + if (!run_revision_walk()) + return 1; + printf("2nd\n"); + if (!run_revision_walk()) + return 1; + + return 0; + } + + fprintf(stderr, "check usage\n"); + return 1; +} diff --git a/t/helper/test-run-command.c b/t/helper/test-run-command.c new file mode 100644 index 0000000000..d24d157379 --- /dev/null +++ b/t/helper/test-run-command.c @@ -0,0 +1,87 @@ +/* + * test-run-command.c: test run command API. + * + * (C) 2009 Ilari Liusvaara <ilari.liusvaara@elisanet.fi> + * + * This code is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "git-compat-util.h" +#include "run-command.h" +#include "argv-array.h" +#include "strbuf.h" +#include <string.h> +#include <errno.h> + +static int number_callbacks; +static int parallel_next(struct child_process *cp, + struct strbuf *err, + void *cb, + void **task_cb) +{ + struct child_process *d = cb; + if (number_callbacks >= 4) + return 0; + + argv_array_pushv(&cp->args, d->argv); + strbuf_addstr(err, "preloaded output of a child\n"); + number_callbacks++; + return 1; +} + +static int no_job(struct child_process *cp, + struct strbuf *err, + void *cb, + void **task_cb) +{ + strbuf_addstr(err, "no further jobs available\n"); + return 0; +} + +static int task_finished(int result, + struct strbuf *err, + void *pp_cb, + void *pp_task_cb) +{ + strbuf_addstr(err, "asking for a quick stop\n"); + return 1; +} + +int cmd_main(int argc, const char **argv) +{ + struct child_process proc = CHILD_PROCESS_INIT; + int jobs; + + if (argc < 3) + return 1; + proc.argv = (const char **)argv + 2; + + if (!strcmp(argv[1], "start-command-ENOENT")) { + if (start_command(&proc) < 0 && errno == ENOENT) + return 0; + fprintf(stderr, "FAIL %s\n", argv[1]); + return 1; + } + if (!strcmp(argv[1], "run-command")) + exit(run_command(&proc)); + + jobs = atoi(argv[2]); + proc.argv = (const char **)argv + 3; + + if (!strcmp(argv[1], "run-command-parallel")) + exit(run_processes_parallel(jobs, parallel_next, + NULL, NULL, &proc)); + + if (!strcmp(argv[1], "run-command-abort")) + exit(run_processes_parallel(jobs, parallel_next, + NULL, task_finished, &proc)); + + if (!strcmp(argv[1], "run-command-no-jobs")) + exit(run_processes_parallel(jobs, no_job, + NULL, task_finished, &proc)); + + fprintf(stderr, "check usage\n"); + return 1; +} diff --git a/t/helper/test-scrap-cache-tree.c b/t/helper/test-scrap-cache-tree.c new file mode 100644 index 0000000000..5b2fd09908 --- /dev/null +++ b/t/helper/test-scrap-cache-tree.c @@ -0,0 +1,17 @@ +#include "cache.h" +#include "lockfile.h" +#include "tree.h" +#include "cache-tree.h" + +static struct lock_file index_lock; + +int cmd_main(int ac, const char **av) +{ + hold_locked_index(&index_lock, 1); + if (read_cache() < 0) + die("unable to read index file"); + active_cache_tree = NULL; + if (write_locked_index(&the_index, &index_lock, COMMIT_LOCK)) + die("unable to write index file"); + return 0; +} diff --git a/t/helper/test-sha1-array.c b/t/helper/test-sha1-array.c new file mode 100644 index 0000000000..09f7790971 --- /dev/null +++ b/t/helper/test-sha1-array.c @@ -0,0 +1,34 @@ +#include "cache.h" +#include "sha1-array.h" + +static void print_sha1(const unsigned char sha1[20], void *data) +{ + puts(sha1_to_hex(sha1)); +} + +int cmd_main(int argc, const char **argv) +{ + struct sha1_array array = SHA1_ARRAY_INIT; + struct strbuf line = STRBUF_INIT; + + while (strbuf_getline(&line, stdin) != EOF) { + const char *arg; + unsigned char sha1[20]; + + if (skip_prefix(line.buf, "append ", &arg)) { + if (get_sha1_hex(arg, sha1)) + die("not a hexadecimal SHA1: %s", arg); + sha1_array_append(&array, sha1); + } else if (skip_prefix(line.buf, "lookup ", &arg)) { + if (get_sha1_hex(arg, sha1)) + die("not a hexadecimal SHA1: %s", arg); + printf("%d\n", sha1_array_lookup(&array, sha1)); + } else if (!strcmp(line.buf, "clear")) + sha1_array_clear(&array); + else if (!strcmp(line.buf, "for_each_unique")) + sha1_array_for_each_unique(&array, print_sha1, NULL); + else + die("unknown command: %s", line.buf); + } + return 0; +} diff --git a/t/helper/test-sha1.c b/t/helper/test-sha1.c new file mode 100644 index 0000000000..a1c13f54ec --- /dev/null +++ b/t/helper/test-sha1.c @@ -0,0 +1,56 @@ +#include "cache.h" + +int cmd_main(int ac, const char **av) +{ + git_SHA_CTX ctx; + unsigned char sha1[20]; + unsigned bufsz = 8192; + int binary = 0; + char *buffer; + + if (ac == 2) { + if (!strcmp(av[1], "-b")) + binary = 1; + else + bufsz = strtoul(av[1], NULL, 10) * 1024 * 1024; + } + + if (!bufsz) + bufsz = 8192; + + while ((buffer = malloc(bufsz)) == NULL) { + fprintf(stderr, "bufsz %u is too big, halving...\n", bufsz); + bufsz /= 2; + if (bufsz < 1024) + die("OOPS"); + } + + git_SHA1_Init(&ctx); + + while (1) { + ssize_t sz, this_sz; + char *cp = buffer; + unsigned room = bufsz; + this_sz = 0; + while (room) { + sz = xread(0, cp, room); + if (sz == 0) + break; + if (sz < 0) + die_errno("test-sha1"); + this_sz += sz; + cp += sz; + room -= sz; + } + if (this_sz == 0) + break; + git_SHA1_Update(&ctx, buffer, this_sz); + } + git_SHA1_Final(sha1, &ctx); + + if (binary) + fwrite(sha1, 1, 20, stdout); + else + puts(sha1_to_hex(sha1)); + exit(0); +} diff --git a/t/helper/test-sha1.sh b/t/helper/test-sha1.sh new file mode 100755 index 0000000000..750b95a0a1 --- /dev/null +++ b/t/helper/test-sha1.sh @@ -0,0 +1,83 @@ +#!/bin/sh + +dd if=/dev/zero bs=1048576 count=100 2>/dev/null | +/usr/bin/time t/helper/test-sha1 >/dev/null + +while read expect cnt pfx +do + case "$expect" in '#'*) continue ;; esac + actual=$( + { + test -z "$pfx" || echo "$pfx" + dd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null | + perl -pe 'y/\000/g/' + } | ./t/helper/test-sha1 $cnt + ) + if test "$expect" = "$actual" + then + echo "OK: $expect $cnt $pfx" + else + echo >&2 "OOPS: $cnt" + echo >&2 "expect: $expect" + echo >&2 "actual: $actual" + exit 1 + fi +done <<EOF +da39a3ee5e6b4b0d3255bfef95601890afd80709 0 +3f786850e387550fdab836ed7e6dc881de23001b 0 a +5277cbb45a15902137d332d97e89cf8136545485 0 ab +03cfd743661f07975fa2f1220c5194cbaff48451 0 abc +3330b4373640f9e4604991e73c7e86bfd8da2dc3 0 abcd +ec11312386ad561674f724b8cca7cf1796e26d1d 0 abcde +bdc37c074ec4ee6050d68bc133c6b912f36474df 0 abcdef +69bca99b923859f2dc486b55b87f49689b7358c7 0 abcdefg +e414af7161c9554089f4106d6f1797ef14a73666 0 abcdefgh +0707f2970043f9f7c22029482db27733deaec029 0 abcdefghi +a4dd8aa74a5636728fe52451636e2e17726033aa 1 +9986b45e2f4d7086372533bb6953a8652fa3644a 1 frotz +23d8d4f788e8526b4877548a32577543cbaaf51f 10 +8cd23f822ab44c7f481b8c92d591f6d1fcad431c 10 frotz +f3b5604a4e604899c1233edb3bf1cc0ede4d8c32 512 +b095bd837a371593048136e429e9ac4b476e1bb3 512 frotz +08fa81d6190948de5ccca3966340cc48c10cceac 1200 xyzzy +e33a291f42c30a159733dd98b8b3e4ff34158ca0 4090 4G +#a3bf783bc20caa958f6cb24dd140a7b21984838d 9999 nitfol +EOF + +exit + +# generating test vectors +# inputs are number of megabytes followed by some random string to prefix. + +while read cnt pfx +do + actual=$( + { + test -z "$pfx" || echo "$pfx" + dd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null | + perl -pe 'y/\000/g/' + } | sha1sum | + sed -e 's/ .*//' + ) + echo "$actual $cnt $pfx" +done <<EOF +0 +0 a +0 ab +0 abc +0 abcd +0 abcde +0 abcdef +0 abcdefg +0 abcdefgh +0 abcdefghi +1 +1 frotz +10 +10 frotz +512 +512 frotz +1200 xyzzy +4090 4G +9999 nitfol +EOF diff --git a/t/helper/test-sigchain.c b/t/helper/test-sigchain.c new file mode 100644 index 0000000000..b71edbd442 --- /dev/null +++ b/t/helper/test-sigchain.c @@ -0,0 +1,22 @@ +#include "cache.h" +#include "sigchain.h" + +#define X(f) \ +static void f(int sig) { \ + puts(#f); \ + fflush(stdout); \ + sigchain_pop(sig); \ + raise(sig); \ +} +X(one) +X(two) +X(three) +#undef X + +int cmd_main(int argc, const char **argv) { + sigchain_push(SIGTERM, one); + sigchain_push(SIGTERM, two); + sigchain_push(SIGTERM, three); + raise(SIGTERM); + return 0; +} diff --git a/t/helper/test-string-list.c b/t/helper/test-string-list.c new file mode 100644 index 0000000000..4a68967bd1 --- /dev/null +++ b/t/helper/test-string-list.c @@ -0,0 +1,103 @@ +#include "cache.h" +#include "string-list.h" + +/* + * Parse an argument into a string list. arg should either be a + * ':'-separated list of strings, or "-" to indicate an empty string + * list (as opposed to "", which indicates a string list containing a + * single empty string). list->strdup_strings must be set. + */ +static void parse_string_list(struct string_list *list, const char *arg) +{ + if (!strcmp(arg, "-")) + return; + + (void)string_list_split(list, arg, ':', -1); +} + +static void write_list(const struct string_list *list) +{ + int i; + for (i = 0; i < list->nr; i++) + printf("[%d]: \"%s\"\n", i, list->items[i].string); +} + +static void write_list_compact(const struct string_list *list) +{ + int i; + if (!list->nr) + printf("-\n"); + else { + printf("%s", list->items[0].string); + for (i = 1; i < list->nr; i++) + printf(":%s", list->items[i].string); + printf("\n"); + } +} + +static int prefix_cb(struct string_list_item *item, void *cb_data) +{ + const char *prefix = (const char *)cb_data; + return starts_with(item->string, prefix); +} + +int cmd_main(int argc, const char **argv) +{ + if (argc == 5 && !strcmp(argv[1], "split")) { + struct string_list list = STRING_LIST_INIT_DUP; + int i; + const char *s = argv[2]; + int delim = *argv[3]; + int maxsplit = atoi(argv[4]); + + i = string_list_split(&list, s, delim, maxsplit); + printf("%d\n", i); + write_list(&list); + string_list_clear(&list, 0); + return 0; + } + + if (argc == 5 && !strcmp(argv[1], "split_in_place")) { + struct string_list list = STRING_LIST_INIT_NODUP; + int i; + char *s = xstrdup(argv[2]); + int delim = *argv[3]; + int maxsplit = atoi(argv[4]); + + i = string_list_split_in_place(&list, s, delim, maxsplit); + printf("%d\n", i); + write_list(&list); + string_list_clear(&list, 0); + free(s); + return 0; + } + + if (argc == 4 && !strcmp(argv[1], "filter")) { + /* + * Retain only the items that have the specified prefix. + * Arguments: list|- prefix + */ + struct string_list list = STRING_LIST_INIT_DUP; + const char *prefix = argv[3]; + + parse_string_list(&list, argv[2]); + filter_string_list(&list, 0, prefix_cb, (void *)prefix); + write_list_compact(&list); + string_list_clear(&list, 0); + return 0; + } + + if (argc == 3 && !strcmp(argv[1], "remove_duplicates")) { + struct string_list list = STRING_LIST_INIT_DUP; + + parse_string_list(&list, argv[2]); + string_list_remove_duplicates(&list, 0); + write_list_compact(&list); + string_list_clear(&list, 0); + return 0; + } + + fprintf(stderr, "%s: unknown function name: %s\n", argv[0], + argv[1] ? argv[1] : "(there was none)"); + return 1; +} diff --git a/t/helper/test-submodule-config.c b/t/helper/test-submodule-config.c new file mode 100644 index 0000000000..2a50217bf5 --- /dev/null +++ b/t/helper/test-submodule-config.c @@ -0,0 +1,76 @@ +#include "cache.h" +#include "submodule-config.h" +#include "submodule.h" + +static void die_usage(int argc, const char **argv, const char *msg) +{ + fprintf(stderr, "%s\n", msg); + fprintf(stderr, "Usage: %s [<commit> <submodulepath>] ...\n", argv[0]); + exit(1); +} + +static int git_test_config(const char *var, const char *value, void *cb) +{ + return parse_submodule_config_option(var, value); +} + +int cmd_main(int argc, const char **argv) +{ + const char **arg = argv; + int my_argc = argc; + int output_url = 0; + int lookup_name = 0; + + arg++; + my_argc--; + while (arg[0] && starts_with(arg[0], "--")) { + if (!strcmp(arg[0], "--url")) + output_url = 1; + if (!strcmp(arg[0], "--name")) + lookup_name = 1; + arg++; + my_argc--; + } + + if (my_argc % 2 != 0) + die_usage(argc, argv, "Wrong number of arguments."); + + setup_git_directory(); + gitmodules_config(); + git_config(git_test_config, NULL); + + while (*arg) { + unsigned char commit_sha1[20]; + const struct submodule *submodule; + const char *commit; + const char *path_or_name; + + commit = arg[0]; + path_or_name = arg[1]; + + if (commit[0] == '\0') + hashcpy(commit_sha1, null_sha1); + else if (get_sha1(commit, commit_sha1) < 0) + die_usage(argc, argv, "Commit not found."); + + if (lookup_name) { + submodule = submodule_from_name(commit_sha1, path_or_name); + } else + submodule = submodule_from_path(commit_sha1, path_or_name); + if (!submodule) + die_usage(argc, argv, "Submodule not found."); + + if (output_url) + printf("Submodule url: '%s' for path '%s'\n", + submodule->url, submodule->path); + else + printf("Submodule name: '%s' for path '%s'\n", + submodule->name, submodule->path); + + arg += 2; + } + + submodule_free(); + + return 0; +} diff --git a/t/helper/test-subprocess.c b/t/helper/test-subprocess.c new file mode 100644 index 0000000000..30c5765bfc --- /dev/null +++ b/t/helper/test-subprocess.c @@ -0,0 +1,19 @@ +#include "cache.h" +#include "run-command.h" + +int cmd_main(int argc, const char **argv) +{ + struct child_process cp = CHILD_PROCESS_INIT; + int nogit = 0; + + setup_git_directory_gently(&nogit); + if (nogit) + die("No git repo found"); + if (argc > 1 && !strcmp(argv[1], "--setup-work-tree")) { + setup_work_tree(); + argv++; + } + cp.git_cmd = 1; + cp.argv = (const char **)argv + 1; + return run_command(&cp); +} diff --git a/t/helper/test-svn-fe.c b/t/helper/test-svn-fe.c new file mode 100644 index 0000000000..7667c0803f --- /dev/null +++ b/t/helper/test-svn-fe.c @@ -0,0 +1,52 @@ +/* + * test-svn-fe: Code to exercise the svn import lib + */ + +#include "git-compat-util.h" +#include "vcs-svn/svndump.h" +#include "vcs-svn/svndiff.h" +#include "vcs-svn/sliding_window.h" +#include "vcs-svn/line_buffer.h" + +static const char test_svnfe_usage[] = + "test-svn-fe (<dumpfile> | [-d] <preimage> <delta> <len>)"; + +static int apply_delta(int argc, const char **argv) +{ + struct line_buffer preimage = LINE_BUFFER_INIT; + struct line_buffer delta = LINE_BUFFER_INIT; + struct sliding_view preimage_view = SLIDING_VIEW_INIT(&preimage, -1); + + if (argc != 5) + usage(test_svnfe_usage); + + if (buffer_init(&preimage, argv[2])) + die_errno("cannot open preimage"); + if (buffer_init(&delta, argv[3])) + die_errno("cannot open delta"); + if (svndiff0_apply(&delta, (off_t) strtoumax(argv[4], NULL, 0), + &preimage_view, stdout)) + return 1; + if (buffer_deinit(&preimage)) + die_errno("cannot close preimage"); + if (buffer_deinit(&delta)) + die_errno("cannot close delta"); + strbuf_release(&preimage_view.buf); + return 0; +} + +int cmd_main(int argc, const char **argv) +{ + if (argc == 2) { + if (svndump_init(argv[1])) + return 1; + svndump_read(NULL, "refs/heads/master", "refs/notes/svn/revs"); + svndump_deinit(); + svndump_reset(); + return 0; + } + + if (argc >= 2 && !strcmp(argv[1], "-d")) + return apply_delta(argc, argv); + usage(test_svnfe_usage); +} diff --git a/t/helper/test-urlmatch-normalization.c b/t/helper/test-urlmatch-normalization.c new file mode 100644 index 0000000000..49b6e836be --- /dev/null +++ b/t/helper/test-urlmatch-normalization.c @@ -0,0 +1,50 @@ +#include "git-compat-util.h" +#include "urlmatch.h" + +int cmd_main(int argc, const char **argv) +{ + const char usage[] = "test-urlmatch-normalization [-p | -l] <url1> | <url1> <url2>"; + char *url1, *url2; + int opt_p = 0, opt_l = 0; + + /* + * For one url, succeed if url_normalize succeeds on it, fail otherwise. + * For two urls, succeed only if url_normalize succeeds on both and + * the results compare equal with strcmp. If -p is given (one url only) + * and url_normalize succeeds, print the result followed by "\n". If + * -l is given (one url only) and url_normalize succeeds, print the + * returned length in decimal followed by "\n". + */ + + if (argc > 1 && !strcmp(argv[1], "-p")) { + opt_p = 1; + argc--; + argv++; + } else if (argc > 1 && !strcmp(argv[1], "-l")) { + opt_l = 1; + argc--; + argv++; + } + + if (argc < 2 || argc > 3) + die("%s", usage); + + if (argc == 2) { + struct url_info info; + url1 = url_normalize(argv[1], &info); + if (!url1) + return 1; + if (opt_p) + printf("%s\n", url1); + if (opt_l) + printf("%u\n", (unsigned)info.url_len); + return 0; + } + + if (opt_p || opt_l) + die("%s", usage); + + url1 = url_normalize(argv[1], NULL); + url2 = url_normalize(argv[2], NULL); + return (url1 && url2 && !strcmp(url1, url2)) ? 0 : 1; +} diff --git a/t/helper/test-wildmatch.c b/t/helper/test-wildmatch.c new file mode 100644 index 0000000000..52be876fed --- /dev/null +++ b/t/helper/test-wildmatch.c @@ -0,0 +1,21 @@ +#include "cache.h" + +int cmd_main(int argc, const char **argv) +{ + int i; + for (i = 2; i < argc; i++) { + if (argv[i][0] == '/') + die("Forward slash is not allowed at the beginning of the\n" + "pattern because Windows does not like it. Use `XXX/' instead."); + else if (!strncmp(argv[i], "XXX/", 4)) + argv[i] += 3; + } + if (!strcmp(argv[1], "wildmatch")) + return !!wildmatch(argv[3], argv[2], WM_PATHNAME, NULL); + else if (!strcmp(argv[1], "iwildmatch")) + return !!wildmatch(argv[3], argv[2], WM_PATHNAME | WM_CASEFOLD, NULL); + else if (!strcmp(argv[1], "pathmatch")) + return !!wildmatch(argv[3], argv[2], 0, NULL); + else + return 1; +} diff --git a/t/lib-git-daemon.sh b/t/lib-git-daemon.sh index 340534c064..f9cbd47931 100644 --- a/t/lib-git-daemon.sh +++ b/t/lib-git-daemon.sh @@ -82,8 +82,7 @@ stop_git_daemon() { kill "$GIT_DAEMON_PID" wait "$GIT_DAEMON_PID" >&3 2>&4 ret=$? - # expect exit with status 143 = 128+15 for signal TERM=15 - if test $ret -ne 143 + if test_match_signal 15 $? then error "git daemon exited with status: $ret" fi diff --git a/t/lib-git-p4.sh b/t/lib-git-p4.sh index 012d40e746..54fd5a6ca0 100644 --- a/t/lib-git-p4.sh +++ b/t/lib-git-p4.sh @@ -33,7 +33,7 @@ fi # Older versions of perforce were available compiled natively for # cygwin. Those do not accept native windows paths, so make sure # not to convert for them. -native_path() { +native_path () { path="$1" && if test_have_prereq CYGWIN && ! p4 -V | grep -q CYGWIN then @@ -49,7 +49,7 @@ native_path() { # Attention: This function is not safe again against time offset updates # at runtime (e.g. via NTP). The 'clock_gettime(CLOCK_MONOTONIC)' # function could fix that but it is not in Python until 3.3. -time_in_seconds() { +time_in_seconds () { (cd / && "$PYTHON_PATH" -c 'import time; print(int(time.time()))') } @@ -75,7 +75,7 @@ git="$TRASH_DIRECTORY/git" pidfile="$TRASH_DIRECTORY/p4d.pid" # Sometimes "prove" seems to hang on exit because p4d is still running -cleanup() { +cleanup () { if test -f "$pidfile" then kill -9 $(cat "$pidfile") 2>/dev/null && exit 255 @@ -89,7 +89,7 @@ trap cleanup EXIT TMPDIR="$TRASH_DIRECTORY" export TMPDIR -start_p4d() { +start_p4d () { mkdir -p "$db" "$cli" "$git" && rm -f "$pidfile" && ( @@ -151,7 +151,7 @@ start_p4d() { return 0 } -p4_add_user() { +p4_add_user () { name=$1 && p4 user -f -i <<-EOF User: $name @@ -160,7 +160,16 @@ p4_add_user() { EOF } -retry_until_success() { +p4_add_job () { + p4 job -f -i <<-EOF + Job: $1 + Status: open + User: dummy + Description: + EOF +} + +retry_until_success () { timeout=$(($(time_in_seconds) + $RETRY_TIMEOUT)) until "$@" 2>/dev/null || test $(time_in_seconds) -gt $timeout do @@ -168,7 +177,7 @@ retry_until_success() { done } -retry_until_fail() { +retry_until_fail () { timeout=$(($(time_in_seconds) + $RETRY_TIMEOUT)) until ! "$@" 2>/dev/null || test $(time_in_seconds) -gt $timeout do @@ -176,7 +185,7 @@ retry_until_fail() { done } -kill_p4d() { +kill_p4d () { pid=$(cat "$pidfile") retry_until_fail kill $pid retry_until_fail kill -9 $pid @@ -186,13 +195,13 @@ kill_p4d() { retry_until_fail kill -9 $watchdog_pid } -cleanup_git() { +cleanup_git () { retry_until_success rm -r "$git" test_must_fail test -d "$git" && retry_until_success mkdir "$git" } -marshal_dump() { +marshal_dump () { what=$1 && line=${2:-1} && cat >"$TRASH_DIRECTORY/marshal-dump.py" <<-EOF && @@ -209,7 +218,7 @@ marshal_dump() { # # Construct a client with this list of View lines # -client_view() { +client_view () { ( cat <<-EOF && Client: $P4CLIENT @@ -223,7 +232,7 @@ client_view() { ) | p4 client -i } -is_cli_file_writeable() { +is_cli_file_writeable () { # cygwin version of p4 does not set read-only attr, # will be marked 444 but -w is true file="$1" && diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh index 6a50b8793e..fb8823224e 100644 --- a/t/lib-git-svn.sh +++ b/t/lib-git-svn.sh @@ -1,8 +1,5 @@ . ./test-lib.sh -remotes_git_svn=remotes/git""-svn -git_svn_id=git""-svn-id - if test -n "$NO_SVN_TESTS" then skip_all='skipping git svn tests, NO_SVN_TESTS defined' diff --git a/t/lib-gpg.sh b/t/lib-gpg.sh index db2ef22e8f..ec2aa8f687 100755 --- a/t/lib-gpg.sh +++ b/t/lib-gpg.sh @@ -1,9 +1,8 @@ #!/bin/sh gpg_version=$(gpg --version 2>&1) -if test $? = 127; then - say "You do not seem to have gpg installed" -else +if test $? != 127 +then # As said here: http://www.gnupg.org/documentation/faqs.html#q6.19 # the gpg version 1.0.6 didn't parse trust packets correctly, so for # that version, creation of signed tags using the generated key fails. diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf index 9317ba0858..018a83a5a1 100644 --- a/t/lib-httpd/apache.conf +++ b/t/lib-httpd/apache.conf @@ -102,6 +102,10 @@ Alias /auth/dumb/ www/auth/dumb/ SetEnv GIT_HTTP_EXPORT_ALL Header set Set-Cookie name=value </LocationMatch> +<LocationMatch /smart_headers/> + SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH} + SetEnv GIT_HTTP_EXPORT_ALL +</LocationMatch> ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1 ScriptAlias /broken_smart/ broken-smart-http.sh/ ScriptAlias /error/ error.sh/ @@ -128,6 +132,18 @@ RewriteRule ^/ftp-redir/(.*)$ ftp://localhost:1000/$1 [R=302] RewriteRule ^/loop-redir/x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-(.*) /$1 [R=302] RewriteRule ^/loop-redir/(.*)$ /loop-redir/x-$1 [R=302] +# Apache 2.2 does not understand <RequireAll>, so we use RewriteCond. +# And as RewriteCond does not allow testing for non-matches, we match +# the desired case first (one has abra, two has cadabra), and let it +# pass by marking the RewriteRule as [L], "last rule, do not process +# any other matching RewriteRules after this"), and then have another +# RewriteRule that matches all other cases and lets them fail via '[F]', +# "fail the request". +RewriteCond %{HTTP:x-magic-one} =abra +RewriteCond %{HTTP:x-magic-two} =cadabra +RewriteRule ^/smart_headers/.* - [L] +RewriteRule ^/smart_headers/.* - [F] + <IfDefine SSL> LoadModule ssl_module modules/mod_ssl.so diff --git a/t/perf/p3404-rebase-interactive.sh b/t/perf/p3404-rebase-interactive.sh new file mode 100755 index 0000000000..88f47de282 --- /dev/null +++ b/t/perf/p3404-rebase-interactive.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +test_description='Tests rebase -i performance' +. ./perf-lib.sh + +test_perf_default_repo + +# This commit merges a sufficiently long topic branch for reasonable +# performance testing +branch_merge=ba5312da19c6fdb6c6747d479f58932aae6e900c^{commit} +export branch_merge + +git rev-parse --verify $branch_merge >/dev/null 2>&1 || { + skip_all='skipping because $branch_merge was not found' + test_done +} + +write_script swap-first-two.sh <<\EOF +case "$1" in +*/COMMIT_EDITMSG) + mv "$1" "$1".bak && + sed -e '1{h;d}' -e 2G <"$1".bak >"$1" + ;; +esac +EOF + +test_expect_success 'setup' ' + git config core.editor "\"$PWD"/swap-first-two.sh\" && + git checkout -f $branch_merge^2 +' + +test_perf 'rebase -i' ' + git rebase -i $branch_merge^ +' + +test_done diff --git a/t/perf/perf-lib.sh b/t/perf/perf-lib.sh index 5cf74eddec..773f955d4a 100644 --- a/t/perf/perf-lib.sh +++ b/t/perf/perf-lib.sh @@ -80,23 +80,29 @@ test_perf_create_repo_from () { error "bug in the test script: not 2 parameters to test-create-repo" repo="$1" source="$2" - source_git=$source/$(cd "$source" && git rev-parse --git-dir) + source_git="$(git -C "$source" rev-parse --git-dir)" + objects_dir="$(git -C "$source" rev-parse --git-path objects)" mkdir -p "$repo/.git" ( - cd "$repo/.git" && - { cp -Rl "$source_git/objects" . 2>/dev/null || - cp -R "$source_git/objects" .; } && + cd "$source" && + { cp -Rl "$objects_dir" "$repo/.git/" 2>/dev/null || + cp -R "$objects_dir" "$repo/.git/"; } && for stuff in "$source_git"/*; do case "$stuff" in - */objects|*/hooks|*/config) + */objects|*/hooks|*/config|*/commondir) ;; *) - cp -R "$stuff" . || exit 1 + cp -R "$stuff" "$repo/.git/" || exit 1 ;; esac - done && - cd .. && - git init -q && + done + ) && + ( + cd "$repo" && + git init -q && { + test_have_prereq SYMLINKS || + git config core.symlinks false + } && mv .git/hooks .git/hooks-disabled 2>/dev/null ) || error "failed to copy repository '$source' to '$repo'" } @@ -121,11 +127,15 @@ test_checkout_worktree () { # Performance tests should never fail. If they do, stop immediately immediate=t +# Perf tests require GNU time +case "$(uname -s)" in Darwin) GTIME="${GTIME:-gtime}";; esac +GTIME="${GTIME:-/usr/bin/time}" + test_run_perf_ () { test_cleanup=: test_export_="test_cleanup" export test_cleanup test_export_ - /usr/bin/time -f "%E %U %S" -o test_time.$i "$SHELL" -c ' + "$GTIME" -f "%E %U %S" -o test_time.$i "$SHELL" -c ' . '"$TEST_DIRECTORY"/test-lib-functions.sh' test_export () { [ $# != 0 ] || return 0 diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 60811a3a7c..1aa5093f36 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -834,7 +834,7 @@ test_expect_success 'git write-tree should be able to write an empty tree' ' ' test_expect_success 'validate object ID of a known tree' ' - test "$tree" = 4b825dc642cb6eb9a060e54bf8d69288fbee4904 + test "$tree" = $EMPTY_TREE ' # Various types of objects diff --git a/t/t0005-signals.sh b/t/t0005-signals.sh index e7f27ebbc1..46042f1f13 100755 --- a/t/t0005-signals.sh +++ b/t/t0005-signals.sh @@ -11,12 +11,13 @@ EOF test_expect_success 'sigchain works' ' { test-sigchain >actual; ret=$?; } && - case "$ret" in - 143) true ;; # POSIX w/ SIGTERM=15 - 271) true ;; # ksh w/ SIGTERM=15 - 3) true ;; # Windows - *) false ;; - esac && + { + # Signal death by raise() on Windows acts like exit(3), + # regardless of the signal number. So we must allow that + # as well as the normal signal check. + test_match_signal 15 "$ret" || + test "$ret" = 3 + } && test_cmp expect actual ' @@ -41,12 +42,12 @@ test_expect_success 'create blob' ' test_expect_success !MINGW 'a constipated git dies with SIGPIPE' ' OUT=$( ((large_git; echo $? 1>&3) | :) 3>&1 ) && - test "$OUT" -eq 141 + test_match_signal 13 "$OUT" ' test_expect_success !MINGW 'a constipated git dies with SIGPIPE even if parent ignores it' ' OUT=$( ((trap "" PIPE; large_git; echo $? 1>&3) | :) 3>&1 ) && - test "$OUT" -eq 141 + test_match_signal 13 "$OUT" ' test_done diff --git a/t/t0006-date.sh b/t/t0006-date.sh index fac0986134..c0c910867d 100755 --- a/t/t0006-date.sh +++ b/t/t0006-date.sh @@ -6,26 +6,55 @@ test_description='test date parsing and printing' # arbitrary reference time: 2009-08-30 19:20:00 TEST_DATE_NOW=1251660000; export TEST_DATE_NOW -check_show() { +check_relative() { t=$(($TEST_DATE_NOW - $1)) echo "$t -> $2" >expect test_expect_${3:-success} "relative date ($2)" " - test-date show $t >actual && + test-date relative $t >actual && test_i18ncmp expect actual " } -check_show 5 '5 seconds ago' -check_show 300 '5 minutes ago' -check_show 18000 '5 hours ago' -check_show 432000 '5 days ago' -check_show 1728000 '3 weeks ago' -check_show 13000000 '5 months ago' -check_show 37500000 '1 year, 2 months ago' -check_show 55188000 '1 year, 9 months ago' -check_show 630000000 '20 years ago' -check_show 31449600 '12 months ago' -check_show 62985600 '2 years ago' +check_relative 5 '5 seconds ago' +check_relative 300 '5 minutes ago' +check_relative 18000 '5 hours ago' +check_relative 432000 '5 days ago' +check_relative 1728000 '3 weeks ago' +check_relative 13000000 '5 months ago' +check_relative 37500000 '1 year, 2 months ago' +check_relative 55188000 '1 year, 9 months ago' +check_relative 630000000 '20 years ago' +check_relative 31449600 '12 months ago' +check_relative 62985600 '2 years ago' + +check_show () { + format=$1 + time=$2 + expect=$3 + test_expect_success $4 "show date ($format:$time)" ' + echo "$time -> $expect" >expect && + test-date show:$format "$time" >actual && + test_cmp expect actual + ' +} + +# arbitrary but sensible time for examples +TIME='1466000000 +0200' +check_show iso8601 "$TIME" '2016-06-15 16:13:20 +0200' +check_show iso8601-strict "$TIME" '2016-06-15T16:13:20+02:00' +check_show rfc2822 "$TIME" 'Wed, 15 Jun 2016 16:13:20 +0200' +check_show short "$TIME" '2016-06-15' +check_show default "$TIME" 'Wed Jun 15 16:13:20 2016 +0200' +check_show raw "$TIME" '1466000000 +0200' +check_show unix "$TIME" '1466000000' +check_show iso-local "$TIME" '2016-06-15 14:13:20 +0000' +check_show raw-local "$TIME" '1466000000 +0000' +check_show unix-local "$TIME" '1466000000' + +# arbitrary time absurdly far in the future +FUTURE="5758122296 -0400" +check_show iso "$FUTURE" "2152-06-19 18:24:56 -0400" LONG_IS_64BIT +check_show iso-local "$FUTURE" "2152-06-19 22:24:56 +0000" LONG_IS_64BIT check_parse() { echo "$1 -> $2" >expect diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh index 89544dd833..b425f3a0d2 100755 --- a/t/t0008-ignores.sh +++ b/t/t0008-ignores.sh @@ -605,7 +605,7 @@ cat <<-EOF >expected-verbose a/b/.gitignore:8:!on* a/b/one a/b/.gitignore:8:!on* a/b/one one a/b/.gitignore:8:!on* a/b/one two - a/b/.gitignore:8:!on* "a/b/one\"three" + a/b/.gitignore:8:!on* "a/b/one\\"three" a/b/.gitignore:9:!two a/b/two a/.gitignore:1:two* a/b/twooo $global_excludes:2:!globaltwo globaltwo @@ -686,7 +686,7 @@ cat <<-EOF >expected-all a/b/.gitignore:8:!on* b/one a/b/.gitignore:8:!on* b/one one a/b/.gitignore:8:!on* b/one two - a/b/.gitignore:8:!on* "b/one\"three" + a/b/.gitignore:8:!on* "b/one\\"three" a/b/.gitignore:9:!two b/two :: b/not-ignored a/.gitignore:1:two* b/twooo diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh index 7bac2bcf26..e799e59544 100755 --- a/t/t0021-conversion.sh +++ b/t/t0021-conversion.sh @@ -268,4 +268,15 @@ test_expect_success 'disable filter with empty override' ' test_must_be_empty err ' +test_expect_success 'diff does not reuse worktree files that need cleaning' ' + test_config filter.counter.clean "echo . >>count; sed s/^/clean:/" && + echo "file filter=counter" >.gitattributes && + test_commit one file && + test_commit two file && + + >count && + git diff-tree -p HEAD && + test_line_count = 0 count +' + test_done diff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh index c164b4662a..d0bee08b2e 100755 --- a/t/t0025-crlf-auto.sh +++ b/t/t0025-crlf-auto.sh @@ -114,7 +114,7 @@ test_expect_success 'autocrlf=true does not normalize CRLF files' ' test -z "$LFonlydiff" -a -z "$CRLFonlydiff" -a -z "$LFwithNULdiff" ' -test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' ' +test_expect_success 'text=auto, autocrlf=true does not normalize CRLF files' ' rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && git config core.autocrlf true && @@ -126,7 +126,7 @@ test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' ' LFonlydiff=$(git diff LFonly) && CRLFonlydiff=$(git diff CRLFonly) && LFwithNULdiff=$(git diff LFwithNUL) && - test -z "$LFonlydiff" -a -n "$CRLFonlydiff" -a -z "$LFwithNULdiff" + test -z "$LFonlydiff" -a -z "$CRLFonlydiff" -a -z "$LFwithNULdiff" ' test_expect_success 'text=auto, autocrlf=true does not normalize binary files' ' diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh index 93725895a4..2860d2d08b 100755 --- a/t/t0027-auto-crlf.sh +++ b/t/t0027-auto-crlf.sh @@ -175,8 +175,8 @@ attr_ascii () { text,lf) echo "text eol=lf" ;; text,crlf) echo "text eol=crlf" ;; auto,) echo "text=auto" ;; - auto,lf) echo "text eol=lf" ;; - auto,crlf) echo "text eol=crlf" ;; + auto,lf) echo "text=auto eol=lf" ;; + auto,crlf) echo "text=auto eol=crlf" ;; lf,) echo "text eol=lf" ;; crlf,) echo "text eol=crlf" ;; ,) echo "" ;; @@ -397,10 +397,9 @@ commit_chk_wrnNNO "" "" false "" "" "" "" commit_chk_wrnNNO "" "" true LF_CRLF "" "" "" "" commit_chk_wrnNNO "" "" input "" "" "" "" "" -commit_chk_wrnNNO "auto" "" false "$WILC" "$WICL" "$WAMIX" "" "" -commit_chk_wrnNNO "auto" "" true LF_CRLF "" LF_CRLF "" "" -commit_chk_wrnNNO "auto" "" input "" CRLF_LF CRLF_LF "" "" - +commit_chk_wrnNNO "auto" "" false "$WILC" "" "" "" "" +commit_chk_wrnNNO "auto" "" true LF_CRLF "" "" "" "" +commit_chk_wrnNNO "auto" "" input "" "" "" "" "" for crlf in true false input do commit_chk_wrnNNO -text "" $crlf "" "" "" "" "" @@ -408,8 +407,8 @@ do commit_chk_wrnNNO -text crlf $crlf "" "" "" "" "" commit_chk_wrnNNO "" lf $crlf "" CRLF_LF CRLF_LF "" CRLF_LF commit_chk_wrnNNO "" crlf $crlf LF_CRLF "" LF_CRLF LF_CRLF "" - commit_chk_wrnNNO auto lf $crlf "" CRLF_LF CRLF_LF "" CRLF_LF - commit_chk_wrnNNO auto crlf $crlf LF_CRLF "" LF_CRLF LF_CRLF "" + commit_chk_wrnNNO auto lf $crlf "" "" "" "" "" + commit_chk_wrnNNO auto crlf $crlf LF_CRLF "" "" "" "" commit_chk_wrnNNO text lf $crlf "" CRLF_LF CRLF_LF "" CRLF_LF commit_chk_wrnNNO text crlf $crlf LF_CRLF "" LF_CRLF LF_CRLF "" done @@ -454,9 +453,9 @@ do check_in_repo_NNO -text "" $crlf LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul check_in_repo_NNO -text lf $crlf LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul check_in_repo_NNO -text crlf $crlf LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul - check_in_repo_NNO auto "" $crlf LF LF LF LF_mix_CR CRLF_nul - check_in_repo_NNO auto lf $crlf LF LF LF LF_mix_CR LF_nul - check_in_repo_NNO auto crlf $crlf LF LF LF LF_mix_CR LF_nul + check_in_repo_NNO auto "" $crlf LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul + check_in_repo_NNO auto lf $crlf LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul + check_in_repo_NNO auto crlf $crlf LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul check_in_repo_NNO text "" $crlf LF LF LF LF_mix_CR LF_nul check_in_repo_NNO text lf $crlf LF LF LF LF_mix_CR LF_nul check_in_repo_NNO text crlf $crlf LF LF LF LF_mix_CR LF_nul @@ -509,7 +508,7 @@ do checkout_files text "$id" "crlf" "$crlf" "$ceol" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul # currently the same as text, eol=XXX checkout_files auto "$id" "lf" "$crlf" "$ceol" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul - checkout_files auto "$id" "crlf" "$crlf" "$ceol" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + checkout_files auto "$id" "crlf" "$crlf" "$ceol" CRLF CRLF CRLF_mix_LF LF_mix_CR LF_nul done # core.autocrlf false, different core.eol @@ -517,7 +516,7 @@ do # core.autocrlf true checkout_files "" "$id" "" true "$ceol" CRLF CRLF CRLF_mix_LF LF_mix_CR LF_nul # text: core.autocrlf = true overrides core.eol - checkout_files auto "$id" "" true "$ceol" CRLF CRLF CRLF LF_mix_CR LF_nul + checkout_files auto "$id" "" true "$ceol" CRLF CRLF CRLF_mix_LF LF_mix_CR LF_nul checkout_files text "$id" "" true "$ceol" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul # text: core.autocrlf = input overrides core.eol checkout_files text "$id" "" input "$ceol" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul @@ -531,8 +530,8 @@ do checkout_files text "$id" "" false "" $NL CRLF $MIX_CRLF_LF $MIX_LF_CR $LFNUL checkout_files text "$id" "" false native $NL CRLF $MIX_CRLF_LF $MIX_LF_CR $LFNUL # auto: core.autocrlf=false and core.eol unset(or native) uses native eol - checkout_files auto "$id" "" false "" $NL CRLF $MIX_CRLF_LF LF_mix_CR LF_nul - checkout_files auto "$id" "" false native $NL CRLF $MIX_CRLF_LF LF_mix_CR LF_nul + checkout_files auto "$id" "" false "" $NL CRLF CRLF_mix_LF LF_mix_CR LF_nul + checkout_files auto "$id" "" false native $NL CRLF CRLF_mix_LF LF_mix_CR LF_nul done # Should be the last test case: remove some files from the worktree diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index 9be6411104..db5f60d0c5 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -7,7 +7,7 @@ test_description='our own option parser' . ./test-lib.sh -cat > expect << EOF +cat >expect <<\EOF usage: test-parse-options <options> --yes get a boolean @@ -45,63 +45,24 @@ Standard options -v, --verbose be verbose -n, --dry-run dry run -q, --quiet be quiet + --expect <string> expected output in the variable dump EOF test_expect_success 'test help' ' - test_must_fail test-parse-options -h > output 2> output.err && + test_must_fail test-parse-options -h >output 2>output.err && test_must_be_empty output.err && test_i18ncmp expect output ' mv expect expect.err -cat >expect.template <<EOF -boolean: 0 -integer: 0 -magnitude: 0 -timestamp: 0 -string: (not set) -abbrev: 7 -verbose: 0 -quiet: no -dry run: no -file: (not set) -EOF - -check() { +check () { what="$1" && shift && expect="$1" && shift && - sed "s/^$what .*/$what $expect/" <expect.template >expect && - test-parse-options $* >output 2>output.err && - test_must_be_empty output.err && - test_cmp expect output -} - -check_i18n() { - what="$1" && - shift && - expect="$1" && - shift && - sed "s/^$what .*/$what $expect/" <expect.template >expect && - test-parse-options $* >output 2>output.err && - test_must_be_empty output.err && - test_i18ncmp expect output -} - -check_unknown() { - case "$1" in - --*) - echo error: unknown option \`${1#--}\' >expect ;; - -*) - echo error: unknown switch \`${1#-}\' >expect ;; - esac && - cat expect.err >>expect && - test_must_fail test-parse-options $* >output 2>output.err && - test_must_be_empty output && - test_cmp expect output.err + test-parse-options --expect="$what $expect" "$@" } check_unknown_i18n() { @@ -156,7 +117,7 @@ test_expect_success 'OPT_MAGNITUDE() 3giga' ' check magnitude: 3221225472 -m 3g ' -cat > expect << EOF +cat >expect <<\EOF boolean: 2 integer: 1729 magnitude: 16384 @@ -164,7 +125,7 @@ timestamp: 0 string: 123 abbrev: 7 verbose: 2 -quiet: no +quiet: 0 dry run: yes file: prefix/my.file EOF @@ -176,7 +137,7 @@ test_expect_success 'short options' ' test_must_be_empty output.err ' -cat > expect << EOF +cat >expect <<\EOF boolean: 2 integer: 1729 magnitude: 16384 @@ -184,7 +145,7 @@ timestamp: 0 string: 321 abbrev: 10 verbose: 2 -quiet: no +quiet: 0 dry run: no file: prefix/fi.le EOF @@ -204,15 +165,15 @@ test_expect_success 'missing required value' ' test_expect_code 129 test-parse-options --file ' -cat > expect << EOF +cat >expect <<\EOF boolean: 1 integer: 13 magnitude: 0 timestamp: 0 string: 123 abbrev: 7 -verbose: 0 -quiet: no +verbose: -1 +quiet: 0 dry run: no file: (not set) arg 00: a1 @@ -222,32 +183,32 @@ EOF test_expect_success 'intermingled arguments' ' test-parse-options a1 --string 123 b1 --boolean -j 13 -- --boolean \ - > output 2> output.err && + >output 2>output.err && test_must_be_empty output.err && test_cmp expect output ' -cat > expect << EOF +cat >expect <<\EOF boolean: 0 integer: 2 magnitude: 0 timestamp: 0 string: (not set) abbrev: 7 -verbose: 0 -quiet: no +verbose: -1 +quiet: 0 dry run: no file: (not set) EOF test_expect_success 'unambiguously abbreviated option' ' - test-parse-options --int 2 --boolean --no-bo > output 2> output.err && + test-parse-options --int 2 --boolean --no-bo >output 2>output.err && test_must_be_empty output.err && test_cmp expect output ' test_expect_success 'unambiguously abbreviated option with "="' ' - test-parse-options --int=2 > output 2> output.err && + test-parse-options --int=2 >output 2>output.err && test_must_be_empty output.err && test_cmp expect output ' @@ -256,74 +217,74 @@ test_expect_success 'ambiguously abbreviated option' ' test_expect_code 129 test-parse-options --strin 123 ' -cat > expect << EOF +cat >expect <<\EOF boolean: 0 integer: 0 magnitude: 0 timestamp: 0 string: 123 abbrev: 7 -verbose: 0 -quiet: no +verbose: -1 +quiet: 0 dry run: no file: (not set) EOF test_expect_success 'non ambiguous option (after two options it abbreviates)' ' - test-parse-options --st 123 > output 2> output.err && + test-parse-options --st 123 >output 2>output.err && test_must_be_empty output.err && test_cmp expect output ' -cat > typo.err << EOF -error: did you mean \`--boolean\` (with two dashes ?) +cat >typo.err <<\EOF +error: did you mean `--boolean` (with two dashes ?) EOF test_expect_success 'detect possible typos' ' - test_must_fail test-parse-options -boolean > output 2> output.err && + test_must_fail test-parse-options -boolean >output 2>output.err && test_must_be_empty output && test_cmp typo.err output.err ' -cat > typo.err << EOF -error: did you mean \`--ambiguous\` (with two dashes ?) +cat >typo.err <<\EOF +error: did you mean `--ambiguous` (with two dashes ?) EOF test_expect_success 'detect possible typos' ' - test_must_fail test-parse-options -ambiguous > output 2> output.err && + test_must_fail test-parse-options -ambiguous >output 2>output.err && test_must_be_empty output && test_cmp typo.err output.err ' -cat > expect <<EOF +cat >expect <<\EOF boolean: 0 integer: 0 magnitude: 0 timestamp: 0 string: (not set) abbrev: 7 -verbose: 0 -quiet: no +verbose: -1 +quiet: 0 dry run: no file: (not set) arg 00: --quux EOF test_expect_success 'keep some options as arguments' ' - test-parse-options --quux > output 2> output.err && + test-parse-options --quux >output 2>output.err && test_must_be_empty output.err && - test_cmp expect output + test_cmp expect output ' -cat > expect <<EOF +cat >expect <<\EOF boolean: 0 integer: 0 magnitude: 0 timestamp: 1 string: (not set) abbrev: 7 -verbose: 0 -quiet: yes +verbose: -1 +quiet: 1 dry run: no file: (not set) arg 00: foo @@ -331,12 +292,12 @@ EOF test_expect_success 'OPT_DATE() works' ' test-parse-options -t "1970-01-01 00:00:01 +0000" \ - foo -q > output 2> output.err && + foo -q >output 2>output.err && test_must_be_empty output.err && test_cmp expect output ' -cat > expect <<EOF +cat >expect <<\EOF Callback: "four", 0 boolean: 5 integer: 4 @@ -344,112 +305,110 @@ magnitude: 0 timestamp: 0 string: (not set) abbrev: 7 -verbose: 0 -quiet: no +verbose: -1 +quiet: 0 dry run: no file: (not set) EOF test_expect_success 'OPT_CALLBACK() and OPT_BIT() work' ' - test-parse-options --length=four -b -4 > output 2> output.err && + test-parse-options --length=four -b -4 >output 2>output.err && test_must_be_empty output.err && test_cmp expect output ' -cat > expect <<EOF -Callback: "not set", 1 -EOF +>expect test_expect_success 'OPT_CALLBACK() and callback errors work' ' - test_must_fail test-parse-options --no-length > output 2> output.err && + test_must_fail test-parse-options --no-length >output 2>output.err && test_i18ncmp expect output && test_i18ncmp expect.err output.err ' -cat > expect <<EOF +cat >expect <<\EOF boolean: 1 integer: 23 magnitude: 0 timestamp: 0 string: (not set) abbrev: 7 -verbose: 0 -quiet: no +verbose: -1 +quiet: 0 dry run: no file: (not set) EOF test_expect_success 'OPT_BIT() and OPT_SET_INT() work' ' - test-parse-options --set23 -bbbbb --no-or4 > output 2> output.err && + test-parse-options --set23 -bbbbb --no-or4 >output 2>output.err && test_must_be_empty output.err && test_cmp expect output ' test_expect_success 'OPT_NEGBIT() and OPT_SET_INT() work' ' - test-parse-options --set23 -bbbbb --neg-or4 > output 2> output.err && + test-parse-options --set23 -bbbbb --neg-or4 >output 2>output.err && test_must_be_empty output.err && test_cmp expect output ' -cat > expect <<EOF +cat >expect <<\EOF boolean: 6 integer: 0 magnitude: 0 timestamp: 0 string: (not set) abbrev: 7 -verbose: 0 -quiet: no +verbose: -1 +quiet: 0 dry run: no file: (not set) EOF test_expect_success 'OPT_BIT() works' ' - test-parse-options -bb --or4 > output 2> output.err && + test-parse-options -bb --or4 >output 2>output.err && test_must_be_empty output.err && test_cmp expect output ' test_expect_success 'OPT_NEGBIT() works' ' - test-parse-options -bb --no-neg-or4 > output 2> output.err && + test-parse-options -bb --no-neg-or4 >output 2>output.err && test_must_be_empty output.err && test_cmp expect output ' test_expect_success 'OPT_COUNTUP() with PARSE_OPT_NODASH works' ' - test-parse-options + + + + + + > output 2> output.err && + test-parse-options + + + + + + >output 2>output.err && test_must_be_empty output.err && test_cmp expect output ' -cat > expect <<EOF +cat >expect <<\EOF boolean: 0 integer: 12345 magnitude: 0 timestamp: 0 string: (not set) abbrev: 7 -verbose: 0 -quiet: no +verbose: -1 +quiet: 0 dry run: no file: (not set) EOF test_expect_success 'OPT_NUMBER_CALLBACK() works' ' - test-parse-options -12345 > output 2> output.err && + test-parse-options -12345 >output 2>output.err && test_must_be_empty output.err && test_cmp expect output ' -cat >expect <<EOF +cat >expect <<\EOF boolean: 0 integer: 0 magnitude: 0 timestamp: 0 string: (not set) abbrev: 7 -verbose: 0 -quiet: no +verbose: -1 +quiet: 0 dry run: no file: (not set) EOF @@ -460,7 +419,7 @@ test_expect_success 'negation of OPT_NONEG flags is not ambiguous' ' test_cmp expect output ' -cat >>expect <<'EOF' +cat >>expect <<\EOF list: foo list: bar list: baz @@ -476,4 +435,118 @@ test_expect_success '--no-list resets list' ' test_cmp expect output ' +cat >expect <<\EOF +boolean: 0 +integer: 0 +magnitude: 0 +timestamp: 0 +string: (not set) +abbrev: 7 +verbose: -1 +quiet: 3 +dry run: no +file: (not set) +EOF + +test_expect_success 'multiple quiet levels' ' + test-parse-options -q -q -q >output 2>output.err && + test_must_be_empty output.err && + test_cmp expect output +' + +cat >expect <<\EOF +boolean: 0 +integer: 0 +magnitude: 0 +timestamp: 0 +string: (not set) +abbrev: 7 +verbose: 3 +quiet: 0 +dry run: no +file: (not set) +EOF + +test_expect_success 'multiple verbose levels' ' + test-parse-options -v -v -v >output 2>output.err && + test_must_be_empty output.err && + test_cmp expect output +' + +cat >expect <<\EOF +boolean: 0 +integer: 0 +magnitude: 0 +timestamp: 0 +string: (not set) +abbrev: 7 +verbose: -1 +quiet: 0 +dry run: no +file: (not set) +EOF + +test_expect_success '--no-quiet sets --quiet to 0' ' + test-parse-options --no-quiet >output 2>output.err && + test_must_be_empty output.err && + test_cmp expect output +' + +cat >expect <<\EOF +boolean: 0 +integer: 0 +magnitude: 0 +timestamp: 0 +string: (not set) +abbrev: 7 +verbose: -1 +quiet: 0 +dry run: no +file: (not set) +EOF + +test_expect_success '--no-quiet resets multiple -q to 0' ' + test-parse-options -q -q -q --no-quiet >output 2>output.err && + test_must_be_empty output.err && + test_cmp expect output +' + +cat >expect <<\EOF +boolean: 0 +integer: 0 +magnitude: 0 +timestamp: 0 +string: (not set) +abbrev: 7 +verbose: 0 +quiet: 0 +dry run: no +file: (not set) +EOF + +test_expect_success '--no-verbose sets verbose to 0' ' + test-parse-options --no-verbose >output 2>output.err && + test_must_be_empty output.err && + test_cmp expect output +' + +cat >expect <<\EOF +boolean: 0 +integer: 0 +magnitude: 0 +timestamp: 0 +string: (not set) +abbrev: 7 +verbose: 0 +quiet: 0 +dry run: no +file: (not set) +EOF + +test_expect_success '--no-verbose resets multiple verbose to 0' ' + test-parse-options -v -v -v --no-verbose >output 2>output.err && + test_must_be_empty output.err && + test_cmp expect output +' + test_done diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh index 8532a028e7..bf2deee109 100755 --- a/t/t0060-path-utils.sh +++ b/t/t0060-path-utils.sh @@ -19,6 +19,13 @@ relative_path() { "test \"\$(test-path-utils relative_path '$1' '$2')\" = '$expected'" } +test_submodule_relative_url() { + test_expect_success "test_submodule_relative_url: $1 $2 $3 => $4" " + actual=\$(git submodule--helper resolve-relative-url-test '$1' '$2' '$3') && + test \"\$actual\" = '$4' + " +} + test_git_path() { test_expect_success "git-path $1 $2 => $3" " $1 git rev-parse --git-path $2 >actual && @@ -298,4 +305,43 @@ test_git_path GIT_COMMON_DIR=bar config bar/config test_git_path GIT_COMMON_DIR=bar packed-refs bar/packed-refs test_git_path GIT_COMMON_DIR=bar shallow bar/shallow +# In the tests below, the distinction between $PWD and $(pwd) is important: +# on Windows, $PWD is POSIX style (/c/foo), $(pwd) has drive letter (c:/foo). + +test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule" +test_submodule_relative_url "../" "../foo/bar" "../submodule" "../../foo/submodule" +test_submodule_relative_url "../" "../foo/submodule" "../submodule" "../../foo/submodule" +test_submodule_relative_url "../" "./foo" "../submodule" "../submodule" +test_submodule_relative_url "../" "./foo/bar" "../submodule" "../foo/submodule" +test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" "../../../../foo/sub/a/b/c" +test_submodule_relative_url "../" "$PWD/addtest" "../repo" "$(pwd)/repo" +test_submodule_relative_url "../" "foo/bar" "../submodule" "../foo/submodule" +test_submodule_relative_url "../" "foo" "../submodule" "../submodule" + +test_submodule_relative_url "(null)" "../foo/bar" "../sub/a/b/c" "../foo/sub/a/b/c" +test_submodule_relative_url "(null)" "../foo/bar" "../submodule" "../foo/submodule" +test_submodule_relative_url "(null)" "../foo/submodule" "../submodule" "../foo/submodule" +test_submodule_relative_url "(null)" "../foo" "../submodule" "../submodule" +test_submodule_relative_url "(null)" "./foo/bar" "../submodule" "foo/submodule" +test_submodule_relative_url "(null)" "./foo" "../submodule" "submodule" +test_submodule_relative_url "(null)" "//somewhere else/repo" "../subrepo" "//somewhere else/subrepo" +test_submodule_relative_url "(null)" "$PWD/subsuper_update_r" "../subsubsuper_update_r" "$(pwd)/subsubsuper_update_r" +test_submodule_relative_url "(null)" "$PWD/super_update_r2" "../subsuper_update_r" "$(pwd)/subsuper_update_r" +test_submodule_relative_url "(null)" "$PWD/." "../." "$(pwd)/." +test_submodule_relative_url "(null)" "$PWD" "./." "$(pwd)/." +test_submodule_relative_url "(null)" "$PWD/addtest" "../repo" "$(pwd)/repo" +test_submodule_relative_url "(null)" "$PWD" "./Ã¥ äö" "$(pwd)/Ã¥ äö" +test_submodule_relative_url "(null)" "$PWD/." "../submodule" "$(pwd)/submodule" +test_submodule_relative_url "(null)" "$PWD/submodule" "../submodule" "$(pwd)/submodule" +test_submodule_relative_url "(null)" "$PWD/home2/../remote" "../bundle1" "$(pwd)/home2/../bundle1" +test_submodule_relative_url "(null)" "$PWD/submodule_update_repo" "./." "$(pwd)/submodule_update_repo/." +test_submodule_relative_url "(null)" "file:///tmp/repo" "../subrepo" "file:///tmp/subrepo" +test_submodule_relative_url "(null)" "foo/bar" "../submodule" "foo/submodule" +test_submodule_relative_url "(null)" "foo" "../submodule" "submodule" +test_submodule_relative_url "(null)" "helper:://hostname/repo" "../subrepo" "helper:://hostname/subrepo" +test_submodule_relative_url "(null)" "ssh://hostname/repo" "../subrepo" "ssh://hostname/subrepo" +test_submodule_relative_url "(null)" "ssh://hostname:22/repo" "../subrepo" "ssh://hostname:22/subrepo" +test_submodule_relative_url "(null)" "user@host:path/to/repo" "../subrepo" "user@host:path/to/subrepo" +test_submodule_relative_url "(null)" "user@host:repo" "../subrepo" "user@host:subrepo" + test_done diff --git a/t/t0070-fundamental.sh b/t/t0070-fundamental.sh index 5ed69a6f56..991ed2a48d 100755 --- a/t/t0070-fundamental.sh +++ b/t/t0070-fundamental.sh @@ -31,7 +31,7 @@ test_expect_success 'git_mkstemps_mode does not fail if fd 0 is not open' ' test_expect_success 'check for a bug in the regex routines' ' # if this test fails, re-build git with NO_REGEX=1 - test-regex + test-regex --bug ' test_done diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh index d7ef44b4a2..03bd31e9f2 100755 --- a/t/t0300-credentials.sh +++ b/t/t0300-credentials.sh @@ -298,4 +298,15 @@ test_expect_success 'helpers can abort the process' ' test_cmp expect stdout ' +test_expect_success 'empty helper spec resets helper list' ' + test_config credential.helper "verbatim file file" && + check fill "" "verbatim cmdline cmdline" <<-\EOF + -- + username=cmdline + password=cmdline + -- + verbatim: get + EOF +' + test_done diff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh index 0c74beedd2..81e85e08d9 100755 --- a/t/t1011-read-tree-sparse-checkout.sh +++ b/t/t1011-read-tree-sparse-checkout.sh @@ -15,11 +15,11 @@ test_description='sparse checkout tests . "$TEST_DIRECTORY"/lib-read-tree.sh test_expect_success 'setup' ' - cat >expected <<-\EOF && + cat >expected <<-EOF && 100644 77f0ba1734ed79d12881f81b36ee134de6a3327b 0 init.t - 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 sub/added - 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 sub/addedtoo - 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 subsub/added + 100644 $EMPTY_BLOB 0 sub/added + 100644 $EMPTY_BLOB 0 sub/addedtoo + 100644 $EMPTY_BLOB 0 subsub/added EOF cat >expected.swt <<-\EOF && H init.t @@ -244,7 +244,7 @@ test_expect_success 'print errors when failed to update worktree' ' error: The following untracked working tree files would be overwritten by checkout: sub/added sub/addedtoo -Please move or remove them before you can switch branches. +Please move or remove them before you switch branches. Aborting EOF test_cmp expected actual diff --git a/t/t1050-large.sh b/t/t1050-large.sh index f9f3d1391f..096dbffecc 100755 --- a/t/t1050-large.sh +++ b/t/t1050-large.sh @@ -177,10 +177,9 @@ test_expect_success 'zip achiving, deflate' ' git archive --format=zip HEAD >/dev/null ' -test_expect_success 'fsck' ' - test_must_fail git fsck 2>err && - n=$(grep "error: attempting to allocate .* over limit" err | wc -l) && - test "$n" -gt 1 +test_expect_success 'fsck large blobs' ' + git fsck 2>err && + test_must_be_empty err ' test_done diff --git a/t/t1100-commit-tree-options.sh b/t/t1100-commit-tree-options.sh index b7e9b4fc5b..ae66ba5bab 100755 --- a/t/t1100-commit-tree-options.sh +++ b/t/t1100-commit-tree-options.sh @@ -15,7 +15,7 @@ Also make sure that command line parser understands the normal . ./test-lib.sh cat >expected <<EOF -tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904 +tree $EMPTY_TREE author Author Name <author@email> 1117148400 +0000 committer Committer Name <committer@email> 1117150200 +0000 diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 3d6f1db9da..d934a24417 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -1087,6 +1087,20 @@ test_expect_success 'git -c complains about empty key and value' ' test_must_fail git -c "" rev-parse ' +test_expect_success 'multiple git -c appends config' ' + test_config alias.x "!git -c x.two=2 config --get-regexp ^x\.*" && + cat >expect <<-\EOF && + x.one 1 + x.two 2 + EOF + git -c x.one=1 x >actual && + test_cmp expect actual +' + +test_expect_success 'git -c is not confused by empty environment' ' + GIT_CONFIG_PARAMETERS="" git -c x.one=1 config --list +' + test_expect_success 'git config --edit works' ' git config -f tmp test.value no && echo test.value=yes >expect && diff --git a/t/t1350-config-hooks-path.sh b/t/t1350-config-hooks-path.sh new file mode 100755 index 0000000000..5e3fb3a6af --- /dev/null +++ b/t/t1350-config-hooks-path.sh @@ -0,0 +1,37 @@ +#!/bin/sh + +test_description='Test the core.hooksPath configuration variable' + +. ./test-lib.sh + +test_expect_success 'set up a pre-commit hook in core.hooksPath' ' + mkdir -p .git/custom-hooks .git/hooks && + write_script .git/custom-hooks/pre-commit <<-\EOF && + echo CUSTOM >>actual + EOF + write_script .git/hooks/pre-commit <<-\EOF + echo NORMAL >>actual + EOF +' + +test_expect_success 'Check that various forms of specifying core.hooksPath work' ' + test_commit no_custom_hook && + git config core.hooksPath .git/custom-hooks && + test_commit have_custom_hook && + git config core.hooksPath .git/custom-hooks/ && + test_commit have_custom_hook_trailing_slash && + git config core.hooksPath "$PWD/.git/custom-hooks" && + test_commit have_custom_hook_abs_path && + git config core.hooksPath "$PWD/.git/custom-hooks/" && + test_commit have_custom_hook_abs_path_trailing_slash && + cat >expect <<-\EOF && + NORMAL + CUSTOM + CUSTOM + CUSTOM + CUSTOM + EOF + test_cmp expect actual +' + +test_done diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh index 417eecc3af..ca3fa406c3 100755 --- a/t/t1401-symbolic-ref.sh +++ b/t/t1401-symbolic-ref.sh @@ -110,7 +110,7 @@ test_expect_success 'symbolic-ref writes reflog entry' ' update create EOF - git log --format=%gs -g >actual && + git log --format=%gs -g -2 >actual && test_cmp expect actual ' diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh index c623824b4d..553e26d9ce 100755 --- a/t/t1410-reflog.sh +++ b/t/t1410-reflog.sh @@ -338,4 +338,35 @@ 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' ' + git branch -l the_symref && + git branch -l referrent && + git update-ref referrent HEAD && + git symbolic-ref refs/heads/the_symref refs/heads/referrent && + test_when_finished "rm -f .git/refs/heads/referrent.lock" && + touch .git/refs/heads/referrent.lock && + git reflog expire --expire=all the_symref +' + +test_expect_success 'continue walking past root commits' ' + git init orphanage && + ( + cd orphanage && + cat >expect <<-\EOF && + HEAD@{0} commit (initial): orphan2-1 + HEAD@{1} commit: orphan1-2 + HEAD@{2} commit (initial): orphan1-1 + HEAD@{3} commit (initial): initial + EOF + test_commit initial && + git checkout --orphan orphan1 && + test_commit orphan1-1 && + test_commit orphan1-2 && + git checkout --orphan orphan2 && + test_commit orphan2-1 && + git log -g --format="%gd %gs" >actual && + test_cmp expect actual + ) +' + test_done diff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh index c465abe8e3..25ddab4e98 100755 --- a/t/t1430-bad-ref-name.sh +++ b/t/t1430-bad-ref-name.sh @@ -42,7 +42,7 @@ test_expect_success 'git branch shows badly named ref as warning' ' cp .git/refs/heads/master .git/refs/heads/broken...ref && test_when_finished "rm -f .git/refs/heads/broken...ref" && git branch >output 2>error && - grep -e "broken\.\.\.ref" error && + test_i18ngrep -e "ignoring ref with broken name refs/heads/broken\.\.\.ref" error && ! grep -e "broken\.\.\.ref" output ' @@ -147,35 +147,145 @@ test_expect_success 'rev-parse skips symref pointing to broken name' ' test_when_finished "rm -f .git/refs/heads/broken...ref" && git branch shadow one && cp .git/refs/heads/master .git/refs/heads/broken...ref && - git symbolic-ref refs/tags/shadow refs/heads/broken...ref && - + printf "ref: refs/heads/broken...ref\n" >.git/refs/tags/shadow && + test_when_finished "rm -f .git/refs/tags/shadow" && git rev-parse --verify one >expect && git rev-parse --verify shadow >actual 2>err && test_cmp expect actual && - test_i18ngrep "ignoring.*refs/tags/shadow" err + test_i18ngrep "ignoring dangling symref refs/tags/shadow" err ' -test_expect_success 'update-ref --no-deref -d can delete reference to broken name' ' - git symbolic-ref refs/heads/badname refs/heads/broken...ref && +test_expect_success 'for-each-ref emits warnings for broken names' ' + cp .git/refs/heads/master .git/refs/heads/broken...ref && + test_when_finished "rm -f .git/refs/heads/broken...ref" && + printf "ref: refs/heads/broken...ref\n" >.git/refs/heads/badname && test_when_finished "rm -f .git/refs/heads/badname" && - test_path_is_file .git/refs/heads/badname && - git update-ref --no-deref -d refs/heads/badname && - test_path_is_missing .git/refs/heads/badname + printf "ref: refs/heads/master\n" >.git/refs/heads/broken...symref && + test_when_finished "rm -f .git/refs/heads/broken...symref" && + git for-each-ref >output 2>error && + ! grep -e "broken\.\.\.ref" output && + ! 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 ref with broken name refs/heads/broken\.\.\.symref" error ' test_expect_success 'update-ref -d can delete broken name' ' cp .git/refs/heads/master .git/refs/heads/broken...ref && test_when_finished "rm -f .git/refs/heads/broken...ref" && - git update-ref -d refs/heads/broken...ref && + git update-ref -d refs/heads/broken...ref >output 2>error && + test_must_be_empty output && + test_must_be_empty error && + git branch >output 2>error && + ! grep -e "broken\.\.\.ref" error && + ! grep -e "broken\.\.\.ref" output +' + +test_expect_success 'branch -d can delete broken name' ' + cp .git/refs/heads/master .git/refs/heads/broken...ref && + test_when_finished "rm -f .git/refs/heads/broken...ref" && + git branch -d broken...ref >output 2>error && + test_i18ngrep "Deleted branch broken...ref (was broken)" output && + test_must_be_empty error && git branch >output 2>error && ! grep -e "broken\.\.\.ref" error && ! grep -e "broken\.\.\.ref" output ' +test_expect_success 'update-ref --no-deref -d can delete symref to broken name' ' + cp .git/refs/heads/master .git/refs/heads/broken...ref && + test_when_finished "rm -f .git/refs/heads/broken...ref" && + printf "ref: refs/heads/broken...ref\n" >.git/refs/heads/badname && + test_when_finished "rm -f .git/refs/heads/badname" && + git update-ref --no-deref -d refs/heads/badname >output 2>error && + test_path_is_missing .git/refs/heads/badname && + test_must_be_empty output && + test_must_be_empty error +' + +test_expect_success 'branch -d can delete symref to broken name' ' + cp .git/refs/heads/master .git/refs/heads/broken...ref && + test_when_finished "rm -f .git/refs/heads/broken...ref" && + printf "ref: refs/heads/broken...ref\n" >.git/refs/heads/badname && + test_when_finished "rm -f .git/refs/heads/badname" && + git branch -d badname >output 2>error && + test_path_is_missing .git/refs/heads/badname && + test_i18ngrep "Deleted branch badname (was refs/heads/broken\.\.\.ref)" output && + test_must_be_empty error +' + +test_expect_success 'update-ref --no-deref -d can delete dangling symref to broken name' ' + printf "ref: refs/heads/broken...ref\n" >.git/refs/heads/badname && + test_when_finished "rm -f .git/refs/heads/badname" && + git update-ref --no-deref -d refs/heads/badname >output 2>error && + test_path_is_missing .git/refs/heads/badname && + test_must_be_empty output && + test_must_be_empty error +' + +test_expect_success 'branch -d can delete dangling symref to broken name' ' + printf "ref: refs/heads/broken...ref\n" >.git/refs/heads/badname && + test_when_finished "rm -f .git/refs/heads/badname" && + git branch -d badname >output 2>error && + test_path_is_missing .git/refs/heads/badname && + test_i18ngrep "Deleted branch badname (was refs/heads/broken\.\.\.ref)" output && + test_must_be_empty error +' + +test_expect_success 'update-ref -d can delete broken name through symref' ' + cp .git/refs/heads/master .git/refs/heads/broken...ref && + test_when_finished "rm -f .git/refs/heads/broken...ref" && + printf "ref: refs/heads/broken...ref\n" >.git/refs/heads/badname && + test_when_finished "rm -f .git/refs/heads/badname" && + git update-ref -d refs/heads/badname >output 2>error && + test_path_is_missing .git/refs/heads/broken...ref && + test_must_be_empty output && + test_must_be_empty error +' + +test_expect_success 'update-ref --no-deref -d can delete symref with broken name' ' + printf "ref: refs/heads/master\n" >.git/refs/heads/broken...symref && + test_when_finished "rm -f .git/refs/heads/broken...symref" && + git update-ref --no-deref -d refs/heads/broken...symref >output 2>error && + test_path_is_missing .git/refs/heads/broken...symref && + test_must_be_empty output && + test_must_be_empty error +' + +test_expect_success 'branch -d can delete symref with broken name' ' + printf "ref: refs/heads/master\n" >.git/refs/heads/broken...symref && + test_when_finished "rm -f .git/refs/heads/broken...symref" && + git branch -d broken...symref >output 2>error && + test_path_is_missing .git/refs/heads/broken...symref && + test_i18ngrep "Deleted branch broken...symref (was refs/heads/master)" output && + test_must_be_empty error +' + +test_expect_success 'update-ref --no-deref -d can delete dangling symref with broken name' ' + printf "ref: refs/heads/idonotexist\n" >.git/refs/heads/broken...symref && + test_when_finished "rm -f .git/refs/heads/broken...symref" && + git update-ref --no-deref -d refs/heads/broken...symref >output 2>error && + test_path_is_missing .git/refs/heads/broken...symref && + test_must_be_empty output && + test_must_be_empty error +' + +test_expect_success 'branch -d can delete dangling symref with broken name' ' + printf "ref: refs/heads/idonotexist\n" >.git/refs/heads/broken...symref && + test_when_finished "rm -f .git/refs/heads/broken...symref" && + git branch -d broken...symref >output 2>error && + test_path_is_missing .git/refs/heads/broken...symref && + test_i18ngrep "Deleted branch broken...symref (was refs/heads/idonotexist)" output && + test_must_be_empty error +' + test_expect_success 'update-ref -d cannot delete non-ref in .git dir' ' echo precious >.git/my-private-file && echo precious >expect && - test_must_fail git update-ref -d my-private-file && + test_must_fail git update-ref -d my-private-file >output 2>error && + test_must_be_empty output && + test_i18ngrep -e "cannot lock .*: unable to resolve reference" error && test_cmp expect .git/my-private-file ' diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh index 48ee07779d..038e24c401 100755 --- a/t/t1500-rev-parse.sh +++ b/t/t1500-rev-parse.sh @@ -3,85 +3,88 @@ test_description='test git rev-parse' . ./test-lib.sh -test_rev_parse() { - name=$1 - shift - - test_expect_success "$name: is-bare-repository" \ - "test '$1' = \"\$(git rev-parse --is-bare-repository)\"" - shift - [ $# -eq 0 ] && return - - test_expect_success "$name: is-inside-git-dir" \ - "test '$1' = \"\$(git rev-parse --is-inside-git-dir)\"" - shift - [ $# -eq 0 ] && return +# usage: [options] label is-bare is-inside-git is-inside-work prefix git-dir +test_rev_parse () { + d= + bare= + gitdir= + while : + do + case "$1" in + -C) d="$2"; shift; shift ;; + -b) case "$2" in + [tfu]*) bare="$2"; shift; shift ;; + *) error "test_rev_parse: bogus core.bare value '$2'" ;; + esac ;; + -g) gitdir="$2"; shift; shift ;; + -*) error "test_rev_parse: unrecognized option '$1'" ;; + *) break ;; + esac + done - test_expect_success "$name: is-inside-work-tree" \ - "test '$1' = \"\$(git rev-parse --is-inside-work-tree)\"" - shift - [ $# -eq 0 ] && return - - test_expect_success "$name: prefix" \ - "test '$1' = \"\$(git rev-parse --show-prefix)\"" + name=$1 shift - [ $# -eq 0 ] && return - test_expect_success "$name: git-dir" \ - "test '$1' = \"\$(git rev-parse --git-dir)\"" - shift - [ $# -eq 0 ] && return + for o in --is-bare-repository \ + --is-inside-git-dir \ + --is-inside-work-tree \ + --show-prefix \ + --git-dir + do + test $# -eq 0 && break + expect="$1" + test_expect_success "$name: $o" ' + if test -n "$gitdir" + then + test_when_finished "unset GIT_DIR" && + GIT_DIR="$gitdir" && + export GIT_DIR + fi && + + case "$bare" in + t*) test_config ${d:+-C} ${d:+"$d"} core.bare true ;; + f*) test_config ${d:+-C} ${d:+"$d"} core.bare false ;; + u*) test_unconfig ${d:+-C} ${d:+"$d"} core.bare ;; + esac && + + echo "$expect" >expect && + git ${d:+-C} ${d:+"$d"} rev-parse $o >actual && + test_cmp expect actual + ' + shift + done } -# label is-bare is-inside-git is-inside-work prefix git-dir - ROOT=$(pwd) +test_expect_success 'setup' ' + mkdir -p sub/dir work && + cp -R .git repo.git +' + test_rev_parse toplevel false false true '' .git -cd .git || exit 1 -test_rev_parse .git/ false true false '' . -cd objects || exit 1 -test_rev_parse .git/objects/ false true false '' "$ROOT/.git" -cd ../.. || exit 1 +test_rev_parse -C .git .git/ false true false '' . +test_rev_parse -C .git/objects .git/objects/ false true false '' "$ROOT/.git" -mkdir -p sub/dir || exit 1 -cd sub/dir || exit 1 -test_rev_parse subdirectory false false true sub/dir/ "$ROOT/.git" -cd ../.. || exit 1 +test_rev_parse -C sub/dir subdirectory false false true sub/dir/ "$ROOT/.git" -git config core.bare true -test_rev_parse 'core.bare = true' true false false +test_rev_parse -b t 'core.bare = true' true false false -git config --unset core.bare -test_rev_parse 'core.bare undefined' false false true +test_rev_parse -b u 'core.bare undefined' false false true -mkdir work || exit 1 -cd work || exit 1 -GIT_DIR=../.git -GIT_CONFIG="$(pwd)"/../.git/config -export GIT_DIR GIT_CONFIG -git config core.bare false -test_rev_parse 'GIT_DIR=../.git, core.bare = false' false false true '' +test_rev_parse -C work -g ../.git -b f 'GIT_DIR=../.git, core.bare = false' false false true '' -git config core.bare true -test_rev_parse 'GIT_DIR=../.git, core.bare = true' true false false '' +test_rev_parse -C work -g ../.git -b t 'GIT_DIR=../.git, core.bare = true' true false false '' -git config --unset core.bare -test_rev_parse 'GIT_DIR=../.git, core.bare undefined' false false true '' +test_rev_parse -C work -g ../.git -b u 'GIT_DIR=../.git, core.bare undefined' false false true '' -mv ../.git ../repo.git || exit 1 -GIT_DIR=../repo.git -GIT_CONFIG="$(pwd)"/../repo.git/config -git config core.bare false -test_rev_parse 'GIT_DIR=../repo.git, core.bare = false' false false true '' +test_rev_parse -C work -g ../repo.git -b f 'GIT_DIR=../repo.git, core.bare = false' false false true '' -git config core.bare true -test_rev_parse 'GIT_DIR=../repo.git, core.bare = true' true false false '' +test_rev_parse -C work -g ../repo.git -b t 'GIT_DIR=../repo.git, core.bare = true' true false false '' -git config --unset core.bare -test_rev_parse 'GIT_DIR=../repo.git, core.bare undefined' false false true '' +test_rev_parse -C work -g ../repo.git -b u 'GIT_DIR=../repo.git, core.bare undefined' false false true '' test_done diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh index 8aef49f236..292a0720fc 100755 --- a/t/t1700-split-index.sh +++ b/t/t1700-split-index.sh @@ -33,14 +33,14 @@ test_expect_success 'add one file' ' git update-index --add one && git ls-files --stage >ls-files.actual && cat >ls-files.expect <<EOF && -100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one +100644 $EMPTY_BLOB 0 one EOF test_cmp ls-files.expect ls-files.actual && test-dump-split-index .git/index | sed "/^own/d" >actual && cat >expect <<EOF && base $base -100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one +100644 $EMPTY_BLOB 0 one replacements: deletions: EOF @@ -51,7 +51,7 @@ test_expect_success 'disable split index' ' git update-index --no-split-index && git ls-files --stage >ls-files.actual && cat >ls-files.expect <<EOF && -100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one +100644 $EMPTY_BLOB 0 one EOF test_cmp ls-files.expect ls-files.actual && @@ -67,7 +67,7 @@ test_expect_success 'enable split index again, "one" now belongs to base index"' git update-index --split-index && git ls-files --stage >ls-files.actual && cat >ls-files.expect <<EOF && -100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one +100644 $EMPTY_BLOB 0 one EOF test_cmp ls-files.expect ls-files.actual && @@ -105,7 +105,7 @@ test_expect_success 'add another file, which stays index' ' git ls-files --stage >ls-files.actual && cat >ls-files.expect <<EOF && 100644 2e0996000b7e9019eabcad29391bf0f5c7702f0b 0 one -100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 two +100644 $EMPTY_BLOB 0 two EOF test_cmp ls-files.expect ls-files.actual && @@ -113,7 +113,7 @@ EOF q_to_tab >expect <<EOF && $BASE 100644 2e0996000b7e9019eabcad29391bf0f5c7702f0b 0Q -100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 two +100644 $EMPTY_BLOB 0 two replacements: 0 deletions: EOF @@ -159,14 +159,14 @@ test_expect_success 'add original file back' ' git update-index --add one && git ls-files --stage >ls-files.actual && cat >ls-files.expect <<EOF && -100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one +100644 $EMPTY_BLOB 0 one EOF test_cmp ls-files.expect ls-files.actual && test-dump-split-index .git/index | sed "/^own/d" >actual && cat >expect <<EOF && $BASE -100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one +100644 $EMPTY_BLOB 0 one replacements: deletions: 0 EOF @@ -178,8 +178,8 @@ test_expect_success 'add new file' ' git update-index --add two && git ls-files --stage >actual && cat >expect <<EOF && -100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one -100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 two +100644 $EMPTY_BLOB 0 one +100644 $EMPTY_BLOB 0 two EOF test_cmp expect actual ' @@ -188,8 +188,8 @@ test_expect_success 'unify index, two files remain' ' git update-index --no-split-index && git ls-files --stage >ls-files.actual && cat >ls-files.expect <<EOF && -100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one -100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 two +100644 $EMPTY_BLOB 0 one +100644 $EMPTY_BLOB 0 two EOF test_cmp ls-files.expect ls-files.actual && diff --git a/t/t2020-checkout-detach.sh b/t/t2020-checkout-detach.sh index 5d68729d7a..fbb4ee9bb4 100755 --- a/t/t2020-checkout-detach.sh +++ b/t/t2020-checkout-detach.sh @@ -163,4 +163,27 @@ test_expect_success 'tracking count is accurate after orphan check' ' test_i18ncmp expect stdout ' +test_expect_success 'no advice given for explicit detached head state' ' + # baseline + test_config advice.detachedHead true && + git checkout child && git checkout HEAD^0 >expect.advice 2>&1 && + test_config advice.detachedHead false && + git checkout child && git checkout HEAD^0 >expect.no-advice 2>&1 && + test_unconfig advice.detachedHead && + # without configuration, the advice.* variables default to true + git checkout child && git checkout HEAD^0 >actual 2>&1 && + test_cmp expect.advice actual && + + # with explicit --detach + # no configuration + test_unconfig advice.detachedHead && + git checkout child && git checkout --detach HEAD^0 >actual 2>&1 && + test_cmp expect.no-advice actual && + + # explicitly decline advice + test_config advice.detachedHead false && + git checkout child && git checkout --detach HEAD^0 >actual 2>&1 && + test_cmp expect.no-advice actual +' + test_done diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh index cbfa41ec61..3a22fc55fc 100755 --- a/t/t2025-worktree-add.sh +++ b/t/t2025-worktree-add.sh @@ -4,6 +4,8 @@ test_description='test git worktree add' . ./test-lib.sh +. "$TEST_DIRECTORY"/lib-rebase.sh + test_expect_success 'setup' ' test_commit init ' @@ -213,4 +215,73 @@ test_expect_success 'local clone from linked checkout' ' ( cd here-clone && git fsck ) ' +test_expect_success '"add" worktree with --no-checkout' ' + git worktree add --no-checkout -b swamp swamp && + ! test -e swamp/init.t && + git -C swamp reset --hard && + test_cmp init.t swamp/init.t +' + +test_expect_success '"add" worktree with --checkout' ' + git worktree add --checkout -b swmap2 swamp2 && + test_cmp init.t swamp2/init.t +' + +test_expect_success 'put a worktree under rebase' ' + git worktree add under-rebase && + ( + cd under-rebase && + set_fake_editor && + FAKE_LINES="edit 1" git rebase -i HEAD^ && + git worktree list | grep "under-rebase.*detached HEAD" + ) +' + +test_expect_success 'add a worktree, checking out a rebased branch' ' + test_must_fail git worktree add new-rebase under-rebase && + ! test -d new-rebase +' + +test_expect_success 'checking out a rebased branch from another worktree' ' + git worktree add new-place && + test_must_fail git -C new-place checkout under-rebase +' + +test_expect_success 'not allow to delete a branch under rebase' ' + ( + cd under-rebase && + test_must_fail git branch -D under-rebase + ) +' + +test_expect_success 'rename a branch under rebase not allowed' ' + test_must_fail git branch -M under-rebase rebase-with-new-name +' + +test_expect_success 'check out from current worktree branch ok' ' + ( + cd under-rebase && + git checkout under-rebase && + git checkout - && + git rebase --abort + ) +' + +test_expect_success 'checkout a branch under bisect' ' + git worktree add under-bisect && + ( + cd under-bisect && + git bisect start && + git bisect bad && + git bisect good HEAD~2 && + git worktree list | grep "under-bisect.*detached HEAD" && + test_must_fail git worktree add new-bisect under-bisect && + ! test -d new-bisect + ) +' + +test_expect_success 'rename a branch under bisect not allowed' ' + test_must_fail git branch -M under-bisect bisect-with-new-name +' + test_done diff --git a/t/t2203-add-intent.sh b/t/t2203-add-intent.sh index 2a4a749b4f..8f22c43e24 100755 --- a/t/t2203-add-intent.sh +++ b/t/t2203-add-intent.sh @@ -82,5 +82,36 @@ test_expect_success 'cache-tree invalidates i-t-a paths' ' test_cmp expect actual ' +test_expect_success 'cache-tree does not ignore dir that has i-t-a entries' ' + git init ita-in-dir && + ( + cd ita-in-dir && + mkdir 2 && + for f in 1 2/1 2/2 3 + do + echo "$f" >"$f" + done && + git add 1 2/2 3 && + git add -N 2/1 && + git commit -m committed && + git ls-tree -r HEAD >actual && + grep 2/2 actual + ) +' + +test_expect_success 'cache-tree does skip dir that becomes empty' ' + rm -fr ita-in-dir && + git init ita-in-dir && + ( + cd ita-in-dir && + mkdir -p 1/2/3 && + echo 4 >1/2/3/4 && + git add -N 1/2/3/4 && + git write-tree >actual && + echo $EMPTY_TREE >expected && + test_cmp expected actual + ) +' + test_done diff --git a/t/t2300-cd-to-toplevel.sh b/t/t2300-cd-to-toplevel.sh index 9965bc5c92..c8de6d8a19 100755 --- a/t/t2300-cd-to-toplevel.sh +++ b/t/t2300-cd-to-toplevel.sh @@ -4,11 +4,20 @@ test_description='cd_to_toplevel' . ./test-lib.sh +EXEC_PATH="$(git --exec-path)" +test_have_prereq !MINGW || +case "$EXEC_PATH" in +[A-Za-z]:/*) + EXEC_PATH="/${EXEC_PATH%%:*}${EXEC_PATH#?:}" + ;; +esac + test_cd_to_toplevel () { test_expect_success $3 "$2" ' ( cd '"'$1'"' && - . "$(git --exec-path)"/git-sh-setup && + PATH="$EXEC_PATH:$PATH" && + . git-sh-setup && cd_to_toplevel && [ "$(pwd -P)" = "$TOPLEVEL" ] ) diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh index f7b0e599f1..470f33466c 100755 --- a/t/t3030-merge-recursive.sh +++ b/t/t3030-merge-recursive.sh @@ -660,4 +660,22 @@ test_expect_success 'merging with triple rename across D/F conflict' ' git merge other ' +test_expect_success 'merge-recursive remembers the names of all base trees' ' + git reset --hard HEAD && + + # more trees than static slots used by oid_to_hex() + for commit in $c0 $c2 $c4 $c5 $c6 $c7 + do + git rev-parse "$commit^{tree}" + done >trees && + + # ignore the return code -- it only fails because the input is weird + test_must_fail git -c merge.verbosity=5 merge-recursive $(cat trees) -- $c1 $c3 >out && + + # 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_done diff --git a/t/t3033-merge-toplevel.sh b/t/t3033-merge-toplevel.sh index 46aadc410b..d314599428 100755 --- a/t/t3033-merge-toplevel.sh +++ b/t/t3033-merge-toplevel.sh @@ -19,6 +19,8 @@ test_expect_success setup ' test_commit three && git checkout right && test_commit four && + git checkout --orphan newroot && + test_commit five && git checkout master ' @@ -133,4 +135,18 @@ test_expect_success 'merge FETCH_HEAD octopus non-fast-forward' ' test_cmp expect actual ' +# two-project merge +test_expect_success 'refuse two-project merge by default' ' + t3033_reset && + git reset --hard four && + test_must_fail git merge five +' + +test_expect_success 'two-project merge with --allow-unrelated-histories' ' + t3033_reset && + git reset --hard four && + git merge --allow-unrelated-histories five && + git diff --exit-code five +' + test_done diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh index 4d4b02e760..e804377f1c 100755 --- a/t/t3102-ls-tree-wildcards.sh +++ b/t/t3102-ls-tree-wildcards.sh @@ -12,16 +12,16 @@ test_expect_success 'setup' ' ' test_expect_success 'ls-tree a[a] matches literally' ' - cat >expect <<-\EOF && - 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 a[a]/three + cat >expect <<-EOF && + 100644 blob $EMPTY_BLOB a[a]/three EOF git ls-tree -r HEAD "a[a]" >actual && test_cmp expect actual ' test_expect_success 'ls-tree outside prefix' ' - cat >expect <<-\EOF && - 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 ../a[a]/three + cat >expect <<-EOF && + 100644 blob $EMPTY_BLOB ../a[a]/three EOF ( cd aa && git ls-tree -r HEAD "../a[a]"; ) >actual && test_cmp expect actual diff --git a/t/t3402-rebase-merge.sh b/t/t3402-rebase-merge.sh index 8f64505e4f..488945e007 100755 --- a/t/t3402-rebase-merge.sh +++ b/t/t3402-rebase-merge.sh @@ -85,6 +85,15 @@ test_expect_success 'rebase -Xtheirs' ' ! grep 11 original ' +test_expect_success 'rebase -Xtheirs from orphan' ' + git checkout --orphan orphan-conflicting master~2 && + echo "AB $T" >> original && + git commit -morphan-conflicting original && + git rebase -Xtheirs master && + grep AB original && + ! grep 11 original +' + test_expect_success 'merge and rebase should match' ' git diff-tree -r test-rebase test-merge >difference && if test -s difference diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index d6d65a3a94..c7ea8bacf4 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -60,9 +60,9 @@ test_expect_success 'setup' ' test_commit P fileP ' -# "exec" commands are ran with the user shell by default, but this may +# "exec" commands are run with the user shell by default, but this may # be non-POSIX. For example, if SHELL=zsh then ">file" doesn't work -# to create a file. Unseting SHELL avoids such non-portable behavior +# to create a file. Unsetting SHELL avoids such non-portable behavior # in tests. It must be exported for it to take effect where needed. SHELL= export SHELL @@ -770,7 +770,6 @@ test_expect_success 'rebase-i history with funny messages' ' test_cmp expect actual ' - test_expect_success 'prepare for rebase -i --exec' ' git checkout master && git checkout -b execute && @@ -779,7 +778,6 @@ test_expect_success 'prepare for rebase -i --exec' ' test_commit three_exec main.txt three_exec ' - test_expect_success 'running "git rebase -i --exec git show HEAD"' ' set_fake_editor && git rebase -i --exec "git show HEAD" HEAD~2 >actual && @@ -792,7 +790,6 @@ test_expect_success 'running "git rebase -i --exec git show HEAD"' ' test_cmp expected actual ' - test_expect_success 'running "git rebase --exec git show HEAD -i"' ' git reset --hard execute && set_fake_editor && @@ -806,7 +803,6 @@ test_expect_success 'running "git rebase --exec git show HEAD -i"' ' test_cmp expected actual ' - test_expect_success 'running "git rebase -ix git show HEAD"' ' git reset --hard execute && set_fake_editor && @@ -834,7 +830,6 @@ test_expect_success 'rebase -ix with several <CMD>' ' test_cmp expected actual ' - test_expect_success 'rebase -ix with several instances of --exec' ' git reset --hard execute && set_fake_editor && @@ -849,7 +844,6 @@ test_expect_success 'rebase -ix with several instances of --exec' ' test_cmp expected actual ' - test_expect_success 'rebase -ix with --autosquash' ' git reset --hard execute && git checkout -b autosquash && @@ -875,16 +869,15 @@ test_expect_success 'rebase -ix with --autosquash' ' test_cmp expected actual ' - -test_expect_success 'rebase --exec without -i shows error message' ' +test_expect_success 'rebase --exec works without -i ' ' git reset --hard execute && - set_fake_editor && - test_must_fail git rebase --exec "git show HEAD" HEAD~2 2>actual && - echo "The --exec option must be used with the --interactive option" >expected && - test_i18ncmp expected actual + rm -rf exec_output && + EDITOR="echo >invoked_editor" git rebase --exec "echo a line >>exec_output" HEAD~2 2>actual && + test_i18ngrep "Successfully rebased and updated" actual && + test_line_count = 2 exec_output && + test_path_is_missing invoked_editor ' - test_expect_success 'rebase -i --exec without <CMD>' ' git reset --hard execute && set_fake_editor && diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh index 0b52105728..73a39f2923 100755 --- a/t/t3412-rebase-root.sh +++ b/t/t3412-rebase-root.sh @@ -133,7 +133,7 @@ test_expect_success 'set up second root and merge' ' rm A B C && test_commit 6 D && git checkout other && - git merge third + git merge --allow-unrelated-histories third ' cat > expect-third <<'EOF' diff --git a/t/t3419-rebase-patch-id.sh b/t/t3419-rebase-patch-id.sh index 217dd79b2e..49f548cdb9 100755 --- a/t/t3419-rebase-patch-id.sh +++ b/t/t3419-rebase-patch-id.sh @@ -73,17 +73,17 @@ do_tests () { run git format-patch --stdout --ignore-if-in-upstream master " - test_expect_success $pr 'detect upstream patch' " + test_expect_success $pr 'detect upstream patch' ' git checkout -q master && scramble file && git add file && - git commit -q -m 'change big file again' && + git commit -q -m "change big file again" && git checkout -q other^{} && git rebase master && - test_must_fail test -n \"\$(git rev-list master...HEAD~)\" - " + test_must_fail test -n "$(git rev-list master...HEAD~)" + ' - test_expect_success $pr 'do not drop patch' " + test_expect_success $pr 'do not drop patch' ' git branch -f squashed master && git checkout -q -f squashed && git reset -q --soft HEAD~2 && @@ -91,7 +91,7 @@ do_tests () { git checkout -q other^{} && test_must_fail git rebase squashed && rm -rf .git/rebase-apply - " + ' } do_tests 500 diff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh index 944154b2e0..532ff5cbd1 100755 --- a/t/t3420-rebase-autostash.sh +++ b/t/t3420-rebase-autostash.sh @@ -192,4 +192,35 @@ test_expect_success 'abort rebase -i with --autostash' ' test_cmp expected file0 ' +test_expect_success 'restore autostash on editor failure' ' + test_when_finished "git reset --hard" && + echo uncommitted-content >file0 && + ( + test_set_editor "false" && + test_must_fail git rebase -i --autostash HEAD^ + ) && + echo uncommitted-content >expected && + test_cmp expected file0 +' + +test_expect_success 'autostash is saved on editor failure with conflict' ' + test_when_finished "git reset --hard" && + echo uncommitted-content >file0 && + ( + write_script abort-editor.sh <<-\EOF && + echo conflicting-content >file0 + exit 1 + EOF + test_set_editor "$(pwd)/abort-editor.sh" && + test_must_fail git rebase -i --autostash HEAD^ && + rm -f abort-editor.sh + ) && + echo conflicting-content >expected && + test_cmp expected file0 && + git checkout file0 && + git stash pop && + echo uncommitted-content >expected && + test_cmp expected file0 +' + test_done diff --git a/t/t3421-rebase-topology-linear.sh b/t/t3421-rebase-topology-linear.sh index 9c55cba198..68fe2003ef 100755 --- a/t/t3421-rebase-topology-linear.sh +++ b/t/t3421-rebase-topology-linear.sh @@ -253,7 +253,7 @@ test_run_rebase () { " } test_run_rebase success '' -test_run_rebase failure -m +test_run_rebase success -m test_run_rebase success -i test_run_rebase success -p @@ -268,7 +268,7 @@ test_run_rebase () { " } test_run_rebase success '' -test_run_rebase failure -m +test_run_rebase success -m test_run_rebase success -i test_run_rebase failure -p diff --git a/t/t3427-rebase-subtree.sh b/t/t3427-rebase-subtree.sh new file mode 100755 index 0000000000..3780877e4e --- /dev/null +++ b/t/t3427-rebase-subtree.sh @@ -0,0 +1,119 @@ +#!/bin/sh + +test_description='git rebase tests for -Xsubtree + +This test runs git rebase and tests the subtree strategy. +' +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-rebase.sh + +commit_message() { + git log --pretty=format:%s -1 "$1" +} + +test_expect_success 'setup' ' + test_commit README && + mkdir files && + ( + cd files && + git init && + test_commit master1 && + test_commit master2 && + test_commit master3 + ) && + git fetch files master && + git branch files-master FETCH_HEAD && + git read-tree --prefix=files_subtree files-master && + git checkout -- files_subtree && + tree=$(git write-tree) && + head=$(git rev-parse HEAD) && + rev=$(git rev-parse --verify files-master^0) && + commit=$(git commit-tree -p $head -p $rev -m "Add subproject master" $tree) && + git update-ref HEAD $commit && + ( + cd files_subtree && + test_commit master4 + ) && + test_commit files_subtree/master5 +' + +# FAILURE: Does not preserve master4. +test_expect_failure 'Rebase -Xsubtree --preserve-merges --onto commit 4' ' + reset_rebase && + git checkout -b rebase-preserve-merges-4 master && + git filter-branch --prune-empty -f --subdirectory-filter files_subtree && + git commit -m "Empty commit" --allow-empty && + git rebase -Xsubtree=files_subtree --preserve-merges --onto files-master master && + verbose test "$(commit_message HEAD~)" = "files_subtree/master4" +' + +# FAILURE: Does not preserve master5. +test_expect_failure 'Rebase -Xsubtree --preserve-merges --onto commit 5' ' + reset_rebase && + git checkout -b rebase-preserve-merges-5 master && + git filter-branch --prune-empty -f --subdirectory-filter files_subtree && + git commit -m "Empty commit" --allow-empty && + git rebase -Xsubtree=files_subtree --preserve-merges --onto files-master master && + verbose test "$(commit_message HEAD)" = "files_subtree/master5" +' + +# FAILURE: Does not preserve master4. +test_expect_failure 'Rebase -Xsubtree --keep-empty --preserve-merges --onto commit 4' ' + reset_rebase && + git checkout -b rebase-keep-empty-4 master && + git filter-branch --prune-empty -f --subdirectory-filter files_subtree && + git commit -m "Empty commit" --allow-empty && + git rebase -Xsubtree=files_subtree --keep-empty --preserve-merges --onto files-master master && + verbose test "$(commit_message HEAD~2)" = "files_subtree/master4" +' + +# FAILURE: Does not preserve master5. +test_expect_failure 'Rebase -Xsubtree --keep-empty --preserve-merges --onto commit 5' ' + reset_rebase && + git checkout -b rebase-keep-empty-5 master && + git filter-branch --prune-empty -f --subdirectory-filter files_subtree && + git commit -m "Empty commit" --allow-empty && + git rebase -Xsubtree=files_subtree --keep-empty --preserve-merges --onto files-master master && + verbose test "$(commit_message HEAD~)" = "files_subtree/master5" +' + +# FAILURE: Does not preserve Empty. +test_expect_failure 'Rebase -Xsubtree --keep-empty --preserve-merges --onto empty commit' ' + reset_rebase && + git checkout -b rebase-keep-empty-empty master && + git filter-branch --prune-empty -f --subdirectory-filter files_subtree && + git commit -m "Empty commit" --allow-empty && + git rebase -Xsubtree=files_subtree --keep-empty --preserve-merges --onto files-master master && + verbose test "$(commit_message HEAD)" = "Empty commit" +' + +# FAILURE: fatal: Could not parse object +test_expect_failure 'Rebase -Xsubtree --onto commit 4' ' + reset_rebase && + git checkout -b rebase-onto-4 master && + git filter-branch --prune-empty -f --subdirectory-filter files_subtree && + git commit -m "Empty commit" --allow-empty && + git rebase -Xsubtree=files_subtree --onto files-master master && + verbose test "$(commit_message HEAD~2)" = "files_subtree/master4" +' + +# FAILURE: fatal: Could not parse object +test_expect_failure 'Rebase -Xsubtree --onto commit 5' ' + reset_rebase && + git checkout -b rebase-onto-5 master && + git filter-branch --prune-empty -f --subdirectory-filter files_subtree && + git commit -m "Empty commit" --allow-empty && + git rebase -Xsubtree=files_subtree --onto files-master master && + verbose test "$(commit_message HEAD~)" = "files_subtree/master5" +' +# FAILURE: fatal: Could not parse object +test_expect_failure 'Rebase -Xsubtree --onto empty commit' ' + reset_rebase && + git checkout -b rebase-onto-empty master && + git filter-branch --prune-empty -f --subdirectory-filter files_subtree && + git commit -m "Empty commit" --allow-empty && + git rebase -Xsubtree=files_subtree --onto files-master master && + verbose test "$(commit_message HEAD)" = "Empty commit" +' + +test_done diff --git a/t/t3700-add.sh b/t/t3700-add.sh index f14a665356..4865304ebb 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -332,4 +332,34 @@ test_expect_success 'git add --dry-run --ignore-missing of non-existing file out test_i18ncmp expect.err actual.err ' +test_expect_success 'git add --chmod=+x stages a non-executable file with +x' ' + echo foo >foo1 && + git add --chmod=+x foo1 && + case "$(git ls-files --stage foo1)" in + 100755" "*foo1) echo pass;; + *) echo fail; git ls-files --stage foo1; (exit 1);; + esac +' + +test_expect_success 'git add --chmod=-x stages an executable file with -x' ' + echo foo >xfoo1 && + chmod 755 xfoo1 && + git add --chmod=-x xfoo1 && + case "$(git ls-files --stage xfoo1)" in + 100644" "*xfoo1) echo pass;; + *) echo fail; git ls-files --stage xfoo1; (exit 1);; + esac +' + +test_expect_success POSIXPERM,SYMLINKS 'git add --chmod=+x with symlinks' ' + git config core.filemode 1 && + git config core.symlinks 1 && + echo foo >foo2 && + git add --chmod=+x foo2 && + case "$(git ls-files --stage foo2)" in + 100755" "*foo2) echo pass;; + *) echo fail; git ls-files --stage foo2; (exit 1);; + esac +' + test_done diff --git a/t/t4001-diff-rename.sh b/t/t4001-diff-rename.sh index ed90c6c6f9..0d1fa45d25 100755 --- a/t/t4001-diff-rename.sh +++ b/t/t4001-diff-rename.sh @@ -9,21 +9,84 @@ test_description='Test rename detection in diff engine. . ./test-lib.sh . "$TEST_DIRECTORY"/diff-lib.sh -echo >path0 'Line 1 -Line 2 -Line 3 -Line 4 -Line 5 -Line 6 -Line 7 -Line 8 -Line 9 -Line 10 -line 11 -Line 12 -Line 13 -Line 14 -Line 15 +test_expect_success 'setup' ' + cat >path0 <<-\EOF && + Line 1 + Line 2 + Line 3 + Line 4 + Line 5 + Line 6 + Line 7 + Line 8 + Line 9 + Line 10 + line 11 + Line 12 + Line 13 + Line 14 + Line 15 + EOF + cat >expected <<-\EOF && + diff --git a/path0 b/path1 + rename from path0 + rename to path1 + --- a/path0 + +++ b/path1 + @@ -8,7 +8,7 @@ Line 7 + Line 8 + Line 9 + Line 10 + -line 11 + +Line 11 + Line 12 + Line 13 + Line 14 + EOF + cat >no-rename <<-\EOF + diff --git a/path0 b/path0 + deleted file mode 100644 + index fdbec44..0000000 + --- a/path0 + +++ /dev/null + @@ -1,15 +0,0 @@ + -Line 1 + -Line 2 + -Line 3 + -Line 4 + -Line 5 + -Line 6 + -Line 7 + -Line 8 + -Line 9 + -Line 10 + -line 11 + -Line 12 + -Line 13 + -Line 14 + -Line 15 + diff --git a/path1 b/path1 + new file mode 100644 + index 0000000..752c50e + --- /dev/null + +++ b/path1 + @@ -0,0 +1,15 @@ + +Line 1 + +Line 2 + +Line 3 + +Line 4 + +Line 5 + +Line 6 + +Line 7 + +Line 8 + +Line 9 + +Line 10 + +Line 11 + +Line 12 + +Line 13 + +Line 14 + +Line 15 + EOF ' test_expect_success \ @@ -43,27 +106,27 @@ test_expect_success \ test_expect_success \ 'git diff-index -p -M after rename and editing.' \ 'git diff-index -p -M $tree >current' -cat >expected <<\EOF -diff --git a/path0 b/path1 -rename from path0 -rename to path1 ---- a/path0 -+++ b/path1 -@@ -8,7 +8,7 @@ Line 7 - Line 8 - Line 9 - Line 10 --line 11 -+Line 11 - Line 12 - Line 13 - Line 14 -EOF + test_expect_success \ 'validate the output.' \ 'compare_diff_patch current expected' +test_expect_success 'test diff.renames=true' ' + git -c diff.renames=true diff --cached $tree >current && + compare_diff_patch current expected +' + +test_expect_success 'test diff.renames=false' ' + git -c diff.renames=false diff --cached $tree >current && + compare_diff_patch current no-rename +' + +test_expect_success 'test diff.renames unset' ' + git diff --cached $tree >current && + compare_diff_patch current expected +' + test_expect_success 'favour same basenames over different ones' ' cp path1 another-path && git add another-path && diff --git a/t/t4010-diff-pathspec.sh b/t/t4010-diff-pathspec.sh index 43c488b545..35b35a81c8 100755 --- a/t/t4010-diff-pathspec.sh +++ b/t/t4010-diff-pathspec.sh @@ -78,8 +78,6 @@ test_expect_success 'diff-tree pathspec' ' test_cmp expected current ' -EMPTY_TREE=4b825dc642cb6eb9a060e54bf8d69288fbee4904 - test_expect_success 'diff-tree with wildcard shows dir also matches' ' git diff-tree --name-only $EMPTY_TREE $tree -- "f*" >result && echo file0 >expected && diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index 6ec6072118..94ef5000e7 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -90,6 +90,8 @@ test_expect_success setup ' git commit -m "Rearranged lines in dir/sub" && git checkout master && + git config diff.renames false && + git show-branch ' diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index 3b99434e3e..805dc9012d 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -549,7 +549,7 @@ test_expect_success 'cover-letter inherits diff options' ' git mv file foo && git commit -m foo && - git format-patch --cover-letter -1 && + git format-patch --no-renames --cover-letter -1 && check_patch 0000-cover-letter.patch && ! grep "file => foo .* 0 *\$" 0000-cover-letter.patch && git format-patch --cover-letter -1 -M && @@ -703,7 +703,7 @@ test_expect_success 'options no longer allowed for format-patch' ' test_expect_success 'format-patch --numstat should produce a patch' ' git format-patch --numstat --stdout master..side > output && - test 6 = $(grep "^diff --git a/" output | wc -l)' + test 5 = $(grep "^diff --git a/" output | wc -l)' test_expect_success 'format-patch -- <path>' ' git format-patch master..side -- file 2>error && @@ -1072,7 +1072,7 @@ test_expect_success '--from omits redundant in-body header' ' ' test_expect_success 'in-body headers trigger content encoding' ' - GIT_AUTHOR_NAME="éxötìc" test_commit exotic && + test_env GIT_AUTHOR_NAME="éxötìc" test_commit exotic && test_when_finished "git reset --hard HEAD^" && git format-patch -1 --stdout --from >patch && cat >expect <<-\EOF && @@ -1460,4 +1460,109 @@ test_expect_success 'format-patch -o overrides format.outputDirectory' ' test_path_is_dir patchset ' +test_expect_success 'format-patch --base' ' + git checkout side && + git format-patch --stdout --base=HEAD~3 -1 >patch && + grep "^base-commit:" patch >actual && + grep "^prerequisite-patch-id:" patch >>actual && + echo "base-commit: $(git rev-parse HEAD~3)" >expected && + echo "prerequisite-patch-id: $(git show --patch HEAD~2 | git patch-id --stable | awk "{print \$1}")" >>expected && + echo "prerequisite-patch-id: $(git show --patch HEAD~1 | git patch-id --stable | awk "{print \$1}")" >>expected && + test_cmp expected actual +' + +test_expect_success 'format-patch --base errors out when base commit is in revision list' ' + test_must_fail git format-patch --base=HEAD -2 && + test_must_fail git format-patch --base=HEAD~1 -2 && + git format-patch --stdout --base=HEAD~2 -2 >patch && + grep "^base-commit:" patch >actual && + echo "base-commit: $(git rev-parse HEAD~2)" >expected && + test_cmp expected actual +' + +test_expect_success 'format-patch --base errors out when base commit is not ancestor of revision list' ' + # For history as below: + # + # ---Q---P---Z---Y---*---X + # \ / + # ------------W + # + # If "format-patch Z..X" is given, P and Z can not be specified as the base commit + git checkout -b topic1 master && + git rev-parse HEAD >commit-id-base && + test_commit P && + git rev-parse HEAD >commit-id-P && + test_commit Z && + git rev-parse HEAD >commit-id-Z && + test_commit Y && + git checkout -b topic2 master && + test_commit W && + git merge topic1 && + test_commit X && + test_must_fail git format-patch --base=$(cat commit-id-P) -3 && + test_must_fail git format-patch --base=$(cat commit-id-Z) -3 && + git format-patch --stdout --base=$(cat commit-id-base) -3 >patch && + grep "^base-commit:" patch >actual && + echo "base-commit: $(cat commit-id-base)" >expected && + test_cmp expected actual +' + +test_expect_success 'format-patch --base=auto' ' + git checkout -b upstream master && + git checkout -b local upstream && + git branch --set-upstream-to=upstream && + test_commit N1 && + test_commit N2 && + git format-patch --stdout --base=auto -2 >patch && + grep "^base-commit:" patch >actual && + echo "base-commit: $(git rev-parse upstream)" >expected && + test_cmp expected actual +' + +test_expect_success 'format-patch errors out when history involves criss-cross' ' + # setup criss-cross history + # + # B---M1---D + # / \ / + # A X + # \ / \ + # C---M2---E + # + git checkout master && + test_commit A && + git checkout -b xb master && + test_commit B && + git checkout -b xc master && + test_commit C && + git checkout -b xbc xb -- && + git merge xc && + git checkout -b xcb xc -- && + git branch --set-upstream-to=xbc && + git merge xb && + git checkout xbc && + test_commit D && + git checkout xcb && + test_commit E && + test_must_fail git format-patch --base=auto -1 +' + +test_expect_success 'format-patch format.useAutoBaseoption' ' + test_when_finished "git config --unset format.useAutoBase" && + git checkout local && + git config format.useAutoBase true && + git format-patch --stdout -1 >patch && + grep "^base-commit:" patch >actual && + echo "base-commit: $(git rev-parse upstream)" >expected && + test_cmp expected actual +' + +test_expect_success 'format-patch --base overrides format.useAutoBase' ' + test_when_finished "git config --unset format.useAutoBase" && + git config format.useAutoBase true && + git format-patch --stdout --base=HEAD~1 -1 >patch && + grep "^base-commit:" patch >actual && + echo "base-commit: $(git rev-parse HEAD~1)" >expected && + test_cmp expected actual +' + test_done diff --git a/t/t4033-diff-patience.sh b/t/t4033-diff-patience.sh index 3c9932edf3..113304dc59 100755 --- a/t/t4033-diff-patience.sh +++ b/t/t4033-diff-patience.sh @@ -5,6 +5,14 @@ test_description='patience diff algorithm' . ./test-lib.sh . "$TEST_DIRECTORY"/lib-diff-alternative.sh +test_expect_success '--ignore-space-at-eol with a single appended character' ' + printf "a\nb\nc\n" >pre && + printf "a\nbX\nc\n" >post && + test_must_fail git diff --no-index \ + --patience --ignore-space-at-eol pre post >diff && + grep "^+.*X" diff +' + test_diff_frobnitz "patience" test_diff_unique "patience" diff --git a/t/t4047-diff-dirstat.sh b/t/t4047-diff-dirstat.sh index 3b8b7921d6..447a8ffa3a 100755 --- a/t/t4047-diff-dirstat.sh +++ b/t/t4047-diff-dirstat.sh @@ -248,7 +248,8 @@ EOF git rm -r src/move/unchanged && git rm -r src/move/changed && git rm -r src/move/rearranged && - git commit -m "changes" + git commit -m "changes" && + git config diff.renames false ' cat <<EOF >expect_diff_stat diff --git a/t/t4051-diff-function-context.sh b/t/t4051-diff-function-context.sh index 001d678e09..b79b87790b 100755 --- a/t/t4051-diff-function-context.sh +++ b/t/t4051-diff-function-context.sh @@ -3,90 +3,180 @@ test_description='diff function context' . ./test-lib.sh -. "$TEST_DIRECTORY"/diff-lib.sh +dir="$TEST_DIRECTORY/t4051" -cat <<\EOF >hello.c -#include <stdio.h> - -static int a(void) -{ - /* - * Dummy. - */ +commit_and_tag () { + tag=$1 && + shift && + git add "$@" && + test_tick && + git commit -m "$tag" && + git tag "$tag" } -static int hello_world(void) -{ - /* Classic. */ - printf("Hello world.\n"); - - /* Success! */ - return 0; +first_context_line () { + awk ' + found {print; exit} + /^@@/ {found = 1} + ' } -static int b(void) -{ - /* - * Dummy, too. - */ + +last_context_line () { + sed -ne \$p } -int main(int argc, char **argv) -{ - a(); - b(); - return hello_world(); +check_diff () { + name=$1 + desc=$2 + options="-W $3" + + test_expect_success "$desc" ' + git diff $options "$name^" "$name" >"$name.diff" + ' + + test_expect_success ' diff applies' ' + test_when_finished "git reset --hard" && + git checkout --detach "$name^" && + git apply --index "$name.diff" && + git diff --exit-code "$name" + ' } -EOF test_expect_success 'setup' ' - git add hello.c && - test_tick && - git commit -m initial && - - grep -v Classic <hello.c >hello.c.new && - mv hello.c.new hello.c -' - -cat <<\EOF >expected -diff --git a/hello.c b/hello.c ---- a/hello.c -+++ b/hello.c -@@ -10,8 +10,7 @@ static int a(void) - static int hello_world(void) - { -- /* Classic. */ - printf("Hello world.\n"); - - /* Success! */ - return 0; - } -EOF - -test_expect_success 'diff -U0 -W' ' - git diff -U0 -W >actual && - compare_diff_patch actual expected -' - -cat <<\EOF >expected -diff --git a/hello.c b/hello.c ---- a/hello.c -+++ b/hello.c -@@ -9,9 +9,8 @@ static int a(void) - - static int hello_world(void) - { -- /* Classic. */ - printf("Hello world.\n"); - - /* Success! */ - return 0; - } -EOF - -test_expect_success 'diff -W' ' - git diff -W >actual && - compare_diff_patch actual expected + cat "$dir/includes.c" "$dir/dummy.c" "$dir/dummy.c" "$dir/hello.c" \ + "$dir/dummy.c" "$dir/dummy.c" >file.c && + commit_and_tag initial file.c && + + grep -v "delete me from hello" <file.c >file.c.new && + mv file.c.new file.c && + commit_and_tag changed_hello file.c && + + grep -v "delete me from includes" <file.c >file.c.new && + mv file.c.new file.c && + commit_and_tag changed_includes file.c && + + cat "$dir/appended1.c" >>file.c && + commit_and_tag appended file.c && + + cat "$dir/appended2.c" >>file.c && + commit_and_tag extended file.c && + + grep -v "Begin of second part" <file.c >file.c.new && + mv file.c.new file.c && + commit_and_tag long_common_tail file.c && + + git checkout initial && + grep -v "delete me from hello" <file.c >file.c.new && + mv file.c.new file.c && + cat "$dir/appended1.c" >>file.c && + commit_and_tag changed_hello_appended file.c +' + +check_diff changed_hello 'changed function' + +test_expect_success ' context includes begin' ' + grep "^ .*Begin of hello" changed_hello.diff +' + +test_expect_success ' context includes end' ' + grep "^ .*End of hello" changed_hello.diff +' + +test_expect_success ' context does not include other functions' ' + test $(grep -c "^[ +-].*Begin" changed_hello.diff) -le 1 +' + +test_expect_success ' context does not include preceding empty lines' ' + test "$(first_context_line <changed_hello.diff)" != " " +' + +test_expect_success ' context does not include trailing empty lines' ' + test "$(last_context_line <changed_hello.diff)" != " " +' + +check_diff changed_includes 'changed includes' + +test_expect_success ' context includes begin' ' + grep "^ .*Begin.h" changed_includes.diff +' + +test_expect_success ' context includes end' ' + grep "^ .*End.h" changed_includes.diff +' + +test_expect_success ' context does not include other functions' ' + test $(grep -c "^[ +-].*Begin" changed_includes.diff) -le 1 +' + +test_expect_success ' context does not include trailing empty lines' ' + test "$(last_context_line <changed_includes.diff)" != " " +' + +check_diff appended 'appended function' + +test_expect_success ' context includes begin' ' + grep "^[+].*Begin of first part" appended.diff +' + +test_expect_success ' context includes end' ' + grep "^[+].*End of first part" appended.diff +' + +test_expect_success ' context does not include other functions' ' + test $(grep -c "^[ +-].*Begin" appended.diff) -le 1 +' + +check_diff extended 'appended function part' + +test_expect_success ' context includes begin' ' + grep "^ .*Begin of first part" extended.diff +' + +test_expect_success ' context includes end' ' + grep "^[+].*End of second part" extended.diff +' + +test_expect_success ' context does not include other functions' ' + test $(grep -c "^[ +-].*Begin" extended.diff) -le 2 +' + +test_expect_success ' context does not include preceding empty lines' ' + test "$(first_context_line <extended.diff)" != " " +' + +check_diff long_common_tail 'change with long common tail and no context' -U0 + +test_expect_success ' context includes begin' ' + grep "^ .*Begin of first part" long_common_tail.diff +' + +test_expect_success ' context includes end' ' + grep "^ .*End of second part" long_common_tail.diff +' + +test_expect_success ' context does not include other functions' ' + test $(grep -c "^[ +-].*Begin" long_common_tail.diff) -le 2 +' + +test_expect_success ' context does not include preceding empty lines' ' + test "$(first_context_line <long_common_tail.diff.diff)" != " " +' + +check_diff changed_hello_appended 'changed function plus appended function' + +test_expect_success ' context includes begin' ' + grep "^ .*Begin of hello" changed_hello_appended.diff && + grep "^[+].*Begin of first part" changed_hello_appended.diff +' + +test_expect_success ' context includes end' ' + grep "^ .*End of hello" changed_hello_appended.diff && + grep "^[+].*End of first part" changed_hello_appended.diff +' + +test_expect_success ' context does not include other functions' ' + test $(grep -c "^[ +-].*Begin" changed_hello_appended.diff) -le 2 ' test_done diff --git a/t/t4051/appended1.c b/t/t4051/appended1.c new file mode 100644 index 0000000000..a9f56f11db --- /dev/null +++ b/t/t4051/appended1.c @@ -0,0 +1,15 @@ + +int appended(void) // Begin of first part +{ + int i; + char *s = "a string"; + + printf("%s\n", s); + + for (i = 99; + i >= 0; + i--) { + printf("%d bottles of beer on the wall\n", i); + } + + printf("End of first part\n"); diff --git a/t/t4051/appended2.c b/t/t4051/appended2.c new file mode 100644 index 0000000000..e651f7147b --- /dev/null +++ b/t/t4051/appended2.c @@ -0,0 +1,35 @@ + printf("Begin of second part\n"); + + /* + * Lorem ipsum dolor sit amet, consectetuer sadipscing elitr, + * sed diam nonumy eirmod tempor invidunt ut labore et dolore + * magna aliquyam erat, sed diam voluptua. At vero eos et + * accusam et justo duo dolores et ea rebum. Stet clita kasd + * gubergren, no sea takimata sanctus est Lorem ipsum dolor + * sit amet. + * + * Lorem ipsum dolor sit amet, consectetuer sadipscing elitr, + * sed diam nonumy eirmod tempor invidunt ut labore et dolore + * magna aliquyam erat, sed diam voluptua. At vero eos et + * accusam et justo duo dolores et ea rebum. Stet clita kasd + * gubergren, no sea takimata sanctus est Lorem ipsum dolor + * sit amet. + * + * Lorem ipsum dolor sit amet, consectetuer sadipscing elitr, + * sed diam nonumy eirmod tempor invidunt ut labore et dolore + * magna aliquyam erat, sed diam voluptua. At vero eos et + * accusam et justo duo dolores et ea rebum. Stet clita kasd + * gubergren, no sea takimata sanctus est Lorem ipsum dolor + * sit amet. + * + * Lorem ipsum dolor sit amet, consectetuer sadipscing elitr, + * sed diam nonumy eirmod tempor invidunt ut labore et dolore + * magna aliquyam erat, sed diam voluptua. At vero eos et + * accusam et justo duo dolores et ea rebum. Stet clita kasd + * gubergren, no sea takimata sanctus est Lorem ipsum dolor + * sit amet. + * + */ + + return 0; +} // End of second part diff --git a/t/t4051/dummy.c b/t/t4051/dummy.c new file mode 100644 index 0000000000..a43016e870 --- /dev/null +++ b/t/t4051/dummy.c @@ -0,0 +1,7 @@ + +static int dummy(void) // Begin of dummy +{ + int rc = 0; + + return rc; +} // End of dummy diff --git a/t/t4051/hello.c b/t/t4051/hello.c new file mode 100644 index 0000000000..63b1a1e4ef --- /dev/null +++ b/t/t4051/hello.c @@ -0,0 +1,21 @@ + +static void hello(void) // Begin of hello +{ + /* + * Classic. + */ + putchar('H'); + putchar('e'); + putchar('l'); + putchar('l'); + putchar('o'); + putchar(' '); + /* delete me from hello */ + putchar('w'); + putchar('o'); + putchar('r'); + putchar('l'); + putchar('d'); + putchar('.'); + putchar('\n'); +} // End of hello diff --git a/t/t4051/includes.c b/t/t4051/includes.c new file mode 100644 index 0000000000..efc68f8bf6 --- /dev/null +++ b/t/t4051/includes.c @@ -0,0 +1,20 @@ +#include <Begin.h> +#include <unistd.h> +#include <stdio.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stddef.h> +#include <stdlib.h> +#include <stdarg.h> +/* delete me from includes */ +#include <string.h> +#include <sys/types.h> +#include <dirent.h> +#include <sys/time.h> +#include <time.h> +#include <signal.h> +#include <assert.h> +#include <regex.h> +#include <utime.h> +#include <syslog.h> +#include <End.h> diff --git a/t/t4054-diff-bogus-tree.sh b/t/t4054-diff-bogus-tree.sh index 1d6efab3c5..18f42c5fff 100755 --- a/t/t4054-diff-bogus-tree.sh +++ b/t/t4054-diff-bogus-tree.sh @@ -3,8 +3,6 @@ test_description='test diff with a bogus tree containing the null sha1' . ./test-lib.sh -empty_tree=4b825dc642cb6eb9a060e54bf8d69288fbee4904 - test_expect_success 'create bogus tree' ' bogus_tree=$( printf "100644 fooQQQQQQQQQQQQQQQQQQQQQ" | @@ -22,13 +20,13 @@ test_expect_success 'create tree with matching file' ' test_expect_success 'raw diff shows null sha1 (addition)' ' echo ":000000 100644 $_z40 $_z40 A foo" >expect && - git diff-tree $empty_tree $bogus_tree >actual && + git diff-tree $EMPTY_TREE $bogus_tree >actual && test_cmp expect actual ' test_expect_success 'raw diff shows null sha1 (removal)' ' echo ":100644 000000 $_z40 $_z40 D foo" >expect && - git diff-tree $bogus_tree $empty_tree >actual && + git diff-tree $bogus_tree $EMPTY_TREE >actual && test_cmp expect actual ' @@ -57,11 +55,11 @@ test_expect_success 'raw diff shows null sha1 (index)' ' ' test_expect_success 'patch fails due to bogus sha1 (addition)' ' - test_must_fail git diff-tree -p $empty_tree $bogus_tree + test_must_fail git diff-tree -p $EMPTY_TREE $bogus_tree ' test_expect_success 'patch fails due to bogus sha1 (removal)' ' - test_must_fail git diff-tree -p $bogus_tree $empty_tree + test_must_fail git diff-tree -p $bogus_tree $EMPTY_TREE ' test_expect_success 'patch fails due to bogus sha1 (modification)' ' diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index d173acde0f..f8a313bcb9 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -13,9 +13,13 @@ create_file() { } test_expect_success 'setup' ' - create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + # Ensure that file sizes are different, because on Windows + # lstat() does not discover inode numbers, and we need + # other properties to discover swapped files + # (mtime is not always different, either). + create_file file1 "some content" && + create_file file2 "some other content" && + create_file file3 "again something else" && git add file1 file2 file3 && git commit -m 1 ' diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh index ed9c91e25b..1a080e7823 100755 --- a/t/t4200-rerere.sh +++ b/t/t4200-rerere.sh @@ -184,12 +184,27 @@ test_expect_success 'rerere updates postimage timestamp' ' ' test_expect_success 'rerere clear' ' - rm $rr/postimage && + mv $rr/postimage .git/post-saved && echo "$sha1 a1" | perl -pe "y/\012/\000/" >.git/MERGE_RR && git rerere clear && ! test -d $rr ' +test_expect_success 'leftover directory' ' + git reset --hard && + mkdir -p $rr && + test_must_fail git merge first && + test -f $rr/preimage +' + +test_expect_success 'missing preimage' ' + git reset --hard && + mkdir -p $rr && + cp .git/post-saved $rr/postimage && + test_must_fail git merge first && + test -f $rr/preimage +' + test_expect_success 'set up for garbage collection tests' ' mkdir -p $rr && echo Hello >$rr/preimage && @@ -391,4 +406,157 @@ test_expect_success 'rerere -h' ' test_i18ngrep [Uu]sage help ' +concat_insert () { + last=$1 + shift + cat early && printf "%s\n" "$@" && cat late "$last" +} + +count_pre_post () { + find .git/rr-cache/ -type f -name "preimage*" >actual && + test_line_count = "$1" actual && + find .git/rr-cache/ -type f -name "postimage*" >actual && + test_line_count = "$2" actual +} + +test_expect_success 'rerere gc' ' + find .git/rr-cache -type f >original && + xargs test-chmtime -172800 <original && + + git -c gc.rerereresolved=5 -c gc.rerereunresolved=5 rerere gc && + find .git/rr-cache -type f >actual && + test_cmp original actual && + + git -c gc.rerereresolved=5 -c gc.rerereunresolved=0 rerere gc && + find .git/rr-cache -type f >actual && + test_cmp original actual && + + git -c gc.rerereresolved=0 -c gc.rerereunresolved=0 rerere gc && + find .git/rr-cache -type f >actual && + >expect && + test_cmp expect actual +' + +merge_conflict_resolve () { + git reset --hard && + test_must_fail git merge six.1 && + # Resolution is to replace 7 with 6.1 and 6.2 (i.e. take both) + concat_insert short 6.1 6.2 >file1 && + concat_insert long 6.1 6.2 >file2 +} + +test_expect_success 'multiple identical conflicts' ' + git reset --hard && + + test_seq 1 6 >early && + >late && + test_seq 11 15 >short && + test_seq 111 120 >long && + concat_insert short >file1 && + concat_insert long >file2 && + git add file1 file2 && + git commit -m base && + git tag base && + git checkout -b six.1 && + concat_insert short 6.1 >file1 && + concat_insert long 6.1 >file2 && + git add file1 file2 && + git commit -m 6.1 && + git checkout -b six.2 HEAD^ && + concat_insert short 6.2 >file1 && + concat_insert long 6.2 >file2 && + git add file1 file2 && + git commit -m 6.2 && + + # At this point, six.1 and six.2 + # - derive from common ancestor that has two files + # 1...6 7 11..15 (file1) and 1...6 7 111..120 (file2) + # - six.1 replaces these 7s with 6.1 + # - six.2 replaces these 7s with 6.2 + + merge_conflict_resolve && + + # Check that rerere knows that file1 and file2 have conflicts + + printf "%s\n" file1 file2 >expect && + git ls-files -u | sed -e "s/^.* //" | sort -u >actual && + test_cmp expect actual && + + git rerere status | sort >actual && + test_cmp expect actual && + + git rerere remaining >actual && + test_cmp expect actual && + + count_pre_post 2 0 && + + # Pretend that the conflicts were made quite some time ago + find .git/rr-cache/ -type f | xargs test-chmtime -172800 && + + # Unresolved entries have not expired yet + git -c gc.rerereresolved=5 -c gc.rerereunresolved=5 rerere gc && + count_pre_post 2 0 && + + # Unresolved entries have expired + git -c gc.rerereresolved=5 -c gc.rerereunresolved=1 rerere gc && + count_pre_post 0 0 && + + # Recreate the conflicted state + merge_conflict_resolve && + count_pre_post 2 0 && + + # Clear it + git rerere clear && + count_pre_post 0 0 && + + # Recreate the conflicted state + merge_conflict_resolve && + count_pre_post 2 0 && + + # We resolved file1 and file2 + git rerere && + >expect && + git rerere remaining >actual && + test_cmp expect actual && + + # We must have recorded both of them + count_pre_post 2 2 && + + # Now we should be able to resolve them both + git reset --hard && + test_must_fail git merge six.1 && + git rerere && + + >expect && + git rerere remaining >actual && + test_cmp expect actual && + + concat_insert short 6.1 6.2 >file1.expect && + concat_insert long 6.1 6.2 >file2.expect && + test_cmp file1.expect file1 && + test_cmp file2.expect file2 && + + # Forget resolution for file2 + git rerere forget file2 && + echo file2 >expect && + git rerere status >actual && + test_cmp expect actual && + count_pre_post 2 1 && + + # file2 already has correct resolution, so record it again + git rerere && + + # Pretend that the resolutions are old again + find .git/rr-cache/ -type f | xargs test-chmtime -172800 && + + # Resolved entries have not expired yet + git -c gc.rerereresolved=5 -c gc.rerereunresolved=5 rerere gc && + + count_pre_post 2 2 && + + # Resolved entries have expired + git -c gc.rerereresolved=1 -c gc.rerereunresolved=5 rerere gc && + count_pre_post 0 0 +' + test_done diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh index f5e63670fa..a9773658f0 100755 --- a/t/t4201-shortlog.sh +++ b/t/t4201-shortlog.sh @@ -115,7 +115,7 @@ EOF ' test_expect_success !MINGW 'shortlog from non-git directory' ' - git log HEAD >log && + git log --no-expand-tabs HEAD >log && GIT_DIR=non-existing git shortlog -w <log >out && test_cmp expect out ' diff --git a/t/t4202-log.sh b/t/t4202-log.sh index cb82eb7e66..0b53e56694 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -101,8 +101,8 @@ test_expect_success 'oneline' ' test_expect_success 'diff-filter=A' ' - git log --pretty="format:%s" --diff-filter=A HEAD > actual && - git log --pretty="format:%s" --diff-filter A HEAD > actual-separate && + git log --no-renames --pretty="format:%s" --diff-filter=A HEAD > actual && + git log --no-renames --pretty="format:%s" --diff-filter A HEAD > actual-separate && printf "fifth\nfourth\nthird\ninitial" > expect && test_cmp expect actual && test_cmp expect actual-separate @@ -119,7 +119,7 @@ test_expect_success 'diff-filter=M' ' test_expect_success 'diff-filter=D' ' - actual=$(git log --pretty="format:%s" --diff-filter=D HEAD) && + actual=$(git log --no-renames --pretty="format:%s" --diff-filter=D HEAD) && expect=$(echo sixth ; echo third) && verbose test "$actual" = "$expect" @@ -255,6 +255,20 @@ test_expect_success 'log -F -E --grep=<ere> uses ere' ' test_cmp expect actual ' +test_expect_success 'log with grep.patternType configuration' ' + >expect && + git -c grep.patterntype=fixed \ + log -1 --pretty=tformat:%s --grep=s.c.nd >actual && + test_cmp expect actual +' + +test_expect_success 'log with grep.patternType configuration and command line' ' + echo second >expect && + git -c grep.patterntype=fixed \ + log -1 --pretty=tformat:%s --basic-regexp --grep=s.c.nd >actual && + test_cmp expect actual +' + cat > expect <<EOF * Second * sixth @@ -848,7 +862,7 @@ sanitize_output () { } test_expect_success 'log --graph with diff and stats' ' - git log --graph --pretty=short --stat -p >actual && + git log --no-renames --graph --pretty=short --stat -p >actual && sanitize_output >actual.sanitized <actual && test_i18ncmp expect actual.sanitized ' diff --git a/t/t4204-patch-id.sh b/t/t4204-patch-id.sh index baa9d3c82e..84a809690e 100755 --- a/t/t4204-patch-id.sh +++ b/t/t4204-patch-id.sh @@ -30,11 +30,11 @@ test_expect_success 'patch-id output is well-formed' ' #calculate patch id. Make sure output is not empty. calc_patch_id () { - name="$1" + patch_name="$1" shift git patch-id "$@" | - sed "s/ .*//" >patch-id_"$name" && - test_line_count -gt 0 patch-id_"$name" + sed "s/ .*//" >patch-id_"$patch_name" && + test_line_count -gt 0 patch-id_"$patch_name" } get_top_diff () { diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh index 7398605e7b..f5435fd250 100755 --- a/t/t4205-log-pretty-formats.sh +++ b/t/t4205-log-pretty-formats.sh @@ -145,253 +145,310 @@ test_expect_success 'setup more commits' ' test_expect_success 'left alignment formatting' ' git log --pretty="tformat:%<(40)%s" >actual && - qz_to_tab_space <<EOF >expected && -message two Z -message one Z -add bar Z -$(commit_msg) Z -EOF + qz_to_tab_space <<-EOF >expected && + message two Z + message one Z + add bar Z + $(commit_msg) Z + EOF test_cmp expected actual ' test_expect_success 'left alignment formatting. i18n.logOutputEncoding' ' git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%<(40)%s" >actual && - qz_to_tab_space <<EOF | iconv -f utf-8 -t $test_encoding >expected && -message two Z -message one Z -add bar Z -$(commit_msg) Z -EOF + qz_to_tab_space <<-EOF | iconv -f utf-8 -t $test_encoding >expected && + message two Z + message one Z + add bar Z + $(commit_msg) Z + EOF test_cmp expected actual ' test_expect_success 'left alignment formatting at the nth column' ' git log --pretty="tformat:%h %<|(40)%s" >actual && - qz_to_tab_space <<EOF >expected && -$head1 message two Z -$head2 message one Z -$head3 add bar Z -$head4 $(commit_msg) Z -EOF + qz_to_tab_space <<-EOF >expected && + $head1 message two Z + $head2 message one Z + $head3 add bar Z + $head4 $(commit_msg) Z + EOF + test_cmp expected actual +' + +test_expect_success 'left alignment formatting at the nth column' ' + COLUMNS=50 git log --pretty="tformat:%h %<|(-10)%s" >actual && + qz_to_tab_space <<-EOF >expected && + $head1 message two Z + $head2 message one Z + $head3 add bar Z + $head4 $(commit_msg) Z + EOF test_cmp expected actual ' test_expect_success 'left alignment formatting at the nth column. i18n.logOutputEncoding' ' git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%h %<|(40)%s" >actual && - qz_to_tab_space <<EOF | iconv -f utf-8 -t $test_encoding >expected && -$head1 message two Z -$head2 message one Z -$head3 add bar Z -$head4 $(commit_msg) Z -EOF + qz_to_tab_space <<-EOF | iconv -f utf-8 -t $test_encoding >expected && + $head1 message two Z + $head2 message one Z + $head3 add bar Z + $head4 $(commit_msg) Z + EOF test_cmp expected actual ' test_expect_success 'left alignment formatting with no padding' ' git log --pretty="tformat:%<(1)%s" >actual && - cat <<EOF >expected && -message two -message one -add bar -$(commit_msg) -EOF + cat <<-EOF >expected && + message two + message one + add bar + $(commit_msg) + EOF test_cmp expected actual ' test_expect_success 'left alignment formatting with no padding. i18n.logOutputEncoding' ' git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%<(1)%s" >actual && - cat <<EOF | iconv -f utf-8 -t $test_encoding >expected && -message two -message one -add bar -$(commit_msg) -EOF + cat <<-EOF | iconv -f utf-8 -t $test_encoding >expected && + message two + message one + add bar + $(commit_msg) + EOF test_cmp expected actual ' test_expect_success 'left alignment formatting with trunc' ' git log --pretty="tformat:%<(10,trunc)%s" >actual && - qz_to_tab_space <<EOF >expected && -message .. -message .. -add bar Z -initial... -EOF + qz_to_tab_space <<-\EOF >expected && + message .. + message .. + add bar Z + initial... + EOF test_cmp expected actual ' test_expect_success 'left alignment formatting with trunc. i18n.logOutputEncoding' ' git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%<(10,trunc)%s" >actual && - qz_to_tab_space <<EOF | iconv -f utf-8 -t $test_encoding >expected && -message .. -message .. -add bar Z -initial... -EOF + qz_to_tab_space <<-\EOF | iconv -f utf-8 -t $test_encoding >expected && + message .. + message .. + add bar Z + initial... + EOF test_cmp expected actual ' test_expect_success 'left alignment formatting with ltrunc' ' git log --pretty="tformat:%<(10,ltrunc)%s" >actual && - qz_to_tab_space <<EOF >expected && -..sage two -..sage one -add bar Z -..${sample_utf8_part}lich -EOF + qz_to_tab_space <<-EOF >expected && + ..sage two + ..sage one + add bar Z + ..${sample_utf8_part}lich + EOF test_cmp expected actual ' test_expect_success 'left alignment formatting with ltrunc. i18n.logOutputEncoding' ' git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%<(10,ltrunc)%s" >actual && - qz_to_tab_space <<EOF | iconv -f utf-8 -t $test_encoding >expected && -..sage two -..sage one -add bar Z -..${sample_utf8_part}lich -EOF + qz_to_tab_space <<-EOF | iconv -f utf-8 -t $test_encoding >expected && + ..sage two + ..sage one + add bar Z + ..${sample_utf8_part}lich + EOF test_cmp expected actual ' test_expect_success 'left alignment formatting with mtrunc' ' git log --pretty="tformat:%<(10,mtrunc)%s" >actual && - qz_to_tab_space <<EOF >expected && -mess.. two -mess.. one -add bar Z -init..lich -EOF + qz_to_tab_space <<-\EOF >expected && + mess.. two + mess.. one + add bar Z + init..lich + EOF test_cmp expected actual ' test_expect_success 'left alignment formatting with mtrunc. i18n.logOutputEncoding' ' git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%<(10,mtrunc)%s" >actual && - qz_to_tab_space <<EOF | iconv -f utf-8 -t $test_encoding >expected && -mess.. two -mess.. one -add bar Z -init..lich -EOF + qz_to_tab_space <<-\EOF | iconv -f utf-8 -t $test_encoding >expected && + mess.. two + mess.. one + add bar Z + init..lich + EOF test_cmp expected actual ' test_expect_success 'right alignment formatting' ' git log --pretty="tformat:%>(40)%s" >actual && - qz_to_tab_space <<EOF >expected && -Z message two -Z message one -Z add bar -Z $(commit_msg) -EOF + qz_to_tab_space <<-EOF >expected && + Z message two + Z message one + Z add bar + Z $(commit_msg) + EOF test_cmp expected actual ' test_expect_success 'right alignment formatting. i18n.logOutputEncoding' ' git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%>(40)%s" >actual && - qz_to_tab_space <<EOF | iconv -f utf-8 -t $test_encoding >expected && -Z message two -Z message one -Z add bar -Z $(commit_msg) -EOF + qz_to_tab_space <<-EOF | iconv -f utf-8 -t $test_encoding >expected && + Z message two + Z message one + Z add bar + Z $(commit_msg) + EOF test_cmp expected actual ' test_expect_success 'right alignment formatting at the nth column' ' git log --pretty="tformat:%h %>|(40)%s" >actual && - qz_to_tab_space <<EOF >expected && -$head1 message two -$head2 message one -$head3 add bar -$head4 $(commit_msg) -EOF + qz_to_tab_space <<-EOF >expected && + $head1 message two + $head2 message one + $head3 add bar + $head4 $(commit_msg) + EOF + test_cmp expected actual +' + +test_expect_success 'right alignment formatting at the nth column' ' + COLUMNS=50 git log --pretty="tformat:%h %>|(-10)%s" >actual && + qz_to_tab_space <<-EOF >expected && + $head1 message two + $head2 message one + $head3 add bar + $head4 $(commit_msg) + EOF test_cmp expected actual ' test_expect_success 'right alignment formatting at the nth column. i18n.logOutputEncoding' ' git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%h %>|(40)%s" >actual && - qz_to_tab_space <<EOF | iconv -f utf-8 -t $test_encoding >expected && -$head1 message two -$head2 message one -$head3 add bar -$head4 $(commit_msg) -EOF + qz_to_tab_space <<-EOF | iconv -f utf-8 -t $test_encoding >expected && + $head1 message two + $head2 message one + $head3 add bar + $head4 $(commit_msg) + EOF + test_cmp expected actual +' + +# Note: Space between 'message' and 'two' should be in the same column +# as in previous test. +test_expect_success 'right alignment formatting at the nth column with --graph. i18n.logOutputEncoding' ' + git -c i18n.logOutputEncoding=$test_encoding log --graph --pretty="tformat:%h %>|(40)%s" >actual && + iconv -f utf-8 -t $test_encoding >expected <<-EOF && + * $head1 message two + * $head2 message one + * $head3 add bar + * $head4 $(commit_msg) + EOF test_cmp expected actual ' test_expect_success 'right alignment formatting with no padding' ' git log --pretty="tformat:%>(1)%s" >actual && - cat <<EOF >expected && -message two -message one -add bar -$(commit_msg) -EOF + cat <<-EOF >expected && + message two + message one + add bar + $(commit_msg) + EOF + test_cmp expected actual +' + +test_expect_success 'right alignment formatting with no padding and with --graph' ' + git log --graph --pretty="tformat:%>(1)%s" >actual && + cat <<-EOF >expected && + * message two + * message one + * add bar + * $(commit_msg) + EOF test_cmp expected actual ' test_expect_success 'right alignment formatting with no padding. i18n.logOutputEncoding' ' git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%>(1)%s" >actual && - cat <<EOF | iconv -f utf-8 -t $test_encoding >expected && -message two -message one -add bar -$(commit_msg) -EOF + cat <<-EOF | iconv -f utf-8 -t $test_encoding >expected && + message two + message one + add bar + $(commit_msg) + EOF test_cmp expected actual ' test_expect_success 'center alignment formatting' ' git log --pretty="tformat:%><(40)%s" >actual && - qz_to_tab_space <<EOF >expected && -Z message two Z -Z message one Z -Z add bar Z -Z $(commit_msg) Z -EOF + qz_to_tab_space <<-EOF >expected && + Z message two Z + Z message one Z + Z add bar Z + Z $(commit_msg) Z + EOF test_cmp expected actual ' test_expect_success 'center alignment formatting. i18n.logOutputEncoding' ' git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%><(40)%s" >actual && - qz_to_tab_space <<EOF | iconv -f utf-8 -t $test_encoding >expected && -Z message two Z -Z message one Z -Z add bar Z -Z $(commit_msg) Z -EOF + qz_to_tab_space <<-EOF | iconv -f utf-8 -t $test_encoding >expected && + Z message two Z + Z message one Z + Z add bar Z + Z $(commit_msg) Z + EOF test_cmp expected actual ' test_expect_success 'center alignment formatting at the nth column' ' git log --pretty="tformat:%h %><|(40)%s" >actual && - qz_to_tab_space <<EOF >expected && -$head1 message two Z -$head2 message one Z -$head3 add bar Z -$head4 $(commit_msg) Z -EOF + qz_to_tab_space <<-EOF >expected && + $head1 message two Z + $head2 message one Z + $head3 add bar Z + $head4 $(commit_msg) Z + EOF + test_cmp expected actual +' + +test_expect_success 'center alignment formatting at the nth column' ' + COLUMNS=70 git log --pretty="tformat:%h %><|(-30)%s" >actual && + qz_to_tab_space <<-EOF >expected && + $head1 message two Z + $head2 message one Z + $head3 add bar Z + $head4 $(commit_msg) Z + EOF test_cmp expected actual ' test_expect_success 'center alignment formatting at the nth column. i18n.logOutputEncoding' ' git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%h %><|(40)%s" >actual && - qz_to_tab_space <<EOF | iconv -f utf-8 -t $test_encoding >expected && -$head1 message two Z -$head2 message one Z -$head3 add bar Z -$head4 $(commit_msg) Z -EOF + qz_to_tab_space <<-EOF | iconv -f utf-8 -t $test_encoding >expected && + $head1 message two Z + $head2 message one Z + $head3 add bar Z + $head4 $(commit_msg) Z + EOF test_cmp expected actual ' test_expect_success 'center alignment formatting with no padding' ' git log --pretty="tformat:%><(1)%s" >actual && - cat <<EOF >expected && -message two -message one -add bar -$(commit_msg) -EOF + cat <<-EOF >expected && + message two + message one + add bar + $(commit_msg) + EOF test_cmp expected actual ' @@ -400,34 +457,34 @@ EOF old_head1=$(git rev-parse --verify HEAD~0) test_expect_success 'center alignment formatting with no padding. i18n.logOutputEncoding' ' git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%><(1)%s" >actual && - cat <<EOF | iconv -f utf-8 -t $test_encoding >expected && -message two -message one -add bar -$(commit_msg) -EOF + cat <<-EOF | iconv -f utf-8 -t $test_encoding >expected && + message two + message one + add bar + $(commit_msg) + EOF test_cmp expected actual ' test_expect_success 'left/right alignment formatting with stealing' ' git commit --amend -m short --author "long long long <long@me.com>" && git log --pretty="tformat:%<(10,trunc)%s%>>(10,ltrunc)% an" >actual && - cat <<EOF >expected && -short long long long -message .. A U Thor -add bar A U Thor -initial... A U Thor -EOF + cat <<-\EOF >expected && + short long long long + message .. A U Thor + add bar A U Thor + initial... A U Thor + EOF test_cmp expected actual ' test_expect_success 'left/right alignment formatting with stealing. i18n.logOutputEncoding' ' git -c i18n.logOutputEncoding=$test_encoding log --pretty="tformat:%<(10,trunc)%s%>>(10,ltrunc)% an" >actual && - cat <<EOF | iconv -f utf-8 -t $test_encoding >expected && -short long long long -message .. A U Thor -add bar A U Thor -initial... A U Thor -EOF + cat <<-\EOF | iconv -f utf-8 -t $test_encoding >expected && + short long long long + message .. A U Thor + add bar A U Thor + initial... A U Thor + EOF test_cmp expected actual ' @@ -447,8 +504,10 @@ test_expect_success 'ISO and ISO-strict date formats display the same values' ' ' # get new digests (with no abbreviations) -head1=$(git rev-parse --verify HEAD~0) && -head2=$(git rev-parse --verify HEAD~1) && +test_expect_success 'set up log decoration tests' ' + head1=$(git rev-parse --verify HEAD~0) && + head2=$(git rev-parse --verify HEAD~1) +' test_expect_success 'log decoration properly follows tag chain' ' git tag -a tag1 -m tag1 && @@ -456,22 +515,22 @@ test_expect_success 'log decoration properly follows tag chain' ' git tag -d tag1 && git commit --amend -m shorter && git log --no-walk --tags --pretty="%H %d" --decorate=full >actual && - cat <<EOF >expected && -$head1 (tag: refs/tags/tag2) -$head2 (tag: refs/tags/message-one) -$old_head1 (tag: refs/tags/message-two) -EOF + cat <<-EOF >expected && + $head1 (tag: refs/tags/tag2) + $head2 (tag: refs/tags/message-one) + $old_head1 (tag: refs/tags/message-two) + EOF sort actual >actual1 && test_cmp expected actual1 ' test_expect_success 'clean log decoration' ' git log --no-walk --tags --pretty="%H %D" --decorate=full >actual && - cat >expected <<EOF && -$head1 tag: refs/tags/tag2 -$head2 tag: refs/tags/message-one -$old_head1 tag: refs/tags/message-two -EOF + cat >expected <<-EOF && + $head1 tag: refs/tags/tag2 + $head2 tag: refs/tags/message-one + $old_head1 tag: refs/tags/message-two + EOF sort actual >actual1 && test_cmp expected actual1 ' diff --git a/t/t4213-log-tabexpand.sh b/t/t4213-log-tabexpand.sh new file mode 100755 index 0000000000..e01a8f6ac9 --- /dev/null +++ b/t/t4213-log-tabexpand.sh @@ -0,0 +1,105 @@ +#!/bin/sh + +test_description='log/show --expand-tabs' + +. ./test-lib.sh + +HT=" " +title='tab indent at the beginning of the title line' +body='tab indent on a line in the body' + +# usage: count_expand $indent $numSP $numHT @format_args +count_expand () +{ + expect= + count=$(( $1 + $2 )) ;# expected spaces + while test $count -gt 0 + do + expect="$expect " + count=$(( $count - 1 )) + done + shift 2 + count=$1 ;# expected tabs + while test $count -gt 0 + do + expect="$expect$HT" + count=$(( $count - 1 )) + done + shift + + # The remainder of the command line is "git show -s" options + case " $* " in + *' --pretty=short '*) + line=$title ;; + *) + line=$body ;; + esac + + # Prefix the output with the command line arguments, and + # replace SP with a dot both in the expecte and actual output + # so that test_cmp would show the differene together with the + # breakage in a way easier to consume by the debugging user. + { + echo "git show -s $*" + echo "$expect$line" + } | sed -e 's/ /./g' >expect + + { + echo "git show -s $*" + git show -s "$@" | + sed -n -e "/$line\$/p" + } | sed -e 's/ /./g' >actual + + test_cmp expect actual +} + +test_expand () +{ + fmt=$1 + case "$fmt" in + *=raw | *=short | *=email) + default="0 1" ;; + *) + default="8 0" ;; + esac + case "$fmt" in + *=email) + in=0 ;; + *) + in=4 ;; + esac + test_expect_success "expand/no-expand${fmt:+ for $fmt}" ' + count_expand $in $default $fmt && + count_expand $in 8 0 $fmt --expand-tabs && + count_expand $in 8 0 --expand-tabs $fmt && + count_expand $in 8 0 $fmt --expand-tabs=8 && + count_expand $in 8 0 --expand-tabs=8 $fmt && + count_expand $in 0 1 $fmt --no-expand-tabs && + count_expand $in 0 1 --no-expand-tabs $fmt && + count_expand $in 0 1 $fmt --expand-tabs=0 && + count_expand $in 0 1 --expand-tabs=0 $fmt && + count_expand $in 4 0 $fmt --expand-tabs=4 && + count_expand $in 4 0 --expand-tabs=4 $fmt + ' +} + +test_expect_success 'setup' ' + test_tick && + sed -e "s/Q/$HT/g" <<-EOF >msg && + Q$title + + Q$body + EOF + git commit --allow-empty -F msg +' + +test_expand "" +test_expand --pretty +test_expand --pretty=short +test_expand --pretty=medium +test_expand --pretty=full +test_expand --pretty=fuller +test_expand --pretty=raw +test_expand --pretty=email + +test_done diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh index d446706e94..3893afd687 100755 --- a/t/t5310-pack-bitmaps.sh +++ b/t/t5310-pack-bitmaps.sh @@ -47,6 +47,12 @@ rev_list_tests() { test_cmp expect actual ' + test_expect_success "counting commits with limit ($state)" ' + git rev-list --count -n 1 HEAD >expect && + git rev-list --use-bitmap-index --count -n 1 HEAD >actual && + test_cmp expect actual + ' + test_expect_success "counting non-linear history ($state)" ' git rev-list --count other...master >expect && git rev-list --use-bitmap-index --count other...master >actual && diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh index 9b9bec468a..82d913a6a8 100755 --- a/t/t5500-fetch-pack.sh +++ b/t/t5500-fetch-pack.sh @@ -259,7 +259,8 @@ test_expect_success 'clone shallow object count' ' test_expect_success 'pull in shallow repo with missing merge base' ' ( cd shallow && - test_must_fail git pull --depth 4 .. A + git fetch --depth 4 .. A + test_must_fail git merge --allow-unrelated-histories FETCH_HEAD ) ' @@ -279,9 +280,10 @@ test_expect_success 'clone shallow depth count' ' test_expect_success 'clone shallow object count' ' ( cd shallow && + git prune && git count-objects -v ) > count.shallow && - grep "^count: 55" count.shallow + grep "^count: 54" count.shallow ' test_expect_success 'fetch --no-shallow on full repo' ' @@ -556,7 +558,6 @@ check_prot_path () { } check_prot_host_port_path () { - local diagport case "$2" in *ssh*) pp=ssh diff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh index 44f3d5fb28..9b19cff729 100755 --- a/t/t5504-fetch-receive-strict.sh +++ b/t/t5504-fetch-receive-strict.sh @@ -115,8 +115,8 @@ test_expect_success 'push with transfer.fsckobjects' ' test_cmp exp act ' -cat >bogus-commit <<\EOF -tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904 +cat >bogus-commit <<EOF +tree $EMPTY_TREE author Bugs Bunny 1234567890 +0000 committer Bugs Bunny <bugs@bun.ni> 1234567890 +0000 diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh index c952d5ef5c..739c089d50 100755 --- a/t/t5520-pull.sh +++ b/t/t5520-pull.sh @@ -9,6 +9,24 @@ modify () { mv "$2.x" "$2" } +test_pull_autostash () { + git reset --hard before-rebase && + echo dirty >new_file && + git add new_file && + git pull "$@" . copy && + test_cmp_rev HEAD^ copy && + test "$(cat new_file)" = dirty && + test "$(cat file)" = "modified again" +} + +test_pull_autostash_fail () { + git reset --hard before-rebase && + echo dirty >new_file && + git add new_file && + test_must_fail git pull "$@" . copy 2>err && + test_i18ngrep "uncommitted changes." err +} + test_expect_success setup ' echo file >file && git add file && @@ -247,15 +265,47 @@ test_expect_success '--rebase fails with multiple branches' ' test_expect_success 'pull --rebase succeeds with dirty working directory and rebase.autostash set' ' test_config rebase.autostash true && - git reset --hard before-rebase && - echo dirty >new_file && - git add new_file && - git pull --rebase . copy && - test_cmp_rev HEAD^ copy && - test "$(cat new_file)" = dirty && - test "$(cat file)" = "modified again" + test_pull_autostash --rebase ' +test_expect_success 'pull --rebase --autostash & rebase.autostash=true' ' + test_config rebase.autostash true && + test_pull_autostash --rebase --autostash +' + +test_expect_success 'pull --rebase --autostash & rebase.autostash=false' ' + test_config rebase.autostash false && + test_pull_autostash --rebase --autostash +' + +test_expect_success 'pull --rebase --autostash & rebase.autostash unset' ' + test_unconfig rebase.autostash && + test_pull_autostash --rebase --autostash +' + +test_expect_success 'pull --rebase --no-autostash & rebase.autostash=true' ' + test_config rebase.autostash true && + test_pull_autostash_fail --rebase --no-autostash +' + +test_expect_success 'pull --rebase --no-autostash & rebase.autostash=false' ' + test_config rebase.autostash false && + test_pull_autostash_fail --rebase --no-autostash +' + +test_expect_success 'pull --rebase --no-autostash & rebase.autostash unset' ' + test_unconfig rebase.autostash && + test_pull_autostash_fail --rebase --no-autostash +' + +for i in --autostash --no-autostash +do + test_expect_success "pull $i (without --rebase) is illegal" ' + test_must_fail git pull $i . copy 2>err && + test_i18ngrep "only valid with --rebase" err + ' +done + test_expect_success 'pull.rebase' ' git reset --hard before-rebase && test_config pull.rebase true && @@ -264,6 +314,16 @@ test_expect_success 'pull.rebase' ' test new = "$(git show HEAD:file2)" ' +test_expect_success 'pull --autostash & pull.rebase=true' ' + test_config pull.rebase true && + test_pull_autostash --autostash +' + +test_expect_success 'pull --no-autostash & pull.rebase=true' ' + test_config pull.rebase true && + test_pull_autostash_fail --no-autostash +' + test_expect_success 'branch.to-rebase.rebase' ' git reset --hard before-rebase && test_config branch.to-rebase.rebase true && diff --git a/t/t5521-pull-options.sh b/t/t5521-pull-options.sh index 18372caa15..ded8f98dbe 100755 --- a/t/t5521-pull-options.sh +++ b/t/t5521-pull-options.sh @@ -144,4 +144,25 @@ test_expect_success 'git pull --all --dry-run' ' ) ' +test_expect_success 'git pull --allow-unrelated-histories' ' + test_when_finished "rm -fr src dst" && + git init src && + ( + cd src && + test_commit one && + test_commit two + ) && + git clone src dst && + ( + cd src && + git checkout --orphan side HEAD^ && + test_commit three + ) && + ( + cd dst && + test_must_fail git pull ../src side && + git pull --allow-unrelated-histories ../src side + ) +' + test_done diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh index 1241146227..954d0e43f5 100755 --- a/t/t5526-fetch-submodules.sh +++ b/t/t5526-fetch-submodules.sh @@ -471,4 +471,18 @@ test_expect_success "don't fetch submodule when newly recorded commits are alrea test_i18ncmp expect.err actual.err ' +test_expect_success 'fetching submodules respects parallel settings' ' + git config fetch.recurseSubmodules true && + ( + cd downstream && + GIT_TRACE=$(pwd)/trace.out git fetch --jobs 7 && + grep "7 tasks" trace.out && + git config submodule.fetchJobs 8 && + GIT_TRACE=$(pwd)/trace.out git fetch && + grep "8 tasks" trace.out && + GIT_TRACE=$(pwd)/trace.out git fetch --jobs 9 && + grep "9 tasks" trace.out + ) +' + test_done diff --git a/t/t5533-push-cas.sh b/t/t5533-push-cas.sh index c7320121ec..a2c9e7439f 100755 --- a/t/t5533-push-cas.sh +++ b/t/t5533-push-cas.sh @@ -191,4 +191,42 @@ test_expect_success 'cover everything with default force-with-lease (allowed)' ' test_cmp expect actual ' +test_expect_success 'new branch covered by force-with-lease' ' + setup_srcdst_basic && + ( + cd dst && + git branch branch master && + git push --force-with-lease=branch origin branch + ) && + git ls-remote dst refs/heads/branch >expect && + git ls-remote src refs/heads/branch >actual && + test_cmp expect actual +' + +test_expect_success 'new branch covered by force-with-lease (explicit)' ' + setup_srcdst_basic && + ( + cd dst && + git branch branch master && + git push --force-with-lease=branch: origin branch + ) && + git ls-remote dst refs/heads/branch >expect && + git ls-remote src refs/heads/branch >actual && + test_cmp expect actual +' + +test_expect_success 'new branch already exists' ' + setup_srcdst_basic && + ( + cd src && + git checkout -b branch master && + test_commit F + ) && + ( + cd dst && + git branch branch master && + test_must_fail git push --force-with-lease=branch: origin branch + ) +' + test_done diff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh index fd7d06b9a2..9593fc17f3 100755 --- a/t/t5541-http-push-smart.sh +++ b/t/t5541-http-push-smart.sh @@ -368,5 +368,14 @@ test_expect_success GPG 'push with post-receive to inspect certificate' ' test_cmp expect "$HTTPD_DOCUMENT_ROOT_PATH/push-cert-status" ' +test_expect_success 'push status output scrubs password' ' + cd "$ROOT_PATH/test_repo_clone" && + git push --porcelain \ + "$HTTPD_URL_USER_PASS/smart/test_repo.git" \ + +HEAD:scrub >status && + # should have been scrubbed down to vanilla URL + grep "^To $HTTPD_URL/smart/test_repo.git" status +' + stop_httpd test_done diff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh index 64146352ae..3484b6f0f3 100755 --- a/t/t5550-http-fetch-dumb.sh +++ b/t/t5550-http-fetch-dumb.sh @@ -91,6 +91,55 @@ test_expect_success 'configured username does not override URL' ' expect_askpass pass user@host ' +test_expect_success 'set up repo with http submodules' ' + git init super && + set_askpass user@host pass@host && + ( + cd super && + git submodule add "$HTTPD_URL/auth/dumb/repo.git" sub && + git commit -m "add submodule" + ) +' + +test_expect_success 'cmdline credential config passes to submodule via clone' ' + set_askpass wrong pass@host && + test_must_fail git clone --recursive super super-clone && + rm -rf super-clone && + + set_askpass wrong pass@host && + git -c "credential.$HTTPD_URL.username=user@host" \ + clone --recursive super super-clone && + expect_askpass pass user@host +' + +test_expect_success 'cmdline credential config passes submodule via fetch' ' + set_askpass wrong pass@host && + test_must_fail git -C super-clone fetch --recurse-submodules && + + set_askpass wrong pass@host && + git -C super-clone \ + -c "credential.$HTTPD_URL.username=user@host" \ + fetch --recurse-submodules && + expect_askpass pass user@host +' + +test_expect_success 'cmdline credential config passes submodule update' ' + # advance the submodule HEAD so that a fetch is required + git commit --allow-empty -m foo && + git push "$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/repo.git" HEAD && + sha1=$(git rev-parse HEAD) && + git -C super-clone update-index --cacheinfo 160000,$sha1,sub && + + set_askpass wrong pass@host && + test_must_fail git -C super-clone submodule update && + + set_askpass wrong pass@host && + git -C super-clone \ + -c "credential.$HTTPD_URL.username=user@host" \ + submodule update && + expect_askpass pass user@host +' + test_expect_success 'fetch changes via http' ' echo content >>file && git commit -a -m two && diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh index 58207d8825..2f375eb94d 100755 --- a/t/t5551-http-fetch-smart.sh +++ b/t/t5551-http-fetch-smart.sh @@ -282,5 +282,22 @@ test_expect_success EXPENSIVE 'http can handle enormous ref negotiation' ' test_line_count = 100000 tags ' +test_expect_success 'custom http headers' ' + test_must_fail git -c http.extraheader="x-magic-two: cadabra" \ + fetch "$HTTPD_URL/smart_headers/repo.git" && + git -c http.extraheader="x-magic-one: abra" \ + -c http.extraheader="x-magic-two: cadabra" \ + fetch "$HTTPD_URL/smart_headers/repo.git" && + git update-index --add --cacheinfo 160000,$(git rev-parse HEAD),sub && + git config -f .gitmodules submodule.sub.path sub && + git config -f .gitmodules submodule.sub.url \ + "$HTTPD_URL/smart_headers/repo.git" && + git submodule init sub && + test_must_fail git submodule update sub && + git -c http.extraheader="x-magic-one: abra" \ + -c http.extraheader="x-magic-two: cadabra" \ + submodule update sub +' + stop_httpd test_done diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index 1789d0be3d..a433394200 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -308,7 +308,7 @@ test_expect_success 'clone checking out a tag' ' setup_ssh_wrapper () { test_expect_success 'setup ssh wrapper' ' - cp "$GIT_BUILD_DIR/test-fake-ssh$X" \ + cp "$GIT_BUILD_DIR/t/helper/test-fake-ssh$X" \ "$TRASH_DIRECTORY/ssh-wrapper$X" && GIT_SSH="$TRASH_DIRECTORY/ssh-wrapper$X" && export GIT_SSH && diff --git a/t/t5614-clone-submodules.sh b/t/t5614-clone-submodules.sh new file mode 100755 index 0000000000..da2a67f656 --- /dev/null +++ b/t/t5614-clone-submodules.sh @@ -0,0 +1,70 @@ +#!/bin/sh + +test_description='Test shallow cloning of repos with submodules' + +. ./test-lib.sh + +pwd=$(pwd) + +test_expect_success 'setup' ' + git checkout -b master && + test_commit commit1 && + test_commit commit2 && + mkdir sub && + ( + cd sub && + git init && + test_commit subcommit1 && + test_commit subcommit2 && + test_commit subcommit3 + ) && + git submodule add "file://$pwd/sub" sub && + git commit -m "add submodule" +' + +test_expect_success 'nonshallow clone implies nonshallow submodule' ' + test_when_finished "rm -rf super_clone" && + git clone --recurse-submodules "file://$pwd/." super_clone && + git -C super_clone log --oneline >lines && + test_line_count = 3 lines && + git -C super_clone/sub log --oneline >lines && + test_line_count = 3 lines +' + +test_expect_success 'shallow clone with shallow submodule' ' + test_when_finished "rm -rf super_clone" && + git clone --recurse-submodules --depth 2 --shallow-submodules "file://$pwd/." super_clone && + git -C super_clone log --oneline >lines && + test_line_count = 2 lines && + git -C super_clone/sub log --oneline >lines && + test_line_count = 1 lines +' + +test_expect_success 'shallow clone does not imply shallow submodule' ' + test_when_finished "rm -rf super_clone" && + git clone --recurse-submodules --depth 2 "file://$pwd/." super_clone && + git -C super_clone log --oneline >lines && + test_line_count = 2 lines && + git -C super_clone/sub log --oneline >lines && + test_line_count = 3 lines +' + +test_expect_success 'shallow clone with non shallow submodule' ' + test_when_finished "rm -rf super_clone" && + git clone --recurse-submodules --depth 2 --no-shallow-submodules "file://$pwd/." super_clone && + git -C super_clone log --oneline >lines && + test_line_count = 2 lines && + git -C super_clone/sub log --oneline >lines && + test_line_count = 3 lines +' + +test_expect_success 'non shallow clone with shallow submodule' ' + test_when_finished "rm -rf super_clone" && + git clone --recurse-submodules --no-local --shallow-submodules "file://$pwd/." super_clone && + git -C super_clone log --oneline >lines && + test_line_count = 3 lines && + git -C super_clone/sub log --oneline >lines && + test_line_count = 1 lines +' + +test_done diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh index b77d4c97c1..a1dcdb81d7 100755 --- a/t/t6006-rev-list-format.sh +++ b/t/t6006-rev-list-format.sh @@ -184,38 +184,38 @@ commit $head1 [1;31;43mfoo[m EOF -test_expect_success '%C(auto) does not enable color by default' ' +test_expect_success '%C(auto,...) does not enable color by default' ' git log --format=$AUTO_COLOR -1 >actual && has_no_color actual ' -test_expect_success '%C(auto) enables colors for color.diff' ' +test_expect_success '%C(auto,...) enables colors for color.diff' ' git -c color.diff=always log --format=$AUTO_COLOR -1 >actual && has_color actual ' -test_expect_success '%C(auto) enables colors for color.ui' ' +test_expect_success '%C(auto,...) enables colors for color.ui' ' git -c color.ui=always log --format=$AUTO_COLOR -1 >actual && has_color actual ' -test_expect_success '%C(auto) respects --color' ' +test_expect_success '%C(auto,...) respects --color' ' git log --format=$AUTO_COLOR -1 --color >actual && has_color actual ' -test_expect_success '%C(auto) respects --no-color' ' +test_expect_success '%C(auto,...) respects --no-color' ' git -c color.ui=always log --format=$AUTO_COLOR -1 --no-color >actual && has_no_color actual ' -test_expect_success TTY '%C(auto) respects --color=auto (stdout is tty)' ' +test_expect_success TTY '%C(auto,...) respects --color=auto (stdout is tty)' ' test_terminal env TERM=vt100 \ git log --format=$AUTO_COLOR -1 --color=auto >actual && has_color actual ' -test_expect_success '%C(auto) respects --color=auto (stdout not tty)' ' +test_expect_success '%C(auto,...) respects --color=auto (stdout not tty)' ' ( TERM=vt100 && export TERM && git log --format=$AUTO_COLOR -1 --color=auto >actual && @@ -223,6 +223,18 @@ test_expect_success '%C(auto) respects --color=auto (stdout not tty)' ' ) ' +test_expect_success '%C(auto) respects --color' ' + git log --color --format="%C(auto)%H" -1 >actual && + printf "\\033[33m%s\\033[m\\n" $(git rev-parse HEAD) >expect && + test_cmp expect actual +' + +test_expect_success '%C(auto) respects --no-color' ' + git log --no-color --format="%C(auto)%H" -1 >actual && + git rev-parse HEAD >expect && + test_cmp expect actual +' + iconv -f utf-8 -t $test_encoding > commit-msg <<EOF Test printing of complex bodies diff --git a/t/t6009-rev-list-parent.sh b/t/t6009-rev-list-parent.sh index 66cda17ef3..20e3e2554a 100755 --- a/t/t6009-rev-list-parent.sh +++ b/t/t6009-rev-list-parent.sh @@ -47,7 +47,9 @@ test_expect_success 'setup roots, merges and octopuses' ' git checkout -b yetanotherbranch four && test_commit eight && git checkout master && - test_merge normalmerge newroot && + test_tick && + git merge --allow-unrelated-histories -m normalmerge newroot && + git tag normalmerge && test_tick && git merge -m tripus sidebranch anotherbranch && git tag tripus && diff --git a/t/t6010-merge-base.sh b/t/t6010-merge-base.sh index 39b3238da2..e0c5f44cac 100755 --- a/t/t6010-merge-base.sh +++ b/t/t6010-merge-base.sh @@ -215,11 +215,13 @@ test_expect_success 'criss-cross merge-base for octopus-step' ' git reset --hard E && test_commit CC2 && test_tick && - git merge -s ours CC1 && + # E is a root commit unrelated to MMR root on which CC1 is based + git merge -s ours --allow-unrelated-histories CC1 && test_commit CC-o && test_commit CCB && git reset --hard CC1 && - git merge -s ours CC2 && + # E is a root commit unrelated to MMR root on which CC1 is based + git merge -s ours --allow-unrelated-histories CC2 && test_commit CCA && git rev-parse CC1 CC2 >expected && diff --git a/t/t6012-rev-list-simplify.sh b/t/t6012-rev-list-simplify.sh index b89cd6b07a..2a0fbb87b1 100755 --- a/t/t6012-rev-list-simplify.sh +++ b/t/t6012-rev-list-simplify.sh @@ -71,7 +71,7 @@ test_expect_success setup ' note J && git checkout master && - test_tick && git merge -m "Coolest" unrelated && + test_tick && git merge --allow-unrelated-histories -m "Coolest" unrelated && note K && echo "Immaterial" >elif && diff --git a/t/t6024-recursive-merge.sh b/t/t6024-recursive-merge.sh index 755d30ce2a..3f59e58dfb 100755 --- a/t/t6024-recursive-merge.sh +++ b/t/t6024-recursive-merge.sh @@ -76,7 +76,7 @@ test_expect_success "result contains a conflict" "test_cmp expect a1" git ls-files --stage > out cat > expect << EOF -100644 439cc46de773d8a83c77799b7cc9191c128bfcff 1 a1 +100644 ec3fe2a791706733f2d8fa7ad45d9a9672031f5e 1 a1 100644 cf84443e49e1b366fac938711ddf4be2d4d1d9e9 2 a1 100644 fd7923529855d0b274795ae3349c5e0438333979 3 a1 EOF diff --git a/t/t6026-merge-attr.sh b/t/t6026-merge-attr.sh index 04c0509c47..dd8f88d187 100755 --- a/t/t6026-merge-attr.sh +++ b/t/t6026-merge-attr.sh @@ -176,8 +176,22 @@ test_expect_success 'up-to-date merge without common ancestor' ' test_tick && ( cd repo1 && - git pull ../repo2 master + git fetch ../repo2 master && + git merge --allow-unrelated-histories FETCH_HEAD ) ' +test_expect_success 'custom merge does not lock index' ' + git reset --hard anchor && + write_script sleep-one-second.sh <<-\EOF && + sleep 1 & + EOF + + test_write_lines >.gitattributes \ + "* merge=ours" "text merge=sleep-one-second" && + test_config merge.ours.driver true && + test_config merge.sleep-one-second.driver ./sleep-one-second.sh && + git merge master +' + test_done diff --git a/t/t6029-merge-subtree.sh b/t/t6029-merge-subtree.sh index 73fc240e85..3e692454a7 100755 --- a/t/t6029-merge-subtree.sh +++ b/t/t6029-merge-subtree.sh @@ -49,7 +49,7 @@ test_expect_success 'setup' ' test_expect_success 'initial merge' ' git remote add -f gui ../git-gui && - git merge -s ours --no-commit gui/master && + git merge -s ours --no-commit --allow-unrelated-histories gui/master && git read-tree --prefix=git-gui/ -u gui/master && git commit -m "Merge git-gui as our subdirectory" && git checkout -b work && diff --git a/t/t6036-recursive-corner-cases.sh b/t/t6036-recursive-corner-cases.sh index 9d6621c056..18aa88b5c0 100755 --- a/t/t6036-recursive-corner-cases.sh +++ b/t/t6036-recursive-corner-cases.sh @@ -212,7 +212,8 @@ test_expect_success 'git detects differently handled merges conflict' ' -L "" \ -L "Temporary merge branch 1" \ merged empty merge-me && - test $(git rev-parse :1:new_a) = $(git hash-object merged) + sed -e "s/^\([<=>]\)/\1\1\1/" merged >merged-internal && + test $(git rev-parse :1:new_a) = $(git hash-object merged-internal) ' # @@ -299,89 +300,6 @@ test_expect_success 'git detects conflict merging criss-cross+modify/delete, rev ' # -# criss-cross + modify/modify with very contrived file contents: -# -# B D -# o---o -# / \ / \ -# A o X ? F -# \ / \ / -# o---o -# C E -# -# Commit A: file with contents 'A\n' -# Commit B: file with contents 'B\n' -# Commit C: file with contents 'C\n' -# Commit D: file with contents 'D\n' -# Commit E: file with contents: -# <<<<<<< Temporary merge branch 1 -# C -# ======= -# B -# >>>>>>> Temporary merge branch 2 -# -# Now, when we merge commits D & E, does git detect the conflict? - -test_expect_success 'setup differently handled merges of content conflict' ' - git clean -fdqx && - rm -rf .git && - git init && - - echo A >file && - git add file && - test_tick && - git commit -m A && - - git branch B && - git checkout -b C && - echo C >file && - git add file && - test_tick && - git commit -m C && - - git checkout B && - echo B >file && - git add file && - test_tick && - git commit -m B && - - git checkout B^0 && - test_must_fail git merge C && - echo D >file && - git add file && - test_tick && - git commit -m D && - git tag D && - - git checkout C^0 && - test_must_fail git merge B && - cat <<EOF >file && -<<<<<<< Temporary merge branch 1 -C -======= -B ->>>>>>> Temporary merge branch 2 -EOF - git add file && - test_tick && - git commit -m E && - git tag E -' - -test_expect_failure 'git detects conflict w/ criss-cross+contrived resolution' ' - git checkout D^0 && - - test_must_fail git merge -s recursive E^0 && - - test 3 -eq $(git ls-files -s | wc -l) && - test 3 -eq $(git ls-files -u | wc -l) && - test 0 -eq $(git ls-files -o | wc -l) && - - test $(git rev-parse :2:file) = $(git rev-parse D:file) && - test $(git rev-parse :3:file) = $(git rev-parse E:file) -' - -# # criss-cross + d/f conflict via add/add: # Commit A: Neither file 'a' nor directory 'a/' exists. # Commit B: Introduce 'a' diff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh index 85c10b0940..5e8d5fa50c 100755 --- a/t/t6038-merge-text-auto.sh +++ b/t/t6038-merge-text-auto.sh @@ -16,6 +16,13 @@ test_description='CRLF merge conflict across text=auto change test_have_prereq SED_STRIPS_CR && SED_OPTIONS=-b +compare_files () { + tr '\015\000' QN <"$1" >"$1".expect && + tr '\015\000' QN <"$2" >"$2".actual && + test_cmp "$1".expect "$2".actual && + rm "$1".expect "$2".actual +} + test_expect_success setup ' git config core.autocrlf false && @@ -30,7 +37,7 @@ test_expect_success setup ' git branch side && echo "* text=auto" >.gitattributes && - touch file && + echo first line >file && git add .gitattributes file && test_tick && git commit -m "normalize file" && @@ -81,38 +88,49 @@ test_expect_success 'Merge after setting text=auto' ' rm -f .gitattributes && git reset --hard a && git merge b && - test_cmp expected file + compare_files expected file ' -test_expect_success 'Merge addition of text=auto' ' +test_expect_success 'Merge addition of text=auto eol=LF' ' + git config core.eol lf && cat <<-\EOF >expected && first line same line EOF - if test_have_prereq NATIVE_CRLF; then - append_cr <expected >expected.temp && - mv expected.temp expected - fi && git config merge.renormalize true && git rm -fr . && rm -f .gitattributes && git reset --hard b && git merge a && - test_cmp expected file + compare_files expected file +' + +test_expect_success 'Merge addition of text=auto eol=CRLF' ' + git config core.eol crlf && + cat <<-\EOF >expected && + first line + same line + EOF + + append_cr <expected >expected.temp && + mv expected.temp expected && + git config merge.renormalize true && + git rm -fr . && + rm -f .gitattributes && + git reset --hard b && + echo >&2 "After git reset --hard b" && + git ls-files -s --eol >&2 && + git merge a && + compare_files expected file ' test_expect_success 'Detect CRLF/LF conflict after setting text=auto' ' + git config core.eol native && echo "<<<<<<<" >expected && - if test_have_prereq NATIVE_CRLF; then - echo first line | append_cr >>expected && - echo same line | append_cr >>expected && - echo ======= | append_cr >>expected - else - echo first line >>expected && - echo same line >>expected && - echo ======= >>expected - fi && + echo first line >>expected && + echo same line >>expected && + echo ======= >>expected && echo first line | append_cr >>expected && echo same line | append_cr >>expected && echo ">>>>>>>" >>expected && @@ -121,29 +139,23 @@ test_expect_success 'Detect CRLF/LF conflict after setting text=auto' ' git reset --hard a && test_must_fail git merge b && fuzz_conflict file >file.fuzzy && - test_cmp expected file.fuzzy + compare_files expected file.fuzzy ' test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' ' echo "<<<<<<<" >expected && echo first line | append_cr >>expected && echo same line | append_cr >>expected && - if test_have_prereq NATIVE_CRLF; then - echo ======= | append_cr >>expected && - echo first line | append_cr >>expected && - echo same line | append_cr >>expected - else - echo ======= >>expected && - echo first line >>expected && - echo same line >>expected - fi && + echo ======= >>expected && + echo first line >>expected && + echo same line >>expected && echo ">>>>>>>" >>expected && git config merge.renormalize false && rm -f .gitattributes && git reset --hard b && test_must_fail git merge a && fuzz_conflict file >file.fuzzy && - test_cmp expected file.fuzzy + compare_files expected file.fuzzy ' test_expect_failure 'checkout -m after setting text=auto' ' @@ -158,7 +170,7 @@ test_expect_failure 'checkout -m after setting text=auto' ' git reset --hard initial && git checkout a -- . && git checkout -m b && - test_cmp expected file + compare_files expected file ' test_expect_failure 'checkout -m addition of text=auto' ' @@ -173,7 +185,7 @@ test_expect_failure 'checkout -m addition of text=auto' ' git reset --hard initial && git checkout b -- . && git checkout -m a && - test_cmp expected file + compare_files expected file ' test_expect_failure 'cherry-pick patch from after text=auto was added' ' @@ -187,7 +199,7 @@ test_expect_failure 'cherry-pick patch from after text=auto was added' ' git reset --hard b && test_must_fail git cherry-pick a >err 2>&1 && grep "[Nn]othing added" err && - test_cmp expected file + compare_files expected file ' test_expect_success 'Test delete/normalize conflict' ' diff --git a/t/t6044-merge-unrelated-index-changes.sh b/t/t6044-merge-unrelated-index-changes.sh new file mode 100755 index 0000000000..01023486c5 --- /dev/null +++ b/t/t6044-merge-unrelated-index-changes.sh @@ -0,0 +1,153 @@ +#!/bin/sh + +test_description="merges with unrelated index changes" + +. ./test-lib.sh + +# Testcase for some simple merges +# A +# o-----o B +# \ +# \---o C +# \ +# \-o D +# \ +# o E +# Commit A: some file a +# Commit B: adds file b, modifies end of a +# Commit C: adds file c +# Commit D: adds file d, modifies beginning of a +# Commit E: renames a->subdir/a, adds subdir/e + +test_expect_success 'setup trivial merges' ' + test_seq 1 10 >a && + git add a && + test_tick && git commit -m A && + + git branch A && + git branch B && + git branch C && + git branch D && + git branch E && + + git checkout B && + echo b >b && + echo 11 >>a && + git add a b && + test_tick && git commit -m B && + + git checkout C && + echo c >c && + git add c && + test_tick && git commit -m C && + + git checkout D && + test_seq 2 10 >a && + echo d >d && + git add a d && + test_tick && git commit -m D && + + git checkout E && + mkdir subdir && + git mv a subdir/a && + echo e >subdir/e && + git add subdir && + test_tick && git commit -m E +' + +test_expect_success 'ff update' ' + git reset --hard && + git checkout A^0 && + + touch random_file && git add random_file && + + git merge E^0 && + + test_must_fail git rev-parse HEAD:random_file && + test "$(git diff --name-only --cached E)" = "random_file" +' + +test_expect_success 'ff update, important file modified' ' + git reset --hard && + git checkout A^0 && + + mkdir subdir && + touch subdir/e && + git add subdir/e && + + test_must_fail git merge E^0 +' + +test_expect_success 'resolve, trivial' ' + git reset --hard && + git checkout B^0 && + + touch random_file && git add random_file && + + test_must_fail git merge -s resolve C^0 +' + +test_expect_success 'resolve, non-trivial' ' + git reset --hard && + git checkout B^0 && + + touch random_file && git add random_file && + + test_must_fail git merge -s resolve D^0 +' + +test_expect_success 'recursive' ' + git reset --hard && + git checkout B^0 && + + touch random_file && git add random_file && + + test_must_fail git merge -s recursive C^0 +' + +test_expect_success 'octopus, unrelated file touched' ' + git reset --hard && + git checkout B^0 && + + touch random_file && git add random_file && + + test_must_fail git merge C^0 D^0 +' + +test_expect_success 'octopus, related file removed' ' + git reset --hard && + git checkout B^0 && + + git rm b && + + test_must_fail git merge C^0 D^0 +' + +test_expect_success 'octopus, related file modified' ' + git reset --hard && + git checkout B^0 && + + echo 12 >>a && git add a && + + test_must_fail git merge C^0 D^0 +' + +test_expect_success 'ours' ' + git reset --hard && + git checkout B^0 && + + touch random_file && git add random_file && + + test_must_fail git merge -s ours C^0 +' + +test_expect_success 'subtree' ' + git reset --hard && + git checkout B^0 && + + touch random_file && git add random_file && + + test_must_fail git merge -s subtree E^0 +' + +test_done diff --git a/t/t6101-rev-parse-parents.sh b/t/t6101-rev-parse-parents.sh index 10b1452766..1c6952d049 100755 --- a/t/t6101-rev-parse-parents.sh +++ b/t/t6101-rev-parse-parents.sh @@ -19,7 +19,7 @@ test_expect_success 'setup' ' git checkout --orphan tmp && test_commit start2 && git checkout master && - git merge -m next start2 && + git merge -m next --allow-unrelated-histories start2 && test_commit final && test_seq 40 | diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh index bcf472bf51..d0ab09f4bd 100755 --- a/t/t6302-for-each-ref-filter.sh +++ b/t/t6302-for-each-ref-filter.sh @@ -5,20 +5,27 @@ test_description='test for-each-refs usage of ref-filter APIs' . ./test-lib.sh . "$TEST_DIRECTORY"/lib-gpg.sh -if ! test_have_prereq GPG -then - skip_all="skipping for-each-ref tests, GPG not available" - test_done -fi - test_expect_success 'setup some history and refs' ' test_commit one && test_commit two && test_commit three && git checkout -b side && test_commit four && - git tag -s -m "A signed tag message" signed-tag && - git tag -s -m "Annonated doubly" double-tag signed-tag && + git tag -m "An annotated tag" annotated-tag && + git tag -m "Annonated doubly" doubly-annotated-tag annotated-tag && + + # Note that these "signed" tags might not actually be signed. + # Tests which care about the distinction should be marked + # with the GPG prereq. + if test_have_prereq GPG + then + sign=-s + else + sign= + fi && + git tag $sign -m "A signed tag" signed-tag && + git tag $sign -m "Signed doubly" doubly-signed-tag signed-tag && + git checkout master && git update-ref refs/odd/spot master ' @@ -36,6 +43,7 @@ test_expect_success 'filtering with --points-at' ' test_expect_success 'check signed tags with --points-at' ' sed -e "s/Z$//" >expect <<-\EOF && refs/heads/side Z + refs/tags/annotated-tag four refs/tags/four Z refs/tags/signed-tag four EOF @@ -58,7 +66,9 @@ test_expect_success 'filtering with --merged' ' test_expect_success 'filtering with --no-merged' ' cat >expect <<-\EOF && refs/heads/side - refs/tags/double-tag + refs/tags/annotated-tag + refs/tags/doubly-annotated-tag + refs/tags/doubly-signed-tag refs/tags/four refs/tags/signed-tag EOF @@ -71,7 +81,9 @@ test_expect_success 'filtering with --contains' ' refs/heads/master refs/heads/side refs/odd/spot - refs/tags/double-tag + refs/tags/annotated-tag + refs/tags/doubly-annotated-tag + refs/tags/doubly-signed-tag refs/tags/four refs/tags/signed-tag refs/tags/three @@ -90,7 +102,9 @@ test_expect_success 'left alignment is default' ' refname is refs/heads/master |refs/heads/master refname is refs/heads/side |refs/heads/side refname is refs/odd/spot |refs/odd/spot - refname is refs/tags/double-tag|refs/tags/double-tag + refname is refs/tags/annotated-tag|refs/tags/annotated-tag + refname is refs/tags/doubly-annotated-tag|refs/tags/doubly-annotated-tag + refname is refs/tags/doubly-signed-tag|refs/tags/doubly-signed-tag refname is refs/tags/four |refs/tags/four refname is refs/tags/one |refs/tags/one refname is refs/tags/signed-tag|refs/tags/signed-tag @@ -106,7 +120,9 @@ test_expect_success 'middle alignment' ' | refname is refs/heads/master |refs/heads/master | refname is refs/heads/side |refs/heads/side | refname is refs/odd/spot |refs/odd/spot - |refname is refs/tags/double-tag|refs/tags/double-tag + |refname is refs/tags/annotated-tag|refs/tags/annotated-tag + |refname is refs/tags/doubly-annotated-tag|refs/tags/doubly-annotated-tag + |refname is refs/tags/doubly-signed-tag|refs/tags/doubly-signed-tag | refname is refs/tags/four |refs/tags/four | refname is refs/tags/one |refs/tags/one |refname is refs/tags/signed-tag|refs/tags/signed-tag @@ -122,7 +138,9 @@ test_expect_success 'right alignment' ' | refname is refs/heads/master|refs/heads/master | refname is refs/heads/side|refs/heads/side | refname is refs/odd/spot|refs/odd/spot - |refname is refs/tags/double-tag|refs/tags/double-tag + |refname is refs/tags/annotated-tag|refs/tags/annotated-tag + |refname is refs/tags/doubly-annotated-tag|refs/tags/doubly-annotated-tag + |refname is refs/tags/doubly-signed-tag|refs/tags/doubly-signed-tag | refname is refs/tags/four|refs/tags/four | refname is refs/tags/one|refs/tags/one |refname is refs/tags/signed-tag|refs/tags/signed-tag @@ -137,7 +155,9 @@ cat >expect <<-\EOF | refname is refs/heads/master |refs/heads/master | refname is refs/heads/side |refs/heads/side | refname is refs/odd/spot |refs/odd/spot -| refname is refs/tags/double-tag |refs/tags/double-tag +| refname is refs/tags/annotated-tag |refs/tags/annotated-tag +|refname is refs/tags/doubly-annotated-tag |refs/tags/doubly-annotated-tag +| refname is refs/tags/doubly-signed-tag |refs/tags/doubly-signed-tag | refname is refs/tags/four |refs/tags/four | refname is refs/tags/one |refs/tags/one | refname is refs/tags/signed-tag |refs/tags/signed-tag @@ -182,7 +202,9 @@ test_expect_success 'alignment with format quote' " |' '\''master| A U Thor'\'' '| |' '\''side| A U Thor'\'' '| |' '\''odd/spot| A U Thor'\'' '| - |' '\''double-tag| '\'' '| + |' '\''annotated-tag| '\'' '| + |' '\''doubly-annotated-tag| '\'' '| + |' '\''doubly-signed-tag| '\'' '| |' '\''four| A U Thor'\'' '| |' '\''one| A U Thor'\'' '| |' '\''signed-tag| '\'' '| @@ -198,7 +220,9 @@ test_expect_success 'nested alignment with quote formatting' " |' master '| |' side '| |' odd/spot '| - |' double-tag '| + |' annotated-tag '| + |'doubly-annotated-tag '| + |'doubly-signed-tag '| |' four '| |' one '| |' signed-tag '| @@ -214,10 +238,12 @@ test_expect_success 'check `%(contents:lines=1)`' ' master |three side |four odd/spot |three - double-tag |Annonated doubly + annotated-tag |An annotated tag + doubly-annotated-tag |Annonated doubly + doubly-signed-tag |Signed doubly four |four one |one - signed-tag |A signed tag message + signed-tag |A signed tag three |three two |two EOF @@ -230,7 +256,9 @@ test_expect_success 'check `%(contents:lines=0)`' ' master | side | odd/spot | - double-tag | + annotated-tag | + doubly-annotated-tag | + doubly-signed-tag | four | one | signed-tag | @@ -246,10 +274,12 @@ test_expect_success 'check `%(contents:lines=99999)`' ' master |three side |four odd/spot |three - double-tag |Annonated doubly + annotated-tag |An annotated tag + doubly-annotated-tag |Annonated doubly + doubly-signed-tag |Signed doubly four |four one |one - signed-tag |A signed tag message + signed-tag |A signed tag three |three two |two EOF diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index cf3469b142..f9b7d79af5 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -775,6 +775,47 @@ test_expect_success GPG '-s implies annotated tag' ' test_cmp expect actual ' +get_tag_header forcesignannotated-implied-sign $commit commit $time >expect +echo "A message" >>expect +echo '-----BEGIN PGP SIGNATURE-----' >>expect +test_expect_success GPG \ + 'git tag -s implied if configured with tag.forcesignannotated' \ + 'test_config tag.forcesignannotated true && + git tag -m "A message" forcesignannotated-implied-sign && + get_tag_msg forcesignannotated-implied-sign >actual && + test_cmp expect actual +' + +test_expect_success GPG \ + 'lightweight with no message when configured with tag.forcesignannotated' \ + 'test_config tag.forcesignannotated true && + git tag forcesignannotated-lightweight && + tag_exists forcesignannotated-lightweight && + test_must_fail git tag -v forcesignannotated-no-message +' + +get_tag_header forcesignannotated-annotate $commit commit $time >expect +echo "A message" >>expect +test_expect_success GPG \ + 'git tag -a disable configured tag.forcesignannotated' \ + 'test_config tag.forcesignannotated true && + git tag -a -m "A message" forcesignannotated-annotate && + get_tag_msg forcesignannotated-annotate >actual && + test_cmp expect actual && + test_must_fail git tag -v forcesignannotated-annotate +' + +get_tag_header forcesignannotated-disabled $commit commit $time >expect +echo "A message" >>expect +echo '-----BEGIN PGP SIGNATURE-----' >>expect +test_expect_success GPG \ + 'git tag --sign enable GPG sign' \ + 'test_config tag.forcesignannotated false && + git tag --sign -m "A message" forcesignannotated-disabled && + get_tag_msg forcesignannotated-disabled >actual && + test_cmp expect actual +' + test_expect_success GPG \ 'trying to create a signed tag with non-existing -F file should fail' ' ! test -f nonexistingfile && diff --git a/t/t7011-skip-worktree-reading.sh b/t/t7011-skip-worktree-reading.sh index 88d60c1ce2..84f41451ec 100755 --- a/t/t7011-skip-worktree-reading.sh +++ b/t/t7011-skip-worktree-reading.sh @@ -23,17 +23,15 @@ S sub/1 H sub/2 EOF -NULL_SHA1=e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 - setup_absent() { test -f 1 && rm 1 git update-index --remove 1 && - git update-index --add --cacheinfo 100644 $NULL_SHA1 1 && + git update-index --add --cacheinfo 100644 $EMPTY_BLOB 1 && git update-index --skip-worktree 1 } test_absent() { - echo "100644 $NULL_SHA1 0 1" > expected && + echo "100644 $EMPTY_BLOB 0 1" > expected && git ls-files --stage 1 > result && test_cmp expected result && test ! -f 1 @@ -42,12 +40,12 @@ test_absent() { setup_dirty() { git update-index --force-remove 1 && echo dirty > 1 && - git update-index --add --cacheinfo 100644 $NULL_SHA1 1 && + git update-index --add --cacheinfo 100644 $EMPTY_BLOB 1 && git update-index --skip-worktree 1 } test_dirty() { - echo "100644 $NULL_SHA1 0 1" > expected && + echo "100644 $EMPTY_BLOB 0 1" > expected && git ls-files --stage 1 > result && test_cmp expected result && echo dirty > expected @@ -120,7 +118,7 @@ test_expect_success 'grep with skip-worktree file' ' test "$(git grep --no-ext-grep test)" = "1:test" ' -echo ":000000 100644 $_z40 $NULL_SHA1 A 1" > expected +echo ":000000 100644 $_z40 $EMPTY_BLOB A 1" > expected test_expect_success 'diff-index does not examine skip-worktree absent entries' ' setup_absent && git diff-index HEAD -- 1 > result && diff --git a/t/t7012-skip-worktree-writing.sh b/t/t7012-skip-worktree-writing.sh index 9ceaa4049f..9d1abe50ef 100755 --- a/t/t7012-skip-worktree-writing.sh +++ b/t/t7012-skip-worktree-writing.sh @@ -53,17 +53,15 @@ test_expect_success 'read-tree removes worktree, dirty case' ' git update-index --no-skip-worktree added ' -NULL_SHA1=e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 - setup_absent() { test -f 1 && rm 1 git update-index --remove 1 && - git update-index --add --cacheinfo 100644 $NULL_SHA1 1 && + git update-index --add --cacheinfo 100644 $EMPTY_BLOB 1 && git update-index --skip-worktree 1 } test_absent() { - echo "100644 $NULL_SHA1 0 1" > expected && + echo "100644 $EMPTY_BLOB 0 1" > expected && git ls-files --stage 1 > result && test_cmp expected result && test ! -f 1 @@ -72,12 +70,12 @@ test_absent() { setup_dirty() { git update-index --force-remove 1 && echo dirty > 1 && - git update-index --add --cacheinfo 100644 $NULL_SHA1 1 && + git update-index --add --cacheinfo 100644 $EMPTY_BLOB 1 && git update-index --skip-worktree 1 } test_dirty() { - echo "100644 $NULL_SHA1 0 1" > expected && + echo "100644 $EMPTY_BLOB 0 1" > expected && git ls-files --stage 1 > result && test_cmp expected result && echo dirty > expected diff --git a/t/t7030-verify-tag.sh b/t/t7030-verify-tag.sh index 4608e71343..07079a41c4 100755 --- a/t/t7030-verify-tag.sh +++ b/t/t7030-verify-tag.sh @@ -112,4 +112,17 @@ test_expect_success GPG 'verify signatures with --raw' ' ) ' +test_expect_success GPG 'verify multiple tags' ' + tags="fourth-signed sixth-signed seventh-signed" && + for i in $tags + do + git verify-tag -v --raw $i || return 1 + done >expect.stdout 2>expect.stderr.1 && + grep "^.GNUPG:." <expect.stderr.1 >expect.stderr && + git verify-tag -v --raw $tags >actual.stdout 2>actual.stderr.1 && + grep "^.GNUPG:." <actual.stderr.1 >actual.stderr && + test_cmp expect.stdout actual.stdout && + test_cmp expect.stderr actual.stderr +' + test_done diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh index 44bf1d84af..4d17363a92 100755 --- a/t/t7060-wtstatus.sh +++ b/t/t7060-wtstatus.sh @@ -34,6 +34,7 @@ test_expect_success 'M/D conflict does not segfault' ' On branch side You have unmerged paths. (fix conflicts and run "git commit") + (use "git merge --abort" to abort the merge) Unmerged paths: (use "git add/rm <file>..." as appropriate to mark resolution) @@ -138,6 +139,7 @@ test_expect_success 'status when conflicts with add and rm advice (deleted by th On branch master You have unmerged paths. (fix conflicts and run "git commit") + (use "git merge --abort" to abort the merge) Unmerged paths: (use "git add/rm <file>..." as appropriate to mark resolution) @@ -171,6 +173,7 @@ test_expect_success 'status when conflicts with add and rm advice (both deleted) On branch conflict_second You have unmerged paths. (fix conflicts and run "git commit") + (use "git merge --abort" to abort the merge) Unmerged paths: (use "git add/rm <file>..." as appropriate to mark resolution) @@ -195,6 +198,7 @@ test_expect_success 'status when conflicts with only rm advice (both deleted)' ' On branch conflict_second You have unmerged paths. (fix conflicts and run "git commit") + (use "git merge --abort" to abort the merge) Changes to be committed: diff --git a/t/t7063-status-untracked-cache.sh b/t/t7063-status-untracked-cache.sh index a971884cfd..4e1e290a9f 100755 --- a/t/t7063-status-untracked-cache.sh +++ b/t/t7063-status-untracked-cache.sh @@ -4,6 +4,20 @@ test_description='test untracked cache' . ./test-lib.sh +# On some filesystems (e.g. FreeBSD's ext2 and ufs) directory mtime +# is updated lazily after contents in the directory changes, which +# forces the untracked cache code to take the slow path. A test +# that wants to make sure that the fast path works correctly should +# call this helper to make mtime of the containing directory in sync +# with the reality before checking the fast path behaviour. +# +# See <20160803174522.5571-1-pclouds@gmail.com> if you want to know +# more. + +sync_mtime () { + find . -type d -ls >/dev/null +} + avoid_racy() { sleep 1 } @@ -53,7 +67,7 @@ A two EOF cat >../dump.expect <<EOF && -info/exclude e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 +info/exclude $EMPTY_BLOB core.excludesfile 0000000000000000000000000000000000000000 exclude_per_dir .gitignore flags 00000006 @@ -137,7 +151,7 @@ EOF test_expect_success 'verify untracked cache dump' ' test-dump-untracked-cache >../actual && cat >../expect <<EOF && -info/exclude e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 +info/exclude $EMPTY_BLOB core.excludesfile 0000000000000000000000000000000000000000 exclude_per_dir .gitignore flags 00000006 @@ -184,7 +198,7 @@ EOF test_expect_success 'verify untracked cache dump' ' test-dump-untracked-cache >../actual && cat >../expect <<EOF && -info/exclude e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 +info/exclude $EMPTY_BLOB core.excludesfile 0000000000000000000000000000000000000000 exclude_per_dir .gitignore flags 00000006 @@ -416,7 +430,8 @@ test_expect_success 'create/modify files, some of which are gitignored' ' echo four >done/four && # four is gitignored at a higher level echo five >done/five && # five is not gitignored echo test >base && #we need to ensure that the root dir is touched - rm base + rm base && + sync_mtime ' test_expect_success 'test sparse status with untracked cache' ' diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index 75db023898..3570f7bb8c 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -22,6 +22,22 @@ test_expect_success 'setup - initial commit' ' git branch initial ' +test_expect_success 'submodule init aborts on missing .gitmodules file' ' + test_when_finished "git update-index --remove sub" && + git update-index --add --cacheinfo 160000,$(git rev-parse HEAD),sub && + # missing the .gitmodules file here + test_must_fail git submodule init 2>actual && + test_i18ngrep "No url found for submodule path" actual +' + +test_expect_success 'submodule update aborts on missing .gitmodules file' ' + test_when_finished "git update-index --remove sub" && + git update-index --add --cacheinfo 160000,$(git rev-parse HEAD),sub && + # missing the .gitmodules file here + git submodule update sub 2>actual && + test_i18ngrep "Submodule path .sub. not initialized" actual +' + test_expect_success 'configuration parsing' ' test_when_finished "rm -f .gitmodules" && cat >.gitmodules <<-\EOF && @@ -466,7 +482,7 @@ test_expect_success 'update --init' ' git config --remove-section submodule.example && test_must_fail git config submodule.example.url && - git submodule update init > update.out && + git submodule update init 2> update.out && cat update.out && test_i18ngrep "not initialized" update.out && test_must_fail git rev-parse --resolve-git-dir init/.git && @@ -484,7 +500,7 @@ test_expect_success 'update --init from subdirectory' ' mkdir -p sub && ( cd sub && - git submodule update ../init >update.out && + git submodule update ../init 2>update.out && cat update.out && test_i18ngrep "not initialized" update.out && test_must_fail git rev-parse --resolve-git-dir ../init/.git && @@ -902,7 +918,7 @@ test_expect_success 'submodule deinit works on repository without submodules' ' git init && >file && git add file && - git commit -m "repo should not be empty" + git commit -m "repo should not be empty" && git submodule deinit . && git submodule deinit --all ) diff --git a/t/t7403-submodule-sync.sh b/t/t7403-submodule-sync.sh index 79bc135bf6..5503ec067f 100755 --- a/t/t7403-submodule-sync.sh +++ b/t/t7403-submodule-sync.sh @@ -62,13 +62,13 @@ test_expect_success 'change submodule' ' ' reset_submodule_urls () { - local root - root=$(pwd) && ( + root=$(pwd) && cd super-clone/submodule && git config remote.origin.url "$root/submodule" ) && ( + root=$(pwd) && cd super-clone/submodule/sub-submodule && git config remote.origin.url "$root/submodule" ) diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh index e5af4b4976..5f278799d5 100755 --- a/t/t7406-submodule-update.sh +++ b/t/t7406-submodule-update.sh @@ -108,24 +108,36 @@ pwd=$(pwd) cat <<EOF >expect Submodule path '../super': checked out '$supersha1' -Submodule 'merging' ($pwd/merging) registered for path '../super/merging' -Submodule 'none' ($pwd/none) registered for path '../super/none' -Submodule 'rebasing' ($pwd/rebasing) registered for path '../super/rebasing' -Submodule 'submodule' ($pwd/submodule) registered for path '../super/submodule' Submodule path '../super/merging': checked out '$mergingsha1' Submodule path '../super/none': checked out '$nonesha1' Submodule path '../super/rebasing': checked out '$rebasingsha1' Submodule path '../super/submodule': checked out '$submodulesha1' EOF +cat <<EOF >expect2 +Submodule 'merging' ($pwd/merging) registered for path '../super/merging' +Submodule 'none' ($pwd/none) registered for path '../super/none' +Submodule 'rebasing' ($pwd/rebasing) registered for path '../super/rebasing' +Submodule 'submodule' ($pwd/submodule) registered for path '../super/submodule' +Cloning into '$pwd/recursivesuper/super/merging'... +done. +Cloning into '$pwd/recursivesuper/super/none'... +done. +Cloning into '$pwd/recursivesuper/super/rebasing'... +done. +Cloning into '$pwd/recursivesuper/super/submodule'... +done. +EOF + test_expect_success 'submodule update --init --recursive from subdirectory' ' git -C recursivesuper/super reset --hard HEAD^ && (cd recursivesuper && mkdir tmp && cd tmp && - git submodule update --init --recursive ../super >../../actual + git submodule update --init --recursive ../super >../../actual 2>../../actual2 ) && - test_cmp expect actual + test_cmp expect actual && + test_cmp expect2 actual2 ' apos="'"; @@ -850,4 +862,31 @@ test_expect_success 'submodule update --recursive drops module name before recur test_i18ngrep "Submodule path .deeper/submodule/subsubmodule.: checked out" actual ) ' + +test_expect_success 'submodule update can be run in parallel' ' + (cd super2 && + GIT_TRACE=$(pwd)/trace.out git submodule update --jobs 7 && + grep "7 tasks" trace.out && + git config submodule.fetchJobs 8 && + GIT_TRACE=$(pwd)/trace.out git submodule update && + grep "8 tasks" trace.out && + GIT_TRACE=$(pwd)/trace.out git submodule update --jobs 9 && + grep "9 tasks" trace.out + ) +' + +test_expect_success 'git clone passes the parallel jobs config on to submodules' ' + test_when_finished "rm -rf super4" && + GIT_TRACE=$(pwd)/trace.out git clone --recurse-submodules --jobs 7 . super4 && + grep "7 tasks" trace.out && + rm -rf super4 && + git config --global submodule.fetchJobs 8 && + GIT_TRACE=$(pwd)/trace.out git clone --recurse-submodules . super4 && + grep "8 tasks" trace.out && + rm -rf super4 && + GIT_TRACE=$(pwd)/trace.out git clone --recurse-submodules --jobs 9 . super4 && + grep "9 tasks" trace.out && + rm -rf super4 +' + test_done diff --git a/t/t7411-submodule-config.sh b/t/t7411-submodule-config.sh index fc97c3314e..400e2b1439 100755 --- a/t/t7411-submodule-config.sh +++ b/t/t7411-submodule-config.sh @@ -82,6 +82,17 @@ test_expect_success 'error in one submodule config lets continue' ' ) ' +test_expect_success 'error message contains blob reference' ' + (cd super && + sha1=$(git rev-parse HEAD) && + test-submodule-config \ + HEAD b \ + HEAD submodule \ + 2>actual_err && + grep "submodule-blob $sha1:.gitmodules" actual_err >/dev/null + ) +' + cat >super/expect_url <<EOF Submodule url: 'git@somewhere.else.net:a.git' for path 'b' Submodule url: 'git@somewhere.else.net:submodule.git' for path 'submodule' diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh index 900f7de05a..d84897a67a 100755 --- a/t/t7501-commit.sh +++ b/t/t7501-commit.sh @@ -607,4 +607,24 @@ test_expect_success '--only works on to-be-born branch' ' test_cmp expected actual ' +test_expect_success '--dry-run with conflicts fixed from a merge' ' + # setup two branches with conflicting information + # in the same file, resolve the conflict, + # call commit with --dry-run + echo "Initial contents, unimportant" >test-file && + git add test-file && + git commit -m "Initial commit" && + echo "commit-1-state" >test-file && + git commit -m "commit 1" -i test-file && + git tag commit-1 && + git checkout -b branch-2 HEAD^1 && + echo "commit-2-state" >test-file && + git commit -m "commit 2" -i test-file && + ! $(git merge --no-commit commit-1) && + echo "commit-2-state" >test-file && + git add test-file && + git commit --dry-run && + git commit -m "conflicts fixed from merge." +' + test_done diff --git a/t/t7507-commit-verbose.sh b/t/t7507-commit-verbose.sh index 2ddf28c984..ed2653d46f 100755 --- a/t/t7507-commit-verbose.sh +++ b/t/t7507-commit-verbose.sh @@ -3,11 +3,10 @@ test_description='verbose commit template' . ./test-lib.sh -cat >check-for-diff <<EOF -#!$SHELL_PATH -exec grep '^diff --git' "\$1" +write_script "check-for-diff" <<\EOF && +grep '^diff --git' "$1" >out +exit 0 EOF -chmod +x check-for-diff test_set_editor "$PWD/check-for-diff" cat >message <<'EOF' @@ -23,7 +22,8 @@ test_expect_success 'setup' ' ' test_expect_success 'initial commit shows verbose diff' ' - git commit --amend -v + git commit --amend -v && + test_line_count = 1 out ' test_expect_success 'second commit' ' @@ -39,13 +39,15 @@ check_message() { test_expect_success 'verbose diff is stripped out' ' git commit --amend -v && - check_message message + check_message message && + test_line_count = 1 out ' test_expect_success 'verbose diff is stripped out (mnemonicprefix)' ' git config diff.mnemonicprefix true && git commit --amend -v && - check_message message + check_message message && + test_line_count = 1 out ' cat >diff <<'EOF' @@ -96,4 +98,60 @@ test_expect_success 'verbose diff is stripped out with set core.commentChar' ' test_i18ngrep "Aborting commit due to empty commit message." err ' +test_expect_success 'status does not verbose without --verbose' ' + git status >actual && + ! grep "^diff --git" actual +' + +test_expect_success 'setup -v -v' ' + echo dirty >file +' + +for i in true 1 +do + test_expect_success "commit.verbose=$i and --verbose omitted" " + git -c commit.verbose=$i commit --amend && + test_line_count = 1 out + " +done + +for i in false -2 -1 0 +do + test_expect_success "commit.verbose=$i and --verbose omitted" " + git -c commit.verbose=$i commit --amend && + test_line_count = 0 out + " +done + +for i in 2 3 +do + test_expect_success "commit.verbose=$i and --verbose omitted" " + git -c commit.verbose=$i commit --amend && + test_line_count = 2 out + " +done + +for i in true false -2 -1 0 1 2 3 +do + test_expect_success "commit.verbose=$i and --verbose" " + git -c commit.verbose=$i commit --amend --verbose && + test_line_count = 1 out + " + + test_expect_success "commit.verbose=$i and --no-verbose" " + git -c commit.verbose=$i commit --amend --no-verbose && + test_line_count = 0 out + " + + test_expect_success "commit.verbose=$i and -v -v" " + git -c commit.verbose=$i commit --amend -v -v && + test_line_count = 2 out + " +done + +test_expect_success "status ignores commit.verbose=true" ' + git -c commit.verbose=true status >actual && + ! grep "^diff --git actual" +' + test_done diff --git a/t/t7508-status.sh b/t/t7508-status.sh index c3ed7cb51c..a42aef8317 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -803,7 +803,7 @@ EOF ' cat >expect <<EOF -:100644 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0000000000000000000000000000000000000000 M dir1/modified +:100644 100644 $EMPTY_BLOB 0000000000000000000000000000000000000000 M dir1/modified EOF test_expect_success 'status refreshes the index' ' touch dir2/added && diff --git a/t/t7510-signed-commit.sh b/t/t7510-signed-commit.sh index 18e5cf0663..4177a8609a 100755 --- a/t/t7510-signed-commit.sh +++ b/t/t7510-signed-commit.sh @@ -45,12 +45,18 @@ test_expect_success GPG 'create signed commits' ' git tag seventh-signed && echo 8 >file && test_tick && git commit -a -m eighth -SB7227189 && - git tag eighth-signed-alt + git tag eighth-signed-alt && + + # commit.gpgsign is still on but this must not be signed + git tag ninth-unsigned $(echo 9 | git commit-tree HEAD^{tree}) && + # explicit -S of course must sign. + git tag tenth-signed $(echo 9 | git commit-tree -S HEAD^{tree}) ' test_expect_success GPG 'verify and show signatures' ' ( - for commit in initial second merge fourth-signed fifth-signed sixth-signed seventh-signed + for commit in initial second merge fourth-signed \ + fifth-signed sixth-signed seventh-signed tenth-signed do git verify-commit $commit && git show --pretty=short --show-signature $commit >actual && @@ -60,7 +66,8 @@ test_expect_success GPG 'verify and show signatures' ' done ) && ( - for commit in merge^2 fourth-unsigned sixth-unsigned seventh-unsigned + for commit in merge^2 fourth-unsigned sixth-unsigned \ + seventh-unsigned ninth-unsigned do test_must_fail git verify-commit $commit && git show --pretty=short --show-signature $commit >actual && diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh index 49d19a3b36..5c3db656df 100755 --- a/t/t7512-status-help.sh +++ b/t/t7512-status-help.sh @@ -29,6 +29,7 @@ test_expect_success 'status when conflicts unresolved' ' On branch conflicts You have unmerged paths. (fix conflicts and run "git commit") + (use "git merge --abort" to abort the merge) Unmerged paths: (use "git add <file>..." to mark resolution) diff --git a/t/t7605-merge-resolve.sh b/t/t7605-merge-resolve.sh index 0cb9d11f21..5d56c38546 100755 --- a/t/t7605-merge-resolve.sh +++ b/t/t7605-merge-resolve.sh @@ -27,7 +27,7 @@ test_expect_success 'setup' ' git tag c3 ' -test_expect_success 'merge c1 to c2' ' +merge_c1_to_c2_cmds=' git reset --hard c1 && git merge -s resolve c2 && test "$(git rev-parse c1)" != "$(git rev-parse HEAD)" && @@ -41,6 +41,10 @@ test_expect_success 'merge c1 to c2' ' test 3 = $(git ls-files | wc -l) ' +test_expect_success 'merge c1 to c2' "$merge_c1_to_c2_cmds" + +test_expect_success 'merge c1 to c2, again' "$merge_c1_to_c2_cmds" + test_expect_success 'merge c2 to c3 (fails)' ' git reset --hard c2 && test_must_fail git merge -s resolve c3 diff --git a/t/t7607-merge-overwrite.sh b/t/t7607-merge-overwrite.sh index 758a623cdb..1c59349946 100755 --- a/t/t7607-merge-overwrite.sh +++ b/t/t7607-merge-overwrite.sh @@ -115,7 +115,7 @@ cat >expect <<\EOF error: The following untracked working tree files would be overwritten by merge: sub sub2 -Please move or remove them before you can merge. +Please move or remove them before you merge. Aborting EOF diff --git a/t/t7609-merge-co-error-msgs.sh b/t/t7609-merge-co-error-msgs.sh index 6729cb379f..f80bdb81e1 100755 --- a/t/t7609-merge-co-error-msgs.sh +++ b/t/t7609-merge-co-error-msgs.sh @@ -31,7 +31,7 @@ error: The following untracked working tree files would be overwritten by merge: four three two -Please move or remove them before you can merge. +Please move or remove them before you merge. Aborting EOF @@ -53,10 +53,10 @@ error: Your local changes to the following files would be overwritten by merge: four three two -Please commit your changes or stash them before you can merge. +Please commit your changes or stash them before you merge. error: The following untracked working tree files would be overwritten by merge: five -Please move or remove them before you can merge. +Please move or remove them before you merge. Aborting EOF @@ -72,7 +72,7 @@ cat >expect <<\EOF error: Your local changes to the following files would be overwritten by checkout: rep/one rep/two -Please commit your changes or stash them before you can switch branches. +Please commit your changes or stash them before you switch branches. Aborting EOF @@ -94,7 +94,7 @@ cat >expect <<\EOF error: Your local changes to the following files would be overwritten by checkout: rep/one rep/two -Please commit your changes or stash them before you can switch branches. +Please commit your changes or stash them before you switch branches. Aborting EOF diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh index 76306cf268..7217f3968d 100755 --- a/t/t7610-mergetool.sh +++ b/t/t7610-mergetool.sh @@ -589,7 +589,12 @@ test_expect_success 'filenames seen by tools start with ./' ' git reset --hard master >/dev/null 2>&1 ' -test_expect_success 'temporary filenames are used with mergetool.writeToTemp' ' +test_lazy_prereq MKTEMP ' + tempdir=$(mktemp -d -t foo.XXXXXX) && + test -d "$tempdir" +' + +test_expect_success MKTEMP 'temporary filenames are used with mergetool.writeToTemp' ' git checkout -b test16 branch1 && test_config mergetool.writeToTemp true && test_config mergetool.myecho.cmd "echo \"\$LOCAL\"" && diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh index 7ce4cd753e..70a2de461a 100755 --- a/t/t7800-difftool.sh +++ b/t/t7800-difftool.sh @@ -124,6 +124,12 @@ test_expect_success PERL 'difftool stops on error with --trust-exit-code' ' test_cmp expect actual ' +test_expect_success PERL 'difftool honors exit status if command not found' ' + test_config difftool.nonexistent.cmd i-dont-exist && + test_config difftool.trustExitCode false && + test_must_fail git difftool -y -t nonexistent branch +' + test_expect_success PERL 'difftool honors --gui' ' difftool_test_setup && test_config merge.tool bogus-tool && @@ -412,6 +418,20 @@ run_dir_diff_test 'difftool --dir-diff from subdirectory' ' ) ' +run_dir_diff_test 'difftool --dir-diff from subdirectory with GIT_DIR set' ' + ( + GIT_DIR=$(pwd)/.git && + export GIT_DIR && + GIT_WORK_TREE=$(pwd) && + export GIT_WORK_TREE && + cd sub && + git difftool --dir-diff $symlinks --extcmd ls \ + branch -- sub >output && + grep sub output && + ! grep file output + ) +' + run_dir_diff_test 'difftool --dir-diff when worktree file is missing' ' test_when_finished git reset --hard && rm file2 && @@ -446,7 +466,7 @@ write_script .git/CHECK_SYMLINKS <<\EOF for f in file file2 sub/sub do echo "$f" - readlink "$2/$f" + ls -ld "$2/$f" | sed -e 's/.* -> //' done >actual EOF diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index 1e72971a16..cf3f9ec631 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -9,7 +9,9 @@ test_description='git grep various. . ./test-lib.sh cat >hello.c <<EOF +#include <assert.h> #include <stdio.h> + int main(int argc, const char **argv) { printf("Hello world.\n"); @@ -175,7 +177,7 @@ do test_expect_success "grep -c $L (no /dev/null)" ' ! git grep -c test $H | grep /dev/null - ' + ' test_expect_success "grep --max-depth -1 $L" ' { @@ -353,7 +355,7 @@ test_expect_success 'grep -l -C' ' cat >expected <<EOF file:5 EOF -test_expect_success 'grep -l -C' ' +test_expect_success 'grep -c -C' ' git grep -c -C1 foo >actual && test_cmp expected actual ' @@ -715,6 +717,7 @@ test_expect_success 'grep -p' ' cat >expected <<EOF hello.c-#include <stdio.h> +hello.c- hello.c=int main(int argc, const char **argv) hello.c-{ hello.c- printf("Hello world.\n"); @@ -741,6 +744,16 @@ test_expect_success 'grep -W' ' ' cat >expected <<EOF +hello.c-#include <assert.h> +hello.c:#include <stdio.h> +EOF + +test_expect_success 'grep -W shows no trailing empty lines' ' + git grep -W stdio >actual && + test_cmp expected actual +' + +cat >expected <<EOF hello.c= printf("Hello world.\n"); hello.c: return 0; hello.c- /* char ?? */ @@ -1232,8 +1245,8 @@ test_expect_success 'grep --heading' ' cat >expected <<EOF <BOLD;GREEN>hello.c<RESET> -2:int main(int argc, const <BLACK;BYELLOW>char<RESET> **argv) -6: /* <BLACK;BYELLOW>char<RESET> ?? */ +4:int main(int argc, const <BLACK;BYELLOW>char<RESET> **argv) +8: /* <BLACK;BYELLOW>char<RESET> ?? */ <BOLD;GREEN>hello_world<RESET> 3:Hel<BLACK;BYELLOW>lo_w<RESET>orld @@ -1340,7 +1353,7 @@ test_expect_success 'grep --color -e A --and --not -e B with context' ' ' cat >expected <<EOF -hello.c-#include <stdio.h> +hello.c- hello.c=int main(int argc, const char **argv) hello.c-{ hello.c: pr<RED>int<RESET>f("<RED>Hello<RESET> world.\n"); @@ -1364,4 +1377,62 @@ test_expect_success 'grep --color -e A --and -e B -p with context' ' test_cmp expected actual ' +test_expect_success 'grep can find things only in the work tree' ' + : >work-tree-only && + git add work-tree-only && + test_when_finished "git rm -f work-tree-only" && + echo "find in work tree" >work-tree-only && + git grep --quiet "find in work tree" && + test_must_fail git grep --quiet --cached "find in work tree" && + test_must_fail git grep --quiet "find in work tree" HEAD +' + +test_expect_success 'grep can find things only in the work tree (i-t-a)' ' + echo "intend to add this" >intend-to-add && + git add -N intend-to-add && + test_when_finished "git rm -f intend-to-add" && + git grep --quiet "intend to add this" && + test_must_fail git grep --quiet --cached "intend to add this" && + test_must_fail git grep --quiet "intend to add this" HEAD +' + +test_expect_success 'grep does not search work tree with assume unchanged' ' + echo "intend to add this" >intend-to-add && + git add -N intend-to-add && + git update-index --assume-unchanged intend-to-add && + test_when_finished "git rm -f intend-to-add" && + test_must_fail git grep --quiet "intend to add this" && + test_must_fail git grep --quiet --cached "intend to add this" && + test_must_fail git grep --quiet "intend to add this" HEAD +' + +test_expect_success 'grep can find things only in the index' ' + echo "only in the index" >cache-this && + git add cache-this && + rm cache-this && + test_when_finished "git rm --cached cache-this" && + test_must_fail git grep --quiet "only in the index" && + git grep --quiet --cached "only in the index" && + test_must_fail git grep --quiet "only in the index" HEAD +' + +test_expect_success 'grep does not report i-t-a with -L --cached' ' + echo "intend to add this" >intend-to-add && + git add -N intend-to-add && + test_when_finished "git rm -f intend-to-add" && + git ls-files | grep -v "^intend-to-add\$" >expected && + git grep -L --cached "nonexistent_string" >actual && + test_cmp expected actual +' + +test_expect_success 'grep does not report i-t-a and assume unchanged with -L' ' + echo "intend to add this" >intend-to-add-assume-unchanged && + git add -N intend-to-add-assume-unchanged && + test_when_finished "git rm -f intend-to-add-assume-unchanged" && + git update-index --assume-unchanged intend-to-add-assume-unchanged && + git ls-files | grep -v "^intend-to-add-assume-unchanged\$" >expected && + git grep -L "nonexistent_string" >actual && + test_cmp expected actual +' + test_done diff --git a/t/t7812-grep-icase-non-ascii.sh b/t/t7812-grep-icase-non-ascii.sh new file mode 100755 index 0000000000..169fd8d706 --- /dev/null +++ b/t/t7812-grep-icase-non-ascii.sh @@ -0,0 +1,71 @@ +#!/bin/sh + +test_description='grep icase on non-English locales' + +. ./lib-gettext.sh + +test_expect_success GETTEXT_LOCALE 'setup' ' + test_write_lines "TILRAUN: Halló Heimur!" >file && + git add file && + LC_ALL="$is_IS_locale" && + export LC_ALL +' + +test_have_prereq GETTEXT_LOCALE && +test-regex "HALLÓ" "Halló" ICASE && +test_set_prereq REGEX_LOCALE + +test_expect_success REGEX_LOCALE 'grep literal string, no -F' ' + git grep -i "TILRAUN: Halló Heimur!" && + git grep -i "TILRAUN: HALLÓ HEIMUR!" +' + +test_expect_success GETTEXT_LOCALE,LIBPCRE 'grep pcre utf-8 icase' ' + git grep --perl-regexp "TILRAUN: H.lló Heimur!" && + git grep --perl-regexp -i "TILRAUN: H.lló Heimur!" && + git grep --perl-regexp -i "TILRAUN: H.LLÓ HEIMUR!" +' + +test_expect_success GETTEXT_LOCALE,LIBPCRE 'grep pcre utf-8 string with "+"' ' + test_write_lines "TILRAUN: Hallóó Heimur!" >file2 && + git add file2 && + git grep -l --perl-regexp "TILRAUN: H.lló+ Heimur!" >actual && + echo file >expected && + echo file2 >>expected && + test_cmp expected actual +' + +test_expect_success REGEX_LOCALE 'grep literal string, with -F' ' + git grep --debug -i -F "TILRAUN: Halló Heimur!" 2>&1 >/dev/null | + grep fixed >debug1 && + test_write_lines "fixed TILRAUN: Halló Heimur!" >expect1 && + test_cmp expect1 debug1 && + + git grep --debug -i -F "TILRAUN: HALLÓ HEIMUR!" 2>&1 >/dev/null | + grep fixed >debug2 && + test_write_lines "fixed TILRAUN: HALLÓ HEIMUR!" >expect2 && + test_cmp expect2 debug2 +' + +test_expect_success REGEX_LOCALE 'grep string with regex, with -F' ' + test_write_lines "^*TILR^AUN:.* \\Halló \$He[]imur!\$" >file && + + git grep --debug -i -F "^*TILR^AUN:.* \\Halló \$He[]imur!\$" 2>&1 >/dev/null | + grep fixed >debug1 && + test_write_lines "fixed \\^*TILR^AUN:\\.\\* \\\\Halló \$He\\[]imur!\\\$" >expect1 && + test_cmp expect1 debug1 && + + git grep --debug -i -F "^*TILR^AUN:.* \\HALLÓ \$HE[]IMUR!\$" 2>&1 >/dev/null | + grep fixed >debug2 && + test_write_lines "fixed \\^*TILR^AUN:\\.\\* \\\\HALLÓ \$HE\\[]IMUR!\\\$" >expect2 && + test_cmp expect2 debug2 +' + +test_expect_success REGEX_LOCALE 'pickaxe -i on non-ascii' ' + git commit -m first && + git log --format=%f -i -S"TILRAUN: HALLÓ HEIMUR!" >actual && + echo first >expected && + test_cmp expected actual +' + +test_done diff --git a/t/t7813-grep-icase-iso.sh b/t/t7813-grep-icase-iso.sh new file mode 100755 index 0000000000..efef7fb81f --- /dev/null +++ b/t/t7813-grep-icase-iso.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +test_description='grep icase on non-English locales' + +. ./lib-gettext.sh + +test_expect_success GETTEXT_ISO_LOCALE 'setup' ' + printf "TILRAUN: Halló Heimur!" >file && + git add file && + LC_ALL="$is_IS_iso_locale" && + export LC_ALL +' + +test_expect_success GETTEXT_ISO_LOCALE,LIBPCRE 'grep pcre string' ' + git grep --perl-regexp -i "TILRAUN: H.lló Heimur!" && + git grep --perl-regexp -i "TILRAUN: H.LLÓ HEIMUR!" +' + +test_done diff --git a/t/t8003-blame-corner-cases.sh b/t/t8003-blame-corner-cases.sh index a9b266f0d3..e48370dfa0 100755 --- a/t/t8003-blame-corner-cases.sh +++ b/t/t8003-blame-corner-cases.sh @@ -41,12 +41,12 @@ test_expect_success setup ' test_tick && GIT_AUTHOR_NAME=Fourth git commit -m Fourth && - { - echo ABC - echo DEF - echo XXXX - echo GHIJK - } >cow && + cat >cow <<-\EOF && + ABC + DEF + XXXX + GHIJK + EOF git add cow && test_tick && GIT_AUTHOR_NAME=Fifth git commit -m Fifth @@ -115,11 +115,11 @@ test_expect_success 'append with -C -C -C' ' test_expect_success 'blame wholesale copy' ' git blame -f -C -C1 HEAD^ -- cow | sed -e "$pick_fc" >current && - { - echo mouse-Initial - echo mouse-Second - echo mouse-Third - } >expected && + cat >expected <<-\EOF && + mouse-Initial + mouse-Second + mouse-Third + EOF test_cmp expected current ' @@ -127,16 +127,61 @@ test_expect_success 'blame wholesale copy' ' test_expect_success 'blame wholesale copy and more' ' git blame -f -C -C1 HEAD -- cow | sed -e "$pick_fc" >current && - { - echo mouse-Initial - echo mouse-Second - echo cow-Fifth - echo mouse-Third - } >expected && + cat >expected <<-\EOF && + mouse-Initial + mouse-Second + cow-Fifth + mouse-Third + EOF test_cmp expected current ' +test_expect_success 'blame wholesale copy and more in the index' ' + + cat >horse <<-\EOF && + ABC + DEF + XXXX + YYYY + GHIJK + EOF + git add horse && + test_when_finished "git rm -f horse" && + git blame -f -C -C1 -- horse | sed -e "$pick_fc" >current && + cat >expected <<-\EOF && + mouse-Initial + mouse-Second + cow-Fifth + horse-Not + mouse-Third + EOF + test_cmp expected current + +' + +test_expect_success 'blame during cherry-pick with file rename conflict' ' + + test_when_finished "git reset --hard && git checkout master" && + git checkout HEAD~3 && + echo MOUSE >> mouse && + git mv mouse rodent && + git add rodent && + GIT_AUTHOR_NAME=Rodent git commit -m "rodent" && + git checkout --detach master && + (git cherry-pick HEAD@{1} || test $? -eq 1) && + git show HEAD@{1}:rodent > rodent && + git add rodent && + git blame -f -C -C1 rodent | sed -e "$pick_fc" >current && + cat current && + cat >expected <<-\EOF && + mouse-Initial + mouse-Second + rodent-Not + EOF + test_cmp expected current +' + test_expect_success 'blame path that used to be a directory' ' mkdir path && echo A A A A A >path/file && diff --git a/t/t8008-blame-formats.sh b/t/t8008-blame-formats.sh index 29f84a6dd1..92c8e792d1 100755 --- a/t/t8008-blame-formats.sh +++ b/t/t8008-blame-formats.sh @@ -87,4 +87,21 @@ test_expect_success 'blame --line-porcelain output' ' test_cmp expect actual ' +test_expect_success '--porcelain detects first non-blank line as subject' ' + ( + GIT_INDEX_FILE=.git/tmp-index && + export GIT_INDEX_FILE && + echo "This is it" >single-file && + git add single-file && + tree=$(git write-tree) && + commit=$(printf "%s\n%s\n%s\n\n\n \noneline\n\nbody\n" \ + "tree $tree" \ + "author A <a@b.c> 123456789 +0000" \ + "committer C <c@d.e> 123456789 +0000" | + git hash-object -w -t commit --stdin) && + git blame --porcelain $commit -- single-file >output && + grep "^summary oneline$" output + ) +' + test_done diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh index 22d8367ff3..28082b134f 100755 --- a/t/t9100-git-svn-basic.sh +++ b/t/t9100-git-svn-basic.sh @@ -45,13 +45,13 @@ test_expect_success "checkout from svn" 'svn co "$svnrepo" "$SVN_TREE"' name='try a deep --rmdir with a commit' test_expect_success "$name" ' - git checkout -f -b mybranch ${remotes_git_svn} && + git checkout -f -b mybranch remotes/git-svn && mv dir/a/b/c/d/e/file dir/file && cp dir/file file && git update-index --add --remove dir/a/b/c/d/e/file dir/file file && git commit -m "$name" && git svn set-tree --find-copies-harder --rmdir \ - ${remotes_git_svn}..mybranch && + remotes/git-svn..mybranch && svn_cmd up "$SVN_TREE" && test -d "$SVN_TREE"/dir && test ! -d "$SVN_TREE"/dir/a' @@ -65,14 +65,14 @@ test_expect_success "$name" " git update-index --add dir/file/file && git commit -m '$name' && test_must_fail git svn set-tree --find-copies-harder --rmdir \ - ${remotes_git_svn}..mybranch + remotes/git-svn..mybranch " name='detect node change from directory to file #1' test_expect_success "$name" ' rm -rf dir "$GIT_DIR"/index && - git checkout -f -b mybranch2 ${remotes_git_svn} && + git checkout -f -b mybranch2 remotes/git-svn && mv bar/zzz zzz && rm -rf bar && mv zzz bar && @@ -80,14 +80,14 @@ test_expect_success "$name" ' git update-index --add -- bar && git commit -m "$name" && test_must_fail git svn set-tree --find-copies-harder --rmdir \ - ${remotes_git_svn}..mybranch2 + remotes/git-svn..mybranch2 ' name='detect node change from file to directory #2' test_expect_success "$name" ' rm -f "$GIT_DIR"/index && - git checkout -f -b mybranch3 ${remotes_git_svn} && + git checkout -f -b mybranch3 remotes/git-svn && rm bar/zzz && git update-index --remove bar/zzz && mkdir bar/zzz && @@ -95,7 +95,7 @@ test_expect_success "$name" ' git update-index --add bar/zzz/yyy && git commit -m "$name" && git svn set-tree --find-copies-harder --rmdir \ - ${remotes_git_svn}..mybranch3 && + remotes/git-svn..mybranch3 && svn_cmd up "$SVN_TREE" && test -d "$SVN_TREE"/bar/zzz && test -e "$SVN_TREE"/bar/zzz/yyy @@ -104,7 +104,7 @@ test_expect_success "$name" ' name='detect node change from directory to file #2' test_expect_success "$name" ' rm -f "$GIT_DIR"/index && - git checkout -f -b mybranch4 ${remotes_git_svn} && + git checkout -f -b mybranch4 remotes/git-svn && rm -rf dir && git update-index --remove -- dir/file && touch dir && @@ -112,19 +112,19 @@ test_expect_success "$name" ' git update-index --add -- dir && git commit -m "$name" && test_must_fail git svn set-tree --find-copies-harder --rmdir \ - ${remotes_git_svn}..mybranch4 + remotes/git-svn..mybranch4 ' name='remove executable bit from a file' test_expect_success POSIXPERM "$name" ' rm -f "$GIT_DIR"/index && - git checkout -f -b mybranch5 ${remotes_git_svn} && + git checkout -f -b mybranch5 remotes/git-svn && chmod -x exec.sh && git update-index exec.sh && git commit -m "$name" && git svn set-tree --find-copies-harder --rmdir \ - ${remotes_git_svn}..mybranch5 && + remotes/git-svn..mybranch5 && svn_cmd up "$SVN_TREE" && test ! -x "$SVN_TREE"/exec.sh' @@ -135,7 +135,7 @@ test_expect_success POSIXPERM "$name" ' git update-index exec.sh && git commit -m "$name" && git svn set-tree --find-copies-harder --rmdir \ - ${remotes_git_svn}..mybranch5 && + remotes/git-svn..mybranch5 && svn_cmd up "$SVN_TREE" && test -x "$SVN_TREE"/exec.sh' @@ -147,7 +147,7 @@ test_expect_success SYMLINKS "$name" ' git update-index exec.sh && git commit -m "$name" && git svn set-tree --find-copies-harder --rmdir \ - ${remotes_git_svn}..mybranch5 && + remotes/git-svn..mybranch5 && svn_cmd up "$SVN_TREE" && test -h "$SVN_TREE"/exec.sh' @@ -159,7 +159,7 @@ test_expect_success POSIXPERM,SYMLINKS "$name" ' git update-index --add file exec-2.sh && git commit -m "$name" && git svn set-tree --find-copies-harder --rmdir \ - ${remotes_git_svn}..mybranch5 && + remotes/git-svn..mybranch5 && svn_cmd up "$SVN_TREE" && test -x "$SVN_TREE"/file && test -h "$SVN_TREE"/exec-2.sh' @@ -172,7 +172,7 @@ test_expect_success POSIXPERM,SYMLINKS "$name" ' git update-index exec-2.sh && git commit -m "$name" && git svn set-tree --find-copies-harder --rmdir \ - ${remotes_git_svn}..mybranch5 && + remotes/git-svn..mybranch5 && svn_cmd up "$SVN_TREE" && test -f "$SVN_TREE"/exec-2.sh && test ! -h "$SVN_TREE"/exec-2.sh && @@ -194,7 +194,7 @@ GIT_SVN_ID=alt export GIT_SVN_ID test_expect_success "$name" \ 'git svn init "$svnrepo" && git svn fetch && - git rev-list --pretty=raw ${remotes_git_svn} | grep ^tree | uniq > a && + git rev-list --pretty=raw remotes/git-svn | grep ^tree | uniq > a && git rev-list --pretty=raw remotes/alt | grep ^tree | uniq > b && test_cmp a b' @@ -217,17 +217,17 @@ EOF test_expect_success POSIXPERM,SYMLINKS "$name" "test_cmp a expected" -test_expect_success 'exit if remote refs are ambigious' " +test_expect_success 'exit if remote refs are ambigious' ' git config --add svn-remote.svn.fetch \ - bar:refs/${remotes_git_svn} && + bar:refs/remotes/git-svn && test_must_fail git svn migrate -" +' test_expect_success 'exit if init-ing a would clobber a URL' ' svnadmin create "${PWD}/svnrepo2" && svn mkdir -m "mkdir bar" "${svnrepo}2/bar" && git config --unset svn-remote.svn.fetch \ - "^bar:refs/${remotes_git_svn}$" && + "^bar:refs/remotes/git-svn$" && test_must_fail git svn init "${svnrepo}2/bar" ' @@ -237,7 +237,7 @@ test_expect_success \ git config --get svn-remote.svn.fetch \ "^bar:refs/remotes/bar$" && git config --get svn-remote.svn.fetch \ - "^:refs/${remotes_git_svn}$" + "^:refs/remotes/git-svn$" ' test_expect_success 'dcommit $rev does not clobber current branch' ' @@ -259,26 +259,26 @@ test_expect_success 'dcommit $rev does not clobber current branch' ' git branch -D my-bar ' -test_expect_success 'able to dcommit to a subdirectory' " +test_expect_success 'able to dcommit to a subdirectory' ' git svn fetch -i bar && git checkout -b my-bar refs/remotes/bar && echo abc > d && git update-index --add d && - git commit -m '/bar/d should be in the log' && + git commit -m "/bar/d should be in the log" && git svn dcommit -i bar && - test -z \"\$(git diff refs/heads/my-bar refs/remotes/bar)\" && + test -z "$(git diff refs/heads/my-bar refs/remotes/bar)" && mkdir newdir && echo new > newdir/dir && git update-index --add newdir/dir && - git commit -m 'add a new directory' && + git commit -m "add a new directory" && git svn dcommit -i bar && - test -z \"\$(git diff refs/heads/my-bar refs/remotes/bar)\" && + test -z "$(git diff refs/heads/my-bar refs/remotes/bar)" && echo foo >> newdir/dir && git update-index newdir/dir && - git commit -m 'modify a file in new directory' && + git commit -m "modify a file in new directory" && git svn dcommit -i bar && - test -z \"\$(git diff refs/heads/my-bar refs/remotes/bar)\" - " + test -z "$(git diff refs/heads/my-bar refs/remotes/bar)" +' test_expect_success 'dcommit should not fail with a touched file' ' test_commit "commit-new-file-foo2" foo2 && @@ -291,13 +291,13 @@ test_expect_success 'rebase should not fail with a touched file' ' git svn rebase ' -test_expect_success 'able to set-tree to a subdirectory' " +test_expect_success 'able to set-tree to a subdirectory' ' echo cba > d && git update-index d && - git commit -m 'update /bar/d' && + git commit -m "update /bar/d" && git svn set-tree -i bar HEAD && - test -z \"\$(git diff refs/heads/my-bar refs/remotes/bar)\" - " + test -z "$(git diff refs/heads/my-bar refs/remotes/bar)" +' test_expect_success 'git-svn works in a bare repository' ' mkdir bare-repo && diff --git a/t/t9101-git-svn-props.sh b/t/t9101-git-svn-props.sh index e8173d5fef..07bfb63777 100755 --- a/t/t9101-git-svn-props.sh +++ b/t/t9101-git-svn-props.sh @@ -73,11 +73,11 @@ test_expect_success 'fetch revisions from svn' 'git svn fetch' name='test svn:keywords ignoring' test_expect_success "$name" \ - 'git checkout -b mybranch ${remotes_git_svn} && + 'git checkout -b mybranch remotes/git-svn && echo Hi again >> kw.c && git commit -a -m "test keywords ignoring" && - git svn set-tree ${remotes_git_svn}..mybranch && - git pull . ${remotes_git_svn}' + git svn set-tree remotes/git-svn..mybranch && + git pull . remotes/git-svn' expect='/* $Id$ */' got="$(sed -ne 2p kw.c)" @@ -95,7 +95,7 @@ test_expect_success "propset CR on crlf files" ' test_expect_success 'fetch and pull latest from svn and checkout a new wc' \ 'git svn fetch && - git pull . ${remotes_git_svn} && + git pull . remotes/git-svn && svn_cmd co "$svnrepo" new_wc' for i in crlf ne_crlf lf ne_lf cr ne_cr empty_cr empty_lf empty empty_crlf @@ -117,7 +117,7 @@ cd test_wc svn_cmd commit -m "propset CRLF on cr files"' cd .. test_expect_success 'fetch and pull latest from svn' \ - 'git svn fetch && git pull . ${remotes_git_svn}' + 'git svn fetch && git pull . remotes/git-svn' b_cr="$(git hash-object cr)" b_ne_cr="$(git hash-object ne_cr)" @@ -168,7 +168,7 @@ cat >create-ignore-index.expect <<\EOF EOF test_expect_success 'test create-ignore' " - git svn fetch && git pull . ${remotes_git_svn} && + git svn fetch && git pull . remotes/git-svn && git svn create-ignore && cmp ./.gitignore create-ignore.expect && cmp ./deeply/.gitignore create-ignore.expect && diff --git a/t/t9102-git-svn-deep-rmdir.sh b/t/t9102-git-svn-deep-rmdir.sh index eb70f4839c..66cd51102c 100755 --- a/t/t9102-git-svn-deep-rmdir.sh +++ b/t/t9102-git-svn-deep-rmdir.sh @@ -17,7 +17,7 @@ test_expect_success 'initialize repo' ' test_expect_success 'mirror via git svn' ' git svn init "$svnrepo" && git svn fetch && - git checkout -f -b test-rmdir ${remotes_git_svn} + git checkout -f -b test-rmdir remotes/git-svn ' test_expect_success 'Try a commit on rmdir' ' diff --git a/t/t9103-git-svn-tracked-directory-removed.sh b/t/t9103-git-svn-tracked-directory-removed.sh index 3413164cb1..b28271345c 100755 --- a/t/t9103-git-svn-tracked-directory-removed.sh +++ b/t/t9103-git-svn-tracked-directory-removed.sh @@ -23,17 +23,19 @@ test_expect_success 'make history for tracking' ' test_expect_success 'clone repo with git' ' git svn clone -s "$svnrepo" x && - test -f x/FOLLOWME && - test ! -f x/README + test_path_is_file x/FOLLOWME && + test_path_is_missing x/README ' -test_expect_success 'make sure r2 still has old file' " - cd x && - test -n \"\$(git svn find-rev r1)\" && - git reset --hard \$(git svn find-rev r1) && - test -f README && - test ! -f FOLLOWME && - test x\$(git svn find-rev r2) = x -" +test_expect_success 'make sure r2 still has old file' ' + ( + cd x && + test -n "$(git svn find-rev r1)" && + git reset --hard "$(git svn find-rev r1)" && + test_path_is_file README && + test_path_is_missing FOLLOWME && + test -z "$(git svn find-rev r2)" + ) +' test_done diff --git a/t/t9106-git-svn-commit-diff-clobber.sh b/t/t9106-git-svn-commit-diff-clobber.sh index f6d7ac7c5f..dbe8deac0d 100755 --- a/t/t9106-git-svn-commit-diff-clobber.sh +++ b/t/t9106-git-svn-commit-diff-clobber.sh @@ -44,7 +44,7 @@ test_expect_success 'commit complementing change from git' ' test_expect_success 'dcommit fails to commit because of conflict' ' git svn init "$svnrepo" && git svn fetch && - git reset --hard refs/${remotes_git_svn} && + git reset --hard refs/remotes/git-svn && svn_cmd co "$svnrepo" t.svn && ( cd t.svn && @@ -59,7 +59,7 @@ test_expect_success 'dcommit fails to commit because of conflict' ' ' test_expect_success 'dcommit does the svn equivalent of an index merge' " - git reset --hard refs/${remotes_git_svn} && + git reset --hard refs/remotes/git-svn && echo 'index merge' > file2 && git update-index --add file2 && git commit -a -m 'index merge' && @@ -81,7 +81,7 @@ test_expect_success 'commit another change from svn side' ' ' test_expect_success 'multiple dcommit from git svn will not clobber svn' " - git reset --hard refs/${remotes_git_svn} && + git reset --hard refs/remotes/git-svn && echo new file >> new-file && git update-index --add new-file && git commit -a -m 'new file' && diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh index 9060198037..9f3ef8f2ef 100755 --- a/t/t9107-git-svn-migrate.sh +++ b/t/t9107-git-svn-migrate.sh @@ -19,13 +19,14 @@ test_expect_success 'setup old-looking metadata' ' git svn init "$svnrepo" && git svn fetch && rm -rf "$GIT_DIR"/svn && - git update-ref refs/heads/git-svn-HEAD refs/${remotes_git_svn} && - git update-ref refs/heads/svn-HEAD refs/${remotes_git_svn} && - git update-ref -d refs/${remotes_git_svn} refs/${remotes_git_svn} + git update-ref refs/heads/git-svn-HEAD refs/remotes/git-svn && + git update-ref refs/heads/svn-HEAD refs/remotes/git-svn && + git update-ref -d refs/remotes/git-svn refs/remotes/git-svn ' -head=$(git rev-parse --verify refs/heads/git-svn-HEAD^0) -test_expect_success 'git-svn-HEAD is a real HEAD' "test -n '$head'" +test_expect_success 'git-svn-HEAD is a real HEAD' ' + git rev-parse --verify refs/heads/git-svn-HEAD^0 +' svnrepo_escaped=$(echo $svnrepo | sed 's/ /%20/') @@ -35,11 +36,11 @@ test_expect_success 'initialize old-style (v0) git svn layout' ' echo "$svnrepo" > "$GIT_DIR"/svn/info/url && git svn migrate && ! test -d "$GIT_DIR"/git-svn && - git rev-parse --verify refs/${remotes_git_svn}^0 && + git rev-parse --verify refs/remotes/git-svn^0 && git rev-parse --verify refs/remotes/svn^0 && test "$(git config --get svn-remote.svn.url)" = "$svnrepo_escaped" && test $(git config --get svn-remote.svn.fetch) = \ - ":refs/${remotes_git_svn}" + ":refs/remotes/git-svn" ' test_expect_success 'initialize a multi-repository repo' ' @@ -56,9 +57,11 @@ test_expect_success 'initialize a multi-repository repo' ' "^tags/\*:refs/remotes/origin/tags/\*$" && git config --add svn-remote.svn.fetch "branches/a:refs/remotes/origin/a" && git config --add svn-remote.svn.fetch "branches/b:refs/remotes/origin/b" && - for i in tags/0.1 tags/0.2 tags/0.3; do + for i in tags/0.1 tags/0.2 tags/0.3 + do git config --add svn-remote.svn.fetch \ - $i:refs/remotes/origin/$i || exit 1; done && + $i:refs/remotes/origin/$i || return 1 + done && git config --get-all svn-remote.svn.fetch > fetch.out && grep "^trunk:refs/remotes/origin/trunk$" fetch.out && grep "^branches/a:refs/remotes/origin/a$" fetch.out && @@ -66,34 +69,42 @@ test_expect_success 'initialize a multi-repository repo' ' grep "^tags/0\.1:refs/remotes/origin/tags/0\.1$" fetch.out && grep "^tags/0\.2:refs/remotes/origin/tags/0\.2$" fetch.out && grep "^tags/0\.3:refs/remotes/origin/tags/0\.3$" fetch.out && - grep "^:refs/${remotes_git_svn}" fetch.out + grep "^:refs/remotes/git-svn" fetch.out ' # refs should all be different, but the trees should all be the same: -test_expect_success 'multi-fetch works on partial urls + paths' " +test_expect_success 'multi-fetch works on partial urls + paths' ' + refs="trunk a b tags/0.1 tags/0.2 tags/0.3" && git svn multi-fetch && - for i in trunk a b tags/0.1 tags/0.2 tags/0.3; do - git rev-parse --verify refs/remotes/origin/\$i^0 >> refs.out || exit 1; - done && - test -z \"\$(sort < refs.out | uniq -d)\" && - for i in trunk a b tags/0.1 tags/0.2 tags/0.3; do - for j in trunk a b tags/0.1 tags/0.2 tags/0.3; do - if test \$j != \$i; then continue; fi - test -z \"\$(git diff refs/remotes/origin/\$i \ - refs/remotes/origin/\$j)\" ||exit 1; done; done - " + for i in $refs + do + git rev-parse --verify refs/remotes/origin/$i^0 || return 1; + done >refs.out && + test -z "$(sort <refs.out | uniq -d)" && + for i in $refs + do + for j in $refs + do + git diff --exit-code refs/remotes/origin/$i \ + refs/remotes/origin/$j || + return 1 + done + done +' test_expect_success 'migrate --minimize on old inited layout' ' git config --unset-all svn-remote.svn.fetch && git config --unset-all svn-remote.svn.url && rm -rf "$GIT_DIR"/svn && - for i in $(cat fetch.out); do + for i in $(cat fetch.out) + do path=$(expr $i : "\([^:]*\):.*$") ref=$(expr $i : "[^:]*:\(refs/remotes/.*\)$") if test -z "$ref"; then continue; fi if test -n "$path"; then path="/$path"; fi - ( mkdir -p "$GIT_DIR"/svn/$ref/info/ && - echo "$svnrepo"$path > "$GIT_DIR"/svn/$ref/info/url ) || exit 1; + mkdir -p "$GIT_DIR"/svn/$ref/info/ && + echo "$svnrepo"$path >"$GIT_DIR"/svn/$ref/info/url || + return 1 done && git svn migrate --minimize && test -z "$(git config -l | grep "^svn-remote\.git-svn\.")" && @@ -104,7 +115,7 @@ test_expect_success 'migrate --minimize on old inited layout' ' grep "^tags/0\.1:refs/remotes/origin/tags/0\.1$" fetch.out && grep "^tags/0\.2:refs/remotes/origin/tags/0\.2$" fetch.out && grep "^tags/0\.3:refs/remotes/origin/tags/0\.3$" fetch.out && - grep "^:refs/${remotes_git_svn}" fetch.out + grep "^:refs/remotes/git-svn" fetch.out ' test_expect_success ".rev_db auto-converted to .rev_map.UUID" ' diff --git a/t/t9110-git-svn-use-svm-props.sh b/t/t9110-git-svn-use-svm-props.sh index 29fbdfdd3f..dde0a3c222 100755 --- a/t/t9110-git-svn-use-svm-props.sh +++ b/t/t9110-git-svn-use-svm-props.sh @@ -22,31 +22,31 @@ uuid=161ce429-a9dd-4828-af4a-52023f968c89 bar_url=http://mayonaise/svnrepo/bar test_expect_success 'verify metadata for /bar' " git cat-file commit refs/remotes/bar | \ - grep '^${git_svn_id}: $bar_url@12 $uuid$' && + grep '^git-svn-id: $bar_url@12 $uuid$' && git cat-file commit refs/remotes/bar~1 | \ - grep '^${git_svn_id}: $bar_url@11 $uuid$' && + grep '^git-svn-id: $bar_url@11 $uuid$' && git cat-file commit refs/remotes/bar~2 | \ - grep '^${git_svn_id}: $bar_url@10 $uuid$' && + grep '^git-svn-id: $bar_url@10 $uuid$' && git cat-file commit refs/remotes/bar~3 | \ - grep '^${git_svn_id}: $bar_url@9 $uuid$' && + grep '^git-svn-id: $bar_url@9 $uuid$' && git cat-file commit refs/remotes/bar~4 | \ - grep '^${git_svn_id}: $bar_url@6 $uuid$' && + grep '^git-svn-id: $bar_url@6 $uuid$' && git cat-file commit refs/remotes/bar~5 | \ - grep '^${git_svn_id}: $bar_url@1 $uuid$' + grep '^git-svn-id: $bar_url@1 $uuid$' " e_url=http://mayonaise/svnrepo/dir/a/b/c/d/e test_expect_success 'verify metadata for /dir/a/b/c/d/e' " git cat-file commit refs/remotes/e | \ - grep '^${git_svn_id}: $e_url@1 $uuid$' + grep '^git-svn-id: $e_url@1 $uuid$' " dir_url=http://mayonaise/svnrepo/dir test_expect_success 'verify metadata for /dir' " git cat-file commit refs/remotes/dir | \ - grep '^${git_svn_id}: $dir_url@2 $uuid$' && + grep '^git-svn-id: $dir_url@2 $uuid$' && git cat-file commit refs/remotes/dir~1 | \ - grep '^${git_svn_id}: $dir_url@1 $uuid$' + grep '^git-svn-id: $dir_url@1 $uuid$' " test_expect_success 'find commit based on SVN revision number' " diff --git a/t/t9111-git-svn-use-svnsync-props.sh b/t/t9111-git-svn-use-svnsync-props.sh index bd081c2ec3..22b6e5ee7d 100755 --- a/t/t9111-git-svn-use-svnsync-props.sh +++ b/t/t9111-git-svn-use-svnsync-props.sh @@ -21,31 +21,31 @@ uuid=161ce429-a9dd-4828-af4a-52023f968c89 bar_url=http://mayonaise/svnrepo/bar test_expect_success 'verify metadata for /bar' " git cat-file commit refs/remotes/bar | \ - grep '^${git_svn_id}: $bar_url@12 $uuid$' && + grep '^git-svn-id: $bar_url@12 $uuid$' && git cat-file commit refs/remotes/bar~1 | \ - grep '^${git_svn_id}: $bar_url@11 $uuid$' && + grep '^git-svn-id: $bar_url@11 $uuid$' && git cat-file commit refs/remotes/bar~2 | \ - grep '^${git_svn_id}: $bar_url@10 $uuid$' && + grep '^git-svn-id: $bar_url@10 $uuid$' && git cat-file commit refs/remotes/bar~3 | \ - grep '^${git_svn_id}: $bar_url@9 $uuid$' && + grep '^git-svn-id: $bar_url@9 $uuid$' && git cat-file commit refs/remotes/bar~4 | \ - grep '^${git_svn_id}: $bar_url@6 $uuid$' && + grep '^git-svn-id: $bar_url@6 $uuid$' && git cat-file commit refs/remotes/bar~5 | \ - grep '^${git_svn_id}: $bar_url@1 $uuid$' + grep '^git-svn-id: $bar_url@1 $uuid$' " e_url=http://mayonaise/svnrepo/dir/a/b/c/d/e test_expect_success 'verify metadata for /dir/a/b/c/d/e' " git cat-file commit refs/remotes/e | \ - grep '^${git_svn_id}: $e_url@1 $uuid$' + grep '^git-svn-id: $e_url@1 $uuid$' " dir_url=http://mayonaise/svnrepo/dir test_expect_success 'verify metadata for /dir' " git cat-file commit refs/remotes/dir | \ - grep '^${git_svn_id}: $dir_url@2 $uuid$' && + grep '^git-svn-id: $dir_url@2 $uuid$' && git cat-file commit refs/remotes/dir~1 | \ - grep '^${git_svn_id}: $dir_url@1 $uuid$' + grep '^git-svn-id: $dir_url@1 $uuid$' " test_done diff --git a/t/t9120-git-svn-clone-with-percent-escapes.sh b/t/t9120-git-svn-clone-with-percent-escapes.sh index 1c84ce1023..59465b147e 100755 --- a/t/t9120-git-svn-clone-with-percent-escapes.sh +++ b/t/t9120-git-svn-clone-with-percent-escapes.sh @@ -22,7 +22,7 @@ test_expect_success 'test clone with percent escapes' ' git svn clone "$svnrepo/pr%20ject" clone && ( cd clone && - git rev-parse refs/${remotes_git_svn} + git rev-parse refs/remotes/git-svn ) ' @@ -42,7 +42,7 @@ test_expect_success 'test clone trunk with percent escapes and minimize-url' ' git svn clone --minimize-url "$svnrepo/pr%20ject/trunk" minimize && ( cd minimize && - git rev-parse refs/${remotes_git_svn} + git rev-parse refs/remotes/git-svn ) ' @@ -50,7 +50,7 @@ test_expect_success 'test clone trunk with percent escapes' ' git svn clone "$svnrepo/pr%20ject/trunk" trunk && ( cd trunk && - git rev-parse refs/${remotes_git_svn} + git rev-parse refs/remotes/git-svn ) ' diff --git a/t/t9123-git-svn-rebuild-with-rewriteroot.sh b/t/t9123-git-svn-rebuild-with-rewriteroot.sh index fd8184787f..ead404589e 100755 --- a/t/t9123-git-svn-rebuild-with-rewriteroot.sh +++ b/t/t9123-git-svn-rebuild-with-rewriteroot.sh @@ -17,7 +17,7 @@ rm -rf import test_expect_success 'init, fetch and checkout repository' ' git svn init --rewrite-root=http://invalid.invalid/ "$svnrepo" && git svn fetch && - git checkout -b mybranch ${remotes_git_svn} + git checkout -b mybranch remotes/git-svn ' test_expect_success 'remove rev_map' ' diff --git a/t/t9153-git-svn-rewrite-uuid.sh b/t/t9153-git-svn-rewrite-uuid.sh index 88a2cfa233..372ef15685 100755 --- a/t/t9153-git-svn-rewrite-uuid.sh +++ b/t/t9153-git-svn-rewrite-uuid.sh @@ -17,9 +17,9 @@ test_expect_success 'load svn repo' " test_expect_success 'verify uuid' " git cat-file commit refs/remotes/git-svn~0 | \ - grep '^${git_svn_id}: .*@2 $uuid$' && + grep '^git-svn-id: .*@2 $uuid$' && git cat-file commit refs/remotes/git-svn~1 | \ - grep '^${git_svn_id}: .*@1 $uuid$' + grep '^git-svn-id: .*@1 $uuid$' " test_done diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 25bb60b281..4bca35c259 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -2650,6 +2650,21 @@ test_expect_success 'R: ignore non-git options' ' git fast-import <input ' +test_expect_success 'R: corrupt lines do not mess marks file' ' + rm -f io.marks && + blob=$(echo hi | git hash-object --stdin) && + cat >expect <<-EOF && + :3 0000000000000000000000000000000000000000 + :1 $blob + :2 $blob + EOF + cp expect io.marks && + test_must_fail git fast-import --import-marks=io.marks --export-marks=io.marks <<-\EOF && + + EOF + test_cmp expect io.marks +' + ## ## R: very large blobs ## diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh index d708cbf032..432c61d246 100755 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@ -45,7 +45,8 @@ test_expect_success 'setup' ' touch secondrootfile && git add secondrootfile && git commit -m "second root") && - git pull secondroot master && + git fetch secondroot master && + git merge --allow-unrelated-histories FETCH_HEAD && git clone -q --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 && GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true && GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log" && diff --git a/t/t9826-git-p4-keep-empty-commits.sh b/t/t9826-git-p4-keep-empty-commits.sh index be12960d39..fa8b9daf1f 100755 --- a/t/t9826-git-p4-keep-empty-commits.sh +++ b/t/t9826-git-p4-keep-empty-commits.sh @@ -47,23 +47,23 @@ test_expect_success 'Clone repo root path with all history' ' git init . && git p4 clone --use-client-spec --destination="$git" //depot@all && cat >expect <<-\EOF && -Remove file 4 -[git-p4: depot-paths = "//depot/": change = 6] + Remove file 4 + [git-p4: depot-paths = "//depot/": change = 6] -Remove file 3 -[git-p4: depot-paths = "//depot/": change = 5] + Remove file 3 + [git-p4: depot-paths = "//depot/": change = 5] -Add file 4 -[git-p4: depot-paths = "//depot/": change = 4] + Add file 4 + [git-p4: depot-paths = "//depot/": change = 4] -Add file 3 -[git-p4: depot-paths = "//depot/": change = 3] + Add file 3 + [git-p4: depot-paths = "//depot/": change = 3] -Add file 2 -[git-p4: depot-paths = "//depot/": change = 2] + Add file 2 + [git-p4: depot-paths = "//depot/": change = 2] -Add file 1 -[git-p4: depot-paths = "//depot/": change = 1] + Add file 1 + [git-p4: depot-paths = "//depot/": change = 1] EOF git log --format=%B >actual && @@ -80,23 +80,23 @@ test_expect_success 'Clone repo subdir with all history but keep empty commits' git config git-p4.keepEmptyCommits true && git p4 clone --use-client-spec --destination="$git" //depot@all && cat >expect <<-\EOF && -Remove file 4 -[git-p4: depot-paths = "//depot/": change = 6] + Remove file 4 + [git-p4: depot-paths = "//depot/": change = 6] -Remove file 3 -[git-p4: depot-paths = "//depot/": change = 5] + Remove file 3 + [git-p4: depot-paths = "//depot/": change = 5] -Add file 4 -[git-p4: depot-paths = "//depot/": change = 4] + Add file 4 + [git-p4: depot-paths = "//depot/": change = 4] -Add file 3 -[git-p4: depot-paths = "//depot/": change = 3] + Add file 3 + [git-p4: depot-paths = "//depot/": change = 3] -Add file 2 -[git-p4: depot-paths = "//depot/": change = 2] + Add file 2 + [git-p4: depot-paths = "//depot/": change = 2] -Add file 1 -[git-p4: depot-paths = "//depot/": change = 1] + Add file 1 + [git-p4: depot-paths = "//depot/": change = 1] EOF git log --format=%B >actual && @@ -112,14 +112,14 @@ test_expect_success 'Clone repo subdir with all history' ' git init . && git p4 clone --use-client-spec --destination="$git" --verbose //depot@all && cat >expect <<-\EOF && -Remove file 3 -[git-p4: depot-paths = "//depot/": change = 5] + Remove file 3 + [git-p4: depot-paths = "//depot/": change = 5] -Add file 3 -[git-p4: depot-paths = "//depot/": change = 3] + Add file 3 + [git-p4: depot-paths = "//depot/": change = 3] -Add file 1 -[git-p4: depot-paths = "//depot/": change = 1] + Add file 1 + [git-p4: depot-paths = "//depot/": change = 1] EOF git log --format=%B >actual && diff --git a/t/t9828-git-p4-map-user.sh b/t/t9828-git-p4-map-user.sh new file mode 100755 index 0000000000..e20395c89f --- /dev/null +++ b/t/t9828-git-p4-map-user.sh @@ -0,0 +1,61 @@ +#!/bin/sh + +test_description='Clone repositories and map users' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'Create a repo with different users' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + + >author.txt && + p4 add author.txt && + p4 submit -d "Add file author\\n" && + + P4USER=mmax && + >max.txt && + p4 add max.txt && + p4 submit -d "Add file max" && + + P4USER=eri && + >moritz.txt && + p4 add moritz.txt && + p4 submit -d "Add file moritz" && + + P4USER=no && + >nobody.txt && + p4 add nobody.txt && + p4 submit -d "Add file nobody" + ) +' + +test_expect_success 'Clone repo root path with all history' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config --add git-p4.mapUser "mmax = Max Musterman <max@example.com> " && + git config --add git-p4.mapUser " eri=Erika Musterman <erika@example.com>" && + git p4 clone --use-client-spec --destination="$git" //depot@all && + cat >expect <<-\EOF && + no <no@client> + Erika Musterman <erika@example.com> + Max Musterman <max@example.com> + Dr. author <author@example.com> + EOF + git log --format="%an <%ae>" >actual && + test_cmp expect actual + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9829-git-p4-jobs.sh b/t/t9829-git-p4-jobs.sh new file mode 100755 index 0000000000..971aeeea1f --- /dev/null +++ b/t/t9829-git-p4-jobs.sh @@ -0,0 +1,99 @@ +#!/bin/sh + +test_description='git p4 retrieve job info' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'add p4 jobs' ' + ( + p4_add_job TESTJOB-A && + p4_add_job TESTJOB-B + ) +' + +test_expect_success 'add p4 files' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + >file1 && + p4 add file1 && + p4 submit -d "Add file 1" + ) +' + +test_expect_success 'check log message of changelist with no jobs' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git p4 clone --use-client-spec --destination="$git" //depot@all && + cat >expect <<-\EOF && + Add file 1 + [git-p4: depot-paths = "//depot/": change = 1] + + EOF + git log --format=%B >actual && + test_cmp expect actual + ) +' + +test_expect_success 'add TESTJOB-A to change 1' ' + ( + cd "$cli" && + p4 fix -c 1 TESTJOB-A + ) +' + +test_expect_success 'check log message of changelist with one job' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git p4 clone --use-client-spec --destination="$git" //depot@all && + cat >expect <<-\EOF && + Add file 1 + Jobs: TESTJOB-A + [git-p4: depot-paths = "//depot/": change = 1] + + EOF + git log --format=%B >actual && + test_cmp expect actual + ) +' + +test_expect_success 'add TESTJOB-B to change 1' ' + ( + cd "$cli" && + p4 fix -c 1 TESTJOB-B + ) +' + +test_expect_success 'check log message of changelist with more jobs' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git p4 clone --use-client-spec --destination="$git" //depot@all && + cat >expect <<-\EOF && + Add file 1 + Jobs: TESTJOB-A TESTJOB-B + [git-p4: depot-paths = "//depot/": change = 1] + + EOF + git log --format=%B >actual && + test_cmp expect actual + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index 3978fc0b45..ca40a1289f 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -612,7 +612,7 @@ test_must_fail () { then echo >&2 "test_must_fail: command succeeded: $*" return 1 - elif test $exit_code -eq 141 && list_contains "$_test_ok" sigpipe + elif test_match_signal 13 $exit_code && list_contains "$_test_ok" sigpipe then return 0 elif test $exit_code -gt 129 && test $exit_code -le 192 @@ -939,3 +939,40 @@ mingw_read_file_strip_cr_ () { eval "$1=\$$1\$line" done } + +# Like "env FOO=BAR some-program", but run inside a subshell, which means +# it also works for shell functions (though those functions cannot impact +# the environment outside of the test_env invocation). +test_env () { + ( + while test $# -gt 0 + do + case "$1" in + *=*) + eval "${1%%=*}=\${1#*=}" + eval "export ${1%%=*}" + shift + ;; + *) + "$@" + exit + ;; + esac + done + ) +} + +# Returns true if the numeric exit code in "$2" represents the expected signal +# in "$1". Signals should be given numerically. +test_match_signal () { + if test "$2" = "$((128 + $1))" + then + # POSIX + return 0 + elif test "$2" = "$((256 + $1))" + then + # ksh + return 0 + fi + return 1 +} diff --git a/t/test-lib.sh b/t/test-lib.sh index 39c70f0326..d731d66e36 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -162,6 +162,9 @@ _x40="$_x05$_x05$_x05$_x05$_x05$_x05$_x05$_x05" # Zero SHA-1 _z40=0000000000000000000000000000000000000000 +EMPTY_TREE=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +EMPTY_BLOB=e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 + # Line feed LF=' ' @@ -170,7 +173,7 @@ LF=' # when case-folding filenames u200c=$(printf '\342\200\214') -export _x05 _x40 _z40 LF u200c +export _x05 _x40 _z40 LF u200c EMPTY_TREE EMPTY_BLOB # Each test should start with something like this, after copyright notices: # @@ -798,7 +801,7 @@ then # override all git executables in TEST_DIRECTORY/.. GIT_VALGRIND=$TEST_DIRECTORY/valgrind mkdir -p "$GIT_VALGRIND"/bin - for file in $GIT_BUILD_DIR/git* $GIT_BUILD_DIR/test-* + for file in $GIT_BUILD_DIR/git* $GIT_BUILD_DIR/t/helper/test-* do make_valgrind_symlink $file done @@ -867,10 +870,10 @@ test -d "$GIT_BUILD_DIR"/templates/blt || { error "You haven't built things yet, have you?" } -if ! test -x "$GIT_BUILD_DIR"/test-chmtime +if ! test -x "$GIT_BUILD_DIR"/t/helper/test-chmtime then echo >&2 'You need to build test-chmtime:' - echo >&2 'Run "make test-chmtime" in the source (toplevel) directory' + echo >&2 'Run "make t/helper/test-chmtime" in the source (toplevel) directory' exit 1 fi @@ -1111,3 +1114,12 @@ run_with_limited_cmdline () { } test_lazy_prereq CMDLINE_LIMIT 'run_with_limited_cmdline true' + +build_option () { + git version --build-options | + sed -ne "s/^$1: //p" +} + +test_lazy_prereq LONG_IS_64BIT ' + test 8 -le "$(build_option sizeof-long)" +' |