summaryrefslogtreecommitdiff
path: root/t
diff options
context:
space:
mode:
Diffstat (limited to 't')
-rw-r--r--t/README14
-rw-r--r--t/helper/test-dump-untracked-cache.c4
-rw-r--r--t/helper/test-hashmap.c53
-rw-r--r--t/helper/test-run-command.c9
-rw-r--r--t/helper/test-wildmatch.c2
-rw-r--r--t/lib-git-daemon.sh41
-rwxr-xr-xt/perf/aggregate.perl50
-rwxr-xr-xt/t0002-gitfile.sh53
-rwxr-xr-xt/t0008-ignores.sh22
-rwxr-xr-xt/t0050-filesystem.sh16
-rwxr-xr-xt/t0061-run-command.sh37
-rwxr-xr-xt/t0205-gettext-poison.sh4
-rwxr-xr-xt/t0410-partial-clone.sh343
-rwxr-xr-xt/t1300-repo-config.sh23
-rwxr-xr-xt/t1506-rev-parse-diagnosis.sh2
-rwxr-xr-xt/t1700-split-index.sh38
-rwxr-xr-xt/t2025-worktree-add.sh54
-rwxr-xr-xt/t3070-wildmatch.sh655
-rwxr-xr-xt/t3400-rebase.sh34
-rwxr-xr-xt/t3404-rebase-interactive.sh22
-rwxr-xr-xt/t3405-rebase-malformed.sh23
-rwxr-xr-xt/t3408-rebase-multi-line.sh26
-rwxr-xr-xt/t3501-revert-cherry-pick.sh7
-rwxr-xr-xt/t3512-cherry-pick-submodule.sh1
-rwxr-xr-xt/t3513-revert-submodule.sh1
-rwxr-xr-xt/t4001-diff-rename.sh11
-rwxr-xr-xt/t4052-stat-output.sh46
-rwxr-xr-xt/t4135-apply-weird-filenames.sh17
-rwxr-xr-xt/t4150-am.sh17
-rwxr-xr-xt/t5500-fetch-pack.sh63
-rwxr-xr-xt/t5510-fetch.sh247
-rwxr-xr-xt/t5526-fetch-submodules.sh2
-rwxr-xr-xt/t5536-fetch-conflicts.sh2
-rwxr-xr-xt/t5541-http-push-smart.sh2
-rwxr-xr-xt/t5545-push-options.sh40
-rwxr-xr-xt/t5551-http-fetch-smart.sh33
-rwxr-xr-xt/t5570-git-daemon.sh37
-rwxr-xr-xt/t5601-clone.sh101
-rwxr-xr-xt/t5616-partial-clone.sh146
-rwxr-xr-xt/t5812-proto-disable-http.sh5
-rwxr-xr-xt/t6015-rev-list-show-all-parents.sh31
-rwxr-xr-xt/t6022-merge-rename.sh6
-rwxr-xr-xt/t6120-describe.sh8
-rwxr-xr-xt/t6200-fmt-merge-msg.sh2
-rwxr-xr-xt/t6300-for-each-ref.sh7
-rwxr-xr-xt/t7001-mv.sh6
-rwxr-xr-xt/t7004-tag.sh30
-rwxr-xr-xt/t7063-status-untracked-cache.sh87
-rwxr-xr-xt/t7409-submodule-detached-work-tree.sh2
-rwxr-xr-xt/t7505-prepare-commit-msg-hook.sh134
-rw-r--r--t/t7505/expected-rebase-i17
-rw-r--r--t/t7505/expected-rebase-p18
-rwxr-xr-xt/t7519-status-fsmonitor.sh39
-rwxr-xr-xt/t7600-merge.sh38
-rwxr-xr-xt/t7607-merge-overwrite.sh5
-rwxr-xr-xt/t9001-send-email.sh17
-rw-r--r--t/test-lib-functions.sh110
-rw-r--r--t/test-lib.sh33
58 files changed, 2353 insertions, 540 deletions
diff --git a/t/README b/t/README
index b3f7b44..1a1361a 100644
--- a/t/README
+++ b/t/README
@@ -655,7 +655,7 @@ library for your script to use.
test_expect_code 1 git merge "merge msg" B master
'
- - test_must_fail <git-command>
+ - test_must_fail [<options>] <git-command>
Run a git command and ensure it fails in a controlled way. Use
this instead of "! <git-command>". When git-command dies due to a
@@ -663,11 +663,21 @@ library for your script to use.
treats it as just another expected failure, which would let such a
bug go unnoticed.
- - test_might_fail <git-command>
+ Accepts the following options:
+
+ ok=<signal-name>[,<...>]:
+ Don't treat an exit caused by the given signal as error.
+ Multiple signals can be specified as a comma separated list.
+ Currently recognized signal names are: sigpipe, success.
+ (Don't use 'success', use 'test_might_fail' instead.)
+
+ - test_might_fail [<options>] <git-command>
Similar to test_must_fail, but tolerate success, too. Use this
instead of "<git-command> || :" to catch failures due to segv.
+ Accepts the same options as test_must_fail.
+
- test_cmp <expected> <actual>
Check whether the content of the <actual> file matches the
diff --git a/t/helper/test-dump-untracked-cache.c b/t/helper/test-dump-untracked-cache.c
index f752532..d7c55c2 100644
--- a/t/helper/test-dump-untracked-cache.c
+++ b/t/helper/test-dump-untracked-cache.c
@@ -54,8 +54,8 @@ int cmd_main(int ac, const char **av)
printf("no untracked cache\n");
return 0;
}
- printf("info/exclude %s\n", sha1_to_hex(uc->ss_info_exclude.sha1));
- printf("core.excludesfile %s\n", sha1_to_hex(uc->ss_excludes_file.sha1));
+ printf("info/exclude %s\n", oid_to_hex(&uc->ss_info_exclude.oid));
+ printf("core.excludesfile %s\n", oid_to_hex(&uc->ss_excludes_file.oid));
printf("exclude_per_dir %s\n", uc->exclude_per_dir);
printf("flags %08x\n", uc->dir_flags);
if (uc->root)
diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c
index 1145d51..9ae9281 100644
--- a/t/helper/test-hashmap.c
+++ b/t/helper/test-hashmap.c
@@ -1,5 +1,6 @@
#include "git-compat-util.h"
#include "hashmap.h"
+#include "strbuf.h"
struct test_entry
{
@@ -29,11 +30,12 @@ static int test_entry_cmp(const void *cmp_data,
return strcmp(e1->key, key ? key : e2->key);
}
-static struct test_entry *alloc_test_entry(int hash, char *key, int klen,
- char *value, int vlen)
+static struct test_entry *alloc_test_entry(unsigned int hash,
+ char *key, char *value)
{
- struct test_entry *entry = malloc(sizeof(struct test_entry) + klen
- + vlen + 2);
+ size_t klen = strlen(key);
+ size_t vlen = strlen(value);
+ struct test_entry *entry = xmalloc(st_add4(sizeof(*entry), klen, vlen, 2));
hashmap_entry_init(entry, hash);
memcpy(entry->key, key, klen + 1);
memcpy(entry->key + klen + 1, value, vlen + 1);
@@ -85,11 +87,11 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
unsigned int *hashes;
unsigned int i, j;
- entries = malloc(TEST_SIZE * sizeof(struct test_entry *));
- hashes = malloc(TEST_SIZE * sizeof(int));
+ ALLOC_ARRAY(entries, TEST_SIZE);
+ ALLOC_ARRAY(hashes, TEST_SIZE);
for (i = 0; i < TEST_SIZE; i++) {
- snprintf(buf, sizeof(buf), "%i", i);
- entries[i] = alloc_test_entry(0, buf, strlen(buf), "", 0);
+ xsnprintf(buf, sizeof(buf), "%i", i);
+ entries[i] = alloc_test_entry(0, buf, "");
hashes[i] = hash(method, i, entries[i]->key);
}
@@ -144,7 +146,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
*/
int cmd_main(int argc, const char **argv)
{
- char line[1024];
+ struct strbuf line = STRBUF_INIT;
struct hashmap map;
int icase;
@@ -153,44 +155,42 @@ int cmd_main(int argc, const char **argv)
hashmap_init(&map, test_entry_cmp, &icase, 0);
/* process commands from stdin */
- while (fgets(line, sizeof(line), stdin)) {
+ while (strbuf_getline(&line, stdin) != EOF) {
char *cmd, *p1 = NULL, *p2 = NULL;
- int l1 = 0, l2 = 0, hash = 0;
+ unsigned int hash = 0;
struct test_entry *entry;
/* break line into command and up to two parameters */
- cmd = strtok(line, DELIM);
+ cmd = strtok(line.buf, DELIM);
/* ignore empty lines */
if (!cmd || *cmd == '#')
continue;
p1 = strtok(NULL, DELIM);
if (p1) {
- l1 = strlen(p1);
hash = icase ? strihash(p1) : strhash(p1);
p2 = strtok(NULL, DELIM);
- if (p2)
- l2 = strlen(p2);
}
- if (!strcmp("hash", cmd) && l1) {
+ if (!strcmp("hash", cmd) && p1) {
/* print results of different hash functions */
- printf("%u %u %u %u\n", strhash(p1), memhash(p1, l1),
- strihash(p1), memihash(p1, l1));
+ printf("%u %u %u %u\n",
+ strhash(p1), memhash(p1, strlen(p1)),
+ strihash(p1), memihash(p1, strlen(p1)));
- } else if (!strcmp("add", cmd) && l1 && l2) {
+ } else if (!strcmp("add", cmd) && p1 && p2) {
/* create entry with key = p1, value = p2 */
- entry = alloc_test_entry(hash, p1, l1, p2, l2);
+ entry = alloc_test_entry(hash, p1, p2);
/* add to hashmap */
hashmap_add(&map, entry);
- } else if (!strcmp("put", cmd) && l1 && l2) {
+ } else if (!strcmp("put", cmd) && p1 && p2) {
/* create entry with key = p1, value = p2 */
- entry = alloc_test_entry(hash, p1, l1, p2, l2);
+ entry = alloc_test_entry(hash, p1, p2);
/* add / replace entry */
entry = hashmap_put(&map, entry);
@@ -199,7 +199,7 @@ int cmd_main(int argc, const char **argv)
puts(entry ? get_value(entry) : "NULL");
free(entry);
- } else if (!strcmp("get", cmd) && l1) {
+ } else if (!strcmp("get", cmd) && p1) {
/* lookup entry in hashmap */
entry = hashmap_get_from_hash(&map, hash, p1);
@@ -212,7 +212,7 @@ int cmd_main(int argc, const char **argv)
entry = hashmap_get_next(&map, entry);
}
- } else if (!strcmp("remove", cmd) && l1) {
+ } else if (!strcmp("remove", cmd) && p1) {
/* setup static key */
struct hashmap_entry key;
@@ -238,7 +238,7 @@ int cmd_main(int argc, const char **argv)
printf("%u %u\n", map.tablesize,
hashmap_get_size(&map));
- } else if (!strcmp("intern", cmd) && l1) {
+ } else if (!strcmp("intern", cmd) && p1) {
/* test that strintern works */
const char *i1 = strintern(p1);
@@ -252,7 +252,7 @@ int cmd_main(int argc, const char **argv)
else
printf("%s\n", i1);
- } else if (!strcmp("perfhashmap", cmd) && l1 && l2) {
+ } else if (!strcmp("perfhashmap", cmd) && p1 && p2) {
perf_hashmap(atoi(p1), atoi(p2));
@@ -263,6 +263,7 @@ int cmd_main(int argc, const char **argv)
}
}
+ strbuf_release(&line);
hashmap_free(&map, 1);
return 0;
}
diff --git a/t/helper/test-run-command.c b/t/helper/test-run-command.c
index d24d157..153342e 100644
--- a/t/helper/test-run-command.c
+++ b/t/helper/test-run-command.c
@@ -56,6 +56,15 @@ int cmd_main(int argc, const char **argv)
if (argc < 3)
return 1;
+ while (!strcmp(argv[1], "env")) {
+ if (!argv[2])
+ die("env specifier without a value");
+ argv_array_push(&proc.env_array, argv[2]);
+ argv += 2;
+ argc -= 2;
+ }
+ if (argc < 3)
+ return 1;
proc.argv = (const char **)argv + 2;
if (!strcmp(argv[1], "start-command-ENOENT")) {
diff --git a/t/helper/test-wildmatch.c b/t/helper/test-wildmatch.c
index 921d7b3..66d33df 100644
--- a/t/helper/test-wildmatch.c
+++ b/t/helper/test-wildmatch.c
@@ -16,6 +16,8 @@ int cmd_main(int argc, const char **argv)
return !!wildmatch(argv[3], argv[2], WM_PATHNAME | WM_CASEFOLD);
else if (!strcmp(argv[1], "pathmatch"))
return !!wildmatch(argv[3], argv[2], 0);
+ else if (!strcmp(argv[1], "ipathmatch"))
+ return !!wildmatch(argv[3], argv[2], WM_CASEFOLD);
else
return 1;
}
diff --git a/t/lib-git-daemon.sh b/t/lib-git-daemon.sh
index 987d406..edbea2d 100644
--- a/t/lib-git-daemon.sh
+++ b/t/lib-git-daemon.sh
@@ -32,7 +32,8 @@ LIB_GIT_DAEMON_PORT=${LIB_GIT_DAEMON_PORT-${this_test#t}}
GIT_DAEMON_PID=
GIT_DAEMON_DOCUMENT_ROOT_PATH="$PWD"/repo
-GIT_DAEMON_URL=git://127.0.0.1:$LIB_GIT_DAEMON_PORT
+GIT_DAEMON_HOST_PORT=127.0.0.1:$LIB_GIT_DAEMON_PORT
+GIT_DAEMON_URL=git://$GIT_DAEMON_HOST_PORT
start_git_daemon() {
if test -n "$GIT_DAEMON_PID"
@@ -53,11 +54,19 @@ start_git_daemon() {
"$@" "$GIT_DAEMON_DOCUMENT_ROOT_PATH" \
>&3 2>git_daemon_output &
GIT_DAEMON_PID=$!
+ >daemon.log
{
- read line <&7
- echo >&4 "$line"
- cat <&7 >&4 &
- } 7<git_daemon_output &&
+ read -r line <&7
+ printf "%s\n" "$line"
+ printf >&4 "%s\n" "$line"
+ (
+ while read -r line <&7
+ do
+ printf "%s\n" "$line"
+ printf >&4 "%s\n" "$line"
+ done
+ ) &
+ } 7<git_daemon_output >>"$TRASH_DIRECTORY/daemon.log" &&
# Check expected output
if test x"$(expr "$line" : "\[[0-9]*\] \(.*\)")" != x"Ready to rumble"
@@ -90,3 +99,25 @@ stop_git_daemon() {
GIT_DAEMON_PID=
rm -f git_daemon_output
}
+
+# A stripped-down version of a netcat client, that connects to a "host:port"
+# given in $1, sends its stdin followed by EOF, then dumps the response (until
+# EOF) to stdout.
+fake_nc() {
+ if ! test_declared_prereq FAKENC
+ then
+ echo >&4 "fake_nc: need to declare FAKENC prerequisite"
+ return 127
+ fi
+ perl -Mstrict -MIO::Socket::INET -e '
+ my $s = IO::Socket::INET->new(shift)
+ or die "unable to open socket: $!";
+ print $s <STDIN>;
+ $s->shutdown(1);
+ print <$s>;
+ ' "$@"
+}
+
+test_lazy_prereq FAKENC '
+ perl -MIO::Socket::INET -e "exit 0"
+'
diff --git a/t/perf/aggregate.perl b/t/perf/aggregate.perl
index 5c439f6..821cf14 100755
--- a/t/perf/aggregate.perl
+++ b/t/perf/aggregate.perl
@@ -1,6 +1,6 @@
#!/usr/bin/perl
-use lib '../../perl/blib/lib';
+use lib '../../perl/build/lib';
use strict;
use warnings;
use JSON;
@@ -36,7 +36,8 @@ sub format_times {
return $out;
}
-my (@dirs, %dirnames, %dirabbrevs, %prefixes, @tests, $codespeed);
+my (@dirs, %dirnames, %dirabbrevs, %prefixes, @tests,
+ $codespeed, $subsection, $reponame);
while (scalar @ARGV) {
my $arg = $ARGV[0];
my $dir;
@@ -45,6 +46,24 @@ while (scalar @ARGV) {
shift @ARGV;
next;
}
+ if ($arg eq "--subsection") {
+ shift @ARGV;
+ $subsection = $ARGV[0];
+ shift @ARGV;
+ if (! $subsection) {
+ die "empty subsection";
+ }
+ next;
+ }
+ if ($arg eq "--reponame") {
+ shift @ARGV;
+ $reponame = $ARGV[0];
+ shift @ARGV;
+ if (! $reponame) {
+ die "empty reponame";
+ }
+ next;
+ }
last if -f $arg or $arg eq "--";
if (! -d $arg) {
my $rev = Git::command_oneline(qw(rev-parse --verify), $arg);
@@ -76,10 +95,15 @@ if (not @tests) {
}
my $resultsdir = "test-results";
-my $results_section = "";
-if (exists $ENV{GIT_PERF_SUBSECTION} and $ENV{GIT_PERF_SUBSECTION} ne "") {
- $resultsdir .= "/" . $ENV{GIT_PERF_SUBSECTION};
- $results_section = $ENV{GIT_PERF_SUBSECTION};
+
+if (! $subsection and
+ exists $ENV{GIT_PERF_SUBSECTION} and
+ $ENV{GIT_PERF_SUBSECTION} ne "") {
+ $subsection = $ENV{GIT_PERF_SUBSECTION};
+}
+
+if ($subsection) {
+ $resultsdir .= "/" . $subsection;
}
my @subtests;
@@ -183,19 +207,21 @@ sub print_default_results {
}
sub print_codespeed_results {
- my ($results_section) = @_;
+ my ($subsection) = @_;
my $project = "Git";
my $executable = `uname -s -m`;
chomp $executable;
- if ($results_section ne "") {
- $executable .= ", " . $results_section;
+ if ($subsection) {
+ $executable .= ", " . $subsection;
}
my $environment;
- if (exists $ENV{GIT_PERF_REPO_NAME} and $ENV{GIT_PERF_REPO_NAME} ne "") {
+ if ($reponame) {
+ $environment = $reponame;
+ } elsif (exists $ENV{GIT_PERF_REPO_NAME} and $ENV{GIT_PERF_REPO_NAME} ne "") {
$environment = $ENV{GIT_PERF_REPO_NAME};
} elsif (exists $ENV{GIT_TEST_INSTALLED} and $ENV{GIT_TEST_INSTALLED} ne "") {
$environment = $ENV{GIT_TEST_INSTALLED};
@@ -227,13 +253,13 @@ sub print_codespeed_results {
}
}
- print to_json(\@data, {utf8 => 1, pretty => 1}), "\n";
+ print to_json(\@data, {utf8 => 1, pretty => 1, canonical => 1}), "\n";
}
binmode STDOUT, ":utf8" or die "PANIC on binmode: $!";
if ($codespeed) {
- print_codespeed_results($results_section);
+ print_codespeed_results($subsection);
} else {
print_default_results();
}
diff --git a/t/t0002-gitfile.sh b/t/t0002-gitfile.sh
index 9670e8c..3691023 100755
--- a/t/t0002-gitfile.sh
+++ b/t/t0002-gitfile.sh
@@ -10,15 +10,6 @@ objpath() {
echo "$1" | sed -e 's|\(..\)|\1/|'
}
-objck() {
- p=$(objpath "$1")
- if test ! -f "$REAL/objects/$p"
- then
- echo "Object not found: $REAL/objects/$p"
- false
- fi
-}
-
test_expect_success 'initial setup' '
REAL="$(pwd)/.real" &&
mv .git "$REAL"
@@ -26,30 +17,14 @@ test_expect_success 'initial setup' '
test_expect_success 'bad setup: invalid .git file format' '
echo "gitdir $REAL" >.git &&
- if git rev-parse 2>.err
- then
- echo "git rev-parse accepted an invalid .git file"
- false
- fi &&
- if ! grep "Invalid gitfile format" .err
- then
- echo "git rev-parse returned wrong error"
- false
- fi
+ test_must_fail git rev-parse 2>.err &&
+ test_i18ngrep "invalid gitfile format" .err
'
test_expect_success 'bad setup: invalid .git file path' '
echo "gitdir: $REAL.not" >.git &&
- if git rev-parse 2>.err
- then
- echo "git rev-parse accepted an invalid .git file path"
- false
- fi &&
- if ! grep "Not a git repository" .err
- then
- echo "git rev-parse returned wrong error"
- false
- fi
+ test_must_fail git rev-parse 2>.err &&
+ test_i18ngrep "not a git repository" .err
'
test_expect_success 'final setup + check rev-parse --git-dir' '
@@ -60,7 +35,7 @@ test_expect_success 'final setup + check rev-parse --git-dir' '
test_expect_success 'check hash-object' '
echo "foo" >bar &&
SHA=$(cat bar | git hash-object -w --stdin) &&
- objck $SHA
+ test_path_is_file "$REAL/objects/$(objpath $SHA)"
'
test_expect_success 'check cat-file' '
@@ -69,29 +44,21 @@ test_expect_success 'check cat-file' '
'
test_expect_success 'check update-index' '
- if test -f "$REAL/index"
- then
- echo "Hmm, $REAL/index exists?"
- false
- fi &&
+ test_path_is_missing "$REAL/index" &&
rm -f "$REAL/objects/$(objpath $SHA)" &&
git update-index --add bar &&
- if ! test -f "$REAL/index"
- then
- echo "$REAL/index not found"
- false
- fi &&
- objck $SHA
+ test_path_is_file "$REAL/index" &&
+ test_path_is_file "$REAL/objects/$(objpath $SHA)"
'
test_expect_success 'check write-tree' '
SHA=$(git write-tree) &&
- objck $SHA
+ test_path_is_file "$REAL/objects/$(objpath $SHA)"
'
test_expect_success 'check commit-tree' '
SHA=$(echo "commit bar" | git commit-tree $SHA) &&
- objck $SHA
+ test_path_is_file "$REAL/objects/$(objpath $SHA)"
'
test_expect_success 'check rev-list' '
diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh
index d27f438..c03f155 100755
--- a/t/t0008-ignores.sh
+++ b/t/t0008-ignores.sh
@@ -307,7 +307,7 @@ test_expect_success_multi 'needs work tree' '' '
cd .git &&
test_check_ignore "foo" 128
) &&
- stderr_contains "fatal: This operation must be run in a work tree"
+ stderr_contains "fatal: this operation must be run in a work tree"
'
############################################################################
@@ -775,6 +775,26 @@ test_expect_success PIPE 'streaming support for --stdin' '
echo "$response" | grep "^:: two"
'
+test_expect_success 'existing file and directory' '
+ test_when_finished "rm one" &&
+ test_when_finished "rmdir top-level-dir" &&
+ >one &&
+ mkdir top-level-dir &&
+ git check-ignore one top-level-dir >actual &&
+ grep one actual &&
+ grep top-level-dir actual
+'
+
+test_expect_success 'existing directory and file' '
+ test_when_finished "rm one" &&
+ test_when_finished "rmdir top-level-dir" &&
+ >one &&
+ mkdir top-level-dir &&
+ git check-ignore top-level-dir one >actual &&
+ grep one actual &&
+ grep top-level-dir actual
+'
+
############################################################################
#
# test whitespace handling
diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh
index b29d749..192c94e 100755
--- a/t/t0050-filesystem.sh
+++ b/t/t0050-filesystem.sh
@@ -80,7 +80,21 @@ test_expect_success 'merge (case change)' '
git merge topic
'
-
+test_expect_success CASE_INSENSITIVE_FS 'add directory (with different case)' '
+ git reset --hard initial &&
+ mkdir -p dir1/dir2 &&
+ echo >dir1/dir2/a &&
+ echo >dir1/dir2/b &&
+ git add dir1/dir2/a &&
+ git add dir1/DIR2/b &&
+ git ls-files >actual &&
+ cat >expected <<-\EOF &&
+ camelcase
+ dir1/dir2/a
+ dir1/dir2/b
+ EOF
+ test_cmp expected actual
+'
test_expect_failure CASE_INSENSITIVE_FS 'add (with different case)' '
git reset --hard initial &&
diff --git a/t/t0061-run-command.sh b/t/t0061-run-command.sh
index e473917..24c92b6 100755
--- a/t/t0061-run-command.sh
+++ b/t/t0061-run-command.sh
@@ -141,4 +141,41 @@ test_expect_success 'run_command outputs ' '
test_cmp expect actual
'
+test_trace () {
+ expect="$1"
+ shift
+ GIT_TRACE=1 test-run-command "$@" run-command true 2>&1 >/dev/null | \
+ sed 's/.* run_command: //' >actual &&
+ echo "$expect true" >expect &&
+ test_cmp expect actual
+}
+
+test_expect_success 'GIT_TRACE with environment variables' '
+ test_trace "abc=1 def=2" env abc=1 env def=2 &&
+ test_trace "abc=2" env abc env abc=1 env abc=2 &&
+ test_trace "abc=2" env abc env abc=2 &&
+ (
+ abc=1 && export abc &&
+ test_trace "def=1" env abc=1 env def=1
+ ) &&
+ (
+ abc=1 && export abc &&
+ test_trace "def=1" env abc env abc=1 env def=1
+ ) &&
+ test_trace "def=1" env non-exist env def=1 &&
+ test_trace "abc=2" env abc=1 env abc env abc=2 &&
+ (
+ abc=1 def=2 && export abc def &&
+ test_trace "unset abc def;" env abc env def
+ ) &&
+ (
+ abc=1 def=2 && export abc def &&
+ test_trace "unset def; abc=3" env abc env def env abc=3
+ ) &&
+ (
+ abc=1 && export abc &&
+ test_trace "unset abc;" env abc=2 env abc
+ )
+'
+
test_done
diff --git a/t/t0205-gettext-poison.sh b/t/t0205-gettext-poison.sh
index 2361590..438e778 100755
--- a/t/t0205-gettext-poison.sh
+++ b/t/t0205-gettext-poison.sh
@@ -7,10 +7,6 @@ test_description='Gettext Shell poison'
. ./lib-gettext.sh
-test_expect_success GETTEXT_POISON "sanity: \$GIT_INTERNAL_GETTEXT_SH_SCHEME is set (to $GIT_INTERNAL_GETTEXT_SH_SCHEME)" '
- test -n "$GIT_INTERNAL_GETTEXT_SH_SCHEME"
-'
-
test_expect_success GETTEXT_POISON 'sanity: $GIT_INTERNAL_GETTEXT_SH_SCHEME" is poison' '
test "$GIT_INTERNAL_GETTEXT_SH_SCHEME" = "poison"
'
diff --git a/t/t0410-partial-clone.sh b/t/t0410-partial-clone.sh
new file mode 100755
index 0000000..cc18b75
--- /dev/null
+++ b/t/t0410-partial-clone.sh
@@ -0,0 +1,343 @@
+#!/bin/sh
+
+test_description='partial clone'
+
+. ./test-lib.sh
+
+delete_object () {
+ rm $1/.git/objects/$(echo $2 | sed -e 's|^..|&/|')
+}
+
+pack_as_from_promisor () {
+ HASH=$(git -C repo pack-objects .git/objects/pack/pack) &&
+ >repo/.git/objects/pack/pack-$HASH.promisor &&
+ echo $HASH
+}
+
+promise_and_delete () {
+ HASH=$(git -C repo rev-parse "$1") &&
+ git -C repo tag -a -m message my_annotated_tag "$HASH" &&
+ git -C repo rev-parse my_annotated_tag | pack_as_from_promisor &&
+ # tag -d prints a message to stdout, so redirect it
+ git -C repo tag -d my_annotated_tag >/dev/null &&
+ delete_object repo "$HASH"
+}
+
+test_expect_success 'missing reflog object, but promised by a commit, passes fsck' '
+ test_create_repo repo &&
+ test_commit -C repo my_commit &&
+
+ A=$(git -C repo commit-tree -m a HEAD^{tree}) &&
+ C=$(git -C repo commit-tree -m c -p $A HEAD^{tree}) &&
+
+ # Reference $A only from reflog, and delete it
+ git -C repo branch my_branch "$A" &&
+ git -C repo branch -f my_branch my_commit &&
+ delete_object repo "$A" &&
+
+ # State that we got $C, which refers to $A, from promisor
+ printf "$C\n" | pack_as_from_promisor &&
+
+ # Normally, it fails
+ test_must_fail git -C repo fsck &&
+
+ # But with the extension, it succeeds
+ git -C repo config core.repositoryformatversion 1 &&
+ git -C repo config extensions.partialclone "arbitrary string" &&
+ git -C repo fsck
+'
+
+test_expect_success 'missing reflog object, but promised by a tag, passes fsck' '
+ rm -rf repo &&
+ test_create_repo repo &&
+ test_commit -C repo my_commit &&
+
+ A=$(git -C repo commit-tree -m a HEAD^{tree}) &&
+ git -C repo tag -a -m d my_tag_name $A &&
+ T=$(git -C repo rev-parse my_tag_name) &&
+ git -C repo tag -d my_tag_name &&
+
+ # Reference $A only from reflog, and delete it
+ git -C repo branch my_branch "$A" &&
+ git -C repo branch -f my_branch my_commit &&
+ delete_object repo "$A" &&
+
+ # State that we got $T, which refers to $A, from promisor
+ printf "$T\n" | pack_as_from_promisor &&
+
+ git -C repo config core.repositoryformatversion 1 &&
+ git -C repo config extensions.partialclone "arbitrary string" &&
+ git -C repo fsck
+'
+
+test_expect_success 'missing reflog object alone fails fsck, even with extension set' '
+ rm -rf repo &&
+ test_create_repo repo &&
+ test_commit -C repo my_commit &&
+
+ A=$(git -C repo commit-tree -m a HEAD^{tree}) &&
+ B=$(git -C repo commit-tree -m b HEAD^{tree}) &&
+
+ # Reference $A only from reflog, and delete it
+ git -C repo branch my_branch "$A" &&
+ git -C repo branch -f my_branch my_commit &&
+ delete_object repo "$A" &&
+
+ git -C repo config core.repositoryformatversion 1 &&
+ git -C repo config extensions.partialclone "arbitrary string" &&
+ test_must_fail git -C repo fsck
+'
+
+test_expect_success 'missing ref object, but promised, passes fsck' '
+ rm -rf repo &&
+ test_create_repo repo &&
+ test_commit -C repo my_commit &&
+
+ A=$(git -C repo commit-tree -m a HEAD^{tree}) &&
+
+ # Reference $A only from ref
+ git -C repo branch my_branch "$A" &&
+ promise_and_delete "$A" &&
+
+ git -C repo config core.repositoryformatversion 1 &&
+ git -C repo config extensions.partialclone "arbitrary string" &&
+ git -C repo fsck
+'
+
+test_expect_success 'missing object, but promised, passes fsck' '
+ rm -rf repo &&
+ test_create_repo repo &&
+ test_commit -C repo 1 &&
+ test_commit -C repo 2 &&
+ test_commit -C repo 3 &&
+ git -C repo tag -a annotated_tag -m "annotated tag" &&
+
+ C=$(git -C repo rev-parse 1) &&
+ T=$(git -C repo rev-parse 2^{tree}) &&
+ B=$(git hash-object repo/3.t) &&
+ AT=$(git -C repo rev-parse annotated_tag) &&
+
+ promise_and_delete "$C" &&
+ promise_and_delete "$T" &&
+ promise_and_delete "$B" &&
+ promise_and_delete "$AT" &&
+
+ git -C repo config core.repositoryformatversion 1 &&
+ git -C repo config extensions.partialclone "arbitrary string" &&
+ git -C repo fsck
+'
+
+test_expect_success 'missing CLI object, but promised, passes fsck' '
+ rm -rf repo &&
+ test_create_repo repo &&
+ test_commit -C repo my_commit &&
+
+ A=$(git -C repo commit-tree -m a HEAD^{tree}) &&
+ promise_and_delete "$A" &&
+
+ git -C repo config core.repositoryformatversion 1 &&
+ git -C repo config extensions.partialclone "arbitrary string" &&
+ git -C repo fsck "$A"
+'
+
+test_expect_success 'fetching of missing objects' '
+ rm -rf repo &&
+ test_create_repo server &&
+ test_commit -C server foo &&
+ git -C server repack -a -d --write-bitmap-index &&
+
+ git clone "file://$(pwd)/server" repo &&
+ HASH=$(git -C repo rev-parse foo) &&
+ rm -rf repo/.git/objects/* &&
+
+ git -C repo config core.repositoryformatversion 1 &&
+ git -C repo config extensions.partialclone "origin" &&
+ git -C repo cat-file -p "$HASH" &&
+
+ # Ensure that the .promisor file is written, and check that its
+ # associated packfile contains the object
+ ls repo/.git/objects/pack/pack-*.promisor >promisorlist &&
+ test_line_count = 1 promisorlist &&
+ IDX=$(cat promisorlist | sed "s/promisor$/idx/") &&
+ git verify-pack --verbose "$IDX" | grep "$HASH"
+'
+
+test_expect_success 'rev-list stops traversal at missing and promised commit' '
+ rm -rf repo &&
+ test_create_repo repo &&
+ test_commit -C repo foo &&
+ test_commit -C repo bar &&
+
+ FOO=$(git -C repo rev-parse foo) &&
+ promise_and_delete "$FOO" &&
+
+ git -C repo config core.repositoryformatversion 1 &&
+ git -C repo config extensions.partialclone "arbitrary string" &&
+ git -C repo rev-list --exclude-promisor-objects --objects bar >out &&
+ grep $(git -C repo rev-parse bar) out &&
+ ! grep $FOO out
+'
+
+test_expect_success 'rev-list stops traversal at missing and promised tree' '
+ rm -rf repo &&
+ test_create_repo repo &&
+ test_commit -C repo foo &&
+ mkdir repo/a_dir &&
+ echo something >repo/a_dir/something &&
+ git -C repo add a_dir/something &&
+ git -C repo commit -m bar &&
+
+ # foo^{tree} (tree referenced from commit)
+ TREE=$(git -C repo rev-parse foo^{tree}) &&
+
+ # a tree referenced by HEAD^{tree} (tree referenced from tree)
+ TREE2=$(git -C repo ls-tree HEAD^{tree} | grep " tree " | head -1 | cut -b13-52) &&
+
+ promise_and_delete "$TREE" &&
+ promise_and_delete "$TREE2" &&
+
+ git -C repo config core.repositoryformatversion 1 &&
+ git -C repo config extensions.partialclone "arbitrary string" &&
+ git -C repo rev-list --exclude-promisor-objects --objects HEAD >out &&
+ grep $(git -C repo rev-parse foo) out &&
+ ! grep $TREE out &&
+ grep $(git -C repo rev-parse HEAD) out &&
+ ! grep $TREE2 out
+'
+
+test_expect_success 'rev-list stops traversal at missing and promised blob' '
+ rm -rf repo &&
+ test_create_repo repo &&
+ echo something >repo/something &&
+ git -C repo add something &&
+ git -C repo commit -m foo &&
+
+ BLOB=$(git -C repo hash-object -w something) &&
+ promise_and_delete "$BLOB" &&
+
+ git -C repo config core.repositoryformatversion 1 &&
+ git -C repo config extensions.partialclone "arbitrary string" &&
+ git -C repo rev-list --exclude-promisor-objects --objects HEAD >out &&
+ grep $(git -C repo rev-parse HEAD) out &&
+ ! grep $BLOB out
+'
+
+test_expect_success 'rev-list stops traversal at promisor commit, tree, and blob' '
+ rm -rf repo &&
+ test_create_repo repo &&
+ test_commit -C repo foo &&
+ test_commit -C repo bar &&
+ test_commit -C repo baz &&
+
+ COMMIT=$(git -C repo rev-parse foo) &&
+ TREE=$(git -C repo rev-parse bar^{tree}) &&
+ BLOB=$(git hash-object repo/baz.t) &&
+ printf "%s\n%s\n%s\n" $COMMIT $TREE $BLOB | pack_as_from_promisor &&
+
+ git -C repo config core.repositoryformatversion 1 &&
+ git -C repo config extensions.partialclone "arbitrary string" &&
+ git -C repo rev-list --exclude-promisor-objects --objects HEAD >out &&
+ ! grep $COMMIT out &&
+ ! grep $TREE out &&
+ ! grep $BLOB out &&
+ grep $(git -C repo rev-parse bar) out # sanity check that some walking was done
+'
+
+test_expect_success 'rev-list accepts missing and promised objects on command line' '
+ rm -rf repo &&
+ test_create_repo repo &&
+ test_commit -C repo foo &&
+ test_commit -C repo bar &&
+ test_commit -C repo baz &&
+
+ COMMIT=$(git -C repo rev-parse foo) &&
+ TREE=$(git -C repo rev-parse bar^{tree}) &&
+ BLOB=$(git hash-object repo/baz.t) &&
+
+ promise_and_delete $COMMIT &&
+ promise_and_delete $TREE &&
+ promise_and_delete $BLOB &&
+
+ git -C repo config core.repositoryformatversion 1 &&
+ git -C repo config extensions.partialclone "arbitrary string" &&
+ git -C repo rev-list --exclude-promisor-objects --objects "$COMMIT" "$TREE" "$BLOB"
+'
+
+test_expect_success 'gc does not repack promisor objects' '
+ rm -rf repo &&
+ test_create_repo repo &&
+ test_commit -C repo my_commit &&
+
+ TREE_HASH=$(git -C repo rev-parse HEAD^{tree}) &&
+ HASH=$(printf "$TREE_HASH\n" | pack_as_from_promisor) &&
+
+ git -C repo config core.repositoryformatversion 1 &&
+ git -C repo config extensions.partialclone "arbitrary string" &&
+ git -C repo gc &&
+
+ # Ensure that the promisor packfile still exists, and remove it
+ test -e repo/.git/objects/pack/pack-$HASH.pack &&
+ rm repo/.git/objects/pack/pack-$HASH.* &&
+
+ # Ensure that the single other pack contains the commit, but not the tree
+ ls repo/.git/objects/pack/pack-*.pack >packlist &&
+ test_line_count = 1 packlist &&
+ git verify-pack repo/.git/objects/pack/pack-*.pack -v >out &&
+ grep "$(git -C repo rev-parse HEAD)" out &&
+ ! grep "$TREE_HASH" out
+'
+
+test_expect_success 'gc stops traversal when a missing but promised object is reached' '
+ rm -rf repo &&
+ test_create_repo repo &&
+ test_commit -C repo my_commit &&
+
+ TREE_HASH=$(git -C repo rev-parse HEAD^{tree}) &&
+ HASH=$(promise_and_delete $TREE_HASH) &&
+
+ git -C repo config core.repositoryformatversion 1 &&
+ git -C repo config extensions.partialclone "arbitrary string" &&
+ git -C repo gc &&
+
+ # Ensure that the promisor packfile still exists, and remove it
+ test -e repo/.git/objects/pack/pack-$HASH.pack &&
+ rm repo/.git/objects/pack/pack-$HASH.* &&
+
+ # Ensure that the single other pack contains the commit, but not the tree
+ ls repo/.git/objects/pack/pack-*.pack >packlist &&
+ test_line_count = 1 packlist &&
+ git verify-pack repo/.git/objects/pack/pack-*.pack -v >out &&
+ grep "$(git -C repo rev-parse HEAD)" out &&
+ ! grep "$TREE_HASH" out
+'
+
+LIB_HTTPD_PORT=12345 # default port, 410, cannot be used as non-root
+. "$TEST_DIRECTORY"/lib-httpd.sh
+start_httpd
+
+test_expect_success 'fetching of missing objects from an HTTP server' '
+ rm -rf repo &&
+ SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" &&
+ test_create_repo "$SERVER" &&
+ test_commit -C "$SERVER" foo &&
+ git -C "$SERVER" repack -a -d --write-bitmap-index &&
+
+ git clone $HTTPD_URL/smart/server repo &&
+ HASH=$(git -C repo rev-parse foo) &&
+ rm -rf repo/.git/objects/* &&
+
+ git -C repo config core.repositoryformatversion 1 &&
+ git -C repo config extensions.partialclone "origin" &&
+ git -C repo cat-file -p "$HASH" &&
+
+ # Ensure that the .promisor file is written, and check that its
+ # associated packfile contains the object
+ ls repo/.git/objects/pack/pack-*.promisor >promisorlist &&
+ test_line_count = 1 promisorlist &&
+ IDX=$(cat promisorlist | sed "s/promisor$/idx/") &&
+ git verify-pack --verbose "$IDX" | grep "$HASH"
+'
+
+stop_httpd
+
+test_done
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index cbeb9be..4f8e6f5 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -1206,6 +1206,29 @@ test_expect_success 'git -c is not confused by empty environment' '
GIT_CONFIG_PARAMETERS="" git -c x.one=1 config --list
'
+sq="'"
+test_expect_success 'detect bogus GIT_CONFIG_PARAMETERS' '
+ cat >expect <<-\EOF &&
+ env.one one
+ env.two two
+ EOF
+ GIT_CONFIG_PARAMETERS="${sq}env.one=one${sq} ${sq}env.two=two${sq}" \
+ git config --get-regexp "env.*" >actual &&
+ test_cmp expect actual &&
+
+ cat >expect <<-EOF &&
+ env.one one${sq}
+ env.two two
+ EOF
+ GIT_CONFIG_PARAMETERS="${sq}env.one=one${sq}\\$sq$sq$sq ${sq}env.two=two${sq}" \
+ git config --get-regexp "env.*" >actual &&
+ test_cmp expect actual &&
+
+ test_must_fail env \
+ GIT_CONFIG_PARAMETERS="${sq}env.one=one${sq}\\$sq ${sq}env.two=two${sq}" \
+ git config --get-regexp "env.*"
+'
+
test_expect_success 'git config --edit works' '
git config -f tmp test.value no &&
echo test.value=yes >expect &&
diff --git a/t/t1506-rev-parse-diagnosis.sh b/t/t1506-rev-parse-diagnosis.sh
index 79a0251..4ee009d 100755
--- a/t/t1506-rev-parse-diagnosis.sh
+++ b/t/t1506-rev-parse-diagnosis.sh
@@ -157,7 +157,7 @@ test_expect_success 'relative path not found' '
test_expect_success 'relative path outside worktree' '
test_must_fail git rev-parse HEAD:../file.txt >output 2>error &&
test -z "$(cat output)" &&
- grep "outside repository" error
+ test_i18ngrep "outside repository" error
'
test_expect_success 'relative path when cwd is outside worktree' '
diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh
index af9b847..a66936f 100755
--- a/t/t1700-split-index.sh
+++ b/t/t1700-split-index.sh
@@ -401,4 +401,42 @@ done <<\EOF
0642 -rw-r---w-
EOF
+test_expect_success POSIXPERM,SANITY 'graceful handling when splitting index is not allowed' '
+ test_create_repo ro &&
+ (
+ cd ro &&
+ test_commit initial &&
+ git update-index --split-index &&
+ test -f .git/sharedindex.*
+ ) &&
+ cp ro/.git/index new-index &&
+ test_when_finished "chmod u+w ro/.git" &&
+ chmod u-w ro/.git &&
+ GIT_INDEX_FILE="$(pwd)/new-index" git -C ro update-index --split-index &&
+ chmod u+w ro/.git &&
+ rm ro/.git/sharedindex.* &&
+ GIT_INDEX_FILE=new-index git ls-files >actual &&
+ echo initial.t >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'writing split index with null sha1 does not write cache tree' '
+ git config core.splitIndex true &&
+ git config splitIndex.maxPercentChange 0 &&
+ git commit -m "commit" &&
+ {
+ git ls-tree HEAD &&
+ printf "160000 commit $_z40\\tbroken\\n"
+ } >broken-tree &&
+ echo "add broken entry" >msg &&
+
+ tree=$(git mktree <broken-tree) &&
+ test_tick &&
+ commit=$(git commit-tree $tree -p HEAD <msg) &&
+ git update-ref HEAD "$commit" &&
+ GIT_ALLOW_NULL_SHA1=1 git reset --hard &&
+ (test-dump-cache-tree >cache-tree.out || true) &&
+ test_line_count = 0 cache-tree.out
+'
+
test_done
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 2b95944..d0d2e4f 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -451,32 +451,68 @@ test_expect_success 'git worktree --no-guess-remote option overrides config' '
'
post_checkout_hook () {
- test_when_finished "rm -f .git/hooks/post-checkout" &&
- mkdir -p .git/hooks &&
- write_script .git/hooks/post-checkout <<-\EOF
- echo $* >hook.actual
+ gitdir=${1:-.git}
+ test_when_finished "rm -f $gitdir/hooks/post-checkout" &&
+ mkdir -p $gitdir/hooks &&
+ write_script $gitdir/hooks/post-checkout <<-\EOF
+ {
+ echo $*
+ git rev-parse --git-dir --show-toplevel
+ } >hook.actual
EOF
}
test_expect_success '"add" invokes post-checkout hook (branch)' '
post_checkout_hook &&
- printf "%s %s 1\n" $_z40 $(git rev-parse HEAD) >hook.expect &&
+ {
+ echo $_z40 $(git rev-parse HEAD) 1 &&
+ echo $(pwd)/.git/worktrees/gumby &&
+ echo $(pwd)/gumby
+ } >hook.expect &&
git worktree add gumby &&
- test_cmp hook.expect hook.actual
+ test_cmp hook.expect gumby/hook.actual
'
test_expect_success '"add" invokes post-checkout hook (detached)' '
post_checkout_hook &&
- printf "%s %s 1\n" $_z40 $(git rev-parse HEAD) >hook.expect &&
+ {
+ echo $_z40 $(git rev-parse HEAD) 1 &&
+ echo $(pwd)/.git/worktrees/grumpy &&
+ echo $(pwd)/grumpy
+ } >hook.expect &&
git worktree add --detach grumpy &&
- test_cmp hook.expect hook.actual
+ test_cmp hook.expect grumpy/hook.actual
'
test_expect_success '"add --no-checkout" suppresses post-checkout hook' '
post_checkout_hook &&
rm -f hook.actual &&
git worktree add --no-checkout gloopy &&
- test_path_is_missing hook.actual
+ test_path_is_missing gloopy/hook.actual
+'
+
+test_expect_success '"add" in other worktree invokes post-checkout hook' '
+ post_checkout_hook &&
+ {
+ echo $_z40 $(git rev-parse HEAD) 1 &&
+ echo $(pwd)/.git/worktrees/guppy &&
+ echo $(pwd)/guppy
+ } >hook.expect &&
+ git -C gloopy worktree add --detach ../guppy &&
+ test_cmp hook.expect guppy/hook.actual
+'
+
+test_expect_success '"add" in bare repo invokes post-checkout hook' '
+ rm -rf bare &&
+ git clone --bare . bare &&
+ {
+ echo $_z40 $(git --git-dir=bare rev-parse HEAD) 1 &&
+ echo $(pwd)/bare/worktrees/goozy &&
+ echo $(pwd)/goozy
+ } >hook.expect &&
+ post_checkout_hook bare &&
+ git -C bare worktree add --detach ../goozy &&
+ test_cmp hook.expect goozy/hook.actual
'
test_done
diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh
index 163a14a..c1fc6ca 100755
--- a/t/t3070-wildmatch.sh
+++ b/t/t3070-wildmatch.sh
@@ -4,266 +4,431 @@ test_description='wildmatch tests'
. ./test-lib.sh
-match() {
- if [ $1 = 1 ]; then
- test_expect_success "wildmatch: match '$3' '$4'" "
- test-wildmatch wildmatch '$3' '$4'
- "
- else
- test_expect_success "wildmatch: no match '$3' '$4'" "
- ! test-wildmatch wildmatch '$3' '$4'
- "
- fi
+should_create_test_file() {
+ file=$1
+
+ case $file in
+ # `touch .` will succeed but obviously not do what we intend
+ # here.
+ ".")
+ return 1
+ ;;
+ # We cannot create a file with an empty filename.
+ "")
+ return 1
+ ;;
+ # The tests that are testing that e.g. foo//bar is matched by
+ # foo/*/bar can't be tested on filesystems since there's no
+ # way we're getting a double slash.
+ *//*)
+ return 1
+ ;;
+ # When testing the difference between foo/bar and foo/bar/ we
+ # can't test the latter.
+ */)
+ return 1
+ ;;
+ # On Windows, \ in paths is silently converted to /, which
+ # would result in the "touch" below working, but the test
+ # itself failing. See 6fd1106aa4 ("t3700: Skip a test with
+ # backslashes in pathspec", 2009-03-13) for prior art and
+ # details.
+ *\\*)
+ if ! test_have_prereq BSLASHPSPEC
+ then
+ return 1
+ fi
+ # NOTE: The ;;& bash extension is not portable, so
+ # this test needs to be at the end of the pattern
+ # list.
+ #
+ # If we want to add more conditional returns we either
+ # need a new case statement, or turn this whole thing
+ # into a series of "if" tests.
+ ;;
+ esac
+
+
+ # On Windows proper (i.e. not Cygwin) many file names which
+ # under Cygwin would be emulated don't work.
+ if test_have_prereq MINGW
+ then
+ case $file in
+ " ")
+ # Files called " " are forbidden on Windows
+ return 1
+ ;;
+ *\<*|*\>*|*:*|*\"*|*\|*|*\?*|*\**)
+ # Files with various special characters aren't
+ # allowed on Windows. Sourced from
+ # https://stackoverflow.com/a/31976060
+ return 1
+ ;;
+ esac
+ fi
+
+ return 0
}
-imatch() {
- if [ $1 = 1 ]; then
- test_expect_success "iwildmatch: match '$2' '$3'" "
- test-wildmatch iwildmatch '$2' '$3'
- "
- else
- test_expect_success "iwildmatch: no match '$2' '$3'" "
- ! test-wildmatch iwildmatch '$2' '$3'
- "
- fi
+match_with_function() {
+ text=$1
+ pattern=$2
+ match_expect=$3
+ match_function=$4
+
+ if test "$match_expect" = 1
+ then
+ test_expect_success "$match_function: match '$text' '$pattern'" "
+ test-wildmatch $match_function '$text' '$pattern'
+ "
+ elif test "$match_expect" = 0
+ then
+ test_expect_success "$match_function: no match '$text' '$pattern'" "
+ test_must_fail test-wildmatch $match_function '$text' '$pattern'
+ "
+ else
+ test_expect_success "PANIC: Test framework error. Unknown matches value $match_expect" 'false'
+ fi
+
+}
+
+match_with_ls_files() {
+ text=$1
+ pattern=$2
+ match_expect=$3
+ match_function=$4
+ ls_files_args=$5
+
+ match_stdout_stderr_cmp="
+ tr -d '\0' <actual.raw >actual &&
+ >expect.err &&
+ test_cmp expect.err actual.err &&
+ test_cmp expect actual"
+
+ if test "$match_expect" = 'E'
+ then
+ if test -e .git/created_test_file
+ then
+ test_expect_success EXPENSIVE_ON_WINDOWS "$match_function (via ls-files): match dies on '$pattern' '$text'" "
+ printf '%s' '$text' >expect &&
+ test_must_fail git$ls_files_args ls-files -z -- '$pattern'
+ "
+ else
+ test_expect_failure EXPENSIVE_ON_WINDOWS "$match_function (via ls-files): match skip '$pattern' '$text'" 'false'
+ fi
+ elif test "$match_expect" = 1
+ then
+ if test -e .git/created_test_file
+ then
+ test_expect_success EXPENSIVE_ON_WINDOWS "$match_function (via ls-files): match '$pattern' '$text'" "
+ printf '%s' '$text' >expect &&
+ git$ls_files_args ls-files -z -- '$pattern' >actual.raw 2>actual.err &&
+ $match_stdout_stderr_cmp
+ "
+ else
+ test_expect_failure EXPENSIVE_ON_WINDOWS "$match_function (via ls-files): match skip '$pattern' '$text'" 'false'
+ fi
+ elif test "$match_expect" = 0
+ then
+ if test -e .git/created_test_file
+ then
+ test_expect_success EXPENSIVE_ON_WINDOWS "$match_function (via ls-files): no match '$pattern' '$text'" "
+ >expect &&
+ git$ls_files_args ls-files -z -- '$pattern' >actual.raw 2>actual.err &&
+ $match_stdout_stderr_cmp
+ "
+ else
+ test_expect_failure EXPENSIVE_ON_WINDOWS "$match_function (via ls-files): no match skip '$pattern' '$text'" 'false'
+ fi
+ else
+ test_expect_success "PANIC: Test framework error. Unknown matches value $match_expect" 'false'
+ fi
}
-pathmatch() {
- if [ $1 = 1 ]; then
- test_expect_success "pathmatch: match '$2' '$3'" "
- test-wildmatch pathmatch '$2' '$3'
- "
- else
- test_expect_success "pathmatch: no match '$2' '$3'" "
- ! test-wildmatch pathmatch '$2' '$3'
- "
- fi
+match() {
+ if test "$#" = 6
+ then
+ # When test-wildmatch and git ls-files produce the same
+ # result.
+ match_glob=$1
+ match_file_glob=$match_glob
+ match_iglob=$2
+ match_file_iglob=$match_iglob
+ match_pathmatch=$3
+ match_file_pathmatch=$match_pathmatch
+ match_pathmatchi=$4
+ match_file_pathmatchi=$match_pathmatchi
+ text=$5
+ pattern=$6
+ elif test "$#" = 10
+ then
+ match_glob=$1
+ match_iglob=$2
+ match_pathmatch=$3
+ match_pathmatchi=$4
+ match_file_glob=$5
+ match_file_iglob=$6
+ match_file_pathmatch=$7
+ match_file_pathmatchi=$8
+ text=$9
+ pattern=${10}
+ fi
+
+ test_expect_success EXPENSIVE_ON_WINDOWS 'cleanup after previous file test' '
+ if test -e .git/created_test_file
+ then
+ git reset &&
+ git clean -df
+ fi
+ '
+
+ printf '%s' "$text" >.git/expected_test_file
+
+ test_expect_success EXPENSIVE_ON_WINDOWS "setup match file test for $text" '
+ file=$(cat .git/expected_test_file) &&
+ if should_create_test_file "$file"
+ then
+ dirs=${file%/*}
+ if test "$file" != "$dirs"
+ then
+ mkdir -p -- "$dirs" &&
+ touch -- "./$text"
+ else
+ touch -- "./$file"
+ fi &&
+ git add -A &&
+ printf "%s" "$file" >.git/created_test_file
+ elif test -e .git/created_test_file
+ then
+ rm .git/created_test_file
+ fi
+ '
+
+ # $1: Case sensitive glob match: test-wildmatch & ls-files
+ match_with_function "$text" "$pattern" $match_glob "wildmatch"
+ match_with_ls_files "$text" "$pattern" $match_file_glob "wildmatch" " --glob-pathspecs"
+
+ # $2: Case insensitive glob match: test-wildmatch & ls-files
+ match_with_function "$text" "$pattern" $match_iglob "iwildmatch"
+ match_with_ls_files "$text" "$pattern" $match_file_iglob "iwildmatch" " --glob-pathspecs --icase-pathspecs"
+
+ # $3: Case sensitive path match: test-wildmatch & ls-files
+ match_with_function "$text" "$pattern" $match_pathmatch "pathmatch"
+ match_with_ls_files "$text" "$pattern" $match_file_pathmatch "pathmatch" ""
+
+ # $4: Case insensitive path match: test-wildmatch & ls-files
+ match_with_function "$text" "$pattern" $match_pathmatchi "ipathmatch"
+ match_with_ls_files "$text" "$pattern" $match_file_pathmatchi "ipathmatch" " --icase-pathspecs"
}
-# Basic wildmat features
-match 1 1 foo foo
-match 0 0 foo bar
-match 1 1 '' ""
-match 1 1 foo '???'
-match 0 0 foo '??'
-match 1 1 foo '*'
-match 1 1 foo 'f*'
-match 0 0 foo '*f'
-match 1 1 foo '*foo*'
-match 1 1 foobar '*ob*a*r*'
-match 1 1 aaaaaaabababab '*ab'
-match 1 1 'foo*' 'foo\*'
-match 0 0 foobar 'foo\*bar'
-match 1 1 'f\oo' 'f\\oo'
-match 1 1 ball '*[al]?'
-match 0 0 ten '[ten]'
-match 0 1 ten '**[!te]'
-match 0 0 ten '**[!ten]'
-match 1 1 ten 't[a-g]n'
-match 0 0 ten 't[!a-g]n'
-match 1 1 ton 't[!a-g]n'
-match 1 1 ton 't[^a-g]n'
-match 1 x 'a]b' 'a[]]b'
-match 1 x a-b 'a[]-]b'
-match 1 x 'a]b' 'a[]-]b'
-match 0 x aab 'a[]-]b'
-match 1 x aab 'a[]a-]b'
-match 1 1 ']' ']'
+# Basic wildmatch features
+match 1 1 1 1 foo foo
+match 0 0 0 0 foo bar
+match 1 1 1 1 '' ""
+match 1 1 1 1 foo '???'
+match 0 0 0 0 foo '??'
+match 1 1 1 1 foo '*'
+match 1 1 1 1 foo 'f*'
+match 0 0 0 0 foo '*f'
+match 1 1 1 1 foo '*foo*'
+match 1 1 1 1 foobar '*ob*a*r*'
+match 1 1 1 1 aaaaaaabababab '*ab'
+match 1 1 1 1 'foo*' 'foo\*'
+match 0 0 0 0 foobar 'foo\*bar'
+match 1 1 1 1 'f\oo' 'f\\oo'
+match 1 1 1 1 ball '*[al]?'
+match 0 0 0 0 ten '[ten]'
+match 0 0 1 1 ten '**[!te]'
+match 0 0 0 0 ten '**[!ten]'
+match 1 1 1 1 ten 't[a-g]n'
+match 0 0 0 0 ten 't[!a-g]n'
+match 1 1 1 1 ton 't[!a-g]n'
+match 1 1 1 1 ton 't[^a-g]n'
+match 1 1 1 1 'a]b' 'a[]]b'
+match 1 1 1 1 a-b 'a[]-]b'
+match 1 1 1 1 'a]b' 'a[]-]b'
+match 0 0 0 0 aab 'a[]-]b'
+match 1 1 1 1 aab 'a[]a-]b'
+match 1 1 1 1 ']' ']'
# Extended slash-matching features
-match 0 0 'foo/baz/bar' 'foo*bar'
-match 0 0 'foo/baz/bar' 'foo**bar'
-match 0 1 'foobazbar' 'foo**bar'
-match 1 1 'foo/baz/bar' 'foo/**/bar'
-match 1 0 'foo/baz/bar' 'foo/**/**/bar'
-match 1 0 'foo/b/a/z/bar' 'foo/**/bar'
-match 1 0 'foo/b/a/z/bar' 'foo/**/**/bar'
-match 1 0 'foo/bar' 'foo/**/bar'
-match 1 0 'foo/bar' 'foo/**/**/bar'
-match 0 0 'foo/bar' 'foo?bar'
-match 0 0 'foo/bar' 'foo[/]bar'
-match 0 0 'foo/bar' 'foo[^a-z]bar'
-match 0 0 'foo/bar' 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r'
-match 1 1 'foo-bar' 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r'
-match 1 0 'foo' '**/foo'
-match 1 x 'XXX/foo' '**/foo'
-match 1 0 'bar/baz/foo' '**/foo'
-match 0 0 'bar/baz/foo' '*/foo'
-match 0 0 'foo/bar/baz' '**/bar*'
-match 1 0 'deep/foo/bar/baz' '**/bar/*'
-match 0 0 'deep/foo/bar/baz/' '**/bar/*'
-match 1 0 'deep/foo/bar/baz/' '**/bar/**'
-match 0 0 'deep/foo/bar' '**/bar/*'
-match 1 0 'deep/foo/bar/' '**/bar/**'
-match 0 0 'foo/bar/baz' '**/bar**'
-match 1 0 'foo/bar/baz/x' '*/bar/**'
-match 0 0 'deep/foo/bar/baz/x' '*/bar/**'
-match 1 0 'deep/foo/bar/baz/x' '**/bar/*/*'
+match 0 0 1 1 'foo/baz/bar' 'foo*bar'
+match 0 0 1 1 'foo/baz/bar' 'foo**bar'
+match 0 0 1 1 'foobazbar' 'foo**bar'
+match 1 1 1 1 'foo/baz/bar' 'foo/**/bar'
+match 1 1 0 0 'foo/baz/bar' 'foo/**/**/bar'
+match 1 1 1 1 'foo/b/a/z/bar' 'foo/**/bar'
+match 1 1 1 1 'foo/b/a/z/bar' 'foo/**/**/bar'
+match 1 1 0 0 'foo/bar' 'foo/**/bar'
+match 1 1 0 0 'foo/bar' 'foo/**/**/bar'
+match 0 0 1 1 'foo/bar' 'foo?bar'
+match 0 0 1 1 'foo/bar' 'foo[/]bar'
+match 0 0 1 1 'foo/bar' 'foo[^a-z]bar'
+match 0 0 1 1 'foo/bar' 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r'
+match 1 1 1 1 'foo-bar' 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r'
+match 1 1 0 0 'foo' '**/foo'
+match 1 1 1 1 'XXX/foo' '**/foo'
+match 1 1 1 1 'bar/baz/foo' '**/foo'
+match 0 0 1 1 'bar/baz/foo' '*/foo'
+match 0 0 1 1 'foo/bar/baz' '**/bar*'
+match 1 1 1 1 'deep/foo/bar/baz' '**/bar/*'
+match 0 0 1 1 'deep/foo/bar/baz/' '**/bar/*'
+match 1 1 1 1 'deep/foo/bar/baz/' '**/bar/**'
+match 0 0 0 0 'deep/foo/bar' '**/bar/*'
+match 1 1 1 1 'deep/foo/bar/' '**/bar/**'
+match 0 0 1 1 'foo/bar/baz' '**/bar**'
+match 1 1 1 1 'foo/bar/baz/x' '*/bar/**'
+match 0 0 1 1 'deep/foo/bar/baz/x' '*/bar/**'
+match 1 1 1 1 'deep/foo/bar/baz/x' '**/bar/*/*'
# Various additional tests
-match 0 0 'acrt' 'a[c-c]st'
-match 1 1 'acrt' 'a[c-c]rt'
-match 0 0 ']' '[!]-]'
-match 1 x 'a' '[!]-]'
-match 0 0 '' '\'
-match 0 x '\' '\'
-match 0 x 'XXX/\' '*/\'
-match 1 x 'XXX/\' '*/\\'
-match 1 1 'foo' 'foo'
-match 1 1 '@foo' '@foo'
-match 0 0 'foo' '@foo'
-match 1 1 '[ab]' '\[ab]'
-match 1 1 '[ab]' '[[]ab]'
-match 1 x '[ab]' '[[:]ab]'
-match 0 x '[ab]' '[[::]ab]'
-match 1 x '[ab]' '[[:digit]ab]'
-match 1 x '[ab]' '[\[:]ab]'
-match 1 1 '?a?b' '\??\?b'
-match 1 1 'abc' '\a\b\c'
-match 0 0 'foo' ''
-match 1 0 'foo/bar/baz/to' '**/t[o]'
+match 0 0 0 0 'acrt' 'a[c-c]st'
+match 1 1 1 1 'acrt' 'a[c-c]rt'
+match 0 0 0 0 ']' '[!]-]'
+match 1 1 1 1 'a' '[!]-]'
+match 0 0 0 0 '' '\'
+match 0 0 0 0 \
+ 1 1 1 1 '\' '\'
+match 0 0 0 0 'XXX/\' '*/\'
+match 1 1 1 1 'XXX/\' '*/\\'
+match 1 1 1 1 'foo' 'foo'
+match 1 1 1 1 '@foo' '@foo'
+match 0 0 0 0 'foo' '@foo'
+match 1 1 1 1 '[ab]' '\[ab]'
+match 1 1 1 1 '[ab]' '[[]ab]'
+match 1 1 1 1 '[ab]' '[[:]ab]'
+match 0 0 0 0 '[ab]' '[[::]ab]'
+match 1 1 1 1 '[ab]' '[[:digit]ab]'
+match 1 1 1 1 '[ab]' '[\[:]ab]'
+match 1 1 1 1 '?a?b' '\??\?b'
+match 1 1 1 1 'abc' '\a\b\c'
+match 0 0 0 0 \
+ E E E E 'foo' ''
+match 1 1 1 1 'foo/bar/baz/to' '**/t[o]'
# Character class tests
-match 1 x 'a1B' '[[:alpha:]][[:digit:]][[:upper:]]'
-match 0 x 'a' '[[:digit:][:upper:][:space:]]'
-match 1 x 'A' '[[:digit:][:upper:][:space:]]'
-match 1 x '1' '[[:digit:][:upper:][:space:]]'
-match 0 x '1' '[[:digit:][:upper:][:spaci:]]'
-match 1 x ' ' '[[:digit:][:upper:][:space:]]'
-match 0 x '.' '[[:digit:][:upper:][:space:]]'
-match 1 x '.' '[[:digit:][:punct:][:space:]]'
-match 1 x '5' '[[:xdigit:]]'
-match 1 x 'f' '[[:xdigit:]]'
-match 1 x 'D' '[[:xdigit:]]'
-match 1 x '_' '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]'
-match 1 x '.' '[^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]'
-match 1 x '5' '[a-c[:digit:]x-z]'
-match 1 x 'b' '[a-c[:digit:]x-z]'
-match 1 x 'y' '[a-c[:digit:]x-z]'
-match 0 x 'q' '[a-c[:digit:]x-z]'
-
-# Additional tests, including some malformed wildmats
-match 1 x ']' '[\\-^]'
-match 0 0 '[' '[\\-^]'
-match 1 x '-' '[\-_]'
-match 1 x ']' '[\]]'
-match 0 0 '\]' '[\]]'
-match 0 0 '\' '[\]]'
-match 0 0 'ab' 'a[]b'
-match 0 x 'a[]b' 'a[]b'
-match 0 x 'ab[' 'ab['
-match 0 0 'ab' '[!'
-match 0 0 'ab' '[-'
-match 1 1 '-' '[-]'
-match 0 0 '-' '[a-'
-match 0 0 '-' '[!a-'
-match 1 x '-' '[--A]'
-match 1 x '5' '[--A]'
-match 1 1 ' ' '[ --]'
-match 1 1 '$' '[ --]'
-match 1 1 '-' '[ --]'
-match 0 0 '0' '[ --]'
-match 1 x '-' '[---]'
-match 1 x '-' '[------]'
-match 0 0 'j' '[a-e-n]'
-match 1 x '-' '[a-e-n]'
-match 1 x 'a' '[!------]'
-match 0 0 '[' '[]-a]'
-match 1 x '^' '[]-a]'
-match 0 0 '^' '[!]-a]'
-match 1 x '[' '[!]-a]'
-match 1 1 '^' '[a^bc]'
-match 1 x '-b]' '[a-]b]'
-match 0 0 '\' '[\]'
-match 1 1 '\' '[\\]'
-match 0 0 '\' '[!\\]'
-match 1 1 'G' '[A-\\]'
-match 0 0 'aaabbb' 'b*a'
-match 0 0 'aabcaa' '*ba*'
-match 1 1 ',' '[,]'
-match 1 1 ',' '[\\,]'
-match 1 1 '\' '[\\,]'
-match 1 1 '-' '[,-.]'
-match 0 0 '+' '[,-.]'
-match 0 0 '-.]' '[,-.]'
-match 1 1 '2' '[\1-\3]'
-match 1 1 '3' '[\1-\3]'
-match 0 0 '4' '[\1-\3]'
-match 1 1 '\' '[[-\]]'
-match 1 1 '[' '[[-\]]'
-match 1 1 ']' '[[-\]]'
-match 0 0 '-' '[[-\]]'
+match 1 1 1 1 'a1B' '[[:alpha:]][[:digit:]][[:upper:]]'
+match 0 1 0 1 'a' '[[:digit:][:upper:][:space:]]'
+match 1 1 1 1 'A' '[[:digit:][:upper:][:space:]]'
+match 1 1 1 1 '1' '[[:digit:][:upper:][:space:]]'
+match 0 0 0 0 '1' '[[:digit:][:upper:][:spaci:]]'
+match 1 1 1 1 ' ' '[[:digit:][:upper:][:space:]]'
+match 0 0 0 0 '.' '[[:digit:][:upper:][:space:]]'
+match 1 1 1 1 '.' '[[:digit:][:punct:][:space:]]'
+match 1 1 1 1 '5' '[[:xdigit:]]'
+match 1 1 1 1 'f' '[[:xdigit:]]'
+match 1 1 1 1 'D' '[[:xdigit:]]'
+match 1 1 1 1 '_' '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]'
+match 1 1 1 1 '.' '[^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]'
+match 1 1 1 1 '5' '[a-c[:digit:]x-z]'
+match 1 1 1 1 'b' '[a-c[:digit:]x-z]'
+match 1 1 1 1 'y' '[a-c[:digit:]x-z]'
+match 0 0 0 0 'q' '[a-c[:digit:]x-z]'
-# Test recursion and the abort code (use "wildtest -i" to see iteration counts)
-match 1 1 '-adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1' '-*-*-*-*-*-*-12-*-*-*-m-*-*-*'
-match 0 0 '-adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1' '-*-*-*-*-*-*-12-*-*-*-m-*-*-*'
-match 0 0 '-adobe-courier-bold-o-normal--12-120-75-75-/-70-iso8859-1' '-*-*-*-*-*-*-12-*-*-*-m-*-*-*'
-match 1 1 'XXX/adobe/courier/bold/o/normal//12/120/75/75/m/70/iso8859/1' 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*'
-match 0 0 'XXX/adobe/courier/bold/o/normal//12/120/75/75/X/70/iso8859/1' 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*'
-match 1 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt' '**/*a*b*g*n*t'
-match 0 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz' '**/*a*b*g*n*t'
-match 0 x foo '*/*/*'
-match 0 x foo/bar '*/*/*'
-match 1 x foo/bba/arr '*/*/*'
-match 0 x foo/bb/aa/rr '*/*/*'
-match 1 x foo/bb/aa/rr '**/**/**'
-match 1 x abcXdefXghi '*X*i'
-match 0 x ab/cXd/efXg/hi '*X*i'
-match 1 x ab/cXd/efXg/hi '*/*X*/*/*i'
-match 1 x ab/cXd/efXg/hi '**/*X*/**/*i'
+# Additional tests, including some malformed wildmatch patterns
+match 1 1 1 1 ']' '[\\-^]'
+match 0 0 0 0 '[' '[\\-^]'
+match 1 1 1 1 '-' '[\-_]'
+match 1 1 1 1 ']' '[\]]'
+match 0 0 0 0 '\]' '[\]]'
+match 0 0 0 0 '\' '[\]]'
+match 0 0 0 0 'ab' 'a[]b'
+match 0 0 0 0 \
+ 1 1 1 1 'a[]b' 'a[]b'
+match 0 0 0 0 \
+ 1 1 1 1 'ab[' 'ab['
+match 0 0 0 0 'ab' '[!'
+match 0 0 0 0 'ab' '[-'
+match 1 1 1 1 '-' '[-]'
+match 0 0 0 0 '-' '[a-'
+match 0 0 0 0 '-' '[!a-'
+match 1 1 1 1 '-' '[--A]'
+match 1 1 1 1 '5' '[--A]'
+match 1 1 1 1 ' ' '[ --]'
+match 1 1 1 1 '$' '[ --]'
+match 1 1 1 1 '-' '[ --]'
+match 0 0 0 0 '0' '[ --]'
+match 1 1 1 1 '-' '[---]'
+match 1 1 1 1 '-' '[------]'
+match 0 0 0 0 'j' '[a-e-n]'
+match 1 1 1 1 '-' '[a-e-n]'
+match 1 1 1 1 'a' '[!------]'
+match 0 0 0 0 '[' '[]-a]'
+match 1 1 1 1 '^' '[]-a]'
+match 0 0 0 0 '^' '[!]-a]'
+match 1 1 1 1 '[' '[!]-a]'
+match 1 1 1 1 '^' '[a^bc]'
+match 1 1 1 1 '-b]' '[a-]b]'
+match 0 0 0 0 '\' '[\]'
+match 1 1 1 1 '\' '[\\]'
+match 0 0 0 0 '\' '[!\\]'
+match 1 1 1 1 'G' '[A-\\]'
+match 0 0 0 0 'aaabbb' 'b*a'
+match 0 0 0 0 'aabcaa' '*ba*'
+match 1 1 1 1 ',' '[,]'
+match 1 1 1 1 ',' '[\\,]'
+match 1 1 1 1 '\' '[\\,]'
+match 1 1 1 1 '-' '[,-.]'
+match 0 0 0 0 '+' '[,-.]'
+match 0 0 0 0 '-.]' '[,-.]'
+match 1 1 1 1 '2' '[\1-\3]'
+match 1 1 1 1 '3' '[\1-\3]'
+match 0 0 0 0 '4' '[\1-\3]'
+match 1 1 1 1 '\' '[[-\]]'
+match 1 1 1 1 '[' '[[-\]]'
+match 1 1 1 1 ']' '[[-\]]'
+match 0 0 0 0 '-' '[[-\]]'
-pathmatch 1 foo foo
-pathmatch 0 foo fo
-pathmatch 1 foo/bar foo/bar
-pathmatch 1 foo/bar 'foo/*'
-pathmatch 1 foo/bba/arr 'foo/*'
-pathmatch 1 foo/bba/arr 'foo/**'
-pathmatch 1 foo/bba/arr 'foo*'
-pathmatch 1 foo/bba/arr 'foo**'
-pathmatch 1 foo/bba/arr 'foo/*arr'
-pathmatch 1 foo/bba/arr 'foo/**arr'
-pathmatch 0 foo/bba/arr 'foo/*z'
-pathmatch 0 foo/bba/arr 'foo/**z'
-pathmatch 1 foo/bar 'foo?bar'
-pathmatch 1 foo/bar 'foo[/]bar'
-pathmatch 1 foo/bar 'foo[^a-z]bar'
-pathmatch 0 foo '*/*/*'
-pathmatch 0 foo/bar '*/*/*'
-pathmatch 1 foo/bba/arr '*/*/*'
-pathmatch 1 foo/bb/aa/rr '*/*/*'
-pathmatch 1 abcXdefXghi '*X*i'
-pathmatch 1 ab/cXd/efXg/hi '*/*X*/*/*i'
-pathmatch 1 ab/cXd/efXg/hi '*Xg*i'
+# Test recursion
+match 1 1 1 1 '-adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1' '-*-*-*-*-*-*-12-*-*-*-m-*-*-*'
+match 0 0 0 0 '-adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1' '-*-*-*-*-*-*-12-*-*-*-m-*-*-*'
+match 0 0 0 0 '-adobe-courier-bold-o-normal--12-120-75-75-/-70-iso8859-1' '-*-*-*-*-*-*-12-*-*-*-m-*-*-*'
+match 1 1 1 1 'XXX/adobe/courier/bold/o/normal//12/120/75/75/m/70/iso8859/1' 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*'
+match 0 0 0 0 'XXX/adobe/courier/bold/o/normal//12/120/75/75/X/70/iso8859/1' 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*'
+match 1 1 1 1 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt' '**/*a*b*g*n*t'
+match 0 0 0 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz' '**/*a*b*g*n*t'
+match 0 0 0 0 foo '*/*/*'
+match 0 0 0 0 foo/bar '*/*/*'
+match 1 1 1 1 foo/bba/arr '*/*/*'
+match 0 0 1 1 foo/bb/aa/rr '*/*/*'
+match 1 1 1 1 foo/bb/aa/rr '**/**/**'
+match 1 1 1 1 abcXdefXghi '*X*i'
+match 0 0 1 1 ab/cXd/efXg/hi '*X*i'
+match 1 1 1 1 ab/cXd/efXg/hi '*/*X*/*/*i'
+match 1 1 1 1 ab/cXd/efXg/hi '**/*X*/**/*i'
-# Case-sensitivity features
-match 0 x 'a' '[A-Z]'
-match 1 x 'A' '[A-Z]'
-match 0 x 'A' '[a-z]'
-match 1 x 'a' '[a-z]'
-match 0 x 'a' '[[:upper:]]'
-match 1 x 'A' '[[:upper:]]'
-match 0 x 'A' '[[:lower:]]'
-match 1 x 'a' '[[:lower:]]'
-match 0 x 'A' '[B-Za]'
-match 1 x 'a' '[B-Za]'
-match 0 x 'A' '[B-a]'
-match 1 x 'a' '[B-a]'
-match 0 x 'z' '[Z-y]'
-match 1 x 'Z' '[Z-y]'
+# Extra pathmatch tests
+match 0 0 0 0 foo fo
+match 1 1 1 1 foo/bar foo/bar
+match 1 1 1 1 foo/bar 'foo/*'
+match 0 0 1 1 foo/bba/arr 'foo/*'
+match 1 1 1 1 foo/bba/arr 'foo/**'
+match 0 0 1 1 foo/bba/arr 'foo*'
+match 0 0 1 1 \
+ 1 1 1 1 foo/bba/arr 'foo**'
+match 0 0 1 1 foo/bba/arr 'foo/*arr'
+match 0 0 1 1 foo/bba/arr 'foo/**arr'
+match 0 0 0 0 foo/bba/arr 'foo/*z'
+match 0 0 0 0 foo/bba/arr 'foo/**z'
+match 0 0 1 1 foo/bar 'foo?bar'
+match 0 0 1 1 foo/bar 'foo[/]bar'
+match 0 0 1 1 foo/bar 'foo[^a-z]bar'
+match 0 0 1 1 ab/cXd/efXg/hi '*Xg*i'
-imatch 1 'a' '[A-Z]'
-imatch 1 'A' '[A-Z]'
-imatch 1 'A' '[a-z]'
-imatch 1 'a' '[a-z]'
-imatch 1 'a' '[[:upper:]]'
-imatch 1 'A' '[[:upper:]]'
-imatch 1 'A' '[[:lower:]]'
-imatch 1 'a' '[[:lower:]]'
-imatch 1 'A' '[B-Za]'
-imatch 1 'a' '[B-Za]'
-imatch 1 'A' '[B-a]'
-imatch 1 'a' '[B-a]'
-imatch 1 'z' '[Z-y]'
-imatch 1 'Z' '[Z-y]'
+# Extra case-sensitivity tests
+match 0 1 0 1 'a' '[A-Z]'
+match 1 1 1 1 'A' '[A-Z]'
+match 0 1 0 1 'A' '[a-z]'
+match 1 1 1 1 'a' '[a-z]'
+match 0 1 0 1 'a' '[[:upper:]]'
+match 1 1 1 1 'A' '[[:upper:]]'
+match 0 1 0 1 'A' '[[:lower:]]'
+match 1 1 1 1 'a' '[[:lower:]]'
+match 0 1 0 1 'A' '[B-Za]'
+match 1 1 1 1 'a' '[B-Za]'
+match 0 1 0 1 'A' '[B-a]'
+match 1 1 1 1 'a' '[B-a]'
+match 0 1 0 1 'z' '[Z-y]'
+match 1 1 1 1 'Z' '[Z-y]'
test_done
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 8ac58d5..72d9564 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -277,4 +277,38 @@ EOF
test_cmp From_.msg out
'
+test_expect_success 'rebase--am.sh and --show-current-patch' '
+ test_create_repo conflict-apply &&
+ (
+ cd conflict-apply &&
+ test_commit init &&
+ echo one >>init.t &&
+ git commit -a -m one &&
+ echo two >>init.t &&
+ git commit -a -m two &&
+ git tag two &&
+ test_must_fail git rebase --onto init HEAD^ &&
+ GIT_TRACE=1 git rebase --show-current-patch >/dev/null 2>stderr &&
+ grep "show.*$(git rev-parse two)" stderr
+ )
+'
+
+test_expect_success 'rebase--merge.sh and --show-current-patch' '
+ test_create_repo conflict-merge &&
+ (
+ cd conflict-merge &&
+ test_commit init &&
+ echo one >>init.t &&
+ git commit -a -m one &&
+ echo two >>init.t &&
+ git commit -a -m two &&
+ git tag two &&
+ test_must_fail git rebase --merge --onto init HEAD^ &&
+ git rebase --show-current-patch >actual.patch &&
+ GIT_TRACE=1 git rebase --show-current-patch >/dev/null 2>stderr &&
+ grep "show.*REBASE_HEAD" stderr &&
+ test "$(git rev-parse REBASE_HEAD)" = "$(git rev-parse two)"
+ )
+'
+
test_done
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 481a350..3b90540 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -225,6 +225,14 @@ test_expect_success 'stop on conflicting pick' '
test 0 = $(grep -c "^[^#]" < .git/rebase-merge/git-rebase-todo)
'
+test_expect_success 'show conflicted patch' '
+ GIT_TRACE=1 git rebase --show-current-patch >/dev/null 2>stderr &&
+ grep "show.*REBASE_HEAD" stderr &&
+ # the original stopped-sha1 is abbreviated
+ stopped_sha1="$(git rev-parse $(cat ".git/rebase-merge/stopped-sha"))" &&
+ test "$(git rev-parse REBASE_HEAD)" = "$stopped_sha1"
+'
+
test_expect_success 'abort' '
git rebase --abort &&
test $(git rev-parse new-branch1) = $(git rev-parse HEAD) &&
@@ -453,6 +461,10 @@ test_expect_success C_LOCALE_OUTPUT 'squash and fixup generate correct log messa
git rebase -i $base &&
git cat-file commit HEAD | sed -e 1,/^\$/d > actual-squash-fixup &&
test_cmp expect-squash-fixup actual-squash-fixup &&
+ git cat-file commit HEAD@{2} |
+ grep "^# This is a combination of 3 commits\." &&
+ git cat-file commit HEAD@{3} |
+ grep "^# This is a combination of 2 commits\." &&
git checkout to-be-rebased &&
git branch -D squash-fixup
'
@@ -1336,6 +1348,16 @@ test_expect_success 'editor saves as CR/LF' '
SQ="'"
test_expect_success 'rebase -i --gpg-sign=<key-id>' '
+ test_when_finished "test_might_fail git rebase --abort" &&
+ set_fake_editor &&
+ FAKE_LINES="edit 1" git rebase -i --gpg-sign="\"S I Gner\"" HEAD^ \
+ >out 2>err &&
+ test_i18ngrep "$SQ-S\"S I Gner\"$SQ" err
+'
+
+test_expect_success 'rebase -i --gpg-sign=<key-id> overrides commit.gpgSign' '
+ test_when_finished "test_might_fail git rebase --abort" &&
+ test_config commit.gpgsign true &&
set_fake_editor &&
FAKE_LINES="edit 1" git rebase -i --gpg-sign="\"S I Gner\"" HEAD^ \
>out 2>err &&
diff --git a/t/t3405-rebase-malformed.sh b/t/t3405-rebase-malformed.sh
index ff8c360..cb7c6de 100755
--- a/t/t3405-rebase-malformed.sh
+++ b/t/t3405-rebase-malformed.sh
@@ -3,6 +3,7 @@
test_description='rebase should handle arbitrary git message'
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-rebase.sh
cat >F <<\EOF
This is an example of a commit log message
@@ -25,6 +26,7 @@ test_expect_success setup '
test_tick &&
git commit -m "Initial commit" &&
git branch diff-in-message &&
+ git branch empty-message-merge &&
git checkout -b multi-line-subject &&
cat F >file2 &&
@@ -45,6 +47,11 @@ test_expect_success setup '
git cat-file commit HEAD | sed -e "1,/^\$/d" >G0 &&
+ git checkout empty-message-merge &&
+ echo file3 >file3 &&
+ git add file3 &&
+ git commit --allow-empty-message -m "" &&
+
git checkout master &&
echo One >file1 &&
@@ -69,4 +76,20 @@ test_expect_success 'rebase commit with diff in message' '
test_cmp G G0
'
+test_expect_success 'rebase -m commit with empty message' '
+ test_must_fail git rebase -m master empty-message-merge &&
+ git rebase --abort &&
+ git rebase -m --allow-empty-message master empty-message-merge
+'
+
+test_expect_success 'rebase -i commit with empty message' '
+ git checkout diff-in-message &&
+ set_fake_editor &&
+ test_must_fail env FAKE_COMMIT_MESSAGE=" " FAKE_LINES="reword 1" \
+ git rebase -i HEAD^ &&
+ git rebase --abort &&
+ FAKE_COMMIT_MESSAGE=" " FAKE_LINES="reword 1" \
+ git rebase -i --allow-empty-message HEAD^
+'
+
test_done
diff --git a/t/t3408-rebase-multi-line.sh b/t/t3408-rebase-multi-line.sh
index 6b84e60..e7292f5 100755
--- a/t/t3408-rebase-multi-line.sh
+++ b/t/t3408-rebase-multi-line.sh
@@ -24,8 +24,23 @@ But otherwise with a sane description." &&
>elif &&
git add elif &&
test_tick &&
- git commit -m second
+ git commit -m second &&
+ git checkout -b side2 &&
+ >afile &&
+ git add afile &&
+ test_tick &&
+ git commit -m third &&
+ echo hello >afile &&
+ test_tick &&
+ git commit -a -m fourth &&
+ git checkout -b side-merge &&
+ git reset --hard HEAD^^ &&
+ git merge --no-ff -m "A merge commit log message that has a long
+summary that spills over multiple lines.
+
+But otherwise with a sane description." side2 &&
+ git branch side-merge-original
'
test_expect_success rebase '
@@ -37,5 +52,14 @@ test_expect_success rebase '
test_cmp expect actual
'
+test_expect_success rebasep '
+
+ git checkout side-merge &&
+ git rebase -p side &&
+ git cat-file commit HEAD | sed -e "1,/^\$/d" >actual &&
+ git cat-file commit side-merge-original | sed -e "1,/^\$/d" >expect &&
+ test_cmp expect actual
+
+'
test_done
diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh
index 4f2a263..783bdbf 100755
--- a/t/t3501-revert-cherry-pick.sh
+++ b/t/t3501-revert-cherry-pick.sh
@@ -141,7 +141,7 @@ test_expect_success 'cherry-pick "-" works with arguments' '
test_cmp expect actual
'
-test_expect_success 'cherry-pick works with dirty renamed file' '
+test_expect_failure 'cherry-pick works with dirty renamed file' '
test_commit to-rename &&
git checkout -b unrelated &&
test_commit unrelated &&
@@ -150,7 +150,10 @@ test_expect_success 'cherry-pick works with dirty renamed file' '
test_tick &&
git commit -m renamed &&
echo modified >renamed &&
- git cherry-pick refs/heads/unrelated
+ test_must_fail git cherry-pick refs/heads/unrelated >out &&
+ test_i18ngrep "Refusing to lose dirty file at renamed" out &&
+ test $(git rev-parse :0:renamed) = $(git rev-parse HEAD^:to-rename.t) &&
+ grep -q "^modified$" renamed
'
test_done
diff --git a/t/t3512-cherry-pick-submodule.sh b/t/t3512-cherry-pick-submodule.sh
index ce48c4f..bd78287 100755
--- a/t/t3512-cherry-pick-submodule.sh
+++ b/t/t3512-cherry-pick-submodule.sh
@@ -5,7 +5,6 @@ test_description='cherry-pick can handle submodules'
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-submodule-update.sh
-KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1
KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1
KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1
test_submodule_switch "git cherry-pick"
diff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh
index db93781..5e39fcd 100755
--- a/t/t3513-revert-submodule.sh
+++ b/t/t3513-revert-submodule.sh
@@ -25,7 +25,6 @@ git_revert () {
git revert HEAD
}
-KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1
KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1
test_submodule_switch "git_revert"
diff --git a/t/t4001-diff-rename.sh b/t/t4001-diff-rename.sh
index eadf4f6..a07816d 100755
--- a/t/t4001-diff-rename.sh
+++ b/t/t4001-diff-rename.sh
@@ -134,11 +134,15 @@ test_expect_success 'favour same basenames over different ones' '
git rm path1 &&
mkdir subdir &&
git mv another-path subdir/path1 &&
- git status | test_i18ngrep "renamed: .*path1 -> subdir/path1"'
+ git status >out &&
+ test_i18ngrep "renamed: .*path1 -> subdir/path1" out
+'
test_expect_success 'favour same basenames even with minor differences' '
git show HEAD:path1 | sed "s/15/16/" > subdir/path1 &&
- git status | test_i18ngrep "renamed: .*path1 -> subdir/path1"'
+ git status >out &&
+ test_i18ngrep "renamed: .*path1 -> subdir/path1" out
+'
test_expect_success 'two files with same basename and same content' '
git reset --hard &&
@@ -148,7 +152,8 @@ test_expect_success 'two files with same basename and same content' '
git add dir &&
git commit -m 2 &&
git mv dir other-dir &&
- git status | test_i18ngrep "renamed: .*dir/A/file -> other-dir/A/file"
+ git status >out &&
+ test_i18ngrep "renamed: .*dir/A/file -> other-dir/A/file" out
'
test_expect_success 'setup for many rename source candidates' '
diff --git a/t/t4052-stat-output.sh b/t/t4052-stat-output.sh
index 9f563db..6e2cf93 100755
--- a/t/t4052-stat-output.sh
+++ b/t/t4052-stat-output.sh
@@ -19,17 +19,33 @@ test_expect_success 'preparation' '
git commit -m message "$name"
'
+cat >expect72 <<-'EOF'
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
+EOF
+test_expect_success "format-patch: small change with long name gives more space to the name" '
+ git format-patch -1 --stdout >output &&
+ grep " | " output >actual &&
+ test_cmp expect72 actual
+'
+
while read cmd args
do
- cat >expect <<-'EOF'
+ cat >expect80 <<-'EOF'
...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
EOF
test_expect_success "$cmd: small change with long name gives more space to the name" '
git $cmd $args >output &&
grep " | " output >actual &&
- test_cmp expect actual
+ test_cmp expect80 actual
'
+done <<\EOF
+diff HEAD^ HEAD --stat
+show --stat
+log -1 --stat
+EOF
+while read cmd args
+do
cat >expect <<-'EOF'
...aaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
EOF
@@ -79,11 +95,11 @@ test_expect_success 'preparation for big change tests' '
git commit -m message abcd
'
-cat >expect80 <<'EOF'
- abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+cat >expect72 <<'EOF'
+ abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EOF
-cat >expect80-graph <<'EOF'
-| abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+cat >expect72-graph <<'EOF'
+| abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EOF
cat >expect200 <<'EOF'
abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -107,7 +123,7 @@ do
test_cmp "$expect-graph" actual
'
done <<\EOF
-ignores expect80 format-patch -1 --stdout
+ignores expect72 format-patch -1 --stdout
respects expect200 diff HEAD^ HEAD --stat
respects expect200 show --stat
respects expect200 log -1 --stat
@@ -135,7 +151,7 @@ do
test_cmp "$expect-graph" actual
'
done <<\EOF
-ignores expect80 format-patch -1 --stdout
+ignores expect72 format-patch -1 --stdout
respects expect40 diff HEAD^ HEAD --stat
respects expect40 show --stat
respects expect40 log -1 --stat
@@ -163,7 +179,7 @@ do
test_cmp "$expect-graph" actual
'
done <<\EOF
-ignores expect80 format-patch -1 --stdout
+ignores expect72 format-patch -1 --stdout
respects expect40 diff HEAD^ HEAD --stat
respects expect40 show --stat
respects expect40 log -1 --stat
@@ -250,11 +266,11 @@ show --stat
log -1 --stat
EOF
-cat >expect80 <<'EOF'
- ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++
+cat >expect72 <<'EOF'
+ ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++++++++++++++
EOF
-cat >expect80-graph <<'EOF'
-| ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++
+cat >expect72-graph <<'EOF'
+| ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++++++++++++++
EOF
cat >expect200 <<'EOF'
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -278,7 +294,7 @@ do
test_cmp "$expect-graph" actual
'
done <<\EOF
-ignores expect80 format-patch -1 --stdout
+ignores expect72 format-patch -1 --stdout
respects expect200 diff HEAD^ HEAD --stat
respects expect200 show --stat
respects expect200 log -1 --stat
@@ -308,7 +324,7 @@ do
test_cmp "$expect-graph" actual
'
done <<\EOF
-ignores expect80 format-patch -1 --stdout
+ignores expect72 format-patch -1 --stdout
respects expect1 diff HEAD^ HEAD --stat
respects expect1 show --stat
respects expect1 log -1 --stat
diff --git a/t/t4135-apply-weird-filenames.sh b/t/t4135-apply-weird-filenames.sh
index 27cb000..c7c688f 100755
--- a/t/t4135-apply-weird-filenames.sh
+++ b/t/t4135-apply-weird-filenames.sh
@@ -89,4 +89,21 @@ test_expect_success 'traditional, whitespace-damaged, colon in timezone' '
test_cmp expected "post image.txt"
'
+cat >diff-from-svn <<\EOF
+Index: Makefile
+===================================================================
+diff --git a/branches/Makefile
+deleted file mode 100644
+--- a/branches/Makefile (revision 13)
++++ /dev/null (nonexistent)
+@@ +1 0,0 @@
+-
+EOF
+
+test_expect_success 'apply handles a diff generated by Subversion' '
+ >Makefile &&
+ git apply -p2 diff-from-svn &&
+ test_path_is_missing Makefile
+'
+
test_done
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 73b67b4..1eccfb7 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -662,6 +662,11 @@ test_expect_success 'am pauses on conflict' '
test -d .git/rebase-apply
'
+test_expect_success 'am --show-current-patch' '
+ git am --show-current-patch >actual.patch &&
+ test_cmp .git/rebase-apply/0001 actual.patch
+'
+
test_expect_success 'am --skip works' '
echo goodbye >expected &&
git am --skip &&
@@ -1045,4 +1050,16 @@ test_expect_success 'am works with multi-line in-body headers' '
git cat-file commit HEAD | grep "^$LONG$"
'
+test_expect_success 'am --quit keeps HEAD where it is' '
+ mkdir .git/rebase-apply &&
+ >.git/rebase-apply/last &&
+ >.git/rebase-apply/next &&
+ git rev-parse HEAD^ >.git/ORIG_HEAD &&
+ git rev-parse HEAD >expected &&
+ git am --quit &&
+ test_path_is_missing .git/rebase-apply &&
+ git rev-parse HEAD >actual &&
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 80a1a32..ec9ba9b 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -755,4 +755,67 @@ test_expect_success 'fetching deepen' '
)
'
+test_expect_success 'filtering by size' '
+ rm -rf server client &&
+ test_create_repo server &&
+ test_commit -C server one &&
+ test_config -C server uploadpack.allowfilter 1 &&
+
+ test_create_repo client &&
+ git -C client fetch-pack --filter=blob:limit=0 ../server HEAD &&
+
+ # Ensure that object is not inadvertently fetched
+ test_must_fail git -C client cat-file -e $(git hash-object server/one.t)
+'
+
+test_expect_success 'filtering by size has no effect if support for it is not advertised' '
+ rm -rf server client &&
+ test_create_repo server &&
+ test_commit -C server one &&
+
+ test_create_repo client &&
+ git -C client fetch-pack --filter=blob:limit=0 ../server HEAD 2> err &&
+
+ # Ensure that object is fetched
+ git -C client cat-file -e $(git hash-object server/one.t) &&
+
+ test_i18ngrep "filtering not recognized by server" err
+'
+
+fetch_filter_blob_limit_zero () {
+ SERVER="$1"
+ URL="$2"
+
+ rm -rf "$SERVER" client &&
+ test_create_repo "$SERVER" &&
+ test_commit -C "$SERVER" one &&
+ test_config -C "$SERVER" uploadpack.allowfilter 1 &&
+
+ git clone "$URL" client &&
+ test_config -C client extensions.partialclone origin &&
+
+ test_commit -C "$SERVER" two &&
+
+ git -C client fetch --filter=blob:limit=0 origin HEAD:somewhere &&
+
+ # Ensure that commit is fetched, but blob is not
+ test_config -C client extensions.partialclone "arbitrary string" &&
+ git -C client cat-file -e $(git -C "$SERVER" rev-parse two) &&
+ test_must_fail git -C client cat-file -e $(git hash-object "$SERVER/two.t")
+}
+
+test_expect_success 'fetch with --filter=blob:limit=0' '
+ fetch_filter_blob_limit_zero server server
+'
+
+. "$TEST_DIRECTORY"/lib-httpd.sh
+start_httpd
+
+test_expect_success 'fetch with --filter=blob:limit=0 and HTTP' '
+ fetch_filter_blob_limit_zero "$HTTPD_DOCUMENT_ROOT_PATH/server" "$HTTPD_URL/smart/server"
+'
+
+stop_httpd
+
+
test_done
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 668c54b..da9ac00 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -222,12 +222,9 @@ test_expect_success 'fetch uses remote ref names to describe new refs' '
(
cd descriptive &&
git fetch o 2>actual &&
- grep " -> refs/crazyheads/descriptive-branch$" actual |
- test_i18ngrep "new branch" &&
- grep " -> descriptive-tag$" actual |
- test_i18ngrep "new tag" &&
- grep " -> crazy$" actual |
- test_i18ngrep "new ref"
+ test_i18ngrep "new branch.* -> refs/crazyheads/descriptive-branch$" actual &&
+ test_i18ngrep "new tag.* -> descriptive-tag$" actual &&
+ test_i18ngrep "new ref.* -> crazy$" actual
) &&
git checkout master
'
@@ -543,82 +540,232 @@ test_expect_success "should be able to fetch with duplicate refspecs" '
set_config_tristate () {
# var=$1 val=$2
case "$2" in
- unset) test_unconfig "$1" ;;
- *) git config "$1" "$2" ;;
+ unset)
+ test_unconfig "$1"
+ ;;
+ *)
+ git config "$1" "$2"
+ key=$(echo $1 | sed -e 's/^remote\.origin/fetch/')
+ git_fetch_c="$git_fetch_c -c $key=$2"
+ ;;
esac
}
test_configured_prune () {
- fetch_prune=$1 remote_origin_prune=$2 cmdline=$3 expected=$4
+ test_configured_prune_type "$@" "name"
+ test_configured_prune_type "$@" "link"
+}
- test_expect_success "prune fetch.prune=$1 remote.origin.prune=$2${3:+ $3}; $4" '
+test_configured_prune_type () {
+ fetch_prune=$1
+ remote_origin_prune=$2
+ fetch_prune_tags=$3
+ remote_origin_prune_tags=$4
+ expected_branch=$5
+ expected_tag=$6
+ cmdline=$7
+ mode=$8
+
+ if test -z "$cmdline_setup"
+ then
+ test_expect_success 'setup cmdline_setup variable for subsequent test' '
+ remote_url="file://$(git -C one config remote.origin.url)" &&
+ remote_fetch="$(git -C one config remote.origin.fetch)" &&
+ cmdline_setup="\"$remote_url\" \"$remote_fetch\""
+ '
+ fi
+
+ if test "$mode" = 'link'
+ then
+ new_cmdline=""
+
+ if test "$cmdline" = ""
+ then
+ new_cmdline=$cmdline_setup
+ else
+ new_cmdline=$(printf "%s" "$cmdline" | perl -pe 's[origin(?!/)]["'"$remote_url"'"]g')
+ fi
+
+ if test "$fetch_prune_tags" = 'true' ||
+ test "$remote_origin_prune_tags" = 'true'
+ then
+ if ! printf '%s' "$cmdline\n" | grep -q refs/remotes/origin/
+ then
+ new_cmdline="$new_cmdline refs/tags/*:refs/tags/*"
+ fi
+ fi
+
+ cmdline="$new_cmdline"
+ fi
+
+ test_expect_success "$mode prune fetch.prune=$1 remote.origin.prune=$2 fetch.pruneTags=$3 remote.origin.pruneTags=$4${7:+ $7}; branch:$5 tag:$6" '
# make sure a newbranch is there in . and also in one
git branch -f newbranch &&
+ git tag -f newtag &&
(
cd one &&
test_unconfig fetch.prune &&
+ test_unconfig fetch.pruneTags &&
test_unconfig remote.origin.prune &&
- git fetch &&
- git rev-parse --verify refs/remotes/origin/newbranch
+ test_unconfig remote.origin.pruneTags &&
+ git fetch '"$cmdline_setup"' &&
+ git rev-parse --verify refs/remotes/origin/newbranch &&
+ git rev-parse --verify refs/tags/newtag
) &&
# now remove it
git branch -d newbranch &&
+ git tag -d newtag &&
# then test
(
cd one &&
+ git_fetch_c="" &&
set_config_tristate fetch.prune $fetch_prune &&
+ set_config_tristate fetch.pruneTags $fetch_prune_tags &&
set_config_tristate remote.origin.prune $remote_origin_prune &&
-
- git fetch $cmdline &&
- case "$expected" in
+ set_config_tristate remote.origin.pruneTags $remote_origin_prune_tags &&
+
+ if test "$mode" != "link"
+ then
+ git_fetch_c=""
+ fi &&
+ git$git_fetch_c fetch '"$cmdline"' &&
+ case "$expected_branch" in
pruned)
test_must_fail git rev-parse --verify refs/remotes/origin/newbranch
;;
kept)
git rev-parse --verify refs/remotes/origin/newbranch
;;
+ esac &&
+ case "$expected_tag" in
+ pruned)
+ test_must_fail git rev-parse --verify refs/tags/newtag
+ ;;
+ kept)
+ git rev-parse --verify refs/tags/newtag
+ ;;
esac
)
'
}
-test_configured_prune unset unset "" kept
-test_configured_prune unset unset "--no-prune" kept
-test_configured_prune unset unset "--prune" pruned
-
-test_configured_prune false unset "" kept
-test_configured_prune false unset "--no-prune" kept
-test_configured_prune false unset "--prune" pruned
-
-test_configured_prune true unset "" pruned
-test_configured_prune true unset "--prune" pruned
-test_configured_prune true unset "--no-prune" kept
-
-test_configured_prune unset false "" kept
-test_configured_prune unset false "--no-prune" kept
-test_configured_prune unset false "--prune" pruned
-
-test_configured_prune false false "" kept
-test_configured_prune false false "--no-prune" kept
-test_configured_prune false false "--prune" pruned
-
-test_configured_prune true false "" kept
-test_configured_prune true false "--prune" pruned
-test_configured_prune true false "--no-prune" kept
-
-test_configured_prune unset true "" pruned
-test_configured_prune unset true "--no-prune" kept
-test_configured_prune unset true "--prune" pruned
-
-test_configured_prune false true "" pruned
-test_configured_prune false true "--no-prune" kept
-test_configured_prune false true "--prune" pruned
-
-test_configured_prune true true "" pruned
-test_configured_prune true true "--prune" pruned
-test_configured_prune true true "--no-prune" kept
+# $1 config: fetch.prune
+# $2 config: remote.<name>.prune
+# $3 config: fetch.pruneTags
+# $4 config: remote.<name>.pruneTags
+# $5 expect: branch to be pruned?
+# $6 expect: tag to be pruned?
+# $7 git-fetch $cmdline:
+#
+# $1 $2 $3 $4 $5 $6 $7
+test_configured_prune unset unset unset unset kept kept ""
+test_configured_prune unset unset unset unset kept kept "--no-prune"
+test_configured_prune unset unset unset unset pruned kept "--prune"
+test_configured_prune unset unset unset unset kept pruned \
+ "--prune origin refs/tags/*:refs/tags/*"
+test_configured_prune unset unset unset unset pruned pruned \
+ "--prune origin refs/tags/*:refs/tags/* +refs/heads/*:refs/remotes/origin/*"
+
+test_configured_prune false unset unset unset kept kept ""
+test_configured_prune false unset unset unset kept kept "--no-prune"
+test_configured_prune false unset unset unset pruned kept "--prune"
+
+test_configured_prune true unset unset unset pruned kept ""
+test_configured_prune true unset unset unset pruned kept "--prune"
+test_configured_prune true unset unset unset kept kept "--no-prune"
+
+test_configured_prune unset false unset unset kept kept ""
+test_configured_prune unset false unset unset kept kept "--no-prune"
+test_configured_prune unset false unset unset pruned kept "--prune"
+
+test_configured_prune false false unset unset kept kept ""
+test_configured_prune false false unset unset kept kept "--no-prune"
+test_configured_prune false false unset unset pruned kept "--prune"
+test_configured_prune false false unset unset kept pruned \
+ "--prune origin refs/tags/*:refs/tags/*"
+test_configured_prune false false unset unset pruned pruned \
+ "--prune origin refs/tags/*:refs/tags/* +refs/heads/*:refs/remotes/origin/*"
+
+test_configured_prune true false unset unset kept kept ""
+test_configured_prune true false unset unset pruned kept "--prune"
+test_configured_prune true false unset unset kept kept "--no-prune"
+
+test_configured_prune unset true unset unset pruned kept ""
+test_configured_prune unset true unset unset kept kept "--no-prune"
+test_configured_prune unset true unset unset pruned kept "--prune"
+
+test_configured_prune false true unset unset pruned kept ""
+test_configured_prune false true unset unset kept kept "--no-prune"
+test_configured_prune false true unset unset pruned kept "--prune"
+
+test_configured_prune true true unset unset pruned kept ""
+test_configured_prune true true unset unset pruned kept "--prune"
+test_configured_prune true true unset unset kept kept "--no-prune"
+test_configured_prune true true unset unset kept pruned \
+ "--prune origin refs/tags/*:refs/tags/*"
+test_configured_prune true true unset unset pruned pruned \
+ "--prune origin refs/tags/*:refs/tags/* +refs/heads/*:refs/remotes/origin/*"
+
+# --prune-tags on its own does nothing, needs --prune as well, same
+# for for fetch.pruneTags without fetch.prune
+test_configured_prune unset unset unset unset kept kept "--prune-tags"
+test_configured_prune unset unset true unset kept kept ""
+test_configured_prune unset unset unset true kept kept ""
+
+# These will prune the tags
+test_configured_prune unset unset unset unset pruned pruned "--prune --prune-tags"
+test_configured_prune true unset true unset pruned pruned ""
+test_configured_prune unset true unset true pruned pruned ""
+
+# remote.<name>.pruneTags overrides fetch.pruneTags, just like
+# remote.<name>.prune overrides fetch.prune if set.
+test_configured_prune true unset true unset pruned pruned ""
+test_configured_prune false true false true pruned pruned ""
+test_configured_prune true false true false kept kept ""
+
+# When --prune-tags is supplied it's ignored if an explicit refspec is
+# given, same for the configuration options.
+test_configured_prune unset unset unset unset pruned kept \
+ "--prune --prune-tags origin +refs/heads/*:refs/remotes/origin/*"
+test_configured_prune unset unset true unset pruned kept \
+ "--prune origin +refs/heads/*:refs/remotes/origin/*"
+test_configured_prune unset unset unset true pruned kept \
+ "--prune origin +refs/heads/*:refs/remotes/origin/*"
+
+# Pruning that also takes place if a file:// url replaces a named
+# remote. However, because there's no implicit
+# +refs/heads/*:refs/remotes/origin/* refspec and supplying it on the
+# command-line negates --prune-tags, the branches will not be pruned.
+test_configured_prune_type unset unset unset unset kept kept "origin --prune-tags" "name"
+test_configured_prune_type unset unset unset unset kept kept "origin --prune-tags" "link"
+test_configured_prune_type unset unset unset unset pruned pruned "origin --prune --prune-tags" "name"
+test_configured_prune_type unset unset unset unset kept pruned "origin --prune --prune-tags" "link"
+test_configured_prune_type unset unset unset unset pruned pruned "--prune --prune-tags origin" "name"
+test_configured_prune_type unset unset unset unset kept pruned "--prune --prune-tags origin" "link"
+test_configured_prune_type unset unset true unset pruned pruned "--prune origin" "name"
+test_configured_prune_type unset unset true unset kept pruned "--prune origin" "link"
+test_configured_prune_type unset unset unset true pruned pruned "--prune origin" "name"
+test_configured_prune_type unset unset unset true kept pruned "--prune origin" "link"
+test_configured_prune_type true unset true unset pruned pruned "origin" "name"
+test_configured_prune_type true unset true unset kept pruned "origin" "link"
+test_configured_prune_type unset true true unset pruned pruned "origin" "name"
+test_configured_prune_type unset true true unset kept pruned "origin" "link"
+test_configured_prune_type unset true unset true pruned pruned "origin" "name"
+test_configured_prune_type unset true unset true kept pruned "origin" "link"
+
+# When all remote.origin.fetch settings are deleted a --prune
+# --prune-tags still implicitly supplies refs/tags/*:refs/tags/* so
+# tags, but not tracking branches, will be deleted.
+test_expect_success 'remove remote.origin.fetch "one"' '
+ (
+ cd one &&
+ git config --unset-all remote.origin.fetch
+ )
+'
+test_configured_prune_type unset unset unset unset kept pruned "origin --prune --prune-tags" "name"
+test_configured_prune_type unset unset unset unset kept pruned "origin --prune --prune-tags" "link"
test_expect_success 'all boundary commits are excluded' '
test_commit base &&
diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh
index a552ad4..74486c7 100755
--- a/t/t5526-fetch-submodules.sh
+++ b/t/t5526-fetch-submodules.sh
@@ -485,7 +485,7 @@ test_expect_success "don't fetch submodule when newly recorded commits are alrea
)
'
-test_expect_success "'fetch.recurseSubmodules=on-demand' works also without .gitmodule entry" '
+test_expect_success "'fetch.recurseSubmodules=on-demand' works also without .gitmodules entry" '
(
cd downstream &&
git fetch --recurse-submodules
diff --git a/t/t5536-fetch-conflicts.sh b/t/t5536-fetch-conflicts.sh
index 2e42cf3..644736b 100755
--- a/t/t5536-fetch-conflicts.sh
+++ b/t/t5536-fetch-conflicts.sh
@@ -22,7 +22,7 @@ verify_stderr () {
cat >expected &&
# We're not interested in the error
# "fatal: The remote end hung up unexpectedly":
- test_i18ngrep -E '^(fatal|warning):' <error | grep -v 'hung up' >actual | sort &&
+ test_i18ngrep -E '^(fatal|warning):' error | grep -v 'hung up' >actual | sort &&
test_i18ncmp expected actual
}
diff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh
index d38bf32..21340e8 100755
--- a/t/t5541-http-push-smart.sh
+++ b/t/t5541-http-push-smart.sh
@@ -234,7 +234,7 @@ test_expect_success TTY 'push --no-progress silences progress but not status' '
test_commit no-progress &&
test_terminal git push --no-progress >output 2>&1 &&
test_i18ngrep "^To http" output &&
- test_i18ngrep ! "^Writing objects"
+ test_i18ngrep ! "^Writing objects" output
'
test_expect_success 'push --progress shows progress to non-tty' '
diff --git a/t/t5545-push-options.sh b/t/t5545-push-options.sh
index 4637837..b47a958 100755
--- a/t/t5545-push-options.sh
+++ b/t/t5545-push-options.sh
@@ -217,17 +217,32 @@ test_expect_success 'invalid push option in config' '
test_refs master HEAD@{1}
'
+test_expect_success 'push options keep quoted characters intact (direct)' '
+ mk_repo_pair &&
+ git -C upstream config receive.advertisePushOptions true &&
+ test_commit -C workbench one &&
+ git -C workbench push --push-option="\"embedded quotes\"" up master &&
+ echo "\"embedded quotes\"" >expect &&
+ test_cmp expect upstream/.git/hooks/pre-receive.push_options
+'
+
. "$TEST_DIRECTORY"/lib-httpd.sh
start_httpd
-test_expect_success 'push option denied properly by http server' '
+# set up http repository for fetching/pushing, with push options config
+# bool set to $1
+mk_http_pair () {
test_when_finished "rm -rf test_http_clone" &&
- test_when_finished "rm -rf \"$HTTPD_DOCUMENT_ROOT_PATH\"/upstream.git" &&
+ test_when_finished 'rm -rf "$HTTPD_DOCUMENT_ROOT_PATH"/upstream.git' &&
mk_repo_pair &&
- git -C upstream config receive.advertisePushOptions false &&
+ git -C upstream config receive.advertisePushOptions "$1" &&
git -C upstream config http.receivepack true &&
cp -R upstream/.git "$HTTPD_DOCUMENT_ROOT_PATH"/upstream.git &&
- git clone "$HTTPD_URL"/smart/upstream test_http_clone &&
+ git clone "$HTTPD_URL"/smart/upstream test_http_clone
+}
+
+test_expect_success 'push option denied properly by http server' '
+ mk_http_pair false &&
test_commit -C test_http_clone one &&
test_must_fail git -C test_http_clone push --push-option=asdf origin master 2>actual &&
test_i18ngrep "the receiving end does not support push options" actual &&
@@ -235,13 +250,7 @@ test_expect_success 'push option denied properly by http server' '
'
test_expect_success 'push options work properly across http' '
- test_when_finished "rm -rf test_http_clone" &&
- test_when_finished "rm -rf \"$HTTPD_DOCUMENT_ROOT_PATH\"/upstream.git" &&
- mk_repo_pair &&
- git -C upstream config receive.advertisePushOptions true &&
- git -C upstream config http.receivepack true &&
- cp -R upstream/.git "$HTTPD_DOCUMENT_ROOT_PATH"/upstream.git &&
- git clone "$HTTPD_URL"/smart/upstream test_http_clone &&
+ mk_http_pair true &&
test_commit -C test_http_clone one &&
git -C test_http_clone push origin master &&
@@ -260,6 +269,15 @@ test_expect_success 'push options work properly across http' '
test_cmp expect actual
'
+test_expect_success 'push options keep quoted characters intact (http)' '
+ mk_http_pair true &&
+
+ test_commit -C test_http_clone one &&
+ git -C test_http_clone push --push-option="\"embedded quotes\"" origin master &&
+ echo "\"embedded quotes\"" >expect &&
+ test_cmp expect "$HTTPD_DOCUMENT_ROOT_PATH"/upstream.git/hooks/pre-receive.push_options
+'
+
stop_httpd
test_done
diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh
index a51b7e2..f5721b4 100755
--- a/t/t5551-http-fetch-smart.sh
+++ b/t/t5551-http-fetch-smart.sh
@@ -364,5 +364,38 @@ test_expect_success 'custom http headers' '
submodule update sub
'
+test_expect_success 'GIT_REDACT_COOKIES redacts cookies' '
+ rm -rf clone &&
+ echo "Set-Cookie: Foo=1" >cookies &&
+ echo "Set-Cookie: Bar=2" >>cookies &&
+ GIT_TRACE_CURL=true GIT_REDACT_COOKIES=Bar,Baz \
+ git -c "http.cookieFile=$(pwd)/cookies" clone \
+ $HTTPD_URL/smart/repo.git clone 2>err &&
+ grep "Cookie:.*Foo=1" err &&
+ grep "Cookie:.*Bar=<redacted>" err &&
+ ! grep "Cookie:.*Bar=2" err
+'
+
+test_expect_success 'GIT_REDACT_COOKIES handles empty values' '
+ rm -rf clone &&
+ echo "Set-Cookie: Foo=" >cookies &&
+ GIT_TRACE_CURL=true GIT_REDACT_COOKIES=Foo \
+ git -c "http.cookieFile=$(pwd)/cookies" clone \
+ $HTTPD_URL/smart/repo.git clone 2>err &&
+ grep "Cookie:.*Foo=<redacted>" err
+'
+
+test_expect_success 'GIT_TRACE_CURL_NO_DATA prevents data from being traced' '
+ rm -rf clone &&
+ GIT_TRACE_CURL=true \
+ git clone $HTTPD_URL/smart/repo.git clone 2>err &&
+ grep "=> Send data" err &&
+
+ rm -rf clone &&
+ GIT_TRACE_CURL=true GIT_TRACE_CURL_NO_DATA=1 \
+ git clone $HTTPD_URL/smart/repo.git clone 2>err &&
+ ! grep "=> Send data" err
+'
+
stop_httpd
test_done
diff --git a/t/t5570-git-daemon.sh b/t/t5570-git-daemon.sh
index 225a022..755b05a 100755
--- a/t/t5570-git-daemon.sh
+++ b/t/t5570-git-daemon.sh
@@ -167,23 +167,48 @@ test_expect_success 'access repo via interpolated hostname' '
git init --bare "$repo" &&
git push "$repo" HEAD &&
>"$repo"/git-daemon-export-ok &&
- rm -rf tmp.git &&
GIT_OVERRIDE_VIRTUAL_HOST=localhost \
- git clone --bare "$GIT_DAEMON_URL/interp.git" tmp.git &&
- rm -rf tmp.git &&
+ git ls-remote "$GIT_DAEMON_URL/interp.git" &&
GIT_OVERRIDE_VIRTUAL_HOST=LOCALHOST \
- git clone --bare "$GIT_DAEMON_URL/interp.git" tmp.git
+ git ls-remote "$GIT_DAEMON_URL/interp.git"
'
test_expect_success 'hostname cannot break out of directory' '
- rm -rf tmp.git &&
repo="$GIT_DAEMON_DOCUMENT_ROOT_PATH/../escape.git" &&
git init --bare "$repo" &&
git push "$repo" HEAD &&
>"$repo"/git-daemon-export-ok &&
test_must_fail \
env GIT_OVERRIDE_VIRTUAL_HOST=.. \
- git clone --bare "$GIT_DAEMON_URL/escape.git" tmp.git
+ git ls-remote "$GIT_DAEMON_URL/escape.git"
+'
+
+test_expect_success 'daemon log records all attributes' '
+ cat >expect <<-\EOF &&
+ Extended attribute "host": localhost
+ Extended attribute "protocol": version=1
+ EOF
+ >daemon.log &&
+ GIT_OVERRIDE_VIRTUAL_HOST=localhost \
+ git -c protocol.version=1 \
+ ls-remote "$GIT_DAEMON_URL/interp.git" &&
+ grep -i extended.attribute daemon.log | cut -d" " -f2- >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success FAKENC 'hostname interpolation works after LF-stripping' '
+ {
+ printf "git-upload-pack /interp.git\n\0host=localhost" | packetize
+ printf "0000"
+ } >input &&
+ fake_nc "$GIT_DAEMON_HOST_PORT" <input >output &&
+ depacketize <output >output.raw &&
+
+ # just pick out the value of master, which avoids any protocol
+ # particulars
+ perl -lne "print \$1 if m{^(\\S+) refs/heads/master}" <output.raw >actual &&
+ git -C "$repo" rev-parse master >expect &&
+ test_cmp expect actual
'
stop_git_daemon
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 8c437bf..0b62037 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -628,4 +628,105 @@ test_expect_success 'clone on case-insensitive fs' '
)
'
+partial_clone () {
+ SERVER="$1" &&
+ URL="$2" &&
+
+ rm -rf "$SERVER" client &&
+ test_create_repo "$SERVER" &&
+ test_commit -C "$SERVER" one &&
+ HASH1=$(git hash-object "$SERVER/one.t") &&
+ git -C "$SERVER" revert HEAD &&
+ test_commit -C "$SERVER" two &&
+ HASH2=$(git hash-object "$SERVER/two.t") &&
+ test_config -C "$SERVER" uploadpack.allowfilter 1 &&
+ test_config -C "$SERVER" uploadpack.allowanysha1inwant 1 &&
+
+ git clone --filter=blob:limit=0 "$URL" client &&
+
+ git -C client fsck &&
+
+ # Ensure that unneeded blobs are not inadvertently fetched.
+ test_config -C client extensions.partialclone "not a remote" &&
+ test_must_fail git -C client cat-file -e "$HASH1" &&
+
+ # But this blob was fetched, because clone performs an initial checkout
+ git -C client cat-file -e "$HASH2"
+}
+
+test_expect_success 'partial clone' '
+ partial_clone server "file://$(pwd)/server"
+'
+
+test_expect_success 'partial clone: warn if server does not support object filtering' '
+ rm -rf server client &&
+ test_create_repo server &&
+ test_commit -C server one &&
+
+ git clone --filter=blob:limit=0 "file://$(pwd)/server" client 2> err &&
+
+ test_i18ngrep "filtering not recognized by server" err
+'
+
+test_expect_success 'batch missing blob request during checkout' '
+ rm -rf server client &&
+
+ test_create_repo server &&
+ echo a >server/a &&
+ echo b >server/b &&
+ git -C server add a b &&
+
+ git -C server commit -m x &&
+ echo aa >server/a &&
+ echo bb >server/b &&
+ git -C server add a b &&
+ git -C server commit -m x &&
+
+ test_config -C server uploadpack.allowfilter 1 &&
+ test_config -C server uploadpack.allowanysha1inwant 1 &&
+
+ git clone --filter=blob:limit=0 "file://$(pwd)/server" client &&
+
+ # Ensure that there is only one negotiation by checking that there is
+ # only "done" line sent. ("done" marks the end of negotiation.)
+ GIT_TRACE_PACKET="$(pwd)/trace" git -C client checkout HEAD^ &&
+ grep "git> done" trace >done_lines &&
+ test_line_count = 1 done_lines
+'
+
+test_expect_success 'batch missing blob request does not inadvertently try to fetch gitlinks' '
+ rm -rf server client &&
+
+ test_create_repo repo_for_submodule &&
+ test_commit -C repo_for_submodule x &&
+
+ test_create_repo server &&
+ echo a >server/a &&
+ echo b >server/b &&
+ git -C server add a b &&
+ git -C server commit -m x &&
+
+ echo aa >server/a &&
+ echo bb >server/b &&
+ # Also add a gitlink pointing to an arbitrary repository
+ git -C server submodule add "$(pwd)/repo_for_submodule" c &&
+ git -C server add a b c &&
+ git -C server commit -m x &&
+
+ test_config -C server uploadpack.allowfilter 1 &&
+ test_config -C server uploadpack.allowanysha1inwant 1 &&
+
+ # Make sure that it succeeds
+ git clone --filter=blob:limit=0 "file://$(pwd)/server" client
+'
+
+. "$TEST_DIRECTORY"/lib-httpd.sh
+start_httpd
+
+test_expect_success 'partial clone using HTTP' '
+ partial_clone "$HTTPD_DOCUMENT_ROOT_PATH/server" "$HTTPD_URL/smart/server"
+'
+
+stop_httpd
+
test_done
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
new file mode 100755
index 0000000..29d8631
--- /dev/null
+++ b/t/t5616-partial-clone.sh
@@ -0,0 +1,146 @@
+#!/bin/sh
+
+test_description='git partial clone'
+
+. ./test-lib.sh
+
+# create a normal "src" repo where we can later create new commits.
+# expect_1.oids will contain a list of the OIDs of all blobs.
+test_expect_success 'setup normal src repo' '
+ echo "{print \$1}" >print_1.awk &&
+ echo "{print \$2}" >print_2.awk &&
+
+ git init src &&
+ for n in 1 2 3 4
+ do
+ echo "This is file: $n" > src/file.$n.txt
+ git -C src add file.$n.txt
+ git -C src commit -m "file $n"
+ git -C src ls-files -s file.$n.txt >>temp
+ done &&
+ awk -f print_2.awk <temp | sort >expect_1.oids &&
+ test_line_count = 4 expect_1.oids
+'
+
+# bare clone "src" giving "srv.bare" for use as our server.
+test_expect_success 'setup bare clone for server' '
+ git clone --bare "file://$(pwd)/src" srv.bare &&
+ git -C srv.bare config --local uploadpack.allowfilter 1 &&
+ git -C srv.bare config --local uploadpack.allowanysha1inwant 1
+'
+
+# do basic partial clone from "srv.bare"
+# confirm we are missing all of the known blobs.
+# confirm partial clone was registered in the local config.
+test_expect_success 'do partial clone 1' '
+ git clone --no-checkout --filter=blob:none "file://$(pwd)/srv.bare" pc1 &&
+ git -C pc1 rev-list HEAD --quiet --objects --missing=print \
+ | awk -f print_1.awk \
+ | sed "s/?//" \
+ | sort >observed.oids &&
+ test_cmp expect_1.oids observed.oids &&
+ test "$(git -C pc1 config --local core.repositoryformatversion)" = "1" &&
+ test "$(git -C pc1 config --local extensions.partialclone)" = "origin" &&
+ test "$(git -C pc1 config --local core.partialclonefilter)" = "blob:none"
+'
+
+# checkout master to force dynamic object fetch of blobs at HEAD.
+test_expect_success 'verify checkout with dynamic object fetch' '
+ git -C pc1 rev-list HEAD --quiet --objects --missing=print >observed &&
+ test_line_count = 4 observed &&
+ git -C pc1 checkout master &&
+ git -C pc1 rev-list HEAD --quiet --objects --missing=print >observed &&
+ test_line_count = 0 observed
+'
+
+# create new commits in "src" repo to establish a blame history on file.1.txt
+# and push to "srv.bare".
+test_expect_success 'push new commits to server' '
+ git -C src remote add srv "file://$(pwd)/srv.bare" &&
+ for x in a b c d e
+ do
+ echo "Mod file.1.txt $x" >>src/file.1.txt
+ git -C src add file.1.txt
+ git -C src commit -m "mod $x"
+ done &&
+ git -C src blame master -- file.1.txt >expect.blame &&
+ git -C src push -u srv master
+'
+
+# (partial) fetch in the partial clone repo from the promisor remote.
+# verify that fetch inherited the filter-spec from the config and DOES NOT
+# have the new blobs.
+test_expect_success 'partial fetch inherits filter settings' '
+ git -C pc1 fetch origin &&
+ git -C pc1 rev-list master..origin/master --quiet --objects --missing=print >observed &&
+ test_line_count = 5 observed
+'
+
+# force dynamic object fetch using diff.
+# we should only get 1 new blob (for the file in origin/master).
+test_expect_success 'verify diff causes dynamic object fetch' '
+ git -C pc1 diff master..origin/master -- file.1.txt &&
+ git -C pc1 rev-list master..origin/master --quiet --objects --missing=print >observed &&
+ test_line_count = 4 observed
+'
+
+# force full dynamic object fetch of the file's history using blame.
+# we should get the intermediate blobs for the file.
+test_expect_success 'verify blame causes dynamic object fetch' '
+ git -C pc1 blame origin/master -- file.1.txt >observed.blame &&
+ test_cmp expect.blame observed.blame &&
+ git -C pc1 rev-list master..origin/master --quiet --objects --missing=print >observed &&
+ test_line_count = 0 observed
+'
+
+# create new commits in "src" repo to establish a history on file.2.txt
+# and push to "srv.bare".
+test_expect_success 'push new commits to server for file.2.txt' '
+ for x in a b c d e f
+ do
+ echo "Mod file.2.txt $x" >>src/file.2.txt
+ git -C src add file.2.txt
+ git -C src commit -m "mod $x"
+ done &&
+ git -C src push -u srv master
+'
+
+# Do FULL fetch by disabling inherited filter-spec using --no-filter.
+# Verify we have all the new blobs.
+test_expect_success 'override inherited filter-spec using --no-filter' '
+ git -C pc1 fetch --no-filter origin &&
+ git -C pc1 rev-list master..origin/master --quiet --objects --missing=print >observed &&
+ test_line_count = 0 observed
+'
+
+# create new commits in "src" repo to establish a history on file.3.txt
+# and push to "srv.bare".
+test_expect_success 'push new commits to server for file.3.txt' '
+ for x in a b c d e f
+ do
+ echo "Mod file.3.txt $x" >>src/file.3.txt
+ git -C src add file.3.txt
+ git -C src commit -m "mod $x"
+ done &&
+ git -C src push -u srv master
+'
+
+# Do a partial fetch and then try to manually fetch the missing objects.
+# This can be used as the basis of a pre-command hook to bulk fetch objects
+# perhaps combined with a command in dry-run mode.
+test_expect_success 'manual prefetch of missing objects' '
+ git -C pc1 fetch --filter=blob:none origin &&
+ git -C pc1 rev-list master..origin/master --quiet --objects --missing=print \
+ | awk -f print_1.awk \
+ | sed "s/?//" \
+ | sort >observed.oids &&
+ test_line_count = 6 observed.oids &&
+ git -C pc1 fetch-pack --stdin "file://$(pwd)/srv.bare" <observed.oids &&
+ git -C pc1 rev-list master..origin/master --quiet --objects --missing=print \
+ | awk -f print_1.awk \
+ | sed "s/?//" \
+ | sort >observed.oids &&
+ test_line_count = 0 observed.oids
+'
+
+test_done
diff --git a/t/t5812-proto-disable-http.sh b/t/t5812-proto-disable-http.sh
index d911afd..872788a 100755
--- a/t/t5812-proto-disable-http.sh
+++ b/t/t5812-proto-disable-http.sh
@@ -20,10 +20,7 @@ test_expect_success 'curl redirects respect whitelist' '
test_must_fail env GIT_ALLOW_PROTOCOL=http:https \
GIT_SMART_HTTP=0 \
git clone "$HTTPD_URL/ftp-redir/repo.git" 2>stderr &&
- {
- test_i18ngrep "ftp.*disabled" stderr ||
- test_i18ngrep "your curl version is too old"
- }
+ test_i18ngrep -E "(ftp.*disabled|your curl version is too old)" stderr
'
test_expect_success 'curl limits redirects' '
diff --git a/t/t6015-rev-list-show-all-parents.sh b/t/t6015-rev-list-show-all-parents.sh
deleted file mode 100755
index 3c73c93..0000000
--- a/t/t6015-rev-list-show-all-parents.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/sh
-
-test_description='--show-all --parents does not rewrite TREESAME commits'
-
-. ./test-lib.sh
-
-test_expect_success 'set up --show-all --parents test' '
- test_commit one foo.txt &&
- commit1=$(git rev-list -1 HEAD) &&
- test_commit two bar.txt &&
- commit2=$(git rev-list -1 HEAD) &&
- test_commit three foo.txt &&
- commit3=$(git rev-list -1 HEAD)
- '
-
-test_expect_success '--parents rewrites TREESAME parents correctly' '
- echo $commit3 $commit1 > expected &&
- echo $commit1 >> expected &&
- git rev-list --parents HEAD -- foo.txt > actual &&
- test_cmp expected actual
- '
-
-test_expect_success '--parents --show-all does not rewrites TREESAME parents' '
- echo $commit3 $commit2 > expected &&
- echo $commit2 $commit1 >> expected &&
- echo $commit1 >> expected &&
- git rev-list --parents --show-all HEAD -- foo.txt > actual &&
- test_cmp expected actual
- '
-
-test_done
diff --git a/t/t6022-merge-rename.sh b/t/t6022-merge-rename.sh
index 05ebba7..c01f721 100755
--- a/t/t6022-merge-rename.sh
+++ b/t/t6022-merge-rename.sh
@@ -242,10 +242,12 @@ test_expect_success 'merge of identical changes in a renamed file' '
rm -f A M N &&
git reset --hard &&
git checkout change+rename &&
- GIT_MERGE_VERBOSITY=3 git merge change | test_i18ngrep "^Skipped B" &&
+ GIT_MERGE_VERBOSITY=3 git merge change >out &&
+ test_i18ngrep "^Skipped B" out &&
git reset --hard HEAD^ &&
git checkout change &&
- GIT_MERGE_VERBOSITY=3 git merge change+rename | test_i18ngrep "^Skipped B"
+ GIT_MERGE_VERBOSITY=3 git merge change+rename >out &&
+ test_i18ngrep "^Skipped B" out
'
test_expect_success 'setup for rename + d/f conflicts' '
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index a5d9015..bae78c4 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -378,4 +378,12 @@ check_describe tags/A --all A
check_describe tags/c --all c
check_describe heads/branch_A --all --match='branch_*' branch_A
+test_expect_success 'describe complains about tree object' '
+ test_must_fail git describe HEAD^{tree}
+'
+
+test_expect_success 'describe complains about missing object' '
+ test_must_fail git describe $_z40
+'
+
test_done
diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh
index 2e2fb0e..a54a52a 100755
--- a/t/t6200-fmt-merge-msg.sh
+++ b/t/t6200-fmt-merge-msg.sh
@@ -512,7 +512,7 @@ test_expect_success 'merge-msg with "merging" an annotated tag' '
test_when_finished "git reset --hard" &&
annote=$(git rev-parse annote) &&
- git merge --no-commit $annote &&
+ git merge --no-commit --no-ff $annote &&
{
cat <<-EOF
Merge tag '\''$annote'\''
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index c128dfc..295d147 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -373,11 +373,8 @@ test_expect_success 'Quoting style: tcl' '
for i in "--perl --shell" "-s --python" "--python --tcl" "--tcl --perl"; do
test_expect_success "more than one quoting style: $i" "
- git for-each-ref $i 2>&1 | (read line &&
- case \$line in
- \"error: more than one quoting style\"*) : happy;;
- *) false
- esac)
+ test_must_fail git for-each-ref $i 2>err &&
+ grep '^error: more than one quoting style' err
"
done
diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh
index 6e5031f..d4e6485 100755
--- a/t/t7001-mv.sh
+++ b/t/t7001-mv.sh
@@ -39,6 +39,12 @@ test_expect_success \
grep "^R100..*path1/COPYING..*path0/COPYING"'
test_expect_success \
+ 'mv --dry-run does not move file' \
+ 'git mv -n path0/COPYING MOVED &&
+ test -f path0/COPYING &&
+ test ! -f MOVED'
+
+test_expect_success \
'checking -k on non-existing file' \
'git mv -k idontexist path0'
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index a9af2de..2aac77a 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -452,6 +452,21 @@ test_expect_success \
test_cmp expect actual
'
+get_tag_header annotated-tag-edit $commit commit $time >expect
+echo "An edited message" >>expect
+test_expect_success 'set up editor' '
+ write_script fakeeditor <<-\EOF
+ sed -e "s/A message/An edited message/g" <"$1" >"$1-"
+ mv "$1-" "$1"
+ EOF
+'
+test_expect_success \
+ 'creating an annotated tag with -m message --edit should succeed' '
+ GIT_EDITOR=./fakeeditor git tag -m "A message" --edit annotated-tag-edit &&
+ get_tag_msg annotated-tag-edit >actual &&
+ test_cmp expect actual
+'
+
cat >msgfile <<EOF
Another message
in a file.
@@ -465,6 +480,21 @@ test_expect_success \
test_cmp expect actual
'
+get_tag_header file-annotated-tag-edit $commit commit $time >expect
+sed -e "s/Another message/Another edited message/g" msgfile >>expect
+test_expect_success 'set up editor' '
+ write_script fakeeditor <<-\EOF
+ sed -e "s/Another message/Another edited message/g" <"$1" >"$1-"
+ mv "$1-" "$1"
+ EOF
+'
+test_expect_success \
+ 'creating an annotated tag with -F messagefile --edit should succeed' '
+ GIT_EDITOR=./fakeeditor git tag -F msgfile --edit file-annotated-tag-edit &&
+ get_tag_msg file-annotated-tag-edit >actual &&
+ test_cmp expect actual
+'
+
cat >inputmsg <<EOF
A message from the
standard input
diff --git a/t/t7063-status-untracked-cache.sh b/t/t7063-status-untracked-cache.sh
index e5fb892..46b9478 100755
--- a/t/t7063-status-untracked-cache.sh
+++ b/t/t7063-status-untracked-cache.sh
@@ -22,6 +22,12 @@ avoid_racy() {
sleep 1
}
+status_is_clean() {
+ >../status.expect &&
+ git status --porcelain >../status.actual &&
+ test_cmp ../status.expect ../status.actual
+}
+
test_lazy_prereq UNTRACKED_CACHE '
{ git update-index --test-untracked-cache; ret=$?; } &&
test $ret -ne 1
@@ -683,4 +689,85 @@ test_expect_success 'untracked cache survives a commit' '
test_cmp ../before ../after
'
+test_expect_success 'teardown worktree' '
+ cd ..
+'
+
+test_expect_success SYMLINKS 'setup worktree for symlink test' '
+ git init worktree-symlink &&
+ cd worktree-symlink &&
+ git config core.untrackedCache true &&
+ mkdir one two &&
+ touch one/file two/file &&
+ git add one/file two/file &&
+ git commit -m"first commit" &&
+ git rm -rf one &&
+ ln -s two one &&
+ git add one &&
+ git commit -m"second commit"
+'
+
+test_expect_success SYMLINKS '"status" after symlink replacement should be clean with UC=true' '
+ git checkout HEAD~ &&
+ status_is_clean &&
+ status_is_clean &&
+ git checkout master &&
+ avoid_racy &&
+ status_is_clean &&
+ status_is_clean
+'
+
+test_expect_success SYMLINKS '"status" after symlink replacement should be clean with UC=false' '
+ git config core.untrackedCache false &&
+ git checkout HEAD~ &&
+ status_is_clean &&
+ status_is_clean &&
+ git checkout master &&
+ avoid_racy &&
+ status_is_clean &&
+ status_is_clean
+'
+
+test_expect_success 'setup worktree for non-symlink test' '
+ git init worktree-non-symlink &&
+ cd worktree-non-symlink &&
+ git config core.untrackedCache true &&
+ mkdir one two &&
+ touch one/file two/file &&
+ git add one/file two/file &&
+ git commit -m"first commit" &&
+ git rm -rf one &&
+ cp two/file one &&
+ git add one &&
+ git commit -m"second commit"
+'
+
+test_expect_success '"status" after file replacement should be clean with UC=true' '
+ git checkout HEAD~ &&
+ status_is_clean &&
+ status_is_clean &&
+ git checkout master &&
+ avoid_racy &&
+ status_is_clean &&
+ test-dump-untracked-cache >../actual &&
+ grep -F "recurse valid" ../actual >../actual.grep &&
+ cat >../expect.grep <<EOF &&
+/ 0000000000000000000000000000000000000000 recurse valid
+/two/ 0000000000000000000000000000000000000000 recurse valid
+EOF
+ status_is_clean &&
+ test_cmp ../expect.grep ../actual.grep
+'
+
+test_expect_success '"status" after file replacement should be clean with UC=false' '
+ git config core.untrackedCache false &&
+ git checkout HEAD~ &&
+ status_is_clean &&
+ status_is_clean &&
+ git checkout master &&
+ avoid_racy &&
+ status_is_clean &&
+ status_is_clean
+'
+
test_done
diff --git a/t/t7409-submodule-detached-work-tree.sh b/t/t7409-submodule-detached-work-tree.sh
index c207171..fc018e3 100755
--- a/t/t7409-submodule-detached-work-tree.sh
+++ b/t/t7409-submodule-detached-work-tree.sh
@@ -6,7 +6,7 @@
test_description='Test submodules on detached working tree
This test verifies that "git submodule" initialization, update and addition works
-on detahced working trees
+on detached working trees
'
TEST_NO_CREATE_REPO=1
diff --git a/t/t7505-prepare-commit-msg-hook.sh b/t/t7505-prepare-commit-msg-hook.sh
index b13f729..1f43b3c 100755
--- a/t/t7505-prepare-commit-msg-hook.sh
+++ b/t/t7505-prepare-commit-msg-hook.sh
@@ -4,6 +4,38 @@ test_description='prepare-commit-msg hook'
. ./test-lib.sh
+test_expect_success 'set up commits for rebasing' '
+ test_commit root &&
+ test_commit a a a &&
+ test_commit b b b &&
+ git checkout -b rebase-me root &&
+ test_commit rebase-a a aa &&
+ test_commit rebase-b b bb &&
+ for i in $(test_seq 1 13)
+ do
+ test_commit rebase-$i c $i
+ done &&
+ git checkout master &&
+
+ cat >rebase-todo <<-EOF
+ pick $(git rev-parse rebase-a)
+ pick $(git rev-parse rebase-b)
+ fixup $(git rev-parse rebase-1)
+ fixup $(git rev-parse rebase-2)
+ pick $(git rev-parse rebase-3)
+ fixup $(git rev-parse rebase-4)
+ squash $(git rev-parse rebase-5)
+ reword $(git rev-parse rebase-6)
+ squash $(git rev-parse rebase-7)
+ fixup $(git rev-parse rebase-8)
+ fixup $(git rev-parse rebase-9)
+ edit $(git rev-parse rebase-10)
+ squash $(git rev-parse rebase-11)
+ squash $(git rev-parse rebase-12)
+ edit $(git rev-parse rebase-13)
+ EOF
+'
+
test_expect_success 'with no hook' '
echo "foo" > file &&
@@ -31,17 +63,41 @@ mkdir -p "$HOOKDIR"
echo "#!$SHELL_PATH" > "$HOOK"
cat >> "$HOOK" <<'EOF'
-if test "$2" = commit; then
- source=$(git rev-parse "$3")
+GIT_DIR=$(git rev-parse --git-dir)
+if test -d "$GIT_DIR/rebase-merge"
+then
+ rebasing=1
else
- source=${2-default}
+ rebasing=0
fi
-if test "$GIT_EDITOR" = :; then
- sed -e "1s/.*/$source (no editor)/" "$1" > msg.tmp
+
+get_last_cmd () {
+ tail -n1 "$GIT_DIR/rebase-merge/done" | {
+ read cmd id _
+ git log --pretty="[$cmd %s]" -n1 $id
+ }
+}
+
+if test "$2" = commit
+then
+ if test $rebasing = 1
+ then
+ source="$3"
+ else
+ source=$(git rev-parse "$3")
+ fi
else
- sed -e "1s/.*/$source/" "$1" > msg.tmp
+ source=${2-default}
+fi
+test "$GIT_EDITOR" = : && source="$source (no editor)"
+
+if test $rebasing = 1
+then
+ echo "$source $(get_last_cmd)" >"$1"
+else
+ sed -e "1s/.*/$source/" "$1" >msg.tmp
+ mv msg.tmp "$1"
fi
-mv msg.tmp "$1"
exit 0
EOF
chmod +x "$HOOK"
@@ -156,6 +212,63 @@ test_expect_success 'with hook and editor (merge)' '
test "$(git log -1 --pretty=format:%s)" = "merge"
'
+test_rebase () {
+ expect=$1 &&
+ mode=$2 &&
+ test_expect_$expect C_LOCALE_OUTPUT "with hook (rebase $mode)" '
+ test_when_finished "\
+ git rebase --abort
+ git checkout -f master
+ git branch -D tmp" &&
+ git checkout -b tmp rebase-me &&
+ GIT_SEQUENCE_EDITOR="cp rebase-todo" &&
+ GIT_EDITOR="\"$FAKE_EDITOR\"" &&
+ (
+ export GIT_SEQUENCE_EDITOR GIT_EDITOR &&
+ test_must_fail git rebase $mode b &&
+ echo x >a &&
+ git add a &&
+ test_must_fail git rebase --continue &&
+ echo x >b &&
+ git add b &&
+ git commit &&
+ git rebase --continue &&
+ echo y >a &&
+ git add a &&
+ git commit &&
+ git rebase --continue &&
+ echo y >b &&
+ git add b &&
+ git rebase --continue
+ ) &&
+ if test $mode = -p # reword amended after pick
+ then
+ n=18
+ else
+ n=17
+ fi &&
+ git log --pretty=%s -g -n$n HEAD@{1} >actual &&
+ test_cmp "$TEST_DIRECTORY/t7505/expected-rebase$mode" actual
+ '
+}
+
+test_rebase success -i
+test_rebase success -p
+
+test_expect_success 'with hook (cherry-pick)' '
+ test_when_finished "git checkout -f master" &&
+ git checkout -B other b &&
+ git cherry-pick rebase-1 &&
+ test "$(git log -1 --pretty=format:%s)" = "message (no editor)"
+'
+
+test_expect_success 'with hook and editor (cherry-pick)' '
+ test_when_finished "git checkout -f master" &&
+ git checkout -B other b &&
+ git cherry-pick -e rebase-1 &&
+ test "$(git log -1 --pretty=format:%s)" = merge
+'
+
cat > "$HOOK" <<'EOF'
#!/bin/sh
exit 1
@@ -197,4 +310,11 @@ test_expect_success 'with failing hook (merge)' '
'
+test_expect_success C_LOCALE_OUTPUT 'with failing hook (cherry-pick)' '
+ test_when_finished "git checkout -f master" &&
+ git checkout -B other b &&
+ test_must_fail git cherry-pick rebase-1 2>actual &&
+ test $(grep -c prepare-commit-msg actual) = 1
+'
+
test_done
diff --git a/t/t7505/expected-rebase-i b/t/t7505/expected-rebase-i
new file mode 100644
index 0000000..c514bdb
--- /dev/null
+++ b/t/t7505/expected-rebase-i
@@ -0,0 +1,17 @@
+message [edit rebase-13]
+message (no editor) [edit rebase-13]
+message [squash rebase-12]
+message (no editor) [squash rebase-11]
+default [edit rebase-10]
+message (no editor) [edit rebase-10]
+message [fixup rebase-9]
+message (no editor) [fixup rebase-8]
+message (no editor) [squash rebase-7]
+message [reword rebase-6]
+message [squash rebase-5]
+message (no editor) [fixup rebase-4]
+message (no editor) [pick rebase-3]
+message (no editor) [fixup rebase-2]
+message (no editor) [fixup rebase-1]
+merge [pick rebase-b]
+message [pick rebase-a]
diff --git a/t/t7505/expected-rebase-p b/t/t7505/expected-rebase-p
new file mode 100644
index 0000000..93bada5
--- /dev/null
+++ b/t/t7505/expected-rebase-p
@@ -0,0 +1,18 @@
+message [edit rebase-13]
+message (no editor) [edit rebase-13]
+message [squash rebase-12]
+message (no editor) [squash rebase-11]
+default [edit rebase-10]
+message (no editor) [edit rebase-10]
+message [fixup rebase-9]
+message (no editor) [fixup rebase-8]
+message (no editor) [squash rebase-7]
+HEAD [reword rebase-6]
+message (no editor) [reword rebase-6]
+message [squash rebase-5]
+message (no editor) [fixup rebase-4]
+message (no editor) [pick rebase-3]
+message (no editor) [fixup rebase-2]
+message (no editor) [fixup rebase-1]
+merge [pick rebase-b]
+message [pick rebase-a]
diff --git a/t/t7519-status-fsmonitor.sh b/t/t7519-status-fsmonitor.sh
index eb2d13b..756beb0 100755
--- a/t/t7519-status-fsmonitor.sh
+++ b/t/t7519-status-fsmonitor.sh
@@ -314,4 +314,43 @@ test_expect_success 'splitting the index results in the same state' '
test_cmp expect actual
'
+test_expect_success UNTRACKED_CACHE 'ignore .git changes when invalidating UNTR' '
+ test_create_repo dot-git &&
+ (
+ cd dot-git &&
+ mkdir -p .git/hooks &&
+ : >tracked &&
+ : >modified &&
+ mkdir dir1 &&
+ : >dir1/tracked &&
+ : >dir1/modified &&
+ mkdir dir2 &&
+ : >dir2/tracked &&
+ : >dir2/modified &&
+ write_integration_script &&
+ git config core.fsmonitor .git/hooks/fsmonitor-test &&
+ git update-index --untracked-cache &&
+ git update-index --fsmonitor &&
+ GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace-before" \
+ git status &&
+ test-dump-untracked-cache >../before
+ ) &&
+ cat >>dot-git/.git/hooks/fsmonitor-test <<-\EOF &&
+ printf ".git\0"
+ printf ".git/index\0"
+ printf "dir1/.git\0"
+ printf "dir1/.git/index\0"
+ EOF
+ (
+ cd dot-git &&
+ GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace-after" \
+ git status &&
+ test-dump-untracked-cache >../after
+ ) &&
+ grep "directory invalidation" trace-before >>before &&
+ grep "directory invalidation" trace-after >>after &&
+ # UNTR extension unchanged, dir invalidation count unchanged
+ test_cmp before after
+'
+
test_done
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index dfde6a6..6736d8d 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -700,6 +700,42 @@ test_expect_success 'merge --no-ff --edit' '
test_cmp expected actual
'
+test_expect_success 'merge annotated/signed tag w/o tracking' '
+ test_when_finished "rm -rf dst; git tag -d anno1" &&
+ git tag -a -m "anno c1" anno1 c1 &&
+ git init dst &&
+ git rev-parse c1 >dst/expect &&
+ (
+ # c0 fast-forwards to c1 but because this repository
+ # is not a "downstream" whose refs/tags follows along
+ # tag from the "upstream", this pull defaults to --no-ff
+ cd dst &&
+ git pull .. c0 &&
+ git pull .. anno1 &&
+ git rev-parse HEAD^2 >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'merge annotated/signed tag w/ tracking' '
+ test_when_finished "rm -rf dst; git tag -d anno1" &&
+ git tag -a -m "anno c1" anno1 c1 &&
+ git init dst &&
+ git rev-parse c1 >dst/expect &&
+ (
+ # c0 fast-forwards to c1 and because this repository
+ # is a "downstream" whose refs/tags follows along
+ # tag from the "upstream", this pull defaults to --ff
+ cd dst &&
+ git remote add origin .. &&
+ git pull origin c0 &&
+ git fetch origin &&
+ git merge anno1 &&
+ git rev-parse HEAD >actual &&
+ test_cmp expect actual
+ )
+'
+
test_expect_success GPG 'merge --ff-only tag' '
git reset --hard c0 &&
git commit --allow-empty -m "A newer commit" &&
@@ -718,7 +754,7 @@ test_expect_success GPG 'merge --no-edit tag should skip editor' '
git tag -f -s -m "A newer commit" signed &&
git reset --hard c0 &&
- EDITOR=false git merge --no-edit signed &&
+ EDITOR=false git merge --no-edit --no-ff signed &&
git rev-parse signed^0 >expect &&
git rev-parse HEAD^2 >actual &&
test_cmp expect actual
diff --git a/t/t7607-merge-overwrite.sh b/t/t7607-merge-overwrite.sh
index 9444d6a..9c422bc 100755
--- a/t/t7607-merge-overwrite.sh
+++ b/t/t7607-merge-overwrite.sh
@@ -97,7 +97,10 @@ test_expect_failure 'will not overwrite unstaged changes in renamed file' '
git mv c1.c other.c &&
git commit -m rename &&
cp important other.c &&
- git merge c1a &&
+ test_must_fail git merge c1a >out &&
+ test_i18ngrep "Refusing to lose dirty file at other.c" out &&
+ test_path_is_file other.c~HEAD &&
+ test $(git hash-object other.c~HEAD) = $(git rev-parse c1a:c1.c) &&
test_cmp important other.c
'
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index a06e5d7..19601fb 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -6,6 +6,12 @@ test_description='git send-email'
# May be altered later in the test
PREREQ="PERL"
+replace_variable_fields () {
+ sed -e "s/^\(Date:\).*/\1 DATE-STRING/" \
+ -e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \
+ -e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/"
+}
+
test_expect_success $PREREQ 'prepare reference tree' '
echo "1A quick brown fox jumps over the" >file &&
echo "lazy dog" >>file &&
@@ -315,10 +321,7 @@ test_expect_success $PREREQ 'Show all headers' '
--bcc=bcc@example.com \
--in-reply-to="<unique-message-id@example.com>" \
--smtp-server relay.example.com \
- $patches |
- sed -e "s/^\(Date:\).*/\1 DATE-STRING/" \
- -e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \
- -e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/" \
+ $patches | replace_variable_fields \
>actual-show-all-headers &&
test_cmp expected-show-all-headers actual-show-all-headers
'
@@ -573,12 +576,6 @@ Result: OK
EOF
"
-replace_variable_fields () {
- sed -e "s/^\(Date:\).*/\1 DATE-STRING/" \
- -e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \
- -e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/"
-}
-
test_suppression () {
git send-email \
--dry-run \
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 1701fe2..42a6781 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -610,6 +610,14 @@ list_contains () {
#
# Writing this as "! git checkout ../outerspace" is wrong, because
# the failure could be due to a segv. We want a controlled failure.
+#
+# Accepts the following options:
+#
+# ok=<signal-name>[,<...>]:
+# Don't treat an exit caused by the given signal as error.
+# Multiple signals can be specified as a comma separated list.
+# Currently recognized signal names are: sigpipe, success.
+# (Don't use 'success', use 'test_might_fail' instead.)
test_must_fail () {
case "$1" in
@@ -625,22 +633,22 @@ test_must_fail () {
exit_code=$?
if test $exit_code -eq 0 && ! list_contains "$_test_ok" success
then
- echo >&2 "test_must_fail: command succeeded: $*"
+ echo >&4 "test_must_fail: command succeeded: $*"
return 1
elif test_match_signal 13 $exit_code && list_contains "$_test_ok" sigpipe
then
return 0
elif test $exit_code -gt 129 && test $exit_code -le 192
then
- echo >&2 "test_must_fail: died by signal $(($exit_code - 128)): $*"
+ echo >&4 "test_must_fail: died by signal $(($exit_code - 128)): $*"
return 1
elif test $exit_code -eq 127
then
- echo >&2 "test_must_fail: command not found: $*"
+ echo >&4 "test_must_fail: command not found: $*"
return 1
elif test $exit_code -eq 126
then
- echo >&2 "test_must_fail: valgrind error: $*"
+ echo >&4 "test_must_fail: valgrind error: $*"
return 1
fi
return 0
@@ -656,6 +664,8 @@ test_must_fail () {
#
# Writing "git config --unset all.configuration || :" would be wrong,
# because we want to notice if it fails due to segv.
+#
+# Accepts the same options as test_must_fail.
test_might_fail () {
test_must_fail ok=success "$@"
@@ -678,7 +688,7 @@ test_expect_code () {
return 0
fi
- echo >&2 "test_expect_code: command exited with $exit_code, we wanted $want_code $*"
+ echo >&4 "test_expect_code: command exited with $exit_code, we wanted $want_code $*"
return 1
}
@@ -705,12 +715,66 @@ test_cmp_bin() {
cmp "$@"
}
+# Use this instead of test_cmp to compare files that contain expected and
+# actual output from git commands that can be translated. When running
+# under GETTEXT_POISON this pretends that the command produced expected
+# results.
+test_i18ncmp () {
+ test -n "$GETTEXT_POISON" || test_cmp "$@"
+}
+
+# Use this instead of "grep expected-string actual" to see if the
+# output from a git command that can be translated either contains an
+# expected string, or does not contain an unwanted one. When running
+# under GETTEXT_POISON this pretends that the command produced expected
+# results.
+test_i18ngrep () {
+ eval "last_arg=\${$#}"
+
+ test -f "$last_arg" ||
+ error "bug in the test script: test_i18ngrep requires a file" \
+ "to read as the last parameter"
+
+ if test $# -lt 2 ||
+ { test "x!" = "x$1" && test $# -lt 3 ; }
+ then
+ error "bug in the test script: too few parameters to test_i18ngrep"
+ fi
+
+ if test -n "$GETTEXT_POISON"
+ then
+ # pretend success
+ return 0
+ fi
+
+ if test "x!" = "x$1"
+ then
+ shift
+ ! grep "$@" && return 0
+
+ echo >&4 "error: '! grep $@' did find a match in:"
+ else
+ grep "$@" && return 0
+
+ echo >&4 "error: 'grep $@' didn't find a match in:"
+ fi
+
+ if test -s "$last_arg"
+ then
+ cat >&4 "$last_arg"
+ else
+ echo >&4 "<File '$last_arg' is empty>"
+ fi
+
+ return 1
+}
+
# Call any command "$@" but be more verbose about its
# failure. This is handy for commands like "test" which do
# not output anything when they fail.
verbose () {
"$@" && return 0
- echo >&2 "command failed: $(git rev-parse --sq-quote "$@")"
+ echo >&4 "command failed: $(git rev-parse --sq-quote "$@")"
return 1
}
@@ -1020,3 +1084,37 @@ nongit () {
"$@"
)
}
+
+# convert stdin to pktline representation; note that empty input becomes an
+# empty packet, not a flush packet (for that you can just print 0000 yourself).
+packetize() {
+ cat >packetize.tmp &&
+ len=$(wc -c <packetize.tmp) &&
+ printf '%04x%s' "$(($len + 4))" &&
+ cat packetize.tmp &&
+ rm -f packetize.tmp
+}
+
+# Parse the input as a series of pktlines, writing the result to stdout.
+# Sideband markers are removed automatically, and the output is routed to
+# stderr if appropriate.
+#
+# NUL bytes are converted to "\\0" for ease of parsing with text tools.
+depacketize () {
+ perl -e '
+ while (read(STDIN, $len, 4) == 4) {
+ if ($len eq "0000") {
+ print "FLUSH\n";
+ } else {
+ read(STDIN, $buf, hex($len) - 4);
+ $buf =~ s/\0/\\0/g;
+ if ($buf =~ s/^[\x2\x3]//) {
+ print STDERR $buf;
+ } else {
+ $buf =~ s/^\x1//;
+ print $buf;
+ }
+ }
+ }
+ '
+}
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 9a0a21f..9535d2e 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -116,6 +116,7 @@ unset VISUAL EMAIL LANGUAGE COLUMNS $("$PERL_PATH" -e '
my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);
print join("\n", @vars);
')
+unset XDG_CACHE_HOME
unset XDG_CONFIG_HOME
unset GITPERLLIB
GIT_AUTHOR_EMAIL=author@example.com
@@ -939,7 +940,7 @@ then
fi
fi
-GITPERLLIB="$GIT_BUILD_DIR"/perl/blib/lib:"$GIT_BUILD_DIR"/perl/blib/arch/auto/Git
+GITPERLLIB="$GIT_BUILD_DIR"/perl/build/lib
export GITPERLLIB
test -d "$GIT_BUILD_DIR"/templates/blt || {
error "You haven't built things yet, have you?"
@@ -1062,32 +1063,6 @@ else
test_set_prereq C_LOCALE_OUTPUT
fi
-# Use this instead of test_cmp to compare files that contain expected and
-# actual output from git commands that can be translated. When running
-# under GETTEXT_POISON this pretends that the command produced expected
-# results.
-test_i18ncmp () {
- test -n "$GETTEXT_POISON" || test_cmp "$@"
-}
-
-# Use this instead of "grep expected-string actual" to see if the
-# output from a git command that can be translated either contains an
-# expected string, or does not contain an unwanted one. When running
-# under GETTEXT_POISON this pretends that the command produced expected
-# results.
-test_i18ngrep () {
- if test -n "$GETTEXT_POISON"
- then
- : # pretend success
- elif test "x!" = "x$1"
- then
- shift
- ! grep "$@"
- else
- grep "$@"
- fi
-}
-
test_lazy_prereq PIPE '
# test whether the filesystem supports FIFOs
test_have_prereq !MINGW,!CYGWIN &&
@@ -1132,6 +1107,10 @@ test_lazy_prereq EXPENSIVE '
test -n "$GIT_TEST_LONG"
'
+test_lazy_prereq EXPENSIVE_ON_WINDOWS '
+ test_have_prereq EXPENSIVE || test_have_prereq !MINGW,!CYGWIN
+'
+
test_lazy_prereq USR_BIN_TIME '
test -x /usr/bin/time
'