diff options
Diffstat (limited to 't')
67 files changed, 2997 insertions, 400 deletions
@@ -334,7 +334,7 @@ that cannot be easily covered by a few specific test cases. These could be enabled by running the test suite with correct GIT_TEST_ environment set. -GIT_TEST_FAIL_PREREQS<non-empty?> fails all prerequisites. This is +GIT_TEST_FAIL_PREREQS=<boolean> fails all prerequisites. This is useful for discovering issues with the tests where say a later test implicitly depends on an optional earlier test. @@ -343,11 +343,11 @@ whether this mode is active, and e.g. skip some tests that are hard to refactor to deal with it. The "SYMLINKS" prerequisite is currently excluded as so much relies on it, but this might change in the future. -GIT_TEST_GETTEXT_POISON=<non-empty?> turns all strings marked for -translation into gibberish if non-empty (think "test -n"). Used for -spotting those tests that need to be marked with a C_LOCALE_OUTPUT -prerequisite when adding more strings for translation. See "Testing -marked strings" in po/README for details. +GIT_TEST_GETTEXT_POISON=<boolean> turns all strings marked for +translation into gibberish if true. Used for spotting those tests that +need to be marked with a C_LOCALE_OUTPUT prerequisite when adding more +strings for translation. See "Testing marked strings" in po/README for +details. GIT_TEST_SPLIT_INDEX=<boolean> forces split-index mode on the whole test suite. Accept any boolean values that are accepted by git-config. diff --git a/t/helper/test-dir-iterator.c b/t/helper/test-dir-iterator.c new file mode 100644 index 0000000000..c7c30664da --- /dev/null +++ b/t/helper/test-dir-iterator.c @@ -0,0 +1,67 @@ +#include "test-tool.h" +#include "git-compat-util.h" +#include "strbuf.h" +#include "iterator.h" +#include "dir-iterator.h" + +static const char *error_name(int error_number) +{ + switch (error_number) { + case ENOENT: return "ENOENT"; + case ENOTDIR: return "ENOTDIR"; + default: return "ESOMETHINGELSE"; + } +} + +/* + * usage: + * tool-test dir-iterator [--follow-symlinks] [--pedantic] directory_path + */ +int cmd__dir_iterator(int argc, const char **argv) +{ + struct strbuf path = STRBUF_INIT; + struct dir_iterator *diter; + unsigned int flags = 0; + int iter_status; + + for (++argv, --argc; *argv && starts_with(*argv, "--"); ++argv, --argc) { + if (strcmp(*argv, "--follow-symlinks") == 0) + flags |= DIR_ITERATOR_FOLLOW_SYMLINKS; + else if (strcmp(*argv, "--pedantic") == 0) + flags |= DIR_ITERATOR_PEDANTIC; + else + die("invalid option '%s'", *argv); + } + + if (!*argv || argc != 1) + die("dir-iterator needs exactly one non-option argument"); + + strbuf_add(&path, *argv, strlen(*argv)); + diter = dir_iterator_begin(path.buf, flags); + + if (!diter) { + printf("dir_iterator_begin failure: %s\n", error_name(errno)); + exit(EXIT_FAILURE); + } + + while ((iter_status = dir_iterator_advance(diter)) == ITER_OK) { + if (S_ISDIR(diter->st.st_mode)) + printf("[d] "); + else if (S_ISREG(diter->st.st_mode)) + printf("[f] "); + else if (S_ISLNK(diter->st.st_mode)) + printf("[s] "); + else + printf("[?] "); + + printf("(%s) [%s] %s\n", diter->relative_path, diter->basename, + diter->path.buf); + } + + if (iter_status != ITER_DONE) { + printf("dir_iterator_advance failure\n"); + return 1; + } + + return 0; +} diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c index 23d2b172fe..aaf17b0ddf 100644 --- a/t/helper/test-hashmap.c +++ b/t/helper/test-hashmap.c @@ -173,14 +173,7 @@ int cmd__hashmap(int argc, const char **argv) p2 = strtok(NULL, DELIM); } - if (!strcmp("hash", cmd) && p1) { - - /* print results of different hash functions */ - printf("%u %u %u %u\n", - strhash(p1), memhash(p1, strlen(p1)), - strihash(p1), memihash(p1, strlen(p1))); - - } else if (!strcmp("add", cmd) && p1 && p2) { + if (!strcmp("add", cmd) && p1 && p2) { /* create entry with key = p1, value = p2 */ entry = alloc_test_entry(hash, p1, p2); diff --git a/t/helper/test-match-trees.c b/t/helper/test-match-trees.c index 96857f26ac..b9fd427571 100644 --- a/t/helper/test-match-trees.c +++ b/t/helper/test-match-trees.c @@ -20,7 +20,7 @@ int cmd__match_trees(int ac, const char **av) if (!two) die("not a tree-ish %s", av[2]); - shift_tree(&one->object.oid, &two->object.oid, &shifted, -1); + shift_tree(the_repository, &one->object.oid, &two->object.oid, &shifted, -1); printf("shifted: %s\n", oid_to_hex(&shifted)); exit(0); diff --git a/t/helper/test-oidmap.c b/t/helper/test-oidmap.c new file mode 100644 index 0000000000..0acf99931e --- /dev/null +++ b/t/helper/test-oidmap.c @@ -0,0 +1,112 @@ +#include "test-tool.h" +#include "cache.h" +#include "oidmap.h" +#include "strbuf.h" + +/* key is an oid and value is a name (could be a refname for example) */ +struct test_entry { + struct oidmap_entry entry; + char name[FLEX_ARRAY]; +}; + +#define DELIM " \t\r\n" + +/* + * Read stdin line by line and print result of commands to stdout: + * + * hash oidkey -> sha1hash(oidkey) + * put oidkey namevalue -> NULL / old namevalue + * get oidkey -> NULL / namevalue + * remove oidkey -> NULL / old namevalue + * iterate -> oidkey1 namevalue1\noidkey2 namevalue2\n... + * + */ +int cmd__oidmap(int argc, const char **argv) +{ + struct strbuf line = STRBUF_INIT; + struct oidmap map = OIDMAP_INIT; + + setup_git_directory(); + + /* init oidmap */ + oidmap_init(&map, 0); + + /* process commands from stdin */ + while (strbuf_getline(&line, stdin) != EOF) { + char *cmd, *p1 = NULL, *p2 = NULL; + struct test_entry *entry; + struct object_id oid; + + /* break line into command and up to two parameters */ + cmd = strtok(line.buf, DELIM); + /* ignore empty lines */ + if (!cmd || *cmd == '#') + continue; + + p1 = strtok(NULL, DELIM); + if (p1) + p2 = strtok(NULL, DELIM); + + if (!strcmp("put", cmd) && p1 && p2) { + + if (get_oid(p1, &oid)) { + printf("Unknown oid: %s\n", p1); + continue; + } + + /* create entry with oid_key = p1, name_value = p2 */ + FLEX_ALLOC_STR(entry, name, p2); + oidcpy(&entry->entry.oid, &oid); + + /* add / replace entry */ + entry = oidmap_put(&map, entry); + + /* print and free replaced entry, if any */ + puts(entry ? entry->name : "NULL"); + free(entry); + + } else if (!strcmp("get", cmd) && p1) { + + if (get_oid(p1, &oid)) { + printf("Unknown oid: %s\n", p1); + continue; + } + + /* lookup entry in oidmap */ + entry = oidmap_get(&map, &oid); + + /* print result */ + puts(entry ? entry->name : "NULL"); + + } else if (!strcmp("remove", cmd) && p1) { + + if (get_oid(p1, &oid)) { + printf("Unknown oid: %s\n", p1); + continue; + } + + /* remove entry from oidmap */ + entry = oidmap_remove(&map, &oid); + + /* print result and free entry*/ + puts(entry ? entry->name : "NULL"); + free(entry); + + } else if (!strcmp("iterate", cmd)) { + + struct oidmap_iter iter; + oidmap_iter_init(&map, &iter); + while ((entry = oidmap_iter_next(&iter))) + printf("%s %s\n", oid_to_hex(&entry->entry.oid), entry->name); + + } else { + + printf("Unknown command %s\n", cmd); + + } + } + + strbuf_release(&line); + oidmap_free(&map, 1); + return 0; +} diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c index 087a8c0cc9..ce7e89028c 100644 --- a/t/helper/test-tool.c +++ b/t/helper/test-tool.c @@ -19,6 +19,7 @@ static struct test_cmd cmds[] = { { "ctype", cmd__ctype }, { "date", cmd__date }, { "delta", cmd__delta }, + { "dir-iterator", cmd__dir_iterator }, { "drop-caches", cmd__drop_caches }, { "dump-cache-tree", cmd__dump_cache_tree }, { "dump-fsmonitor", cmd__dump_fsmonitor }, @@ -35,6 +36,7 @@ static struct test_cmd cmds[] = { { "match-trees", cmd__match_trees }, { "mergesort", cmd__mergesort }, { "mktemp", cmd__mktemp }, + { "oidmap", cmd__oidmap }, { "online-cpus", cmd__online_cpus }, { "parse-options", cmd__parse_options }, { "path-utils", cmd__path_utils }, diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h index 7e703f3038..f805bb39ae 100644 --- a/t/helper/test-tool.h +++ b/t/helper/test-tool.h @@ -9,6 +9,7 @@ int cmd__config(int argc, const char **argv); int cmd__ctype(int argc, const char **argv); int cmd__date(int argc, const char **argv); int cmd__delta(int argc, const char **argv); +int cmd__dir_iterator(int argc, const char **argv); int cmd__drop_caches(int argc, const char **argv); int cmd__dump_cache_tree(int argc, const char **argv); int cmd__dump_fsmonitor(int argc, const char **argv); @@ -25,6 +26,7 @@ int cmd__lazy_init_name_hash(int argc, const char **argv); int cmd__match_trees(int argc, const char **argv); int cmd__mergesort(int argc, const char **argv); int cmd__mktemp(int argc, const char **argv); +int cmd__oidmap(int argc, const char **argv); int cmd__online_cpus(int argc, const char **argv); int cmd__parse_options(int argc, const char **argv); int cmd__path_utils(int argc, const char **argv); diff --git a/t/lib-git-daemon.sh b/t/lib-git-daemon.sh index 7b3407134e..fb8f887080 100644 --- a/t/lib-git-daemon.sh +++ b/t/lib-git-daemon.sh @@ -15,8 +15,7 @@ # # test_done -test_tristate GIT_TEST_GIT_DAEMON -if test "$GIT_TEST_GIT_DAEMON" = false +if ! git env--helper --type=bool --default=true --exit-code GIT_TEST_GIT_DAEMON then skip_all="git-daemon testing disabled (unset GIT_TEST_GIT_DAEMON to enable)" test_done @@ -24,7 +23,7 @@ fi if test_have_prereq !PIPE then - test_skip_or_die $GIT_TEST_GIT_DAEMON "file system does not support FIFOs" + test_skip_or_die GIT_TEST_GIT_DAEMON "file system does not support FIFOs" fi test_set_port LIB_GIT_DAEMON_PORT @@ -73,7 +72,7 @@ start_git_daemon() { kill "$GIT_DAEMON_PID" wait "$GIT_DAEMON_PID" unset GIT_DAEMON_PID - test_skip_or_die $GIT_TEST_GIT_DAEMON \ + test_skip_or_die GIT_TEST_GIT_DAEMON \ "git daemon failed to start" fi } diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh index c1271d6863..5d4ae629e1 100644 --- a/t/lib-git-svn.sh +++ b/t/lib-git-svn.sh @@ -69,14 +69,12 @@ svn_cmd () { maybe_start_httpd () { loc=${1-svn} - test_tristate GIT_SVN_TEST_HTTPD - case $GIT_SVN_TEST_HTTPD in - true) + if git env--helper --type=bool --default=false --exit-code GIT_TEST_HTTPD + then . "$TEST_DIRECTORY"/lib-httpd.sh LIB_HTTPD_SVN="$loc" start_httpd - ;; - esac + fi } convert_to_rev_db () { @@ -106,8 +104,7 @@ EOF } require_svnserve () { - test_tristate GIT_TEST_SVNSERVE - if ! test "$GIT_TEST_SVNSERVE" = true + if ! git env--helper --type=bool --default=false --exit-code GIT_TEST_SVNSERVE then skip_all='skipping svnserve test. (set $GIT_TEST_SVNSERVE to enable)' test_done diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh index b3cc62bd36..0d985758c6 100644 --- a/t/lib-httpd.sh +++ b/t/lib-httpd.sh @@ -41,15 +41,14 @@ then test_done fi -test_tristate GIT_TEST_HTTPD -if test "$GIT_TEST_HTTPD" = false +if ! git env--helper --type=bool --default=true --exit-code GIT_TEST_HTTPD then skip_all="Network testing disabled (unset GIT_TEST_HTTPD to enable)" test_done fi if ! test_have_prereq NOT_ROOT; then - test_skip_or_die $GIT_TEST_HTTPD \ + test_skip_or_die GIT_TEST_HTTPD \ "Cannot run httpd tests as root" fi @@ -95,7 +94,7 @@ GIT_TRACE=$GIT_TRACE; export GIT_TRACE if ! test -x "$LIB_HTTPD_PATH" then - test_skip_or_die $GIT_TEST_HTTPD "no web server found at '$LIB_HTTPD_PATH'" + test_skip_or_die GIT_TEST_HTTPD "no web server found at '$LIB_HTTPD_PATH'" fi HTTPD_VERSION=$($LIB_HTTPD_PATH -v | \ @@ -107,19 +106,19 @@ then then if ! test $HTTPD_VERSION -ge 2 then - test_skip_or_die $GIT_TEST_HTTPD \ + test_skip_or_die GIT_TEST_HTTPD \ "at least Apache version 2 is required" fi if ! test -d "$DEFAULT_HTTPD_MODULE_PATH" then - test_skip_or_die $GIT_TEST_HTTPD \ + test_skip_or_die GIT_TEST_HTTPD \ "Apache module directory not found" fi LIB_HTTPD_MODULE_PATH="$DEFAULT_HTTPD_MODULE_PATH" fi else - test_skip_or_die $GIT_TEST_HTTPD \ + test_skip_or_die GIT_TEST_HTTPD \ "Could not identify web server at '$LIB_HTTPD_PATH'" fi @@ -184,7 +183,7 @@ start_httpd() { if test $? -ne 0 then cat "$HTTPD_ROOT_PATH"/error.log >&4 2>/dev/null - test_skip_or_die $GIT_TEST_HTTPD "web server setup failed" + test_skip_or_die GIT_TEST_HTTPD "web server setup failed" fi } diff --git a/t/perf/p5600-clone-reference.sh b/t/perf/p5600-clone-reference.sh new file mode 100755 index 0000000000..68fed66347 --- /dev/null +++ b/t/perf/p5600-clone-reference.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +test_description='speed of clone --reference' +. ./perf-lib.sh + +test_perf_default_repo + +test_expect_success 'create shareable repository' ' + git clone --bare . shared.git +' + +test_expect_success 'advance base repository' ' + # Do not use test_commit here; its test_tick will + # use some ancient hard-coded date. The resulting clock + # skew will cause pack-objects to traverse in a very + # sub-optimal order, skewing the results. + echo content >new-file-that-does-not-exist && + git add new-file-that-does-not-exist && + git commit -m "new commit" +' + +test_perf 'clone --reference' ' + rm -rf dst.git && + git clone --no-local --bare --reference shared.git . dst.git +' + +test_done diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 31de7e90f3..e89438e619 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -726,7 +726,7 @@ donthaveit=yes test_expect_success DONTHAVEIT 'unmet prerequisite causes test to be skipped' ' donthaveit=no ' -if test -z "$GIT_TEST_FAIL_PREREQS" -a $haveit$donthaveit != yesyes +if test -z "$GIT_TEST_FAIL_PREREQS_INTERNAL" -a $haveit$donthaveit != yesyes then say "bug in test framework: prerequisite tags do not work reliably" exit 1 @@ -747,7 +747,7 @@ donthaveiteither=yes test_expect_success DONTHAVEIT,HAVEIT 'unmet prerequisites causes test to be skipped' ' donthaveiteither=no ' -if test -z "$GIT_TEST_FAIL_PREREQS" -a $haveit$donthaveit$donthaveiteither != yesyesyes +if test -z "$GIT_TEST_FAIL_PREREQS_INTERNAL" -a $haveit$donthaveit$donthaveiteither != yesyesyes then say "bug in test framework: multiple prerequisite tags do not work reliably" exit 1 @@ -763,7 +763,7 @@ test_expect_success !LAZY_TRUE 'missing lazy prereqs skip tests' ' donthavetrue=no ' -if test -z "$GIT_TEST_FAIL_PREREQS" -a "$havetrue$donthavetrue" != yesyes +if test -z "$GIT_TEST_FAIL_PREREQS_INTERNAL" -a "$havetrue$donthavetrue" != yesyes then say 'bug in test framework: lazy prerequisites do not work' exit 1 @@ -779,7 +779,7 @@ test_expect_success LAZY_FALSE 'missing negative lazy prereqs will skip' ' havefalse=no ' -if test -z "$GIT_TEST_FAIL_PREREQS" -a "$nothavefalse$havefalse" != yesyes +if test -z "$GIT_TEST_FAIL_PREREQS_INTERNAL" -a "$nothavefalse$havefalse" != yesyes then say 'bug in test framework: negative lazy prerequisites do not work' exit 1 @@ -790,7 +790,7 @@ test_expect_success 'tests clean up after themselves' ' test_when_finished clean=yes ' -if test -z "$GIT_TEST_FAIL_PREREQS" -a $clean != yes +if test -z "$GIT_TEST_FAIL_PREREQS_INTERNAL" -a $clean != yes then say "bug in test framework: basic cleanup command does not work reliably" exit 1 diff --git a/t/t0011-hashmap.sh b/t/t0011-hashmap.sh index 3f1f505e89..5343ffd3f9 100755 --- a/t/t0011-hashmap.sh +++ b/t/t0011-hashmap.sh @@ -9,15 +9,6 @@ test_hashmap() { test_cmp expect actual } -test_expect_success 'hash functions' ' - -test_hashmap "hash key1" "2215982743 2215982743 116372151 116372151" && -test_hashmap "hash key2" "2215982740 2215982740 116372148 116372148" && -test_hashmap "hash fooBarFrotz" "1383912807 1383912807 3189766727 3189766727" && -test_hashmap "hash foobarfrotz" "2862305959 2862305959 3189766727 3189766727" - -' - test_expect_success 'put' ' test_hashmap "put key1 value1 @@ -179,31 +170,45 @@ NULL ' test_expect_success 'iterate' ' - -test_hashmap "put key1 value1 -put key2 value2 -put fooBarFrotz value3 -iterate" "NULL -NULL -NULL -key2 value2 -key1 value1 -fooBarFrotz value3" - + test-tool hashmap >actual.raw <<-\EOF && + put key1 value1 + put key2 value2 + put fooBarFrotz value3 + iterate + EOF + + cat >expect <<-\EOF && + NULL + NULL + NULL + fooBarFrotz value3 + key1 value1 + key2 value2 + EOF + + sort <actual.raw >actual && + test_cmp expect actual ' test_expect_success 'iterate (case insensitive)' ' - -test_hashmap "put key1 value1 -put key2 value2 -put fooBarFrotz value3 -iterate" "NULL -NULL -NULL -fooBarFrotz value3 -key2 value2 -key1 value1" ignorecase - + test-tool hashmap ignorecase >actual.raw <<-\EOF && + put key1 value1 + put key2 value2 + put fooBarFrotz value3 + iterate + EOF + + cat >expect <<-\EOF && + NULL + NULL + NULL + fooBarFrotz value3 + key1 value1 + key2 value2 + EOF + + sort <actual.raw >actual && + test_cmp expect actual ' test_expect_success 'grow / shrink' ' diff --git a/t/t0016-oidmap.sh b/t/t0016-oidmap.sh new file mode 100755 index 0000000000..31f8276ba8 --- /dev/null +++ b/t/t0016-oidmap.sh @@ -0,0 +1,110 @@ +#!/bin/sh + +test_description='test oidmap' +. ./test-lib.sh + +# This purposefully is very similar to t0011-hashmap.sh + +test_oidmap () { + echo "$1" | test-tool oidmap $3 >actual && + echo "$2" >expect && + test_cmp expect actual +} + + +test_expect_success 'setup' ' + + test_commit one && + test_commit two && + test_commit three && + test_commit four + +' + +test_expect_success 'put' ' + +test_oidmap "put one 1 +put two 2 +put invalidOid 4 +put three 3" "NULL +NULL +Unknown oid: invalidOid +NULL" + +' + +test_expect_success 'replace' ' + +test_oidmap "put one 1 +put two 2 +put three 3 +put invalidOid 4 +put two deux +put one un" "NULL +NULL +NULL +Unknown oid: invalidOid +2 +1" + +' + +test_expect_success 'get' ' + +test_oidmap "put one 1 +put two 2 +put three 3 +get two +get four +get invalidOid +get one" "NULL +NULL +NULL +2 +NULL +Unknown oid: invalidOid +1" + +' + +test_expect_success 'remove' ' + +test_oidmap "put one 1 +put two 2 +put three 3 +remove one +remove two +remove invalidOid +remove four" "NULL +NULL +NULL +1 +2 +Unknown oid: invalidOid +NULL" + +' + +test_expect_success 'iterate' ' + test-tool oidmap >actual.raw <<-\EOF && + put one 1 + put two 2 + put three 3 + iterate + EOF + + # sort "expect" too so we do not rely on the order of particular oids + sort >expect <<-EOF && + NULL + NULL + NULL + $(git rev-parse one) 1 + $(git rev-parse two) 2 + $(git rev-parse three) 3 + EOF + + sort <actual.raw >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t0017-env-helper.sh b/t/t0017-env-helper.sh new file mode 100755 index 0000000000..c1ecf6aeac --- /dev/null +++ b/t/t0017-env-helper.sh @@ -0,0 +1,99 @@ +#!/bin/sh + +test_description='test env--helper' + +. ./test-lib.sh + + +test_expect_success 'env--helper usage' ' + test_must_fail git env--helper && + test_must_fail git env--helper --type=bool && + test_must_fail git env--helper --type=ulong && + test_must_fail git env--helper --type=bool && + test_must_fail git env--helper --type=bool --default && + test_must_fail git env--helper --type=bool --default= && + test_must_fail git env--helper --defaultxyz +' + +test_expect_success 'env--helper bad default values' ' + test_must_fail git env--helper --type=bool --default=1xyz MISSING && + test_must_fail git env--helper --type=ulong --default=1xyz MISSING +' + +test_expect_success 'env--helper --type=bool' ' + # Test various --default bool values + echo true >expected && + git env--helper --type=bool --default=1 MISSING >actual && + test_cmp expected actual && + git env--helper --type=bool --default=yes MISSING >actual && + test_cmp expected actual && + git env--helper --type=bool --default=true MISSING >actual && + test_cmp expected actual && + echo false >expected && + test_must_fail git env--helper --type=bool --default=0 MISSING >actual && + test_cmp expected actual && + test_must_fail git env--helper --type=bool --default=no MISSING >actual && + test_cmp expected actual && + test_must_fail git env--helper --type=bool --default=false MISSING >actual && + test_cmp expected actual && + + # No output with --exit-code + git env--helper --type=bool --default=true --exit-code MISSING >actual.out 2>actual.err && + test_must_be_empty actual.out && + test_must_be_empty actual.err && + test_must_fail git env--helper --type=bool --default=false --exit-code MISSING >actual.out 2>actual.err && + test_must_be_empty actual.out && + test_must_be_empty actual.err && + + # Existing variable + EXISTS=true git env--helper --type=bool --default=false --exit-code EXISTS >actual.out 2>actual.err && + test_must_be_empty actual.out && + test_must_be_empty actual.err && + test_must_fail \ + env EXISTS=false \ + git env--helper --type=bool --default=true --exit-code EXISTS >actual.out 2>actual.err && + test_must_be_empty actual.out && + test_must_be_empty actual.err +' + +test_expect_success 'env--helper --type=ulong' ' + echo 1234567890 >expected && + git env--helper --type=ulong --default=1234567890 MISSING >actual.out 2>actual.err && + test_cmp expected actual.out && + test_must_be_empty actual.err && + + echo 0 >expected && + test_must_fail git env--helper --type=ulong --default=0 MISSING >actual && + test_cmp expected actual && + + git env--helper --type=ulong --default=1234567890 --exit-code MISSING >actual.out 2>actual.err && + test_must_be_empty actual.out && + test_must_be_empty actual.err && + + EXISTS=1234567890 git env--helper --type=ulong --default=0 EXISTS --exit-code >actual.out 2>actual.err && + test_must_be_empty actual.out && + test_must_be_empty actual.err && + + echo 1234567890 >expected && + EXISTS=1234567890 git env--helper --type=ulong --default=0 EXISTS >actual.out 2>actual.err && + test_cmp expected actual.out && + test_must_be_empty actual.err +' + +test_expect_success 'env--helper reads config thanks to trace2' ' + mkdir home && + git config -f home/.gitconfig include.path cycle && + git config -f home/cycle include.path .gitconfig && + + test_must_fail \ + env HOME="$(pwd)/home" GIT_TEST_GETTEXT_POISON=false \ + git config -l 2>err && + grep "exceeded maximum include depth" err && + + test_must_fail \ + env HOME="$(pwd)/home" GIT_TEST_GETTEXT_POISON=true \ + git -C cycle env--helper --type=bool --default=0 --exit-code GIT_TEST_GETTEXT_POISON 2>err && + grep "# GETTEXT POISON #" err +' + +test_done diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh index 3587e454f1..959b6da449 100755 --- a/t/t0027-auto-crlf.sh +++ b/t/t0027-auto-crlf.sh @@ -15,8 +15,10 @@ compare_ws_file () { pfx=$1 exp=$2.expect act=$pfx.actual.$3 - tr '\015\000abcdef0123456789' QN00000000000000000 <"$2" >"$exp" && - tr '\015\000abcdef0123456789' QN00000000000000000 <"$3" >"$act" && + tr '\015\000abcdef0123456789' QN00000000000000000 <"$2" | + sed -e "s/0000*/$ZERO_OID/" >"$exp" && + tr '\015\000abcdef0123456789' QN00000000000000000 <"$3" | + sed -e "s/0000*/$ZERO_OID/" >"$act" && test_cmp "$exp" "$act" && rm "$exp" "$act" } diff --git a/t/t0061-run-command.sh b/t/t0061-run-command.sh index ebc49561ac..015fac8b5d 100755 --- a/t/t0061-run-command.sh +++ b/t/t0061-run-command.sh @@ -210,4 +210,10 @@ test_expect_success MINGW 'verify curlies are quoted properly' ' test_cmp expect actual ' +test_expect_success MINGW 'can spawn with argv[0] containing spaces' ' + cp "$GIT_BUILD_DIR/t/helper/test-fake-ssh$X" ./ && + test_must_fail "$PWD/test-fake-ssh$X" 2>err && + grep TRASH_DIRECTORY err +' + test_done diff --git a/t/t0066-dir-iterator.sh b/t/t0066-dir-iterator.sh new file mode 100755 index 0000000000..92910e4e6c --- /dev/null +++ b/t/t0066-dir-iterator.sh @@ -0,0 +1,148 @@ +#!/bin/sh + +test_description='Test the dir-iterator functionality' + +. ./test-lib.sh + +test_expect_success 'setup' ' + mkdir -p dir && + mkdir -p dir/a/b/c/ && + >dir/b && + >dir/c && + mkdir -p dir/d/e/d/ && + >dir/a/b/c/d && + >dir/a/e && + >dir/d/e/d/a && + + mkdir -p dir2/a/b/c/ && + >dir2/a/b/c/d +' + +test_expect_success 'dir-iterator should iterate through all files' ' + cat >expected-iteration-sorted-output <<-EOF && + [d] (a) [a] ./dir/a + [d] (a/b) [b] ./dir/a/b + [d] (a/b/c) [c] ./dir/a/b/c + [d] (d) [d] ./dir/d + [d] (d/e) [e] ./dir/d/e + [d] (d/e/d) [d] ./dir/d/e/d + [f] (a/b/c/d) [d] ./dir/a/b/c/d + [f] (a/e) [e] ./dir/a/e + [f] (b) [b] ./dir/b + [f] (c) [c] ./dir/c + [f] (d/e/d/a) [a] ./dir/d/e/d/a + EOF + + test-tool dir-iterator ./dir >out && + sort out >./actual-iteration-sorted-output && + + test_cmp expected-iteration-sorted-output actual-iteration-sorted-output +' + +test_expect_success 'dir-iterator should list files in the correct order' ' + cat >expected-pre-order-output <<-EOF && + [d] (a) [a] ./dir2/a + [d] (a/b) [b] ./dir2/a/b + [d] (a/b/c) [c] ./dir2/a/b/c + [f] (a/b/c/d) [d] ./dir2/a/b/c/d + EOF + + test-tool dir-iterator ./dir2 >actual-pre-order-output && + + test_cmp expected-pre-order-output actual-pre-order-output +' + +test_expect_success 'begin should fail upon inexistent paths' ' + test_must_fail test-tool dir-iterator ./inexistent-path \ + >actual-inexistent-path-output && + echo "dir_iterator_begin failure: ENOENT" >expected-inexistent-path-output && + test_cmp expected-inexistent-path-output actual-inexistent-path-output +' + +test_expect_success 'begin should fail upon non directory paths' ' + test_must_fail test-tool dir-iterator ./dir/b >actual-non-dir-output && + echo "dir_iterator_begin failure: ENOTDIR" >expected-non-dir-output && + test_cmp expected-non-dir-output actual-non-dir-output +' + +test_expect_success POSIXPERM,SANITY 'advance should not fail on errors by default' ' + cat >expected-no-permissions-output <<-EOF && + [d] (a) [a] ./dir3/a + EOF + + mkdir -p dir3/a && + >dir3/a/b && + chmod 0 dir3/a && + + test-tool dir-iterator ./dir3 >actual-no-permissions-output && + test_cmp expected-no-permissions-output actual-no-permissions-output && + chmod 755 dir3/a && + rm -rf dir3 +' + +test_expect_success POSIXPERM,SANITY 'advance should fail on errors, w/ pedantic flag' ' + cat >expected-no-permissions-pedantic-output <<-EOF && + [d] (a) [a] ./dir3/a + dir_iterator_advance failure + EOF + + mkdir -p dir3/a && + >dir3/a/b && + chmod 0 dir3/a && + + test_must_fail test-tool dir-iterator --pedantic ./dir3 \ + >actual-no-permissions-pedantic-output && + test_cmp expected-no-permissions-pedantic-output \ + actual-no-permissions-pedantic-output && + chmod 755 dir3/a && + rm -rf dir3 +' + +test_expect_success SYMLINKS 'setup dirs with symlinks' ' + mkdir -p dir4/a && + mkdir -p dir4/b/c && + >dir4/a/d && + ln -s d dir4/a/e && + ln -s ../b dir4/a/f && + + mkdir -p dir5/a/b && + mkdir -p dir5/a/c && + ln -s ../c dir5/a/b/d && + ln -s ../ dir5/a/b/e && + ln -s ../../ dir5/a/b/f +' + +test_expect_success SYMLINKS 'dir-iterator should not follow symlinks by default' ' + cat >expected-no-follow-sorted-output <<-EOF && + [d] (a) [a] ./dir4/a + [d] (b) [b] ./dir4/b + [d] (b/c) [c] ./dir4/b/c + [f] (a/d) [d] ./dir4/a/d + [s] (a/e) [e] ./dir4/a/e + [s] (a/f) [f] ./dir4/a/f + EOF + + test-tool dir-iterator ./dir4 >out && + sort out >actual-no-follow-sorted-output && + + test_cmp expected-no-follow-sorted-output actual-no-follow-sorted-output +' + +test_expect_success SYMLINKS 'dir-iterator should follow symlinks w/ follow flag' ' + cat >expected-follow-sorted-output <<-EOF && + [d] (a) [a] ./dir4/a + [d] (a/f) [f] ./dir4/a/f + [d] (a/f/c) [c] ./dir4/a/f/c + [d] (b) [b] ./dir4/b + [d] (b/c) [c] ./dir4/b/c + [f] (a/d) [d] ./dir4/a/d + [f] (a/e) [e] ./dir4/a/e + EOF + + test-tool dir-iterator --follow-symlinks ./dir4 >out && + sort out >actual-follow-sorted-output && + + test_cmp expected-follow-sorted-output actual-follow-sorted-output +' + +test_done diff --git a/t/t0090-cache-tree.sh b/t/t0090-cache-tree.sh index 504334e552..ce9a4a5f32 100755 --- a/t/t0090-cache-tree.sh +++ b/t/t0090-cache-tree.sh @@ -162,8 +162,8 @@ test_expect_success PERL 'commit --interactive gives cache-tree on partial commi ' test_expect_success PERL 'commit -p with shrinking cache-tree' ' - mkdir -p deep/subdir && - echo content >deep/subdir/file && + mkdir -p deep/very-long-subdir && + echo content >deep/very-long-subdir/file && git add deep && git commit -m add && git rm -r deep && diff --git a/t/t0205-gettext-poison.sh b/t/t0205-gettext-poison.sh index a06269f38a..f9fa16ad83 100755 --- a/t/t0205-gettext-poison.sh +++ b/t/t0205-gettext-poison.sh @@ -5,7 +5,7 @@ test_description='Gettext Shell poison' -GIT_TEST_GETTEXT_POISON=YesPlease +GIT_TEST_GETTEXT_POISON=true export GIT_TEST_GETTEXT_POISON . ./lib-gettext.sh @@ -31,4 +31,9 @@ test_expect_success 'eval_gettext: our eval_gettext() fallback has poison semant test_cmp expect actual ' +test_expect_success "gettext: invalid GIT_TEST_GETTEXT_POISON value doesn't infinitely loop" " + test_must_fail env GIT_TEST_GETTEXT_POISON=xyz git version 2>error && + grep \"fatal: bad numeric config value 'xyz' for 'GIT_TEST_GETTEXT_POISON': invalid unit\" error +" + test_done diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh index 7099d33508..64b340f227 100755 --- a/t/t1007-hash-object.sh +++ b/t/t1007-hash-object.sh @@ -9,22 +9,19 @@ echo_without_newline() { } test_blob_does_not_exist() { - test_expect_success SHA1 'blob does not exist in database' " + test_expect_success 'blob does not exist in database' " test_must_fail git cat-file blob $1 " } test_blob_exists() { - test_expect_success SHA1 'blob exists in database' " + test_expect_success 'blob exists in database' " git cat-file blob $1 " } hello_content="Hello World" -hello_sha1=5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689 - example_content="This is an example" -example_sha1=ddd3f836d3e3fbb7ae289aa9ae83536f76956399 setup_repo() { echo_without_newline "$hello_content" > hello @@ -44,7 +41,16 @@ pop_repo() { rm -rf $test_repo } -setup_repo +test_expect_success 'setup' ' + setup_repo && + test_oid_cache <<-EOF + hello sha1:5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689 + hello sha256:1e3b6c04d2eeb2b3e45c8a330445404c0b7cc7b257e2b097167d26f5230090c4 + + example sha1:ddd3f836d3e3fbb7ae289aa9ae83536f76956399 + example sha256:b44fe1fe65589848253737db859bd490453510719d7424daab03daf0767b85ae + EOF +' # Argument checking @@ -73,23 +79,23 @@ test_expect_success "Can't use --path with --no-filters" ' push_repo -test_expect_success SHA1 'hash a file' ' - test $hello_sha1 = $(git hash-object hello) +test_expect_success 'hash a file' ' + test "$(test_oid hello)" = $(git hash-object hello) ' -test_blob_does_not_exist $hello_sha1 +test_blob_does_not_exist "$(test_oid hello)" -test_expect_success SHA1 'hash from stdin' ' - test $example_sha1 = $(git hash-object --stdin < example) +test_expect_success 'hash from stdin' ' + test "$(test_oid example)" = $(git hash-object --stdin < example) ' -test_blob_does_not_exist $example_sha1 +test_blob_does_not_exist "$(test_oid example)" -test_expect_success SHA1 'hash a file and write to database' ' - test $hello_sha1 = $(git hash-object -w hello) +test_expect_success 'hash a file and write to database' ' + test "$(test_oid hello)" = $(git hash-object -w hello) ' -test_blob_exists $hello_sha1 +test_blob_exists "$(test_oid hello)" test_expect_success 'git hash-object --stdin file1 <file0 first operates on file0, then file1' ' echo foo > file1 && @@ -161,11 +167,11 @@ pop_repo for args in "-w --stdin" "--stdin -w"; do push_repo - test_expect_success SHA1 "hash from stdin and write to database ($args)" ' - test $example_sha1 = $(git hash-object $args < example) + test_expect_success "hash from stdin and write to database ($args)" ' + test "$(test_oid example)" = $(git hash-object $args < example) ' - test_blob_exists $example_sha1 + test_blob_exists "$(test_oid example)" pop_repo done @@ -173,22 +179,22 @@ done filenames="hello example" -sha1s="$hello_sha1 -$example_sha1" +oids="$(test_oid hello) +$(test_oid example)" -test_expect_success SHA1 "hash two files with names on stdin" ' - test "$sha1s" = "$(echo_without_newline "$filenames" | git hash-object --stdin-paths)" +test_expect_success "hash two files with names on stdin" ' + test "$oids" = "$(echo_without_newline "$filenames" | git hash-object --stdin-paths)" ' for args in "-w --stdin-paths" "--stdin-paths -w"; do push_repo - test_expect_success SHA1 "hash two files with names on stdin and write to database ($args)" ' - test "$sha1s" = "$(echo_without_newline "$filenames" | git hash-object $args)" + test_expect_success "hash two files with names on stdin and write to database ($args)" ' + test "$oids" = "$(echo_without_newline "$filenames" | git hash-object $args)" ' - test_blob_exists $hello_sha1 - test_blob_exists $example_sha1 + test_blob_exists "$(test_oid hello)" + test_blob_exists "$(test_oid example)" pop_repo done diff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh index 9571e366f8..d20b4d150d 100755 --- a/t/t1305-config-include.sh +++ b/t/t1305-config-include.sh @@ -349,20 +349,13 @@ test_expect_success 'conditional include, onbranch, implicit /** for /' ' ' test_expect_success 'include cycles are detected' ' - cat >.gitconfig <<-\EOF && - [test]value = gitconfig - [include]path = cycle - EOF - cat >cycle <<-\EOF && - [test]value = cycle - [include]path = .gitconfig - EOF - cat >expect <<-\EOF && - gitconfig - cycle - EOF - test_must_fail git config --get-all test.value 2>stderr && - test_i18ngrep "exceeded maximum include depth" stderr + git init --bare cycle && + git -C cycle config include.path cycle && + git config -f cycle/cycle include.path config && + test_must_fail \ + env GIT_TEST_GETTEXT_POISON=false \ + git -C cycle config --get-all test.value 2>stderr && + grep "exceeded maximum include depth" stderr ' test_done diff --git a/t/t1309-early-config.sh b/t/t1309-early-config.sh index 413642aa56..0c37e7180d 100755 --- a/t/t1309-early-config.sh +++ b/t/t1309-early-config.sh @@ -89,4 +89,9 @@ test_expect_failure 'ignore .git/ with invalid config' ' test_with_config "[" ' +test_expect_success 'early config and onbranch' ' + echo "[broken" >broken && + test_with_config "[includeif \"onbranch:refs/heads/master\"]path=../broken" +' + test_done diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh index 79f731db37..82950c0282 100755 --- a/t/t1410-reflog.sh +++ b/t/t1410-reflog.sh @@ -30,14 +30,13 @@ check_fsck () { } corrupt () { - aa=${1%??????????????????????????????????????} zz=${1#??} - mv .git/objects/$aa/$zz .git/$aa$zz + mv .git/objects/$(test_oid_to_path $1) .git/$1 } recover () { - aa=${1%??????????????????????????????????????} zz=${1#??} + aa=$(echo $1 | cut -c 1-2) mkdir -p .git/objects/$aa - mv .git/$aa$zz .git/objects/$aa/$zz + mv .git/$1 .git/objects/$(test_oid_to_path $1) } check_dont_have () { @@ -55,6 +54,7 @@ check_dont_have () { } test_expect_success setup ' + test_oid_init && mkdir -p A/B && echo rat >C && echo ox >A/D && @@ -313,12 +313,12 @@ test_expect_success 'stale dirs do not cause d/f conflicts (reflogs off)' ' # Each line is 114 characters, so we need 75 to still have a few before the # last 8K. The 89-character padding on the final entry lines up our # newline exactly. -test_expect_success 'parsing reverse reflogs at BUFSIZ boundaries' ' +test_expect_success SHA1 'parsing reverse reflogs at BUFSIZ boundaries' ' git checkout -b reflogskip && - z38=00000000000000000000000000000000000000 && + zf=$(test_oid zero_2) && ident="abc <xyz> 0000000001 +0000" && for i in $(test_seq 1 75); do - printf "$z38%02d $z38%02d %s\t" $i $(($i+1)) "$ident" && + printf "$zf%02d $zf%02d %s\t" $i $(($i+1)) "$ident" && if test $i = 75; then for j in $(test_seq 1 89); do printf X @@ -329,7 +329,7 @@ test_expect_success 'parsing reverse reflogs at BUFSIZ boundaries' ' printf "\n" done >.git/logs/refs/heads/reflogskip && git rev-parse reflogskip@{73} >actual && - echo ${z38}03 >expect && + echo ${zf}03 >expect && test_cmp expect actual ' diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh index 0f268a3664..b36e0528d0 100755 --- a/t/t1450-fsck.sh +++ b/t/t1450-fsck.sh @@ -9,6 +9,7 @@ test_description='git fsck random collection of tests . ./test-lib.sh test_expect_success setup ' + test_oid_init && git config gc.auto 0 && git config i18n.commitencoding ISO-8859-1 && test_commit A fileA one && @@ -54,8 +55,8 @@ test_expect_success 'setup: helpers for corruption tests' ' test_expect_success 'object with bad sha1' ' sha=$(echo blob | git hash-object -w --stdin) && - old=$(echo $sha | sed "s+^..+&/+") && - new=$(dirname $old)/ffffffffffffffffffffffffffffffffffffff && + old=$(test_oid_to_path "$sha") && + new=$(dirname $old)/$(test_oid ff_2) && sha="$(dirname $new)$(basename $new)" && mv .git/objects/$old .git/objects/$new && test_when_finished "remove_object $sha" && @@ -84,7 +85,7 @@ test_expect_success 'branch pointing to non-commit' ' test_expect_success 'HEAD link pointing at a funny object' ' test_when_finished "mv .git/SAVED_HEAD .git/HEAD" && mv .git/HEAD .git/SAVED_HEAD && - echo 0000000000000000000000000000000000000000 >.git/HEAD && + echo $ZERO_OID >.git/HEAD && # avoid corrupt/broken HEAD from interfering with repo discovery test_must_fail env GIT_DIR=.git git fsck 2>out && cat out && @@ -244,10 +245,16 @@ test_expect_success 'tree object with duplicate entries' ' ' test_expect_success 'unparseable tree object' ' + test_oid_cache <<-\EOF && + junk sha1:twenty-bytes-of-junk + junk sha256:twenty-bytes-of-junk-twelve-more + EOF + test_when_finished "git update-ref -d refs/heads/wrong" && test_when_finished "remove_object \$tree_sha1" && test_when_finished "remove_object \$commit_sha1" && - tree_sha1=$(printf "100644 \0twenty-bytes-of-junk" | git hash-object -t tree --stdin -w --literally) && + junk=$(test_oid junk) && + tree_sha1=$(printf "100644 \0$junk" | git hash-object -t tree --stdin -w --literally) && commit_sha1=$(git commit-tree $tree_sha1) && git update-ref refs/heads/wrong $commit_sha1 && test_must_fail git fsck 2>out && @@ -275,8 +282,9 @@ test_expect_success 'tree entry with type mismatch' ' ' test_expect_success 'tag pointing to nonexistent' ' - cat >invalid-tag <<-\EOF && - object ffffffffffffffffffffffffffffffffffffffff + badoid=$(test_oid deadbeef) && + cat >invalid-tag <<-EOF && + object $badoid type commit tag invalid tagger T A Gger <tagger@example.com> 1234567890 -0000 @@ -386,8 +394,8 @@ test_expect_success 'rev-list --verify-objects' ' test_expect_success 'rev-list --verify-objects with bad sha1' ' sha=$(echo blob | git hash-object -w --stdin) && - old=$(echo $sha | sed "s+^..+&/+") && - new=$(dirname $old)/ffffffffffffffffffffffffffffffffffffff && + old=$(test_oid_to_path $sha) && + new=$(dirname $old)/$(test_oid ff_2) && sha="$(dirname $new)$(basename $new)" && mv .git/objects/$old .git/objects/$new && test_when_finished "remove_object $sha" && @@ -402,7 +410,7 @@ test_expect_success 'rev-list --verify-objects with bad sha1' ' test_might_fail git rev-list --verify-objects refs/heads/bogus >/dev/null 2>out && cat out && - test_i18ngrep -q "error: hash mismatch 63ffffffffffffffffffffffffffffffffffffff" out + test_i18ngrep -q "error: hash mismatch $(dirname $new)$(test_oid ff_2)" out ' test_expect_success 'force fsck to ignore double author' ' @@ -417,13 +425,12 @@ test_expect_success 'force fsck to ignore double author' ' ' _bz='\0' -_bz5="$_bz$_bz$_bz$_bz$_bz" -_bz20="$_bz5$_bz5$_bz5$_bz5" +_bzoid=$(printf $ZERO_OID | sed -e 's/00/\\0/g') test_expect_success 'fsck notices blob entry pointing to null sha1' ' (git init null-blob && cd null-blob && - sha=$(printf "100644 file$_bz$_bz20" | + sha=$(printf "100644 file$_bz$_bzoid" | git hash-object -w --stdin -t tree) && git fsck 2>out && cat out && @@ -434,7 +441,7 @@ test_expect_success 'fsck notices blob entry pointing to null sha1' ' test_expect_success 'fsck notices submodule entry pointing to null sha1' ' (git init null-commit && cd null-commit && - sha=$(printf "160000 submodule$_bz$_bz20" | + sha=$(printf "160000 submodule$_bz$_bzoid" | git hash-object -w --stdin -t tree) && git fsck 2>out && cat out && @@ -586,7 +593,7 @@ test_expect_success 'fsck --connectivity-only' ' # its type. That lets us see that --connectivity-only is # not actually looking at the contents, but leaves it # free to examine the type if it chooses. - empty=.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 && + empty=.git/objects/$(test_oid_to_path $EMPTY_BLOB) && blob=$(echo unrelated | git hash-object -w --stdin) && mv -f $(sha1_file $blob) $empty && @@ -631,10 +638,12 @@ test_expect_success 'fsck --name-objects' ' test_expect_success 'alternate objects are correctly blamed' ' test_when_finished "rm -rf alt.git .git/objects/info/alternates" && + name=$(test_oid numeric) && + path=$(test_oid_to_path "$name") && git init --bare alt.git && echo "../../alt.git/objects" >.git/objects/info/alternates && - mkdir alt.git/objects/12 && - >alt.git/objects/12/34567890123456789012345678901234567890 && + mkdir alt.git/objects/$(dirname $path) && + >alt.git/objects/$(dirname $path)/$(basename $path) && test_must_fail git fsck >out 2>&1 && test_i18ngrep alt.git out ' diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh index 4f2f84f309..12a5568844 100755 --- a/t/t1700-split-index.sh +++ b/t/t1700-split-index.sh @@ -20,6 +20,22 @@ create_non_racy_file () { test-tool chmtime =-5 "$1" } +test_expect_success 'setup' ' + test_oid_cache <<-EOF + own_v3 sha1:8299b0bcd1ac364e5f1d7768efb62fa2da79a339 + own_v3 sha256:38a6d2925e3eceec33ad7b34cbff4e0086caa0daf28f31e51f5bd94b4a7af86b + + base_v3 sha1:39d890139ee5356c7ef572216cebcd27aa41f9df + base_v3 sha256:c9baeadf905112bf6c17aefbd7d02267afd70ded613c30cafed2d40cb506e1ed + + own_v4 sha1:432ef4b63f32193984f339431fd50ca796493569 + own_v4 sha256:6738ac6319c25b694afa7bcc313deb182d1a59b68bf7a47b4296de83478c0420 + + base_v4 sha1:508851a7f0dfa8691e9f69c7f055865389012491 + base_v4 sha256:3177d4adfdd4b6904f7e921d91d715a471c0dde7cf6a4bba574927f02b699508 + EOF +' + test_expect_success 'enable split index' ' git config splitIndex.maxPercentChange 100 && git update-index --split-index && @@ -29,11 +45,11 @@ test_expect_success 'enable split index' ' # NEEDSWORK: Stop hard-coding checksums. if test "$indexversion" = "4" then - own=432ef4b63f32193984f339431fd50ca796493569 - base=508851a7f0dfa8691e9f69c7f055865389012491 + own=$(test_oid own_v4) + base=$(test_oid base_v4) else - own=8299b0bcd1ac364e5f1d7768efb62fa2da79a339 - base=39d890139ee5356c7ef572216cebcd27aa41f9df + own=$(test_oid own_v3) + base=$(test_oid base_v3) fi && cat >expect <<-EOF && @@ -99,17 +115,18 @@ test_expect_success 'enable split index again, "one" now belongs to base index"' test_expect_success 'modify original file, base index untouched' ' echo modified | create_non_racy_file one && + file1_blob=$(git hash-object one) && git update-index one && git ls-files --stage >ls-files.actual && cat >ls-files.expect <<-EOF && - 100644 2e0996000b7e9019eabcad29391bf0f5c7702f0b 0 one + 100644 $file1_blob 0 one EOF test_cmp ls-files.expect ls-files.actual && test-tool dump-split-index .git/index | sed "/^own/d" >actual && q_to_tab >expect <<-EOF && $BASE - 100644 2e0996000b7e9019eabcad29391bf0f5c7702f0b 0Q + 100644 $file1_blob 0Q replacements: 0 deletions: EOF @@ -121,7 +138,7 @@ test_expect_success 'add another file, which stays index' ' git update-index --add two && git ls-files --stage >ls-files.actual && cat >ls-files.expect <<-EOF && - 100644 2e0996000b7e9019eabcad29391bf0f5c7702f0b 0 one + 100644 $file1_blob 0 one 100644 $EMPTY_BLOB 0 two EOF test_cmp ls-files.expect ls-files.actual && @@ -129,7 +146,7 @@ test_expect_success 'add another file, which stays index' ' test-tool dump-split-index .git/index | sed "/^own/d" >actual && q_to_tab >expect <<-EOF && $BASE - 100644 2e0996000b7e9019eabcad29391bf0f5c7702f0b 0Q + 100644 $file1_blob 0Q 100644 $EMPTY_BLOB 0 two replacements: 0 deletions: @@ -141,14 +158,14 @@ test_expect_success 'remove file not in base index' ' git update-index --force-remove two && git ls-files --stage >ls-files.actual && cat >ls-files.expect <<-EOF && - 100644 2e0996000b7e9019eabcad29391bf0f5c7702f0b 0 one + 100644 $file1_blob 0 one EOF test_cmp ls-files.expect ls-files.actual && test-tool dump-split-index .git/index | sed "/^own/d" >actual && q_to_tab >expect <<-EOF && $BASE - 100644 2e0996000b7e9019eabcad29391bf0f5c7702f0b 0Q + 100644 $file1_blob 0Q replacements: 0 deletions: EOF @@ -237,9 +254,9 @@ test_expect_success 'set core.splitIndex config variable to true' ' git update-index --add three && git ls-files --stage >ls-files.actual && cat >ls-files.expect <<-EOF && - 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one - 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 three - 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 two + 100644 $EMPTY_BLOB 0 one + 100644 $EMPTY_BLOB 0 three + 100644 $EMPTY_BLOB 0 two EOF test_cmp ls-files.expect ls-files.actual && BASE=$(test-tool dump-split-index .git/index | grep "^base") && @@ -257,8 +274,8 @@ test_expect_success 'set core.splitIndex config variable to false' ' git update-index --force-remove three && 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 && test-tool dump-split-index .git/index | sed "/^own/d" >actual && @@ -285,7 +302,7 @@ test_expect_success 'set core.splitIndex config variable back to true' ' test-tool dump-split-index .git/index | sed "/^own/d" >actual && cat >expect <<-EOF && $BASE - 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 four + 100644 $EMPTY_BLOB 0 four replacements: deletions: EOF @@ -309,7 +326,7 @@ test_expect_success 'check behavior with splitIndex.maxPercentChange unset' ' test-tool dump-split-index .git/index | sed "/^own/d" >actual && cat >expect <<-EOF && $BASE - 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 six + 100644 $EMPTY_BLOB 0 six replacements: deletions: EOF diff --git a/t/t2203-add-intent.sh b/t/t2203-add-intent.sh index 68e54d5c44..5bbe8dcce4 100755 --- a/t/t2203-add-intent.sh +++ b/t/t2203-add-intent.sh @@ -247,12 +247,14 @@ test_expect_success 'diff-files/diff-cached shows ita as new/not-new files' ' test_expect_success '"diff HEAD" includes ita as new files' ' git reset --hard && echo new >new-ita && + oid=$(git hash-object new-ita) && + oid=$(git rev-parse --short $oid) && git add -N new-ita && git diff HEAD >actual && - cat >expected <<-\EOF && + cat >expected <<-EOF && diff --git a/new-ita b/new-ita new file mode 100644 - index 0000000..3e75765 + index 0000000..$oid --- /dev/null +++ b/new-ita @@ -0,0 +1 @@ diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh index 048feaf6dd..ec548654ce 100755 --- a/t/t3206-range-diff.sh +++ b/t/t3206-range-diff.sh @@ -99,7 +99,7 @@ test_expect_success 'changed commit' ' 1: 4de457d = 1: a4b3333 s/5/A/ 2: fccce22 = 2: f51d370 s/4/A/ 3: 147e64e ! 3: 0559556 s/11/B/ - @@ -10,7 +10,7 @@ + @@ file: A 9 10 -11 @@ -109,8 +109,8 @@ test_expect_success 'changed commit' ' 13 14 4: a63e992 ! 4: d966c5c s/12/B/ - @@ -8,7 +8,7 @@ - @@ + @@ file + @@ file: A 9 10 - B @@ -158,7 +158,7 @@ test_expect_success 'changed commit with sm config' ' 1: 4de457d = 1: a4b3333 s/5/A/ 2: fccce22 = 2: f51d370 s/4/A/ 3: 147e64e ! 3: 0559556 s/11/B/ - @@ -10,7 +10,7 @@ + @@ file: A 9 10 -11 @@ -168,8 +168,8 @@ test_expect_success 'changed commit with sm config' ' 13 14 4: a63e992 ! 4: d966c5c s/12/B/ - @@ -8,7 +8,7 @@ - @@ + @@ file + @@ file: A 9 10 - B @@ -181,6 +181,92 @@ test_expect_success 'changed commit with sm config' ' test_cmp expected actual ' +test_expect_success 'renamed file' ' + git range-diff --no-color --submodule=log topic...renamed-file >actual && + sed s/Z/\ /g >expected <<-EOF && + 1: 4de457d = 1: f258d75 s/5/A/ + 2: fccce22 ! 2: 017b62d s/4/A/ + @@ Metadata + ZAuthor: Thomas Rast <trast@inf.ethz.ch> + Z + Z ## Commit message ## + - s/4/A/ + + s/4/A/ + rename file + Z + - ## file ## + + ## file => renamed-file ## + Z@@ + Z 1 + Z 2 + 3: 147e64e ! 3: 3ce7af6 s/11/B/ + @@ Metadata + Z ## Commit message ## + Z s/11/B/ + Z + - ## file ## + -@@ file: A + + ## renamed-file ## + +@@ renamed-file: A + Z 8 + Z 9 + Z 10 + 4: a63e992 ! 4: 1e6226b s/12/B/ + @@ Metadata + Z ## Commit message ## + Z s/12/B/ + Z + - ## file ## + -@@ file: A + + ## renamed-file ## + +@@ renamed-file: A + Z 9 + Z 10 + Z B + EOF + test_cmp expected actual +' + +test_expect_success 'file added and later removed' ' + git range-diff --no-color --submodule=log topic...added-removed >actual && + sed s/Z/\ /g >expected <<-EOF && + 1: 4de457d = 1: 096b1ba s/5/A/ + 2: fccce22 ! 2: d92e698 s/4/A/ + @@ Metadata + ZAuthor: Thomas Rast <trast@inf.ethz.ch> + Z + Z ## Commit message ## + - s/4/A/ + + s/4/A/ + new-file + Z + Z ## file ## + Z@@ + @@ file + Z A + Z 6 + Z 7 + + + + ## new-file (new) ## + 3: 147e64e ! 3: 9a1db4d s/11/B/ + @@ Metadata + ZAuthor: Thomas Rast <trast@inf.ethz.ch> + Z + Z ## Commit message ## + - s/11/B/ + + s/11/B/ + remove file + Z + Z ## file ## + Z@@ file: A + @@ file: A + Z 12 + Z 13 + Z 14 + + + + ## new-file (deleted) ## + 4: a63e992 = 4: fea3b5c s/12/B/ + EOF + test_cmp expected actual +' + test_expect_success 'no commits on one side' ' git commit --amend -m "new message" && git range-diff master HEAD@{1} HEAD @@ -191,15 +277,15 @@ test_expect_success 'changed message' ' sed s/Z/\ /g >expected <<-EOF && 1: 4de457d = 1: f686024 s/5/A/ 2: fccce22 ! 2: 4ab067d s/4/A/ - @@ -2,6 +2,8 @@ - Z + @@ Metadata + Z ## Commit message ## Z s/4/A/ Z + Also a silly comment here! + - Z diff --git a/file b/file - Z --- a/file - Z +++ b/file + Z ## file ## + Z@@ + Z 1 3: 147e64e = 3: b9cb956 s/11/B/ 4: a63e992 = 4: 8add5f1 s/12/B/ EOF @@ -210,17 +296,17 @@ test_expect_success 'dual-coloring' ' sed -e "s|^:||" >expect <<-\EOF && :<YELLOW>1: a4b3333 = 1: f686024 s/5/A/<RESET> :<RED>2: f51d370 <RESET><YELLOW>!<RESET><GREEN> 2: 4ab067d<RESET><YELLOW> s/4/A/<RESET> - : <REVERSE><CYAN>@@ -2,6 +2,8 @@<RESET> - : <RESET> + : <REVERSE><CYAN>@@<RESET> <RESET>Metadata<RESET> + : ## Commit message ##<RESET> : s/4/A/<RESET> : <RESET> : <REVERSE><GREEN>+<RESET><BOLD> Also a silly comment here!<RESET> : <REVERSE><GREEN>+<RESET> - : diff --git a/file b/file<RESET> - : --- a/file<RESET> - : +++ b/file<RESET> + : ## file ##<RESET> + : <CYAN> @@<RESET> + : 1<RESET> :<RED>3: 0559556 <RESET><YELLOW>!<RESET><GREEN> 3: b9cb956<RESET><YELLOW> s/11/B/<RESET> - : <REVERSE><CYAN>@@ -10,7 +10,7 @@<RESET> + : <REVERSE><CYAN>@@<RESET> <RESET>file: A<RESET> : 9<RESET> : 10<RESET> : <RED> -11<RESET> @@ -230,8 +316,8 @@ test_expect_success 'dual-coloring' ' : 13<RESET> : 14<RESET> :<RED>4: d966c5c <RESET><YELLOW>!<RESET><GREEN> 4: 8add5f1<RESET><YELLOW> s/12/B/<RESET> - : <REVERSE><CYAN>@@ -8,7 +8,7 @@<RESET> - : <CYAN> @@<RESET> + : <REVERSE><CYAN>@@<RESET> <RESET>file<RESET> + : <CYAN> @@ file: A<RESET> : 9<RESET> : 10<RESET> : <REVERSE><RED>-<RESET><FAINT> BB<RESET> diff --git a/t/t3206/history.export b/t/t3206/history.export index b8ffff0940..7bb3814962 100644 --- a/t/t3206/history.export +++ b/t/t3206/history.export @@ -22,8 +22,8 @@ data 51 19 20 -reset refs/heads/removed -commit refs/heads/removed +reset refs/heads/renamed-file +commit refs/heads/renamed-file mark :2 author Thomas Rast <trast@inf.ethz.ch> 1374424921 +0200 committer Thomas Rast <trast@inf.ethz.ch> 1374484724 +0200 @@ -599,6 +599,82 @@ s/12/B/ from :46 M 100644 :28 file -reset refs/heads/removed -from :47 +commit refs/heads/added-removed +mark :48 +author Thomas Rast <trast@inf.ethz.ch> 1374485014 +0200 +committer Thomas Gummerer <t.gummerer@gmail.com> 1556574151 +0100 +data 7 +s/5/A/ +from :2 +M 100644 :3 file + +blob +mark :49 +data 0 + +commit refs/heads/added-removed +mark :50 +author Thomas Rast <trast@inf.ethz.ch> 1374485024 +0200 +committer Thomas Gummerer <t.gummerer@gmail.com> 1556574177 +0100 +data 18 +s/4/A/ + new-file +from :48 +M 100644 :5 file +M 100644 :49 new-file + +commit refs/heads/added-removed +mark :51 +author Thomas Rast <trast@inf.ethz.ch> 1374485036 +0200 +committer Thomas Gummerer <t.gummerer@gmail.com> 1556574177 +0100 +data 22 +s/11/B/ + remove file +from :50 +M 100644 :7 file +D new-file + +commit refs/heads/added-removed +mark :52 +author Thomas Rast <trast@inf.ethz.ch> 1374485044 +0200 +committer Thomas Gummerer <t.gummerer@gmail.com> 1556574177 +0100 +data 8 +s/12/B/ +from :51 +M 100644 :9 file + +commit refs/heads/renamed-file +mark :53 +author Thomas Rast <trast@inf.ethz.ch> 1374485014 +0200 +committer Thomas Gummerer <t.gummerer@gmail.com> 1556574309 +0100 +data 7 +s/5/A/ +from :2 +M 100644 :3 file + +commit refs/heads/renamed-file +mark :54 +author Thomas Rast <trast@inf.ethz.ch> 1374485024 +0200 +committer Thomas Gummerer <t.gummerer@gmail.com> 1556574312 +0100 +data 21 +s/4/A/ + rename file +from :53 +D file +M 100644 :5 renamed-file + +commit refs/heads/renamed-file +mark :55 +author Thomas Rast <trast@inf.ethz.ch> 1374485036 +0200 +committer Thomas Gummerer <t.gummerer@gmail.com> 1556574319 +0100 +data 8 +s/11/B/ +from :54 +M 100644 :7 renamed-file + +commit refs/heads/renamed-file +mark :56 +author Thomas Rast <trast@inf.ethz.ch> 1374485044 +0200 +committer Thomas Gummerer <t.gummerer@gmail.com> 1556574319 +0100 +data 8 +s/12/B/ +from :55 +M 100644 :9 renamed-file diff --git a/t/t3311-notes-merge-fanout.sh b/t/t3311-notes-merge-fanout.sh index 93516ef67c..37151a3adc 100755 --- a/t/t3311-notes-merge-fanout.sh +++ b/t/t3311-notes-merge-fanout.sh @@ -114,12 +114,12 @@ cp expect_log_x expect_log_y test_expect_success 'Add a few hundred commits w/notes to trigger fanout (x -> y)' ' git update-ref refs/notes/y refs/notes/x && git config core.notesRef refs/notes/y && - i=5 && - while test $i -lt $num + test_commit_bulk --start=6 --id=commit $((num - 5)) && + i=0 && + while test $i -lt $((num - 5)) do - i=$(($i + 1)) && - test_commit "commit$i" >/dev/null && - git notes add -m "notes for commit$i" || return 1 + git notes add -m "notes for commit$i" HEAD~$i || return 1 + i=$((i + 1)) done && test "$(git rev-parse refs/notes/y)" != "$(git rev-parse refs/notes/x)" && # Expected number of commits and notes diff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh index 9186e90127..b8f4d03467 100755 --- a/t/t3420-rebase-autostash.sh +++ b/t/t3420-rebase-autostash.sh @@ -30,7 +30,8 @@ test_expect_success setup ' echo conflicting-change >file2 && git add . && test_tick && - git commit -m "related commit" + git commit -m "related commit" && + remove_progress_re="$(printf "s/.*\\r//")" ' create_expected_success_am () { @@ -48,8 +49,8 @@ create_expected_success_interactive () { q_to_cr >expected <<-EOF $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual) HEAD is now at $(git rev-parse --short feature-branch) third commit - Rebasing (1/2)QRebasing (2/2)QApplied autostash. - Q QSuccessfully rebased and updated refs/heads/rebased-feature-branch. + Applied autostash. + Successfully rebased and updated refs/heads/rebased-feature-branch. EOF } @@ -67,13 +68,13 @@ create_expected_failure_am () { } create_expected_failure_interactive () { - q_to_cr >expected <<-EOF + cat >expected <<-EOF $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual) HEAD is now at $(git rev-parse --short feature-branch) third commit - Rebasing (1/2)QRebasing (2/2)QApplying autostash resulted in conflicts. + Applying autostash resulted in conflicts. Your changes are safe in the stash. You can run "git stash pop" or "git stash drop" at any time. - Q QSuccessfully rebased and updated refs/heads/rebased-feature-branch. + Successfully rebased and updated refs/heads/rebased-feature-branch. EOF } @@ -109,7 +110,8 @@ testrebase () { suffix=interactive fi && create_expected_success_$suffix && - test_i18ncmp expected actual + sed "$remove_progress_re" <actual >actual2 && + test_i18ncmp expected actual2 ' test_expect_success "rebase$type: dirty index, non-conflicting rebase" ' @@ -209,7 +211,8 @@ testrebase () { suffix=interactive fi && create_expected_failure_$suffix && - test_i18ncmp expected actual + sed "$remove_progress_re" <actual >actual2 && + test_i18ncmp expected actual2 ' } diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh index 941d5026da..793bcc7fe3 100755 --- a/t/t3510-cherry-pick-sequence.sh +++ b/t/t3510-cherry-pick-sequence.sh @@ -93,6 +93,128 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' ' test_path_is_missing .git/sequencer ' +test_expect_success 'cherry-pick --skip requires cherry-pick in progress' ' + pristine_detach initial && + test_must_fail git cherry-pick --skip +' + +test_expect_success 'revert --skip requires revert in progress' ' + pristine_detach initial && + test_must_fail git revert --skip +' + +test_expect_success 'cherry-pick --skip to skip commit' ' + pristine_detach initial && + test_must_fail git cherry-pick anotherpick && + test_must_fail git revert --skip && + git cherry-pick --skip && + test_cmp_rev initial HEAD && + test_path_is_missing .git/CHERRY_PICK_HEAD +' + +test_expect_success 'revert --skip to skip commit' ' + pristine_detach anotherpick && + test_must_fail git revert anotherpick~1 && + test_must_fail git cherry-pick --skip && + git revert --skip && + test_cmp_rev anotherpick HEAD +' + +test_expect_success 'skip "empty" commit' ' + pristine_detach picked && + test_commit dummy foo d && + test_must_fail git cherry-pick anotherpick && + git cherry-pick --skip && + test_cmp_rev dummy HEAD +' + +test_expect_success 'skip a commit and check if rest of sequence is correct' ' + pristine_detach initial && + echo e >expect && + cat >expect.log <<-EOF && + OBJID + :100644 100644 OBJID OBJID M foo + OBJID + :100644 100644 OBJID OBJID M foo + OBJID + :100644 100644 OBJID OBJID M unrelated + OBJID + :000000 100644 OBJID OBJID A foo + :000000 100644 OBJID OBJID A unrelated + EOF + test_must_fail git cherry-pick base..yetanotherpick && + test_must_fail git cherry-pick --skip && + echo d >foo && + git add foo && + git cherry-pick --continue && + { + git rev-list HEAD | + git diff-tree --root --stdin | + sed "s/$OID_REGEX/OBJID/g" + } >actual.log && + test_cmp expect foo && + test_cmp expect.log actual.log +' + +test_expect_success 'check advice when we move HEAD by committing' ' + pristine_detach initial && + cat >expect <<-EOF && + error: there is nothing to skip + hint: have you committed already? + hint: try "git cherry-pick --continue" + fatal: cherry-pick failed + EOF + test_must_fail git cherry-pick base..yetanotherpick && + echo c >foo && + git commit -a && + test_path_is_missing .git/CHERRY_PICK_HEAD && + test_must_fail git cherry-pick --skip 2>advice && + test_i18ncmp expect advice +' + +test_expect_success 'selectively advise --skip while launching another sequence' ' + pristine_detach initial && + cat >expect <<-EOF && + error: cherry-pick is already in progress + hint: try "git cherry-pick (--continue | --skip | --abort | --quit)" + fatal: cherry-pick failed + EOF + test_must_fail git cherry-pick picked..yetanotherpick && + test_must_fail git cherry-pick picked..yetanotherpick 2>advice && + test_i18ncmp expect advice && + cat >expect <<-EOF && + error: cherry-pick is already in progress + hint: try "git cherry-pick (--continue | --abort | --quit)" + fatal: cherry-pick failed + EOF + git reset --merge && + test_must_fail git cherry-pick picked..yetanotherpick 2>advice && + test_i18ncmp expect advice +' + +test_expect_success 'allow skipping commit but not abort for a new history' ' + pristine_detach initial && + cat >expect <<-EOF && + error: cannot abort from a branch yet to be born + fatal: cherry-pick failed + EOF + git checkout --orphan new_disconnected && + git reset --hard && + test_must_fail git cherry-pick anotherpick && + test_must_fail git cherry-pick --abort 2>advice && + git cherry-pick --skip && + test_i18ncmp expect advice +' + +test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' ' + pristine_detach initial && + git rm --cached unrelated && + git commit -m "untrack unrelated" && + test_must_fail git cherry-pick initial base && + test_path_is_missing .git/CHERRY_PICK_HEAD && + git cherry-pick --skip +' + test_expect_success '--quit does not complain when no cherry-pick is in progress' ' pristine_detach initial && git cherry-pick --quit diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index 85ae7dc1e4..66282a720e 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -252,6 +252,19 @@ test_expect_success 'choking "git rm" should not let it die with cruft' ' test_path_is_missing .git/index.lock ' +test_expect_success 'Resolving by removal is not a warning-worthy event' ' + git reset -q --hard && + test_when_finished "rm -f .git/index.lock msg && git reset -q --hard" && + blob=$(echo blob | git hash-object -w --stdin) && + for stage in 1 2 3 + do + echo "100644 $blob $stage blob" + done | git update-index --index-info && + git rm blob >msg 2>&1 && + test_i18ngrep ! "needs merge" msg && + test_must_fail git ls-files -s --error-unmatch blob +' + test_expect_success 'rm removes subdirectories recursively' ' mkdir -p dir/subdir/subsubdir && echo content >dir/subdir/subsubdir/file && diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index b22e671608..b8e337893f 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -1234,4 +1234,11 @@ test_expect_success 'stash works when user.name and user.email are not set' ' ) ' +test_expect_success 'stash --keep-index with file deleted in index does not resurrect it on disk' ' + test_commit to-remove to-remove && + git rm to-remove && + git stash --keep-index && + test_path_is_missing to-remove +' + test_done diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index ab4670d236..6b087df3dc 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -2008,4 +2008,26 @@ test_expect_success 'compare mixed whitespace delta across moved blocks' ' test_cmp expected actual ' +# Note that the "6" in the expected hunk header below is funny, since we only +# show 5 lines (the missing one was blank and thus ignored). This is how +# --ignore-blank-lines behaves even without --function-context, and this test +# is just checking the interaction of the two features. Don't take it as an +# endorsement of that output. +test_expect_success 'combine --ignore-blank-lines with --function-context' ' + test_write_lines 1 "" 2 3 4 5 >a && + test_write_lines 1 2 3 4 >b && + test_must_fail git diff --no-index \ + --ignore-blank-lines --function-context a b >actual.raw && + sed -n "/@@/,\$p" <actual.raw >actual && + cat <<-\EOF >expect && + @@ -1,6 +1,4 @@ + 1 + 2 + 3 + 4 + -5 + EOF + test_cmp expect actual +' + test_done diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh index 43b1522ea2..918ada69eb 100755 --- a/t/t4203-mailmap.sh +++ b/t/t4203-mailmap.sh @@ -442,6 +442,34 @@ test_expect_success 'Log output with log.mailmap' ' test_cmp expect actual ' +test_expect_success 'log.mailmap=false disables mailmap' ' + cat >expect <<-\EOF && + Author: CTO <cto@coompany.xx> + Author: claus <me@company.xx> + Author: santa <me@company.xx> + Author: nick2 <nick2@company.xx> + Author: nick2 <bugs@company.xx> + Author: nick1 <bugs@company.xx> + Author: A U Thor <author@example.com> + EOF + git -c log.mailmap=False log | grep Author > actual && + test_cmp expect actual +' + +test_expect_success '--no-use-mailmap disables mailmap' ' + cat >expect <<-\EOF && + Author: CTO <cto@coompany.xx> + Author: claus <me@company.xx> + Author: santa <me@company.xx> + Author: nick2 <nick2@company.xx> + Author: nick2 <bugs@company.xx> + Author: nick1 <bugs@company.xx> + Author: A U Thor <author@example.com> + EOF + git log --no-use-mailmap | grep Author > actual && + test_cmp expect actual +' + cat >expect <<\EOF Author: Santa Claus <santa.claus@northpole.xx> Author: Santa Claus <santa.claus@northpole.xx> @@ -461,6 +489,11 @@ test_expect_success 'Grep author with log.mailmap' ' test_cmp expect actual ' +test_expect_success 'log.mailmap is true by default these days' ' + git log --author Santa | grep Author >actual && + test_cmp expect actual +' + test_expect_success 'Only grep replaced author with --use-mailmap' ' git log --use-mailmap --author "<cto@coompany.xx>" >actual && test_must_be_empty actual diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index 602bfd9574..37655a237c 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -94,6 +94,13 @@ check_tar() { ' } +test_expect_success 'setup' ' + test_oid_cache <<-EOF + obj sha1:19f9c8273ec45a8938e6999cb59b3ff66739902a + obj sha256:3c666f798798601571f5cec0adb57ce4aba8546875e7693177e0535f34d2c49b + EOF +' + test_expect_success \ 'populate workdir' \ 'mkdir a && @@ -369,11 +376,10 @@ test_lazy_prereq TAR_HUGE ' ' test_expect_success LONG_IS_64BIT 'set up repository with huge blob' ' - obj_d=19 && - obj_f=f9c8273ec45a8938e6999cb59b3ff66739902a && - obj=${obj_d}${obj_f} && - mkdir -p .git/objects/$obj_d && - cp "$TEST_DIRECTORY"/t5000/$obj .git/objects/$obj_d/$obj_f && + obj=$(test_oid obj) && + path=$(test_oid_to_path $obj) && + mkdir -p .git/objects/$(dirname $path) && + cp "$TEST_DIRECTORY"/t5000/huge-object .git/objects/$path && rm -f .git/index && git update-index --add --cacheinfo 100644,$obj,huge && git commit -m huge diff --git a/t/t5000/19f9c8273ec45a8938e6999cb59b3ff66739902a b/t/t5000/huge-object Binary files differindex 5cbe9ec312..5cbe9ec312 100644 --- a/t/t5000/19f9c8273ec45a8938e6999cb59b3ff66739902a +++ b/t/t5000/huge-object diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh index a26c8ba9a2..6640329ebf 100755 --- a/t/t5310-pack-bitmaps.sh +++ b/t/t5310-pack-bitmaps.sh @@ -21,15 +21,9 @@ has_any () { } test_expect_success 'setup repo with moderate-sized history' ' - for i in $(test_seq 1 10) - do - test_commit $i - done && + test_commit_bulk --id=file 100 && git checkout -b other HEAD~5 && - for i in $(test_seq 1 10) - do - test_commit side-$i - done && + test_commit_bulk --id=side 10 && git checkout master && bitmaptip=$(git rev-parse master) && blob=$(echo tagged-blob | git hash-object -w --stdin) && @@ -106,10 +100,7 @@ test_expect_success 'clone from bitmapped repository' ' ' test_expect_success 'setup further non-bitmapped commits' ' - for i in $(test_seq 1 10) - do - test_commit further-$i - done + test_commit_bulk --id=further 10 ' rev_list_tests 'partial bitmap' diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh index 5267c4be20..22cb9d6643 100755 --- a/t/t5318-commit-graph.sh +++ b/t/t5318-commit-graph.sh @@ -20,7 +20,7 @@ test_expect_success 'verify graph with no graph file' ' test_expect_success 'write graph with no packs' ' cd "$TRASH_DIRECTORY/full" && git commit-graph write --object-dir . && - test_path_is_file info/commit-graph + test_path_is_missing info/commit-graph ' test_expect_success 'close with correct error on bad input' ' diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh index 1ebf19ec3c..c72ca04399 100755 --- a/t/t5319-multi-pack-index.sh +++ b/t/t5319-multi-pack-index.sh @@ -363,4 +363,188 @@ test_expect_success 'verify incorrect 64-bit offset' ' "incorrect object offset" ' +test_expect_success 'setup expire tests' ' + mkdir dup && + ( + cd dup && + git init && + test-tool genrandom "data" 4096 >large_file.txt && + git update-index --add large_file.txt && + for i in $(test_seq 1 20) + do + test_commit $i + done && + git branch A HEAD && + git branch B HEAD~8 && + git branch C HEAD~13 && + git branch D HEAD~16 && + git branch E HEAD~18 && + git pack-objects --revs .git/objects/pack/pack-A <<-EOF && + refs/heads/A + ^refs/heads/B + EOF + git pack-objects --revs .git/objects/pack/pack-B <<-EOF && + refs/heads/B + ^refs/heads/C + EOF + git pack-objects --revs .git/objects/pack/pack-C <<-EOF && + refs/heads/C + ^refs/heads/D + EOF + git pack-objects --revs .git/objects/pack/pack-D <<-EOF && + refs/heads/D + ^refs/heads/E + EOF + git pack-objects --revs .git/objects/pack/pack-E <<-EOF && + refs/heads/E + EOF + git multi-pack-index write && + cp -r .git/objects/pack .git/objects/pack-backup + ) +' + +test_expect_success 'expire does not remove any packs' ' + ( + cd dup && + ls .git/objects/pack >expect && + git multi-pack-index expire && + ls .git/objects/pack >actual && + test_cmp expect actual + ) +' + +test_expect_success 'expire removes unreferenced packs' ' + ( + cd dup && + git pack-objects --revs .git/objects/pack/pack-combined <<-EOF && + refs/heads/A + ^refs/heads/C + EOF + git multi-pack-index write && + ls .git/objects/pack | grep -v -e pack-[AB] >expect && + git multi-pack-index expire && + ls .git/objects/pack >actual && + test_cmp expect actual && + ls .git/objects/pack/ | grep idx >expect-idx && + test-tool read-midx .git/objects | grep idx >actual-midx && + test_cmp expect-idx actual-midx && + git multi-pack-index verify && + git fsck + ) +' + +test_expect_success 'repack with minimum size does not alter existing packs' ' + ( + cd dup && + rm -rf .git/objects/pack && + mv .git/objects/pack-backup .git/objects/pack && + touch -m -t 201901010000 .git/objects/pack/pack-D* && + touch -m -t 201901010001 .git/objects/pack/pack-C* && + touch -m -t 201901010002 .git/objects/pack/pack-B* && + touch -m -t 201901010003 .git/objects/pack/pack-A* && + ls .git/objects/pack >expect && + MINSIZE=$(test-tool path-utils file-size .git/objects/pack/*pack | sort -n | head -n 1) && + git multi-pack-index repack --batch-size=$MINSIZE && + ls .git/objects/pack >actual && + test_cmp expect actual + ) +' + +test_expect_success 'repack creates a new pack' ' + ( + cd dup && + ls .git/objects/pack/*idx >idx-list && + test_line_count = 5 idx-list && + THIRD_SMALLEST_SIZE=$(test-tool path-utils file-size .git/objects/pack/*pack | sort -n | head -n 3 | tail -n 1) && + BATCH_SIZE=$(($THIRD_SMALLEST_SIZE + 1)) && + git multi-pack-index repack --batch-size=$BATCH_SIZE && + ls .git/objects/pack/*idx >idx-list && + test_line_count = 6 idx-list && + test-tool read-midx .git/objects | grep idx >midx-list && + test_line_count = 6 midx-list + ) +' + +test_expect_success 'expire removes repacked packs' ' + ( + cd dup && + ls -al .git/objects/pack/*pack && + ls -S .git/objects/pack/*pack | head -n 4 >expect && + git multi-pack-index expire && + ls -S .git/objects/pack/*pack >actual && + test_cmp expect actual && + test-tool read-midx .git/objects | grep idx >midx-list && + test_line_count = 4 midx-list + ) +' + +test_expect_success 'expire works when adding new packs' ' + ( + cd dup && + git pack-objects --revs .git/objects/pack/pack-combined <<-EOF && + refs/heads/A + ^refs/heads/B + EOF + git pack-objects --revs .git/objects/pack/pack-combined <<-EOF && + refs/heads/B + ^refs/heads/C + EOF + git pack-objects --revs .git/objects/pack/pack-combined <<-EOF && + refs/heads/C + ^refs/heads/D + EOF + git multi-pack-index write && + git pack-objects --revs .git/objects/pack/a-pack <<-EOF && + refs/heads/D + ^refs/heads/E + EOF + git multi-pack-index write && + git pack-objects --revs .git/objects/pack/z-pack <<-EOF && + refs/heads/E + EOF + git multi-pack-index expire && + ls .git/objects/pack/ | grep idx >expect && + test-tool read-midx .git/objects | grep idx >actual && + test_cmp expect actual && + git multi-pack-index verify + ) +' + +test_expect_success 'expire respects .keep files' ' + ( + cd dup && + git pack-objects --revs .git/objects/pack/pack-all <<-EOF && + refs/heads/A + EOF + git multi-pack-index write && + PACKA=$(ls .git/objects/pack/a-pack*\.pack | sed s/\.pack\$//) && + touch $PACKA.keep && + git multi-pack-index expire && + ls -S .git/objects/pack/a-pack* | grep $PACKA >a-pack-files && + test_line_count = 3 a-pack-files && + test-tool read-midx .git/objects | grep idx >midx-list && + test_line_count = 2 midx-list + ) +' + +test_expect_success 'repack --batch-size=0 repacks everything' ' + ( + cd dup && + rm .git/objects/pack/*.keep && + ls .git/objects/pack/*idx >idx-list && + test_line_count = 2 idx-list && + git multi-pack-index repack --batch-size=0 && + ls .git/objects/pack/*idx >idx-list && + test_line_count = 3 idx-list && + test-tool read-midx .git/objects | grep idx >midx-list && + test_line_count = 3 midx-list && + git multi-pack-index expire && + ls -al .git/objects/pack/*idx >idx-list && + test_line_count = 1 idx-list && + git multi-pack-index repack --batch-size=0 && + ls -al .git/objects/pack/*idx >new-idx-list && + test_cmp idx-list new-idx-list + ) +' + test_done diff --git a/t/t5324-split-commit-graph.sh b/t/t5324-split-commit-graph.sh new file mode 100755 index 0000000000..03f45a1ed9 --- /dev/null +++ b/t/t5324-split-commit-graph.sh @@ -0,0 +1,343 @@ +#!/bin/sh + +test_description='split commit graph' +. ./test-lib.sh + +GIT_TEST_COMMIT_GRAPH=0 + +test_expect_success 'setup repo' ' + git init && + git config core.commitGraph true && + infodir=".git/objects/info" && + graphdir="$infodir/commit-graphs" && + test_oid_init +' + +graph_read_expect() { + NUM_BASE=0 + if test ! -z $2 + then + NUM_BASE=$2 + fi + cat >expect <<- EOF + header: 43475048 1 1 3 $NUM_BASE + num_commits: $1 + chunks: oid_fanout oid_lookup commit_metadata + EOF + git commit-graph read >output && + test_cmp expect output +} + +test_expect_success 'create commits and write commit-graph' ' + for i in $(test_seq 3) + do + test_commit $i && + git branch commits/$i || return 1 + done && + git commit-graph write --reachable && + test_path_is_file $infodir/commit-graph && + graph_read_expect 3 +' + +graph_git_two_modes() { + git -c core.commitGraph=true $1 >output + git -c core.commitGraph=false $1 >expect + test_cmp expect output +} + +graph_git_behavior() { + MSG=$1 + BRANCH=$2 + COMPARE=$3 + test_expect_success "check normal git operations: $MSG" ' + graph_git_two_modes "log --oneline $BRANCH" && + graph_git_two_modes "log --topo-order $BRANCH" && + graph_git_two_modes "log --graph $COMPARE..$BRANCH" && + graph_git_two_modes "branch -vv" && + graph_git_two_modes "merge-base -a $BRANCH $COMPARE" + ' +} + +graph_git_behavior 'graph exists' commits/3 commits/1 + +verify_chain_files_exist() { + for hash in $(cat $1/commit-graph-chain) + do + test_path_is_file $1/graph-$hash.graph || return 1 + done +} + +test_expect_success 'add more commits, and write a new base graph' ' + git reset --hard commits/1 && + for i in $(test_seq 4 5) + do + test_commit $i && + git branch commits/$i || return 1 + done && + git reset --hard commits/2 && + for i in $(test_seq 6 10) + do + test_commit $i && + git branch commits/$i || return 1 + done && + git reset --hard commits/2 && + git merge commits/4 && + git branch merge/1 && + git reset --hard commits/4 && + git merge commits/6 && + git branch merge/2 && + git commit-graph write --reachable && + graph_read_expect 12 +' + +test_expect_success 'fork and fail to base a chain on a commit-graph file' ' + test_when_finished rm -rf fork && + git clone . fork && + ( + cd fork && + rm .git/objects/info/commit-graph && + echo "$(pwd)/../.git/objects" >.git/objects/info/alternates && + test_commit new-commit && + git commit-graph write --reachable --split && + test_path_is_file $graphdir/commit-graph-chain && + test_line_count = 1 $graphdir/commit-graph-chain && + verify_chain_files_exist $graphdir + ) +' + +test_expect_success 'add three more commits, write a tip graph' ' + git reset --hard commits/3 && + git merge merge/1 && + git merge commits/5 && + git merge merge/2 && + git branch merge/3 && + git commit-graph write --reachable --split && + test_path_is_missing $infodir/commit-graph && + test_path_is_file $graphdir/commit-graph-chain && + ls $graphdir/graph-*.graph >graph-files && + test_line_count = 2 graph-files && + verify_chain_files_exist $graphdir +' + +graph_git_behavior 'split commit-graph: merge 3 vs 2' merge/3 merge/2 + +test_expect_success 'add one commit, write a tip graph' ' + test_commit 11 && + git branch commits/11 && + git commit-graph write --reachable --split && + test_path_is_missing $infodir/commit-graph && + test_path_is_file $graphdir/commit-graph-chain && + ls $graphdir/graph-*.graph >graph-files && + test_line_count = 3 graph-files && + verify_chain_files_exist $graphdir +' + +graph_git_behavior 'three-layer commit-graph: commit 11 vs 6' commits/11 commits/6 + +test_expect_success 'add one commit, write a merged graph' ' + test_commit 12 && + git branch commits/12 && + git commit-graph write --reachable --split && + test_path_is_file $graphdir/commit-graph-chain && + test_line_count = 2 $graphdir/commit-graph-chain && + ls $graphdir/graph-*.graph >graph-files && + test_line_count = 2 graph-files && + verify_chain_files_exist $graphdir +' + +graph_git_behavior 'merged commit-graph: commit 12 vs 6' commits/12 commits/6 + +test_expect_success 'create fork and chain across alternate' ' + git clone . fork && + ( + cd fork && + git config core.commitGraph true && + rm -rf $graphdir && + echo "$(pwd)/../.git/objects" >.git/objects/info/alternates && + test_commit 13 && + git branch commits/13 && + git commit-graph write --reachable --split && + test_path_is_file $graphdir/commit-graph-chain && + test_line_count = 3 $graphdir/commit-graph-chain && + ls $graphdir/graph-*.graph >graph-files && + test_line_count = 1 graph-files && + git -c core.commitGraph=true rev-list HEAD >expect && + git -c core.commitGraph=false rev-list HEAD >actual && + test_cmp expect actual && + test_commit 14 && + git commit-graph write --reachable --split --object-dir=.git/objects/ && + test_line_count = 3 $graphdir/commit-graph-chain && + ls $graphdir/graph-*.graph >graph-files && + test_line_count = 1 graph-files + ) +' + +graph_git_behavior 'alternate: commit 13 vs 6' commits/13 commits/6 + +test_expect_success 'test merge stragety constants' ' + git clone . merge-2 && + ( + cd merge-2 && + git config core.commitGraph true && + test_line_count = 2 $graphdir/commit-graph-chain && + test_commit 14 && + git commit-graph write --reachable --split --size-multiple=2 && + test_line_count = 3 $graphdir/commit-graph-chain + + ) && + git clone . merge-10 && + ( + cd merge-10 && + git config core.commitGraph true && + test_line_count = 2 $graphdir/commit-graph-chain && + test_commit 14 && + git commit-graph write --reachable --split --size-multiple=10 && + test_line_count = 1 $graphdir/commit-graph-chain && + ls $graphdir/graph-*.graph >graph-files && + test_line_count = 1 graph-files + ) && + git clone . merge-10-expire && + ( + cd merge-10-expire && + git config core.commitGraph true && + test_line_count = 2 $graphdir/commit-graph-chain && + test_commit 15 && + git commit-graph write --reachable --split --size-multiple=10 --expire-time=1980-01-01 && + test_line_count = 1 $graphdir/commit-graph-chain && + ls $graphdir/graph-*.graph >graph-files && + test_line_count = 3 graph-files + ) && + git clone --no-hardlinks . max-commits && + ( + cd max-commits && + git config core.commitGraph true && + test_line_count = 2 $graphdir/commit-graph-chain && + test_commit 16 && + test_commit 17 && + git commit-graph write --reachable --split --max-commits=1 && + test_line_count = 1 $graphdir/commit-graph-chain && + ls $graphdir/graph-*.graph >graph-files && + test_line_count = 1 graph-files + ) +' + +test_expect_success 'remove commit-graph-chain file after flattening' ' + git clone . flatten && + ( + cd flatten && + test_line_count = 2 $graphdir/commit-graph-chain && + git commit-graph write --reachable && + test_path_is_missing $graphdir/commit-graph-chain && + ls $graphdir >graph-files && + test_line_count = 0 graph-files + ) +' + +corrupt_file() { + file=$1 + pos=$2 + data="${3:-\0}" + chmod a+w "$file" && + printf "$data" | dd of="$file" bs=1 seek="$pos" conv=notrunc +} + +test_expect_success 'verify hashes along chain, even in shallow' ' + git clone --no-hardlinks . verify && + ( + cd verify && + git commit-graph verify && + base_file=$graphdir/graph-$(head -n 1 $graphdir/commit-graph-chain).graph && + corrupt_file "$base_file" 1760 "\01" && + test_must_fail git commit-graph verify --shallow 2>test_err && + grep -v "^+" test_err >err && + test_i18ngrep "incorrect checksum" err + ) +' + +test_expect_success 'verify --shallow does not check base contents' ' + git clone --no-hardlinks . verify-shallow && + ( + cd verify-shallow && + git commit-graph verify && + base_file=$graphdir/graph-$(head -n 1 $graphdir/commit-graph-chain).graph && + corrupt_file "$base_file" 1000 "\01" && + git commit-graph verify --shallow && + test_must_fail git commit-graph verify 2>test_err && + grep -v "^+" test_err >err && + test_i18ngrep "incorrect checksum" err + ) +' + +test_expect_success 'warn on base graph chunk incorrect' ' + git clone --no-hardlinks . base-chunk && + ( + cd base-chunk && + git commit-graph verify && + base_file=$graphdir/graph-$(tail -n 1 $graphdir/commit-graph-chain).graph && + corrupt_file "$base_file" 1376 "\01" && + git commit-graph verify --shallow 2>test_err && + grep -v "^+" test_err >err && + test_i18ngrep "commit-graph chain does not match" err + ) +' + +test_expect_success 'verify after commit-graph-chain corruption' ' + git clone --no-hardlinks . verify-chain && + ( + cd verify-chain && + corrupt_file "$graphdir/commit-graph-chain" 60 "G" && + git commit-graph verify 2>test_err && + grep -v "^+" test_err >err && + test_i18ngrep "invalid commit-graph chain" err && + corrupt_file "$graphdir/commit-graph-chain" 60 "A" && + git commit-graph verify 2>test_err && + grep -v "^+" test_err >err && + test_i18ngrep "unable to find all commit-graph files" err + ) +' + +test_expect_success 'verify across alternates' ' + git clone --no-hardlinks . verify-alt && + ( + cd verify-alt && + rm -rf $graphdir && + altdir="$(pwd)/../.git/objects" && + echo "$altdir" >.git/objects/info/alternates && + git commit-graph verify --object-dir="$altdir/" && + test_commit extra && + git commit-graph write --reachable --split && + tip_file=$graphdir/graph-$(tail -n 1 $graphdir/commit-graph-chain).graph && + corrupt_file "$tip_file" 100 "\01" && + test_must_fail git commit-graph verify --shallow 2>test_err && + grep -v "^+" test_err >err && + test_i18ngrep "commit-graph has incorrect fanout value" err + ) +' + +test_expect_success 'add octopus merge' ' + git reset --hard commits/10 && + git merge commits/3 commits/4 && + git branch merge/octopus && + git commit-graph write --reachable --split && + git commit-graph verify && + test_line_count = 3 $graphdir/commit-graph-chain +' + +graph_git_behavior 'graph exists' merge/octopus commits/12 + +test_expect_success 'split across alternate where alternate is not split' ' + git commit-graph write --reachable && + test_path_is_file .git/objects/info/commit-graph && + cp .git/objects/info/commit-graph . && + git clone --no-hardlinks . alt-split && + ( + cd alt-split && + echo "$(pwd)"/../.git/objects >.git/objects/info/alternates && + test_commit 18 && + git commit-graph write --reachable --split && + test_line_count = 1 $graphdir/commit-graph-chain + ) && + test_cmp commit-graph .git/objects/info/commit-graph +' + +test_done diff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh index 7bc706873c..fdfe179b11 100755 --- a/t/t5504-fetch-receive-strict.sh +++ b/t/t5504-fetch-receive-strict.sh @@ -164,9 +164,9 @@ test_expect_success 'fsck with unsorted skipList' ' test_expect_success 'fsck with invalid or bogus skipList input' ' git -c fsck.skipList=/dev/null -c fsck.missingEmail=ignore fsck && test_must_fail git -c fsck.skipList=does-not-exist -c fsck.missingEmail=ignore fsck 2>err && - test_i18ngrep "Could not open skip list: does-not-exist" err && + test_i18ngrep "could not open.*: does-not-exist" err && test_must_fail git -c fsck.skipList=.git/config -c fsck.missingEmail=ignore fsck 2>err && - test_i18ngrep "Invalid SHA-1: \[core\]" err + test_i18ngrep "invalid object name: \[core\]" err ' test_expect_success 'fsck with other accepted skipList input (comments & empty lines)' ' @@ -193,7 +193,7 @@ test_expect_success 'fsck no garbage output from comments & empty lines errors' test_expect_success 'fsck with invalid abbreviated skipList input' ' echo $commit | test_copy_bytes 20 >SKIP.abbreviated && test_must_fail git -c fsck.skipList=SKIP.abbreviated fsck 2>err-abbreviated && - test_i18ngrep "^fatal: Invalid SHA-1: " err-abbreviated + test_i18ngrep "^fatal: invalid object name: " err-abbreviated ' test_expect_success 'fsck with exhaustive accepted skipList input (various types of comments etc.)' ' @@ -226,10 +226,10 @@ test_expect_success 'push with receive.fsck.skipList' ' test_must_fail git push --porcelain dst bogus && git --git-dir=dst/.git config receive.fsck.skipList does-not-exist && test_must_fail git push --porcelain dst bogus 2>err && - test_i18ngrep "Could not open skip list: does-not-exist" err && + test_i18ngrep "could not open.*: does-not-exist" err && git --git-dir=dst/.git config receive.fsck.skipList config && test_must_fail git push --porcelain dst bogus 2>err && - test_i18ngrep "Invalid SHA-1: \[core\]" err && + test_i18ngrep "invalid object name: \[core\]" err && git --git-dir=dst/.git config receive.fsck.skipList SKIP && git push --porcelain dst bogus @@ -255,10 +255,10 @@ test_expect_success 'fetch with fetch.fsck.skipList' ' test_must_fail git --git-dir=dst/.git fetch "file://$(pwd)" $refspec && git --git-dir=dst/.git config fetch.fsck.skipList does-not-exist && test_must_fail git --git-dir=dst/.git fetch "file://$(pwd)" $refspec 2>err && - test_i18ngrep "Could not open skip list: does-not-exist" err && + test_i18ngrep "could not open.*: does-not-exist" err && git --git-dir=dst/.git config fetch.fsck.skipList dst/.git/config && test_must_fail git --git-dir=dst/.git fetch "file://$(pwd)" $refspec 2>err && - test_i18ngrep "Invalid SHA-1: \[core\]" err && + test_i18ngrep "invalid object name: \[core\]" err && git --git-dir=dst/.git config fetch.fsck.skipList dst/.git/SKIP && git --git-dir=dst/.git fetch "file://$(pwd)" $refspec diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh index e3c4a48c85..43e1d8d4d2 100755 --- a/t/t5512-ls-remote.sh +++ b/t/t5512-ls-remote.sh @@ -267,8 +267,7 @@ test_expect_success 'ls-remote --symref omits filtered-out matches' ' ' test_lazy_prereq GIT_DAEMON ' - test_tristate GIT_TEST_GIT_DAEMON && - test "$GIT_TEST_GIT_DAEMON" != false + git env--helper --type=bool --default=true --exit-code GIT_TEST_GIT_DAEMON ' # This test spawns a daemon, so run it only if the user would be OK with diff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh index 2e4802e206..b86ddb60f2 100755 --- a/t/t5541-http-push-smart.sh +++ b/t/t5541-http-push-smart.sh @@ -177,6 +177,55 @@ test_expect_success 'push (chunked)' ' test $HEAD = $(git rev-parse --verify HEAD)) ' +test_expect_success 'push --atomic also prevents branch creation, reports collateral' ' + # Setup upstream repo - empty for now + d=$HTTPD_DOCUMENT_ROOT_PATH/atomic-branches.git && + git init --bare "$d" && + test_config -C "$d" http.receivepack true && + up="$HTTPD_URL"/smart/atomic-branches.git && + + # Tell "$up" about two branches for now + test_commit atomic1 && + test_commit atomic2 && + git branch collateral && + git push "$up" master collateral && + + # collateral is a valid push, but should be failed by atomic push + git checkout collateral && + test_commit collateral1 && + + # Make master incompatible with upstream to provoke atomic + git checkout master && + git reset --hard HEAD^ && + + # Add a new branch which should be failed by atomic push. This is a + # regression case. + git branch atomic && + + # --atomic should cause entire push to be rejected + test_must_fail git push --atomic "$up" master atomic collateral 2>output && + + # the new branch should not have been created upstream + test_must_fail git -C "$d" show-ref --verify refs/heads/atomic && + + # upstream should still reflect atomic2, the last thing we pushed + # successfully + git rev-parse atomic2 >expected && + # on master... + git -C "$d" rev-parse refs/heads/master >actual && + test_cmp expected actual && + # ...and collateral. + git -C "$d" rev-parse refs/heads/collateral >actual && + test_cmp expected actual && + + # the failed refs should be indicated to the user + grep "^ ! .*rejected.* master -> master" output && + + # the collateral failure refs should be indicated to the user + grep "^ ! .*rejected.* atomic -> atomic .*atomic push failed" output && + grep "^ ! .*rejected.* collateral -> collateral .*atomic push failed" output +' + test_expect_success 'push --all can push to empty repo' ' d=$HTTPD_DOCUMENT_ROOT_PATH/empty-all.git && git init --bare "$d" && diff --git a/t/t5604-clone-reference.sh b/t/t5604-clone-reference.sh index 4320082b1b..4894237ab8 100755 --- a/t/t5604-clone-reference.sh +++ b/t/t5604-clone-reference.sh @@ -221,4 +221,137 @@ test_expect_success 'clone, dissociate from alternates' ' ( cd C && git fsck ) ' +test_expect_success 'setup repo with garbage in objects/*' ' + git init S && + ( + cd S && + test_commit A && + + cd .git/objects && + >.some-hidden-file && + >some-file && + mkdir .some-hidden-dir && + >.some-hidden-dir/some-file && + >.some-hidden-dir/.some-dot-file && + mkdir some-dir && + >some-dir/some-file && + >some-dir/.some-dot-file + ) +' + +test_expect_success 'clone a repo with garbage in objects/*' ' + for option in --local --no-hardlinks --shared --dissociate + do + git clone $option S S$option || return 1 && + git -C S$option fsck || return 1 + done && + find S-* -name "*some*" | sort >actual && + cat >expected <<-EOF && + S--dissociate/.git/objects/.some-hidden-dir + S--dissociate/.git/objects/.some-hidden-dir/.some-dot-file + S--dissociate/.git/objects/.some-hidden-dir/some-file + S--dissociate/.git/objects/.some-hidden-file + S--dissociate/.git/objects/some-dir + S--dissociate/.git/objects/some-dir/.some-dot-file + S--dissociate/.git/objects/some-dir/some-file + S--dissociate/.git/objects/some-file + S--local/.git/objects/.some-hidden-dir + S--local/.git/objects/.some-hidden-dir/.some-dot-file + S--local/.git/objects/.some-hidden-dir/some-file + S--local/.git/objects/.some-hidden-file + S--local/.git/objects/some-dir + S--local/.git/objects/some-dir/.some-dot-file + S--local/.git/objects/some-dir/some-file + S--local/.git/objects/some-file + S--no-hardlinks/.git/objects/.some-hidden-dir + S--no-hardlinks/.git/objects/.some-hidden-dir/.some-dot-file + S--no-hardlinks/.git/objects/.some-hidden-dir/some-file + S--no-hardlinks/.git/objects/.some-hidden-file + S--no-hardlinks/.git/objects/some-dir + S--no-hardlinks/.git/objects/some-dir/.some-dot-file + S--no-hardlinks/.git/objects/some-dir/some-file + S--no-hardlinks/.git/objects/some-file + EOF + test_cmp expected actual +' + +test_expect_success SYMLINKS 'setup repo with manually symlinked or unknown files at objects/' ' + git init T && + ( + cd T && + git config gc.auto 0 && + test_commit A && + git gc && + test_commit B && + + cd .git/objects && + mv pack packs && + ln -s packs pack && + find ?? -type d >loose-dirs && + last_loose=$(tail -n 1 loose-dirs) && + mv $last_loose a-loose-dir && + ln -s a-loose-dir $last_loose && + first_loose=$(head -n 1 loose-dirs) && + rm -f loose-dirs && + + cd $first_loose && + obj=$(ls *) && + mv $obj ../an-object && + ln -s ../an-object $obj && + + cd ../ && + find . -type f | sort >../../../T.objects-files.raw && + find . -type l | sort >../../../T.objects-symlinks.raw && + echo unknown_content >unknown_file + ) && + git -C T fsck && + git -C T rev-list --all --objects >T.objects +' + + +test_expect_success SYMLINKS 'clone repo with symlinked or unknown files at objects/' ' + for option in --local --no-hardlinks --shared --dissociate + do + git clone $option T T$option || return 1 && + git -C T$option fsck || return 1 && + git -C T$option rev-list --all --objects >T$option.objects && + test_cmp T.objects T$option.objects && + ( + cd T$option/.git/objects && + find . -type f | sort >../../../T$option.objects-files.raw && + find . -type l | sort >../../../T$option.objects-symlinks.raw + ) + done && + + for raw in $(ls T*.raw) + do + sed -e "s!/../!/Y/!; s![0-9a-f]\{38,\}!Z!" -e "/commit-graph/d" \ + -e "/multi-pack-index/d" <$raw >$raw.de-sha || return 1 + done && + + cat >expected-files <<-EOF && + ./Y/Z + ./Y/Z + ./a-loose-dir/Z + ./an-object + ./Y/Z + ./info/packs + ./pack/pack-Z.idx + ./pack/pack-Z.pack + ./packs/pack-Z.idx + ./packs/pack-Z.pack + ./unknown_file + EOF + + for option in --local --no-hardlinks --dissociate + do + test_cmp expected-files T$option.objects-files.raw.de-sha || return 1 && + test_must_be_empty T$option.objects-symlinks.raw.de-sha || return 1 + done && + + echo ./info/alternates >expected-files && + test_cmp expected-files T--shared.objects-files.raw && + test_must_be_empty T--shared.objects-symlinks.raw +' + test_done diff --git a/t/t5618-alternate-refs.sh b/t/t5618-alternate-refs.sh new file mode 100755 index 0000000000..3353216f09 --- /dev/null +++ b/t/t5618-alternate-refs.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +test_description='test handling of --alternate-refs traversal' +. ./test-lib.sh + +# Avoid test_commit because we want a specific and known set of refs: +# +# base -- one +# \ \ +# two -- merged +# +# where "one" and "two" are on separate refs, and "merged" is available only in +# the dependent child repository. +test_expect_success 'set up local refs' ' + git checkout -b one && + test_tick && + git commit --allow-empty -m base && + test_tick && + git commit --allow-empty -m one && + git checkout -b two HEAD^ && + test_tick && + git commit --allow-empty -m two +' + +# We'll enter the child repository after it's set up since that's where +# all of the subsequent tests will want to run (and it's easy to forget a +# "-C child" and get nonsense results). +test_expect_success 'set up shared clone' ' + git clone -s . child && + cd child && + git merge origin/one +' + +test_expect_success 'rev-list --alternate-refs' ' + git rev-list --remotes=origin >expect && + git rev-list --alternate-refs >actual && + test_cmp expect actual +' + +test_expect_success 'rev-list --not --alternate-refs' ' + git rev-parse HEAD >expect && + git rev-list HEAD --not --alternate-refs >actual && + test_cmp expect actual +' + +test_expect_success 'limiting with alternateRefsPrefixes' ' + test_config core.alternateRefsPrefixes refs/heads/one && + git rev-list origin/one >expect && + git rev-list --alternate-refs >actual && + test_cmp expect actual +' + +test_expect_success 'log --source shows .alternate marker' ' + git log --oneline --source --remotes=origin >expect.orig && + sed "s/origin.* /.alternate /" <expect.orig >expect && + git log --oneline --source --alternate-refs >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh index 5b33f625dd..011b81d4fc 100755 --- a/t/t5702-protocol-v2.sh +++ b/t/t5702-protocol-v2.sh @@ -499,10 +499,7 @@ test_expect_success 'upload-pack respects client shallows' ' # Add extra commits to the client so that the whole fetch takes more # than 1 request (due to negotiation) - for i in $(test_seq 1 32) - do - test_commit -C client c$i - done && + test_commit_bulk -C client --id=c 32 && git -C server checkout -b newbranch base && test_commit -C server client_wants && @@ -711,10 +708,7 @@ test_expect_success 'when server does not send "ready", expect FLUSH' ' # Create many commits to extend the negotiation phase across multiple # requests, so that the server does not send "ready" in the first # request. - for i in $(test_seq 1 32) - do - test_commit -C http_child c$i - done && + test_commit_bulk -C http_child --id=c 32 && # After the acknowledgments section, pretend that a DELIM # (0001) was sent instead of a FLUSH (0000). diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh index 0951d1bbdc..de4b6106ef 100755 --- a/t/t5703-upload-pack-ref-in-want.sh +++ b/t/t5703-upload-pack-ref-in-want.sh @@ -176,7 +176,7 @@ test_expect_success 'setup repos for change-while-negotiating test' ' git clone "http://127.0.0.1:$LIB_HTTPD_PORT/smart/repo" "$LOCAL_PRISTINE" && cd "$LOCAL_PRISTINE" && git checkout -b side && - for i in $(test_seq 1 33); do test_commit s$i; done && + test_commit_bulk --id=s 33 && # Add novel commits to upstream git checkout master && @@ -287,7 +287,7 @@ test_expect_success 'setup repos for fetching with ref-in-want tests' ' git clone "file://$REPO" "$LOCAL_PRISTINE" && cd "$LOCAL_PRISTINE" && git checkout -b side && - for i in $(test_seq 1 33); do test_commit s$i; done && + test_commit_bulk --id=s 33 && # Add novel commits to upstream git checkout master && diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh index 49a394bd75..bdc42e9440 100755 --- a/t/t6030-bisect-porcelain.sh +++ b/t/t6030-bisect-porcelain.sh @@ -615,6 +615,7 @@ test_expect_success 'broken branch creation' ' git add missing/MISSING && git commit -m "6(broken): Added file that will be deleted" && git tag BROKEN_HASH6 && + deleted=$(git rev-parse --verify HEAD:missing) && add_line_into_file "7(broken): second line on a broken branch" hello2 && git tag BROKEN_HASH7 && add_line_into_file "8(broken): third line on a broken branch" hello2 && @@ -622,12 +623,12 @@ test_expect_success 'broken branch creation' ' git rm missing/MISSING && git commit -m "9(broken): Remove missing file" && git tag BROKEN_HASH9 && - rm .git/objects/39/f7e61a724187ab767d2e08442d9b6b9dab587d + rm .git/objects/$(test_oid_to_path $deleted) ' echo "" > expected.ok cat > expected.missing-tree.default <<EOF -fatal: unable to read tree 39f7e61a724187ab767d2e08442d9b6b9dab587d +fatal: unable to read tree $deleted EOF test_expect_success 'bisect fails if tree is broken on start commit' ' @@ -713,12 +714,12 @@ test_expect_success 'bisect: demonstrate identification of damage boundary' " " cat > expected.bisect-log <<EOF -# bad: [32a594a3fdac2d57cf6d02987e30eec68511498c] Add <4: Ciao for now> into <hello>. -# good: [7b7f204a749c3125d5224ed61ea2ae1187ad046f] Add <2: A new day for git> into <hello>. -git bisect start '32a594a3fdac2d57cf6d02987e30eec68511498c' '7b7f204a749c3125d5224ed61ea2ae1187ad046f' -# good: [3de952f2416b6084f557ec417709eac740c6818c] Add <3: Another new day for git> into <hello>. -git bisect good 3de952f2416b6084f557ec417709eac740c6818c -# first bad commit: [32a594a3fdac2d57cf6d02987e30eec68511498c] Add <4: Ciao for now> into <hello>. +# bad: [$HASH4] Add <4: Ciao for now> into <hello>. +# good: [$HASH2] Add <2: A new day for git> into <hello>. +git bisect start '$HASH4' '$HASH2' +# good: [$HASH3] Add <3: Another new day for git> into <hello>. +git bisect good $HASH3 +# first bad commit: [$HASH4] Add <4: Ciao for now> into <hello>. EOF test_expect_success 'bisect log: successful result' ' @@ -731,14 +732,14 @@ test_expect_success 'bisect log: successful result' ' ' cat > expected.bisect-skip-log <<EOF -# bad: [32a594a3fdac2d57cf6d02987e30eec68511498c] Add <4: Ciao for now> into <hello>. -# good: [7b7f204a749c3125d5224ed61ea2ae1187ad046f] Add <2: A new day for git> into <hello>. -git bisect start '32a594a3fdac2d57cf6d02987e30eec68511498c' '7b7f204a749c3125d5224ed61ea2ae1187ad046f' -# skip: [3de952f2416b6084f557ec417709eac740c6818c] Add <3: Another new day for git> into <hello>. -git bisect skip 3de952f2416b6084f557ec417709eac740c6818c +# bad: [$HASH4] Add <4: Ciao for now> into <hello>. +# good: [$HASH2] Add <2: A new day for git> into <hello>. +git bisect start '$HASH4' '$HASH2' +# skip: [$HASH3] Add <3: Another new day for git> into <hello>. +git bisect skip $HASH3 # only skipped commits left to test -# possible first bad commit: [32a594a3fdac2d57cf6d02987e30eec68511498c] Add <4: Ciao for now> into <hello>. -# possible first bad commit: [3de952f2416b6084f557ec417709eac740c6818c] Add <3: Another new day for git> into <hello>. +# possible first bad commit: [$HASH4] Add <4: Ciao for now> into <hello>. +# possible first bad commit: [$HASH3] Add <3: Another new day for git> into <hello>. EOF test_expect_success 'bisect log: only skip commits left' ' diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh index febf63f28a..ad1922b999 100755 --- a/t/t6040-tracking-info.sh +++ b/t/t6040-tracking-info.sh @@ -38,7 +38,7 @@ test_expect_success setup ' advance h ' -script='s/^..\(b.\) *[0-9a-f]* \(.*\)$/\1 \2/p' +t6040_script='s/^..\(b.\) *[0-9a-f]* \(.*\)$/\1 \2/p' cat >expect <<\EOF b1 [ahead 1, behind 1] d b2 [ahead 1, behind 1] d @@ -53,7 +53,7 @@ test_expect_success 'branch -v' ' cd test && git branch -v ) | - sed -n -e "$script" >actual && + sed -n -e "$t6040_script" >actual && test_i18ncmp expect actual ' @@ -71,7 +71,7 @@ test_expect_success 'branch -vv' ' cd test && git branch -vv ) | - sed -n -e "$script" >actual && + sed -n -e "$t6040_script" >actual && test_i18ncmp expect actual ' diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh index 93f23cfa82..8a72b4c43a 100755 --- a/t/t6200-fmt-merge-msg.sh +++ b/t/t6200-fmt-merge-msg.sh @@ -66,12 +66,7 @@ test_expect_success setup ' git commit -a -m "Right #5" && git checkout -b long && - i=0 && - while test $i -lt 30 - do - test_commit $i one && - i=$(($i+1)) - done && + test_commit_bulk --start=0 --message=%s --filename=one 30 && git show-branch && diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh index d9235217fc..ab69aa176d 100755 --- a/t/t6300-for-each-ref.sh +++ b/t/t6300-for-each-ref.sh @@ -346,6 +346,32 @@ test_expect_success 'Verify descending sort' ' ' cat >expected <<\EOF +refs/tags/testtag +refs/tags/testtag-2 +EOF + +test_expect_success 'exercise patterns with prefixes' ' + git tag testtag-2 && + test_when_finished "git tag -d testtag-2" && + git for-each-ref --format="%(refname)" \ + refs/tags/testtag refs/tags/testtag-2 >actual && + test_cmp expected actual +' + +cat >expected <<\EOF +refs/tags/testtag +refs/tags/testtag-2 +EOF + +test_expect_success 'exercise glob patterns with prefixes' ' + git tag testtag-2 && + test_when_finished "git tag -d testtag-2" && + git for-each-ref --format="%(refname)" \ + refs/tags/testtag "refs/tags/testtag-*" >actual && + test_cmp expected actual +' + +cat >expected <<\EOF 'refs/heads/master' 'refs/remotes/origin/master' 'refs/tags/testtag' diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh index 53cf42fac1..d5218743e9 100755 --- a/t/t7060-wtstatus.sh +++ b/t/t7060-wtstatus.sh @@ -38,7 +38,6 @@ You have unmerged paths. Unmerged paths: (use "git add/rm <file>..." as appropriate to mark resolution) - deleted by us: foo no changes added to commit (use "git add" and/or "git commit -a") @@ -143,7 +142,6 @@ You have unmerged paths. Unmerged paths: (use "git add/rm <file>..." as appropriate to mark resolution) - both added: conflict.txt deleted by them: main.txt @@ -177,7 +175,6 @@ You have unmerged paths. Unmerged paths: (use "git add/rm <file>..." as appropriate to mark resolution) - both deleted: main.txt added by them: sub_master.txt added by us: sub_second.txt @@ -201,12 +198,10 @@ You have unmerged paths. (use "git merge --abort" to abort the merge) Changes to be committed: - new file: sub_master.txt Unmerged paths: (use "git rm <file>..." to mark resolution) - both deleted: main.txt Untracked files not listed (use -u option to show untracked files) diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 5990299fc9..b696bae5f5 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -249,7 +249,7 @@ test_expect_success 'checkout to detach HEAD (with advice declined)' ' test_expect_success 'checkout to detach HEAD' ' git config advice.detachedHead true && git checkout -f renamer && git clean -f && - GIT_TEST_GETTEXT_POISON= git checkout renamer^ 2>messages && + GIT_TEST_GETTEXT_POISON=false git checkout renamer^ 2>messages && grep "HEAD is now at 7329388" messages && test_line_count -gt 1 messages && H=$(git rev-parse --verify HEAD) && diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh index 7b36954d63..a2c45d1902 100755 --- a/t/t7300-clean.sh +++ b/t/t7300-clean.sh @@ -669,4 +669,16 @@ test_expect_success 'git clean -d skips untracked dirs containing ignored files' test_path_is_missing foo/b/bb ' +test_expect_success MINGW 'handle clean & core.longpaths = false nicely' ' + test_config core.longpaths false && + a50=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa && + mkdir -p $a50$a50/$a50$a50/$a50$a50 && + : >"$a50$a50/test.txt" 2>"$a50$a50/$a50$a50/$a50$a50/test.txt" && + # create a temporary outside the working tree to hide from "git clean" + test_must_fail git clean -xdf 2>.git/err && + # grepping for a strerror string is unportable but it is OK here with + # MINGW prereq + test_i18ngrep "too long" .git/err +' + test_done diff --git a/t/t7508-status.sh b/t/t7508-status.sh index 681bc314b4..4e676cdce8 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -95,18 +95,15 @@ test_expect_success 'status --column' ' # # Changes to be committed: # (use "git restore --staged <file>..." to unstage) -# # new file: dir2/added # # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git restore <file>..." to discard changes in working directory) -# # modified: dir1/modified # # Untracked files: # (use "git add <file>..." to include in what will be committed) -# # dir1/untracked dir2/untracked # dir2/modified untracked # @@ -129,18 +126,15 @@ cat >expect <<\EOF # # Changes to be committed: # (use "git restore --staged <file>..." to unstage) -# # new file: dir2/added # # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git restore <file>..." to discard changes in working directory) -# # modified: dir1/modified # # Untracked files: # (use "git add <file>..." to include in what will be committed) -# # dir1/untracked # dir2/modified # dir2/untracked @@ -279,23 +273,19 @@ and have 1 and 2 different commits each, respectively. Changes to be committed: (use "git restore --staged <file>..." to unstage) - new file: dir2/added Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) - modified: dir1/modified Untracked files: (use "git add <file>..." to include in what will be committed) - dir2/modified Ignored files: (use "git add -f <file>..." to include in what will be committed) - .gitignore dir1/untracked dir2/untracked @@ -348,18 +338,15 @@ and have 1 and 2 different commits each, respectively. Changes to be committed: (use "git restore --staged <file>..." to unstage) - new file: dir2/added Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) - modified: dir1/modified Ignored files: (use "git add -f <file>..." to include in what will be committed) - .gitignore dir1/untracked dir2/modified @@ -421,13 +408,11 @@ and have 1 and 2 different commits each, respectively. Changes to be committed: (use "git restore --staged <file>..." to unstage) - new file: dir2/added Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) - modified: dir1/modified Untracked files not listed (use -u option to show untracked files) @@ -485,18 +470,15 @@ and have 1 and 2 different commits each, respectively. Changes to be committed: (use "git restore --staged <file>..." to unstage) - new file: dir2/added Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) - modified: dir1/modified Untracked files: (use "git add <file>..." to include in what will be committed) - dir1/untracked dir2/modified dir2/untracked @@ -543,18 +525,15 @@ and have 1 and 2 different commits each, respectively. Changes to be committed: (use "git restore --staged <file>..." to unstage) - new file: dir2/added Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) - modified: dir1/modified Untracked files: (use "git add <file>..." to include in what will be committed) - dir1/untracked dir2/modified dir2/untracked @@ -606,18 +585,15 @@ and have 1 and 2 different commits each, respectively. Changes to be committed: (use "git restore --staged <file>..." to unstage) - new file: ../dir2/added Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) - modified: modified Untracked files: (use "git add <file>..." to include in what will be committed) - untracked ../dir2/modified ../dir2/untracked @@ -677,18 +653,15 @@ and have 1 and 2 different commits each, respectively. Changes to be committed: (use "git restore --staged <file>..." to unstage) - <GREEN>new file: dir2/added<RESET> Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) - <RED>modified: dir1/modified<RESET> Untracked files: (use "git add <file>..." to include in what will be committed) - <BLUE>dir1/untracked<RESET> <BLUE>dir2/modified<RESET> <BLUE>dir2/untracked<RESET> @@ -803,18 +776,15 @@ and have 1 and 2 different commits each, respectively. Changes to be committed: (use "git restore --staged <file>..." to unstage) - new file: dir2/added Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) - modified: dir1/modified Untracked files: (use "git add <file>..." to include in what will be committed) - dir1/untracked dir2/modified dir2/untracked @@ -853,12 +823,10 @@ and have 1 and 2 different commits each, respectively. Changes to be committed: (use "git restore --staged <file>..." to unstage) - modified: dir1/modified Untracked files: (use "git add <file>..." to include in what will be committed) - dir1/untracked dir2/ untracked @@ -897,19 +865,16 @@ and have 1 and 2 different commits each, respectively. Changes to be committed: (use "git restore --staged <file>..." to unstage) - new file: dir2/added new file: sm Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) - modified: dir1/modified Untracked files: (use "git add <file>..." to include in what will be committed) - dir1/untracked dir2/modified dir2/untracked @@ -957,14 +922,12 @@ and have 1 and 2 different commits each, respectively. Changes to be committed: (use "git restore --staged <file>..." to unstage) - new file: dir2/added new file: sm Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) - modified: dir1/modified Submodule changes to be committed: @@ -974,7 +937,6 @@ Submodule changes to be committed: Untracked files: (use "git add <file>..." to include in what will be committed) - dir1/untracked dir2/modified dir2/untracked @@ -1020,12 +982,10 @@ and have 2 and 2 different commits each, respectively. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) - modified: dir1/modified Untracked files: (use "git add <file>..." to include in what will be committed) - dir1/untracked dir2/modified dir2/untracked @@ -1069,14 +1029,12 @@ and have 2 and 2 different commits each, respectively. Changes to be committed: (use "git restore --source=HEAD^1 --staged <file>..." to unstage) - new file: dir2/added new file: sm Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) - modified: dir1/modified Submodule changes to be committed: @@ -1086,7 +1044,6 @@ Submodule changes to be committed: Untracked files: (use "git add <file>..." to include in what will be committed) - dir1/untracked dir2/modified dir2/untracked @@ -1124,13 +1081,11 @@ and have 2 and 2 different commits each, respectively. Changes to be committed: (use "git restore --staged <file>..." to unstage) - modified: sm Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) - modified: dir1/modified Submodule changes to be committed: @@ -1140,7 +1095,6 @@ Submodule changes to be committed: Untracked files: (use "git add <file>..." to include in what will be committed) - .gitmodules dir1/untracked dir2/modified @@ -1236,14 +1190,12 @@ and have 2 and 2 different commits each, respectively. Changes to be committed: (use "git restore --staged <file>..." to unstage) - modified: sm Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) (commit or discard the untracked or modified content in submodules) - modified: dir1/modified modified: sm (modified content) @@ -1254,7 +1206,6 @@ Submodule changes to be committed: Untracked files: (use "git add <file>..." to include in what will be committed) - .gitmodules dir1/untracked dir2/modified @@ -1296,13 +1247,11 @@ and have 2 and 2 different commits each, respectively. Changes to be committed: (use "git restore --staged <file>..." to unstage) - modified: sm Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) - modified: dir1/modified modified: sm (new commits) @@ -1318,7 +1267,6 @@ Submodules changed but not updated: Untracked files: (use "git add <file>..." to include in what will be committed) - .gitmodules dir1/untracked dir2/modified @@ -1380,13 +1328,11 @@ cat > expect << EOF ; ; Changes to be committed: ; (use "git restore --staged <file>..." to unstage) -; ; modified: sm ; ; Changes not staged for commit: ; (use "git add <file>..." to update what will be committed) ; (use "git restore <file>..." to discard changes in working directory) -; ; modified: dir1/modified ; modified: sm (new commits) ; @@ -1402,7 +1348,6 @@ cat > expect << EOF ; ; Untracked files: ; (use "git add <file>..." to include in what will be committed) -; ; .gitmodules ; dir1/untracked ; dir2/modified @@ -1432,12 +1377,10 @@ and have 2 and 2 different commits each, respectively. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) - modified: dir1/modified Untracked files: (use "git add <file>..." to include in what will be committed) - .gitmodules dir1/untracked dir2/modified @@ -1459,18 +1402,15 @@ and have 2 and 2 different commits each, respectively. Changes to be committed: (use "git restore --staged <file>..." to unstage) - modified: sm Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) - modified: dir1/modified Untracked files: (use "git add <file>..." to include in what will be committed) - .gitmodules dir1/untracked dir2/modified @@ -1582,13 +1522,11 @@ and have 2 and 2 different commits each, respectively. Changes to be committed: (use "git restore --staged <file>..." to unstage) - modified: sm Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) - modified: dir1/modified Untracked files not listed (use -u option to show untracked files) diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh index b9f5d73423..e01c285cbf 100755 --- a/t/t7512-status-help.sh +++ b/t/t7512-status-help.sh @@ -33,7 +33,6 @@ You have unmerged paths. Unmerged paths: (use "git add <file>..." to mark resolution) - both modified: main.txt no changes added to commit (use "git add" and/or "git commit -a") @@ -54,7 +53,6 @@ All conflicts fixed but you are still merging. (use "git commit" to conclude merge) Changes to be committed: - modified: main.txt Untracked files not listed (use -u option to show untracked files) @@ -87,7 +85,6 @@ You are currently rebasing branch '\''rebase_conflicts'\'' on '\''$ONTO'\''. Unmerged paths: (use "git restore --staged <file>..." to unstage) (use "git add <file>..." to mark resolution) - both modified: main.txt no changes added to commit (use "git add" and/or "git commit -a") @@ -111,7 +108,6 @@ You are currently rebasing branch '\''rebase_conflicts'\'' on '\''$ONTO'\''. Changes to be committed: (use "git restore --staged <file>..." to unstage) - modified: main.txt Untracked files not listed (use -u option to show untracked files) @@ -150,7 +146,6 @@ You are currently rebasing branch '\''rebase_i_conflicts_second'\'' on '\''$ONTO Unmerged paths: (use "git restore --staged <file>..." to unstage) (use "git add <file>..." to mark resolution) - both modified: main.txt no changes added to commit (use "git add" and/or "git commit -a") @@ -177,7 +172,6 @@ You are currently rebasing branch '\''rebase_i_conflicts_second'\'' on '\''$ONTO Changes to be committed: (use "git restore --staged <file>..." to unstage) - modified: main.txt Untracked files not listed (use -u option to show untracked files) @@ -247,7 +241,6 @@ You are currently splitting a commit while rebasing branch '\''split_commit'\'' Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) - modified: main.txt no changes added to commit (use "git add" and/or "git commit -a") @@ -355,7 +348,6 @@ You are currently splitting a commit while rebasing branch '\''several_edits'\'' Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) - modified: main.txt no changes added to commit (use "git add" and/or "git commit -a") @@ -454,7 +446,6 @@ You are currently splitting a commit while rebasing branch '\''several_edits'\'' Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) - modified: main.txt no changes added to commit (use "git add" and/or "git commit -a") @@ -558,7 +549,6 @@ You are currently splitting a commit while rebasing branch '\''several_edits'\'' Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) - modified: main.txt no changes added to commit (use "git add" and/or "git commit -a") @@ -747,7 +737,6 @@ You are currently cherry-picking commit $TO_CHERRY_PICK. Unmerged paths: (use "git add <file>..." to mark resolution) - both modified: main.txt no changes added to commit (use "git add" and/or "git commit -a") @@ -771,7 +760,6 @@ You are currently cherry-picking commit $TO_CHERRY_PICK. (use "git cherry-pick --abort" to cancel the cherry-pick operation) Changes to be committed: - modified: main.txt Untracked files not listed (use -u option to show untracked files) @@ -798,6 +786,22 @@ EOF test_i18ncmp expected actual ' +test_expect_success 'status shows cherry-pick with invalid oid' ' + mkdir .git/sequencer && + test_write_lines "pick invalid-oid" >.git/sequencer/todo && + git status --untracked-files=no >actual 2>err && + git cherry-pick --quit && + test_must_be_empty err && + test_i18ncmp expected actual +' + +test_expect_success 'status does not show error if .git/sequencer is a file' ' + test_when_finished "rm .git/sequencer" && + test_write_lines hello >.git/sequencer && + git status --untracked-files=no 2>err && + test_must_be_empty err +' + test_expect_success 'status showing detached at and from a tag' ' test_commit atag tagging && git checkout atag && @@ -836,7 +840,6 @@ You are currently reverting commit $TO_REVERT. Unmerged paths: (use "git restore --staged <file>..." to unstage) (use "git add <file>..." to mark resolution) - both modified: to-revert.txt no changes added to commit (use "git add" and/or "git commit -a") @@ -856,7 +859,6 @@ You are currently reverting commit $TO_REVERT. Changes to be committed: (use "git restore --staged <file>..." to unstage) - modified: to-revert.txt Untracked files not listed (use -u option to show untracked files) diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh index 86d05160a3..4e855bc21b 100755 --- a/t/t7700-repack.sh +++ b/t/t7700-repack.sh @@ -239,4 +239,27 @@ test_expect_success 'bitmaps can be disabled on bare repos' ' test -z "$bitmap" ' +test_expect_success 'no bitmaps created if .keep files present' ' + pack=$(ls bare.git/objects/pack/*.pack) && + test_path_is_file "$pack" && + keep=${pack%.pack}.keep && + test_when_finished "rm -f \"\$keep\"" && + >"$keep" && + git -C bare.git repack -ad 2>stderr && + test_must_be_empty stderr && + find bare.git/objects/pack/ -type f -name "*.bitmap" >actual && + test_must_be_empty actual +' + +test_expect_success 'auto-bitmaps do not complain if unavailable' ' + test_config -C bare.git pack.packSizeLimit 1M && + blob=$(test-tool genrandom big $((1024*1024)) | + git -C bare.git hash-object -w --stdin) && + git -C bare.git update-ref refs/tags/big $blob && + git -C bare.git repack -ad 2>stderr && + test_must_be_empty stderr && + find bare.git/objects/pack -type f -name "*.bitmap" >actual && + test_must_be_empty actual +' + test_done diff --git a/t/t7814-grep-recurse-submodules.sh b/t/t7814-grep-recurse-submodules.sh index 134a694516..a11366b4ce 100755 --- a/t/t7814-grep-recurse-submodules.sh +++ b/t/t7814-grep-recurse-submodules.sh @@ -14,12 +14,14 @@ test_expect_success 'setup directory structure and submodule' ' echo "(3|4)" >b/b && git add a b && git commit -m "add a and b" && + test_tick && git init submodule && echo "(1|2)d(3|4)" >submodule/a && git -C submodule add a && git -C submodule commit -m "add a" && git submodule add ./submodule && - git commit -m "added submodule" + git commit -m "added submodule" && + test_tick ' test_expect_success 'grep correctly finds patterns in a submodule' ' @@ -65,11 +67,14 @@ test_expect_success 'grep and nested submodules' ' echo "(1|2)d(3|4)" >submodule/sub/a && git -C submodule/sub add a && git -C submodule/sub commit -m "add a" && + test_tick && git -C submodule submodule add ./sub && git -C submodule add sub && git -C submodule commit -m "added sub" && + test_tick && git add submodule && git commit -m "updated submodule" && + test_tick && cat >expect <<-\EOF && a:(1|2)d(3|4) @@ -179,15 +184,18 @@ test_expect_success !MINGW 'grep recurse submodule colon in name' ' echo "(1|2)d(3|4)" >"parent/fi:le" && git -C parent add "fi:le" && git -C parent commit -m "add fi:le" && + test_tick && git init "su:b" && test_when_finished "rm -rf su:b" && echo "(1|2)d(3|4)" >"su:b/fi:le" && git -C "su:b" add "fi:le" && git -C "su:b" commit -m "add fi:le" && + test_tick && git -C parent submodule add "../su:b" "su:b" && git -C parent commit -m "add submodule" && + test_tick && cat >expect <<-\EOF && fi:le:(1|2)d(3|4) @@ -210,15 +218,18 @@ test_expect_success 'grep history with moved submoules' ' echo "(1|2)d(3|4)" >parent/file && git -C parent add file && git -C parent commit -m "add file" && + test_tick && git init sub && test_when_finished "rm -rf sub" && echo "(1|2)d(3|4)" >sub/file && git -C sub add file && git -C sub commit -m "add file" && + test_tick && git -C parent submodule add ../sub dir/sub && git -C parent commit -m "add submodule" && + test_tick && cat >expect <<-\EOF && dir/sub/file:(1|2)d(3|4) @@ -229,6 +240,7 @@ test_expect_success 'grep history with moved submoules' ' git -C parent mv dir/sub sub-moved && git -C parent commit -m "moved submodule" && + test_tick && cat >expect <<-\EOF && file:(1|2)d(3|4) @@ -251,6 +263,7 @@ test_expect_success 'grep using relative path' ' echo "(1|2)d(3|4)" >sub/file && git -C sub add file && git -C sub commit -m "add file" && + test_tick && git init parent && echo "(1|2)d(3|4)" >parent/file && @@ -260,6 +273,7 @@ test_expect_success 'grep using relative path' ' git -C parent add src/file2 && git -C parent submodule add ../sub && git -C parent commit -m "add files and submodule" && + test_tick && # From top works cat >expect <<-\EOF && @@ -293,6 +307,7 @@ test_expect_success 'grep from a subdir' ' echo "(1|2)d(3|4)" >sub/file && git -C sub add file && git -C sub commit -m "add file" && + test_tick && git init parent && mkdir parent/src && @@ -301,6 +316,7 @@ test_expect_success 'grep from a subdir' ' git -C parent submodule add ../sub src/sub && git -C parent submodule add ../sub sub && git -C parent commit -m "add files and submodules" && + test_tick && # Verify grep from root works cat >expect <<-\EOF && diff --git a/t/t8003-blame-corner-cases.sh b/t/t8003-blame-corner-cases.sh index c92a47b6d5..1c5fb1d1f8 100755 --- a/t/t8003-blame-corner-cases.sh +++ b/t/t8003-blame-corner-cases.sh @@ -275,4 +275,40 @@ test_expect_success 'blame file with CRLF core.autocrlf=true' ' grep "A U Thor" actual ' +# Tests the splitting and merging of blame entries in blame_coalesce(). +# The output of blame is the same, regardless of whether blame_coalesce() runs +# or not, so we'd likely only notice a problem if blame crashes or assigned +# blame to the "splitting" commit ('SPLIT' below). +test_expect_success 'blame coalesce' ' + cat >giraffe <<-\EOF && + ABC + DEF + EOF + git add giraffe && + git commit -m "original file" && + oid=$(git rev-parse HEAD) && + + cat >giraffe <<-\EOF && + ABC + SPLIT + DEF + EOF + git add giraffe && + git commit -m "interior SPLIT line" && + + cat >giraffe <<-\EOF && + ABC + DEF + EOF + git add giraffe && + git commit -m "same contents as original" && + + cat >expect <<-EOF && + $oid 1) ABC + $oid 2) DEF + EOF + git -c core.abbrev=40 blame -s giraffe >actual && + test_cmp expect actual +' + test_done diff --git a/t/t8013-blame-ignore-revs.sh b/t/t8013-blame-ignore-revs.sh new file mode 100755 index 0000000000..36dc31eb39 --- /dev/null +++ b/t/t8013-blame-ignore-revs.sh @@ -0,0 +1,274 @@ +#!/bin/sh + +test_description='ignore revisions when blaming' +. ./test-lib.sh + +# Creates: +# A--B--X +# A added line 1 and B added line 2. X makes changes to those lines. Sanity +# check that X is blamed for both lines. +test_expect_success setup ' + test_commit A file line1 && + + echo line2 >>file && + git add file && + test_tick && + git commit -m B && + git tag B && + + test_write_lines line-one line-two >file && + git add file && + test_tick && + git commit -m X && + git tag X && + + git blame --line-porcelain file >blame_raw && + + grep -E "^[0-9a-f]+ [0-9]+ 1" blame_raw | sed -e "s/ .*//" >actual && + git rev-parse X >expect && + test_cmp expect actual && + + grep -E "^[0-9a-f]+ [0-9]+ 2" blame_raw | sed -e "s/ .*//" >actual && + git rev-parse X >expect && + test_cmp expect actual + ' + +# Ignore X, make sure A is blamed for line 1 and B for line 2. +test_expect_success ignore_rev_changing_lines ' + git blame --line-porcelain --ignore-rev X file >blame_raw && + + grep -E "^[0-9a-f]+ [0-9]+ 1" blame_raw | sed -e "s/ .*//" >actual && + git rev-parse A >expect && + test_cmp expect actual && + + grep -E "^[0-9a-f]+ [0-9]+ 2" blame_raw | sed -e "s/ .*//" >actual && + git rev-parse B >expect && + test_cmp expect actual + ' + +# For ignored revs that have added 'unblamable' lines, attribute those to the +# ignored commit. +# A--B--X--Y +# Where Y changes lines 1 and 2, and adds lines 3 and 4. The added lines ought +# to have nothing in common with "line-one" or "line-two", to keep any +# heuristics from matching them with any lines in the parent. +test_expect_success ignore_rev_adding_unblamable_lines ' + test_write_lines line-one-change line-two-changed y3 y4 >file && + git add file && + test_tick && + git commit -m Y && + git tag Y && + + git rev-parse Y >expect && + git blame --line-porcelain file --ignore-rev Y >blame_raw && + + grep -E "^[0-9a-f]+ [0-9]+ 3" blame_raw | sed -e "s/ .*//" >actual && + test_cmp expect actual && + + grep -E "^[0-9a-f]+ [0-9]+ 4" blame_raw | sed -e "s/ .*//" >actual && + test_cmp expect actual + ' + +# Ignore X and Y, both in separate files. Lines 1 == A, 2 == B. +test_expect_success ignore_revs_from_files ' + git rev-parse X >ignore_x && + git rev-parse Y >ignore_y && + git blame --line-porcelain file --ignore-revs-file ignore_x --ignore-revs-file ignore_y >blame_raw && + + grep -E "^[0-9a-f]+ [0-9]+ 1" blame_raw | sed -e "s/ .*//" >actual && + git rev-parse A >expect && + test_cmp expect actual && + + grep -E "^[0-9a-f]+ [0-9]+ 2" blame_raw | sed -e "s/ .*//" >actual && + git rev-parse B >expect && + test_cmp expect actual + ' + +# Ignore X from the config option, Y from a file. +test_expect_success ignore_revs_from_configs_and_files ' + git config --add blame.ignoreRevsFile ignore_x && + git blame --line-porcelain file --ignore-revs-file ignore_y >blame_raw && + + grep -E "^[0-9a-f]+ [0-9]+ 1" blame_raw | sed -e "s/ .*//" >actual && + git rev-parse A >expect && + test_cmp expect actual && + + grep -E "^[0-9a-f]+ [0-9]+ 2" blame_raw | sed -e "s/ .*//" >actual && + git rev-parse B >expect && + test_cmp expect actual + ' + +# Override blame.ignoreRevsFile (ignore_x) with an empty string. X should be +# blamed now for lines 1 and 2, since we are no longer ignoring X. +test_expect_success override_ignore_revs_file ' + git blame --line-porcelain file --ignore-revs-file "" --ignore-revs-file ignore_y >blame_raw && + git rev-parse X >expect && + + grep -E "^[0-9a-f]+ [0-9]+ 1" blame_raw | sed -e "s/ .*//" >actual && + test_cmp expect actual && + + grep -E "^[0-9a-f]+ [0-9]+ 2" blame_raw | sed -e "s/ .*//" >actual && + test_cmp expect actual + ' +test_expect_success bad_files_and_revs ' + test_must_fail git blame file --ignore-rev NOREV 2>err && + test_i18ngrep "cannot find revision NOREV to ignore" err && + + test_must_fail git blame file --ignore-revs-file NOFILE 2>err && + test_i18ngrep "could not open.*: NOFILE" err && + + echo NOREV >ignore_norev && + test_must_fail git blame file --ignore-revs-file ignore_norev 2>err && + test_i18ngrep "invalid object name: NOREV" err + ' + +# For ignored revs that have added 'unblamable' lines, mark those lines with a +# '*' +# A--B--X--Y +# Lines 3 and 4 are from Y and unblamable. This was set up in +# ignore_rev_adding_unblamable_lines. +test_expect_success mark_unblamable_lines ' + git config --add blame.markUnblamableLines true && + + git blame --ignore-rev Y file >blame_raw && + echo "*" >expect && + + sed -n "3p" blame_raw | cut -c1 >actual && + test_cmp expect actual && + + sed -n "4p" blame_raw | cut -c1 >actual && + test_cmp expect actual + ' + +# Commit Z will touch the first two lines. Y touched all four. +# A--B--X--Y--Z +# The blame output when ignoring Z should be: +# ?Y ... 1) +# ?Y ... 2) +# Y ... 3) +# Y ... 4) +# We're checking only the first character +test_expect_success mark_ignored_lines ' + git config --add blame.markIgnoredLines true && + + test_write_lines line-one-Z line-two-Z y3 y4 >file && + git add file && + test_tick && + git commit -m Z && + git tag Z && + + git blame --ignore-rev Z file >blame_raw && + echo "?" >expect && + + sed -n "1p" blame_raw | cut -c1 >actual && + test_cmp expect actual && + + sed -n "2p" blame_raw | cut -c1 >actual && + test_cmp expect actual && + + sed -n "3p" blame_raw | cut -c1 >actual && + ! test_cmp expect actual && + + sed -n "4p" blame_raw | cut -c1 >actual && + ! test_cmp expect actual + ' + +# For ignored revs that added 'unblamable' lines and more recent commits changed +# the blamable lines, mark the unblamable lines with a +# '*' +# A--B--X--Y--Z +# Lines 3 and 4 are from Y and unblamable, as set up in +# ignore_rev_adding_unblamable_lines. Z changed lines 1 and 2. +test_expect_success mark_unblamable_lines_intermediate ' + git config --add blame.markUnblamableLines true && + + git blame --ignore-rev Y file >blame_raw 2>stderr && + echo "*" >expect && + + sed -n "3p" blame_raw | cut -c1 >actual && + test_cmp expect actual && + + sed -n "4p" blame_raw | cut -c1 >actual && + test_cmp expect actual + ' + +# The heuristic called by guess_line_blames() tries to find the size of a +# blame_entry 'e' in the parent's address space. Those calculations need to +# check for negative or zero values for when a blame entry is completely outside +# the window of the parent's version of a file. +# +# This happens when one commit adds several lines (commit B below). A later +# commit (C) changes one line in the middle of B's change. Commit C gets blamed +# for its change, and that breaks up B's change into multiple blame entries. +# When processing B, one of the blame_entries is outside A's window (which was +# zero - it had no lines added on its side of the diff). +# +# A--B--C, ignore B to test the ignore heuristic's boundary checks. +test_expect_success ignored_chunk_negative_parent_size ' + rm -rf .git/ && + git init && + + test_write_lines L1 L2 L7 L8 L9 >file && + git add file && + test_tick && + git commit -m A && + git tag A && + + test_write_lines L1 L2 L3 L4 L5 L6 L7 L8 L9 >file && + git add file && + test_tick && + git commit -m B && + git tag B && + + test_write_lines L1 L2 L3 L4 xxx L6 L7 L8 L9 >file && + git add file && + test_tick && + git commit -m C && + git tag C && + + git blame file --ignore-rev B >blame_raw + ' + +# Resetting the repo and creating: +# +# A--B--M +# \ / +# C-+ +# +# 'A' creates a file. B changes line 1, and C changes line 9. M merges. +test_expect_success ignore_merge ' + rm -rf .git/ && + git init && + + test_write_lines L1 L2 L3 L4 L5 L6 L7 L8 L9 >file && + git add file && + test_tick && + git commit -m A && + git tag A && + + test_write_lines BB L2 L3 L4 L5 L6 L7 L8 L9 >file && + git add file && + test_tick && + git commit -m B && + git tag B && + + git reset --hard A && + test_write_lines L1 L2 L3 L4 L5 L6 L7 L8 CC >file && + git add file && + test_tick && + git commit -m C && + git tag C && + + test_merge M B && + git blame --line-porcelain file --ignore-rev M >blame_raw && + + grep -E "^[0-9a-f]+ [0-9]+ 1" blame_raw | sed -e "s/ .*//" >actual && + git rev-parse B >expect && + test_cmp expect actual && + + grep -E "^[0-9a-f]+ [0-9]+ 9" blame_raw | sed -e "s/ .*//" >actual && + git rev-parse C >expect && + test_cmp expect actual + ' + +test_done diff --git a/t/t8014-blame-ignore-fuzzy.sh b/t/t8014-blame-ignore-fuzzy.sh new file mode 100755 index 0000000000..6e61882b6f --- /dev/null +++ b/t/t8014-blame-ignore-fuzzy.sh @@ -0,0 +1,437 @@ +#!/bin/sh + +test_description='git blame ignore fuzzy heuristic' +. ./test-lib.sh + +pick_author='s/^[0-9a-f^]* *(\([^ ]*\) .*/\1/' + +# Each test is composed of 4 variables: +# titleN - the test name +# aN - the initial content +# bN - the final content +# expectedN - the line numbers from aN that we expect git blame +# on bN to identify, or "Final" if bN itself should +# be identified as the origin of that line. + +# We start at test 2 because setup will show as test 1 +title2="Regression test for partially overlapping search ranges" +cat <<EOF >a2 +1 +2 +3 +abcdef +5 +6 +7 +ijkl +9 +10 +11 +pqrs +13 +14 +15 +wxyz +17 +18 +19 +EOF +cat <<EOF >b2 +abcde +ijk +pqr +wxy +EOF +cat <<EOF >expected2 +4 +8 +12 +16 +EOF + +title3="Combine 3 lines into 2" +cat <<EOF >a3 +if ((maxgrow==0) || + ( single_line_field && (field->dcols < maxgrow)) || + (!single_line_field && (field->drows < maxgrow))) +EOF +cat <<EOF >b3 +if ((maxgrow == 0) || (single_line_field && (field->dcols < maxgrow)) || + (!single_line_field && (field->drows < maxgrow))) { +EOF +cat <<EOF >expected3 +2 +3 +EOF + +title4="Add curly brackets" +cat <<EOF >a4 + if (rows) *rows = field->rows; + if (cols) *cols = field->cols; + if (frow) *frow = field->frow; + if (fcol) *fcol = field->fcol; +EOF +cat <<EOF >b4 + if (rows) { + *rows = field->rows; + } + if (cols) { + *cols = field->cols; + } + if (frow) { + *frow = field->frow; + } + if (fcol) { + *fcol = field->fcol; + } +EOF +cat <<EOF >expected4 +1 +1 +Final +2 +2 +Final +3 +3 +Final +4 +4 +Final +EOF + + +title5="Combine many lines and change case" +cat <<EOF >a5 +for(row=0,pBuffer=field->buf; + row<height; + row++,pBuffer+=width ) +{ + if ((len = (int)( After_End_Of_Data( pBuffer, width ) - pBuffer )) > 0) + { + wmove( win, row, 0 ); + waddnstr( win, pBuffer, len ); +EOF +cat <<EOF >b5 +for (Row = 0, PBuffer = field->buf; Row < Height; Row++, PBuffer += Width) { + if ((Len = (int)(afterEndOfData(PBuffer, Width) - PBuffer)) > 0) { + wmove(win, Row, 0); + waddnstr(win, PBuffer, Len); +EOF +cat <<EOF >expected5 +1 +5 +7 +8 +EOF + +title6="Rename and combine lines" +cat <<EOF >a6 +bool need_visual_update = ((form != (FORM *)0) && + (form->status & _POSTED) && + (form->current==field)); + +if (need_visual_update) + Synchronize_Buffer(form); + +if (single_line_field) +{ + growth = field->cols * amount; + if (field->maxgrow) + growth = Minimum(field->maxgrow - field->dcols,growth); + field->dcols += growth; + if (field->dcols == field->maxgrow) +EOF +cat <<EOF >b6 +bool NeedVisualUpdate = ((Form != (FORM *)0) && (Form->status & _POSTED) && + (Form->current == field)); + +if (NeedVisualUpdate) { + synchronizeBuffer(Form); +} + +if (SingleLineField) { + Growth = field->cols * amount; + if (field->maxgrow) { + Growth = Minimum(field->maxgrow - field->dcols, Growth); + } + field->dcols += Growth; + if (field->dcols == field->maxgrow) { +EOF +cat <<EOF >expected6 +1 +3 +4 +5 +6 +Final +7 +8 +10 +11 +12 +Final +13 +14 +EOF + +# Both lines match identically so position must be used to tie-break. +title7="Same line twice" +cat <<EOF >a7 +abc +abc +EOF +cat <<EOF >b7 +abcd +abcd +EOF +cat <<EOF >expected7 +1 +2 +EOF + +title8="Enforce line order" +cat <<EOF >a8 +abcdef +ghijkl +ab +EOF +cat <<EOF >b8 +ghijk +abcd +EOF +cat <<EOF >expected8 +2 +3 +EOF + +title9="Expand lines and rename variables" +cat <<EOF >a9 +int myFunction(int ArgumentOne, Thing *ArgTwo, Blah XuglyBug) { + Squiggle FabulousResult = squargle(ArgumentOne, *ArgTwo, + XuglyBug) + EwwwGlobalWithAReallyLongNameYepTooLong; + return FabulousResult * 42; +} +EOF +cat <<EOF >b9 +int myFunction(int argument_one, Thing *arg_asdfgh, + Blah xugly_bug) { + Squiggle fabulous_result = squargle(argument_one, + *arg_asdfgh, xugly_bug) + + g_ewww_global_with_a_really_long_name_yep_too_long; + return fabulous_result * 42; +} +EOF +cat <<EOF >expected9 +1 +1 +2 +3 +3 +4 +5 +EOF + +title10="Two close matches versus one less close match" +cat <<EOF >a10 +abcdef +abcdef +ghijkl +EOF +cat <<EOF >b10 +gh +abcdefx +EOF +cat <<EOF >expected10 +Final +2 +EOF + +# The first line of b matches best with the last line of a, but the overall +# match is better if we match it with the the first line of a. +title11="Piggy in the middle" +cat <<EOF >a11 +abcdefg +ijklmn +abcdefgh +EOF +cat <<EOF >b11 +abcdefghx +ijklm +EOF +cat <<EOF >expected11 +1 +2 +EOF + +title12="No trailing newline" +printf "abc\ndef" >a12 +printf "abx\nstu" >b12 +cat <<EOF >expected12 +1 +Final +EOF + +title13="Reorder includes" +cat <<EOF >a13 +#include "c.h" +#include "b.h" +#include "a.h" +#include "e.h" +#include "d.h" +EOF +cat <<EOF >b13 +#include "a.h" +#include "b.h" +#include "c.h" +#include "d.h" +#include "e.h" +EOF +cat <<EOF >expected13 +3 +2 +1 +5 +4 +EOF + +last_test=13 + +test_expect_success setup ' + for i in $(test_seq 2 $last_test) + do + # Append each line in a separate commit to make it easy to + # check which original line the blame output relates to. + + line_count=0 && + while IFS= read line + do + line_count=$((line_count+1)) && + echo "$line" >>"$i" && + git add "$i" && + test_tick && + GIT_AUTHOR_NAME="$line_count" git commit -m "$line_count" + done <"a$i" + done && + + for i in $(test_seq 2 $last_test) + do + # Overwrite the files with the final content. + cp b$i $i && + git add $i + done && + test_tick && + + # Commit the final content all at once so it can all be + # referred to with the same commit ID. + GIT_AUTHOR_NAME=Final git commit -m Final && + + IGNOREME=$(git rev-parse HEAD) +' + +for i in $(test_seq 2 $last_test); do + eval title="\$title$i" + test_expect_success "$title" \ + "git blame -M9 --ignore-rev $IGNOREME $i >output && + sed -e \"$pick_author\" output >actual && + test_cmp expected$i actual" +done + +# This invoked a null pointer dereference when the chunk callback was called +# with a zero length parent chunk and there were no more suspects. +test_expect_success 'Diff chunks with no suspects' ' + test_write_lines xy1 A B C xy1 >file && + git add file && + test_tick && + GIT_AUTHOR_NAME=1 git commit -m 1 && + + test_write_lines xy2 A B xy2 C xy2 >file && + git add file && + test_tick && + GIT_AUTHOR_NAME=2 git commit -m 2 && + REV_2=$(git rev-parse HEAD) && + + test_write_lines xy3 A >file && + git add file && + test_tick && + GIT_AUTHOR_NAME=3 git commit -m 3 && + REV_3=$(git rev-parse HEAD) && + + test_write_lines 1 1 >expected && + + git blame --ignore-rev $REV_2 --ignore-rev $REV_3 file >output && + sed -e "$pick_author" output >actual && + + test_cmp expected actual + ' + +test_expect_success 'position matching' ' + test_write_lines abc def >file2 && + git add file2 && + test_tick && + GIT_AUTHOR_NAME=1 git commit -m 1 && + + test_write_lines abc def abc def >file2 && + git add file2 && + test_tick && + GIT_AUTHOR_NAME=2 git commit -m 2 && + + test_write_lines abcx defx abcx defx >file2 && + git add file2 && + test_tick && + GIT_AUTHOR_NAME=3 git commit -m 3 && + REV_3=$(git rev-parse HEAD) && + + test_write_lines abcy defy abcx defx >file2 && + git add file2 && + test_tick && + GIT_AUTHOR_NAME=4 git commit -m 4 && + REV_4=$(git rev-parse HEAD) && + + test_write_lines 1 1 2 2 >expected && + + git blame --ignore-rev $REV_3 --ignore-rev $REV_4 file2 >output && + sed -e "$pick_author" output >actual && + + test_cmp expected actual + ' + +# This fails if each blame entry is processed independently instead of +# processing each diff change in full. +test_expect_success 'preserve order' ' + test_write_lines bcde >file3 && + git add file3 && + test_tick && + GIT_AUTHOR_NAME=1 git commit -m 1 && + + test_write_lines bcde fghij >file3 && + git add file3 && + test_tick && + GIT_AUTHOR_NAME=2 git commit -m 2 && + + test_write_lines bcde fghij abcd >file3 && + git add file3 && + test_tick && + GIT_AUTHOR_NAME=3 git commit -m 3 && + + test_write_lines abcdx fghijx bcdex >file3 && + git add file3 && + test_tick && + GIT_AUTHOR_NAME=4 git commit -m 4 && + REV_4=$(git rev-parse HEAD) && + + test_write_lines abcdx fghijy bcdex >file3 && + git add file3 && + test_tick && + GIT_AUTHOR_NAME=5 git commit -m 5 && + REV_5=$(git rev-parse HEAD) && + + test_write_lines 1 2 3 >expected && + + git blame --ignore-rev $REV_4 --ignore-rev $REV_5 file3 >output && + sed -e "$pick_author" output >actual && + + test_cmp expected actual + ' + +test_done diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 43cf313a1c..75512c3403 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -1706,7 +1706,7 @@ test_expect_success 'sourcing the completion script clears cached commands' ' ' test_expect_success 'sourcing the completion script clears cached merge strategies' ' - GIT_TEST_GETTEXT_POISON= && + GIT_TEST_GETTEXT_POISON=false && __git_compute_merge_strategies && verbose test -n "$__git_merge_strategies" && . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" && diff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh index 5cadedb2a9..88bc733ad6 100755 --- a/t/t9903-bash-prompt.sh +++ b/t/t9903-bash-prompt.sh @@ -211,8 +211,24 @@ test_expect_success 'prompt - merge' ' test_expect_success 'prompt - cherry-pick' ' printf " (master|CHERRY-PICKING)" >expected && - test_must_fail git cherry-pick b1 && - test_when_finished "git reset --hard" && + test_must_fail git cherry-pick b1 b1^ && + test_when_finished "git cherry-pick --abort" && + __git_ps1 >"$actual" && + test_cmp expected "$actual" && + git reset --merge && + test_must_fail git rev-parse CHERRY_PICK_HEAD && + __git_ps1 >"$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - revert' ' + printf " (master|REVERTING)" >expected && + test_must_fail git revert b1^ b1 && + test_when_finished "git revert --abort" && + __git_ps1 >"$actual" && + test_cmp expected "$actual" && + git reset --merge && + test_must_fail git rev-parse REVERT_HEAD && __git_ps1 >"$actual" && test_cmp expected "$actual" ' diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index 7308f67922..48bd3b467d 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -233,6 +233,129 @@ test_merge () { git tag "$1" } +# Efficiently create <nr> commits, each with a unique number (from 1 to <nr> +# by default) in the commit message. +# +# Usage: test_commit_bulk [options] <nr> +# -C <dir>: +# Run all git commands in directory <dir> +# --ref=<n>: +# ref on which to create commits (default: HEAD) +# --start=<n>: +# number commit messages from <n> (default: 1) +# --message=<msg>: +# use <msg> as the commit mesasge (default: "commit %s") +# --filename=<fn>: +# modify <fn> in each commit (default: %s.t) +# --contents=<string>: +# place <string> in each file (default: "content %s") +# --id=<string>: +# shorthand to use <string> and %s in message, filename, and contents +# +# The message, filename, and contents strings are evaluated by printf, with the +# first "%s" replaced by the current commit number. So you can do: +# +# test_commit_bulk --filename=file --contents="modification %s" +# +# to have every commit touch the same file, but with unique content. +# +test_commit_bulk () { + tmpfile=.bulk-commit.input + indir=. + ref=HEAD + n=1 + message='commit %s' + filename='%s.t' + contents='content %s' + while test $# -gt 0 + do + case "$1" in + -C) + indir=$2 + shift + ;; + --ref=*) + ref=${1#--*=} + ;; + --start=*) + n=${1#--*=} + ;; + --message=*) + message=${1#--*=} + ;; + --filename=*) + filename=${1#--*=} + ;; + --contents=*) + contents=${1#--*=} + ;; + --id=*) + message="${1#--*=} %s" + filename="${1#--*=}-%s.t" + contents="${1#--*=} %s" + ;; + -*) + BUG "invalid test_commit_bulk option: $1" + ;; + *) + break + ;; + esac + shift + done + total=$1 + + add_from= + if git -C "$indir" rev-parse --verify "$ref" + then + add_from=t + fi + + while test "$total" -gt 0 + do + test_tick && + echo "commit $ref" + printf 'author %s <%s> %s\n' \ + "$GIT_AUTHOR_NAME" \ + "$GIT_AUTHOR_EMAIL" \ + "$GIT_AUTHOR_DATE" + printf 'committer %s <%s> %s\n' \ + "$GIT_COMMITTER_NAME" \ + "$GIT_COMMITTER_EMAIL" \ + "$GIT_COMMITTER_DATE" + echo "data <<EOF" + printf "$message\n" $n + echo "EOF" + if test -n "$add_from" + then + echo "from $ref^0" + add_from= + fi + printf "M 644 inline $filename\n" $n + echo "data <<EOF" + printf "$contents\n" $n + echo "EOF" + echo + n=$((n + 1)) + total=$((total - 1)) + done >"$tmpfile" + + git -C "$indir" \ + -c fastimport.unpacklimit=0 \ + fast-import <"$tmpfile" || return 1 + + # This will be left in place on failure, which may aid debugging. + rm -f "$tmpfile" + + # If we updated HEAD, then be nice and update the index and working + # tree, too. + if test "$ref" = "HEAD" + then + git -C "$indir" checkout -f HEAD || return 1 + fi + +} + # This function helps systems where core.filemode=false is set. # Use it instead of plain 'chmod +x' to set or unset the executable bit # of a file in the working directory and add it to the index. @@ -309,7 +432,7 @@ test_unset_prereq () { } test_set_prereq () { - if test -n "$GIT_TEST_FAIL_PREREQS" + if test -n "$GIT_TEST_FAIL_PREREQS_INTERNAL" then case "$1" in # The "!" case is handled below with @@ -1050,62 +1173,20 @@ perl () { command "$PERL_PATH" "$@" 2>&7 } 7>&2 2>&4 -# Is the value one of the various ways to spell a boolean true/false? -test_normalize_bool () { - git -c magic.variable="$1" config --bool magic.variable 2>/dev/null -} - -# Given a variable $1, normalize the value of it to one of "true", -# "false", or "auto" and store the result to it. -# -# test_tristate GIT_TEST_HTTPD -# -# A variable set to an empty string is set to 'false'. -# A variable set to 'false' or 'auto' keeps its value. -# Anything else is set to 'true'. -# An unset variable defaults to 'auto'. -# -# The last rule is to allow people to set the variable to an empty -# string and export it to decline testing the particular feature -# for versions both before and after this change. We used to treat -# both unset and empty variable as a signal for "do not test" and -# took any non-empty string as "please test". - -test_tristate () { - if eval "test x\"\${$1+isset}\" = xisset" - then - # explicitly set - eval " - case \"\$$1\" in - '') $1=false ;; - auto) ;; - *) $1=\$(test_normalize_bool \$$1 || echo true) ;; - esac - " - else - eval "$1=auto" - fi -} - # Exit the test suite, either by skipping all remaining tests or by -# exiting with an error. If "$1" is "auto", we then we assume we were -# opportunistically trying to set up some tests and we skip. If it is -# "true", then we report a failure. +# exiting with an error. If our prerequisite variable $1 falls back +# on a default assume we were opportunistically trying to set up some +# tests and we skip. If it is explicitly "true", then we report a failure. # # The error/skip message should be given by $2. # test_skip_or_die () { - case "$1" in - auto) + if ! git env--helper --type=bool --default=false --exit-code $1 + then skip_all=$2 test_done - ;; - true) - error "$2" - ;; - *) - error "BUG: test tristate is '$1' (real error: $2)" - esac + fi + error "$2" } # The following mingw_* functions obey POSIX shell syntax, but are actually @@ -1349,6 +1430,12 @@ test_oid () { eval "printf '%s' \"\${$var}\"" } +# Insert a slash into an object ID so it can be used to reference a location +# under ".git/objects". For example, "deadbeef..." becomes "de/adbeef..". +test_oid_to_path () { + echo "${1%${1#??}}/${1#??}" +} + # Choose a port number based on the test script's number and store it in # the given variable name, unless that variable already contains a number. test_set_port () { diff --git a/t/test-lib.sh b/t/test-lib.sh index d1ba33745a..30b07e310f 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -1388,6 +1388,25 @@ yes () { done } +# The GIT_TEST_FAIL_PREREQS code hooks into test_set_prereq(), and +# thus needs to be set up really early, and set an internal variable +# for convenience so the hot test_set_prereq() codepath doesn't need +# to call "git env--helper". Only do that work if needed by seeing if +# GIT_TEST_FAIL_PREREQS is set at all. +GIT_TEST_FAIL_PREREQS_INTERNAL= +if test -n "$GIT_TEST_FAIL_PREREQS" +then + if git env--helper --type=bool --default=0 --exit-code GIT_TEST_FAIL_PREREQS + then + GIT_TEST_FAIL_PREREQS_INTERNAL=true + test_set_prereq FAIL_PREREQS + fi +else + test_lazy_prereq FAIL_PREREQS ' + git env--helper --type=bool --default=0 --exit-code GIT_TEST_FAIL_PREREQS + ' +fi + # Fix some commands on Windows uname_s=$(uname -s) case $uname_s in @@ -1442,11 +1461,9 @@ then unset GIT_TEST_GETTEXT_POISON_ORIG fi -# Can we rely on git's output in the C locale? -if test -z "$GIT_TEST_GETTEXT_POISON" -then - test_set_prereq C_LOCALE_OUTPUT -fi +test_lazy_prereq C_LOCALE_OUTPUT ' + ! git env--helper --type=bool --default=0 --exit-code GIT_TEST_GETTEXT_POISON +' if test -z "$GIT_TEST_CHECK_CACHE_TREE" then @@ -1606,7 +1623,3 @@ test_lazy_prereq SHA1 ' test_lazy_prereq REBASE_P ' test -z "$GIT_TEST_SKIP_REBASE_P" ' - -test_lazy_prereq FAIL_PREREQS ' - test -n "$GIT_TEST_FAIL_PREREQS" -' |