aboutsummaryrefslogtreecommitdiffstats
path: root/t
diff options
context:
space:
mode:
Diffstat (limited to 't')
-rw-r--r--t/Makefile2
-rwxr-xr-xt/chainlint.pl173
-rw-r--r--t/chainlint/block-comment.expect2
-rw-r--r--t/chainlint/case-comment.expect3
-rw-r--r--t/chainlint/close-subshell.expect3
-rw-r--r--t/chainlint/comment.expect4
-rw-r--r--t/chainlint/double-here-doc.expect14
-rw-r--r--t/chainlint/empty-here-doc.expect3
-rw-r--r--t/chainlint/for-loop.expect4
-rw-r--r--t/chainlint/here-doc-close-subshell.expect4
-rw-r--r--t/chainlint/here-doc-indent-operator.expect10
-rw-r--r--t/chainlint/here-doc-multi-line-command-subst.expect5
-rw-r--r--t/chainlint/here-doc-multi-line-string.expect4
-rw-r--r--t/chainlint/here-doc.expect24
-rw-r--r--t/chainlint/if-then-else.expect4
-rw-r--r--t/chainlint/incomplete-line.expect10
-rw-r--r--t/chainlint/inline-comment.expect4
-rw-r--r--t/chainlint/loop-detect-status.expect2
-rw-r--r--t/chainlint/nested-here-doc.expect27
-rw-r--r--t/chainlint/nested-subshell-comment.expect2
-rw-r--r--t/chainlint/subshell-here-doc.expect28
-rw-r--r--t/chainlint/t7900-subtree.expect4
-rw-r--r--t/chainlint/while-loop.expect4
-rw-r--r--t/helper/test-cache-tree.c65
-rw-r--r--t/helper/test-dump-cache-tree.c5
-rw-r--r--t/helper/test-dump-split-index.c1
-rw-r--r--t/helper/test-dump-untracked-cache.c4
-rw-r--r--t/helper/test-fast-rebase.c4
-rw-r--r--t/helper/test-lazy-init-name-hash.c21
-rw-r--r--t/helper/test-read-cache.c5
-rw-r--r--t/helper/test-scrap-cache-tree.c9
-rw-r--r--t/helper/test-sha1.c8
-rw-r--r--t/helper/test-submodule.c84
-rw-r--r--t/helper/test-tool.c2
-rw-r--r--t/helper/test-tool.h3
-rw-r--r--t/helper/test-write-cache.c6
-rw-r--r--t/lib-httpd.sh8
-rw-r--r--t/lib-httpd/apache.conf19
-rwxr-xr-xt/perf/p0006-read-tree-checkout.sh8
-rwxr-xr-xt/perf/p0090-cache-tree.sh36
-rwxr-xr-xt/perf/p7102-reset.sh21
-rwxr-xr-xt/t0003-attributes.sh59
-rwxr-xr-xt/t0013-sha1dc.sh6
-rwxr-xr-xt/t0040-parse-options.sh12
-rwxr-xr-xt/t0061-run-command.sh15
-rwxr-xr-xt/t0066-dir-iterator.sh27
-rwxr-xr-xt/t0068-for-each-repo.sh6
-rwxr-xr-xt/t0211-trace2-perf.sh4
-rwxr-xr-xt/t1022-read-tree-partial-clone.sh2
-rwxr-xr-xt/t1050-large.sh6
-rwxr-xr-xt/t1091-sparse-checkout-builtin.sh11
-rwxr-xr-xt/t1300-config.sh6
-rwxr-xr-xt/t1450-fsck.sh24
-rwxr-xr-xt/t1800-hook.sh2
-rwxr-xr-xt/t3104-ls-tree-format.sh6
-rwxr-xr-xt/t3200-branch.sh36
-rwxr-xr-xt/t3404-rebase-interactive.sh107
-rwxr-xr-xt/t3430-rebase-merges.sh17
-rwxr-xr-xt/t3920-crlf-messages.sh2
-rwxr-xr-xt/t4023-diff-rename-typechange.sh12
-rwxr-xr-xt/t4045-diff-relative.sh29
-rwxr-xr-xt/t4115-apply-symlink.sh81
-rwxr-xr-xt/t4205-log-pretty-formats.sh78
-rwxr-xr-xt/t4211-line-log.sh22
-rwxr-xr-xt/t5304-prune.sh8
-rwxr-xr-xt/t5314-pack-cycle-detection.sh17
-rwxr-xr-xt/t5516-fetch-push.sh6
-rwxr-xr-xt/t5526-fetch-submodules.sh8
-rwxr-xr-xt/t5531-deep-submodule-push.sh50
-rwxr-xr-xt/t5551-http-fetch-smart.sh13
-rwxr-xr-xt/t5559-http-fetch-smart-http2.sh4
-rwxr-xr-xt/t5604-clone-reference.sh16
-rwxr-xr-xt/t5619-clone-local-ambiguous-transport.sh70
-rwxr-xr-xt/t6018-rev-list-glob.sh40
-rwxr-xr-xt/t6020-bundle-misc.sh7
-rwxr-xr-xt/t6021-rev-list-exclude-hidden.sh163
-rwxr-xr-xt/t6030-bisect-porcelain.sh10
-rwxr-xr-xt/t6102-rev-list-unexpected-objects.sh4
-rwxr-xr-xt/t7400-submodule-basic.sh10
-rwxr-xr-xt/t7407-submodule-foreach.sh5
-rwxr-xr-xt/t7411-submodule-config.sh36
-rwxr-xr-xt/t7418-submodule-sparse-gitmodules.sh4
-rwxr-xr-xt/t7422-submodule-output.sh170
-rwxr-xr-xt/t7600-merge.sh2
-rwxr-xr-xt/t7610-mergetool.sh4
-rwxr-xr-xt/t7700-repack.sh137
-rwxr-xr-xt/t7900-maintenance.sh21
-rwxr-xr-xt/t9210-scalar.sh14
88 files changed, 1863 insertions, 175 deletions
diff --git a/t/Makefile b/t/Makefile
index 882782a519..2c2b252240 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -94,7 +94,7 @@ check-chainlint:
done \
} >'$(CHAINLINTTMP_SQ)'/expect && \
$(CHAINLINT) --emit-all '$(CHAINLINTTMP_SQ)'/tests | \
- grep -v '^[ ]*$$' >'$(CHAINLINTTMP_SQ)'/actual && \
+ sed -e 's/^[1-9][0-9]* //;/^[ ]*$$/d' >'$(CHAINLINTTMP_SQ)'/actual && \
if test -f ../GIT-BUILD-OPTIONS; then \
. ../GIT-BUILD-OPTIONS; \
fi && \
diff --git a/t/chainlint.pl b/t/chainlint.pl
index 976db4b8a0..e966412999 100755
--- a/t/chainlint.pl
+++ b/t/chainlint.pl
@@ -67,6 +67,7 @@ sub new {
bless {
parser => $parser,
buff => $s,
+ lineno => 1,
heretags => []
} => $class;
}
@@ -75,7 +76,9 @@ sub scan_heredoc_tag {
my $self = shift @_;
${$self->{buff}} =~ /\G(-?)/gc;
my $indented = $1;
- my $tag = $self->scan_token();
+ my $token = $self->scan_token();
+ return "<<$indented" unless $token;
+ my $tag = $token->[0];
$tag =~ s/['"\\]//g;
push(@{$self->{heretags}}, $indented ? "\t$tag" : "$tag");
return "<<$indented$tag";
@@ -95,7 +98,9 @@ sub scan_op {
sub scan_sqstring {
my $self = shift @_;
${$self->{buff}} =~ /\G([^']*'|.*\z)/sgc;
- return "'" . $1;
+ my $s = $1;
+ $self->{lineno} += () = $s =~ /\n/sg;
+ return "'" . $s;
}
sub scan_dqstring {
@@ -113,7 +118,7 @@ sub scan_dqstring {
if ($c eq '\\') {
$s .= '\\', last unless $$b =~ /\G(.)/sgc;
$c = $1;
- next if $c eq "\n"; # line splice
+ $self->{lineno}++, next if $c eq "\n"; # line splice
# backslash escapes only $, `, ", \ in dq-string
$s .= '\\' unless $c =~ /^[\$`"\\]$/;
$s .= $c;
@@ -121,6 +126,7 @@ sub scan_dqstring {
}
die("internal error scanning dq-string '$c'\n");
}
+ $self->{lineno} += () = $s =~ /\n/sg;
return $s;
}
@@ -135,6 +141,7 @@ sub scan_balanced {
$depth--;
last if $depth == 0;
}
+ $self->{lineno} += () = $s =~ /\n/sg;
return $s;
}
@@ -149,7 +156,7 @@ sub scan_dollar {
my $self = shift @_;
my $b = $self->{buff};
return $self->scan_balanced('(', ')') if $$b =~ /\G\((?=\()/gc; # $((...))
- return '(' . join(' ', $self->scan_subst()) . ')' if $$b =~ /\G\(/gc; # $(...)
+ return '(' . join(' ', map {$_->[0]} $self->scan_subst()) . ')' if $$b =~ /\G\(/gc; # $(...)
return $self->scan_balanced('{', '}') if $$b =~ /\G\{/gc; # ${...}
return $1 if $$b =~ /\G(\w+)/gc; # $var
return $1 if $$b =~ /\G([@*#?$!0-9-])/gc; # $*, $1, $$, etc.
@@ -161,8 +168,11 @@ sub swallow_heredocs {
my $b = $self->{buff};
my $tags = $self->{heretags};
while (my $tag = shift @$tags) {
+ my $start = pos($$b);
my $indent = $tag =~ s/^\t// ? '\\s*' : '';
$$b =~ /(?:\G|\n)$indent\Q$tag\E(?:\n|\z)/gc;
+ my $body = substr($$b, $start, pos($$b) - $start);
+ $self->{lineno} += () = $body =~ /\n/sg;
}
}
@@ -170,34 +180,37 @@ sub scan_token {
my $self = shift @_;
my $b = $self->{buff};
my $token = '';
+ my ($start, $startln);
RESTART:
+ $startln = $self->{lineno};
$$b =~ /\G[ \t]+/gc; # skip whitespace (but not newline)
- return "\n" if $$b =~ /\G#[^\n]*(?:\n|\z)/gc; # comment
+ $start = pos($$b) || 0;
+ $self->{lineno}++, return ["\n", $start, pos($$b), $startln, $startln] if $$b =~ /\G#[^\n]*(?:\n|\z)/gc; # comment
while (1) {
# slurp up non-special characters
$token .= $1 if $$b =~ /\G([^\\;&|<>(){}'"\$\s]+)/gc;
# handle special characters
last unless $$b =~ /\G(.)/sgc;
my $c = $1;
- last if $c =~ /^[ \t]$/; # whitespace ends token
+ pos($$b)--, last if $c =~ /^[ \t]$/; # whitespace ends token
pos($$b)--, last if length($token) && $c =~ /^[;&|<>(){}\n]$/;
$token .= $self->scan_sqstring(), next if $c eq "'";
$token .= $self->scan_dqstring(), next if $c eq '"';
$token .= $c . $self->scan_dollar(), next if $c eq '$';
- $self->swallow_heredocs(), $token = $c, last if $c eq "\n";
+ $self->{lineno}++, $self->swallow_heredocs(), $token = $c, last if $c eq "\n";
$token = $self->scan_op($c), last if $c =~ /^[;&|<>]$/;
$token = $c, last if $c =~ /^[(){}]$/;
if ($c eq '\\') {
$token .= '\\', last unless $$b =~ /\G(.)/sgc;
$c = $1;
- next if $c eq "\n" && length($token); # line splice
- goto RESTART if $c eq "\n"; # line splice
+ $self->{lineno}++, next if $c eq "\n" && length($token); # line splice
+ $self->{lineno}++, goto RESTART if $c eq "\n"; # line splice
$token .= '\\' . $c;
next;
}
die("internal error scanning character '$c'\n");
}
- return length($token) ? $token : undef;
+ return length($token) ? [$token, $start, pos($$b), $startln, $self->{lineno}] : undef;
}
# ShellParser parses POSIX shell scripts (with minor extensions for Bash). It
@@ -239,14 +252,14 @@ sub stop_at {
my ($self, $token) = @_;
return 1 unless defined($token);
my $stop = ${$self->{stop}}[-1] if @{$self->{stop}};
- return defined($stop) && $token =~ $stop;
+ return defined($stop) && $token->[0] =~ $stop;
}
sub expect {
my ($self, $expect) = @_;
my $token = $self->next_token();
- return $token if defined($token) && $token eq $expect;
- push(@{$self->{output}}, "?!ERR?! expected '$expect' but found '" . (defined($token) ? $token : "<end-of-input>") . "'\n");
+ return $token if defined($token) && $token->[0] eq $expect;
+ push(@{$self->{output}}, "?!ERR?! expected '$expect' but found '" . (defined($token) ? $token->[0] : "<end-of-input>") . "'\n");
$self->untoken($token) if defined($token);
return ();
}
@@ -255,7 +268,7 @@ sub optional_newlines {
my $self = shift @_;
my @tokens;
while (my $token = $self->peek()) {
- last unless $token eq "\n";
+ last unless $token->[0] eq "\n";
push(@tokens, $self->next_token());
}
return @tokens;
@@ -278,7 +291,7 @@ sub parse_case_pattern {
my @tokens;
while (defined(my $token = $self->next_token())) {
push(@tokens, $token);
- last if $token eq ')';
+ last if $token->[0] eq ')';
}
return @tokens;
}
@@ -293,13 +306,13 @@ sub parse_case {
$self->optional_newlines());
while (1) {
my $token = $self->peek();
- last unless defined($token) && $token ne 'esac';
+ last unless defined($token) && $token->[0] ne 'esac';
push(@tokens,
$self->parse_case_pattern(),
$self->optional_newlines(),
$self->parse(qr/^(?:;;|esac)$/)); # item body
$token = $self->peek();
- last unless defined($token) && $token ne 'esac';
+ last unless defined($token) && $token->[0] ne 'esac';
push(@tokens,
$self->expect(';;'),
$self->optional_newlines());
@@ -315,7 +328,7 @@ sub parse_for {
$self->next_token(), # variable
$self->optional_newlines());
my $token = $self->peek();
- if (defined($token) && $token eq 'in') {
+ if (defined($token) && $token->[0] eq 'in') {
push(@tokens,
$self->expect('in'),
$self->optional_newlines());
@@ -339,11 +352,11 @@ sub parse_if {
$self->optional_newlines(),
$self->parse(qr/^(?:elif|else|fi)$/)); # if/elif body
my $token = $self->peek();
- last unless defined($token) && $token eq 'elif';
+ last unless defined($token) && $token->[0] eq 'elif';
push(@tokens, $self->expect('elif'));
}
my $token = $self->peek();
- if (defined($token) && $token eq 'else') {
+ if (defined($token) && $token->[0] eq 'else') {
push(@tokens,
$self->expect('else'),
$self->optional_newlines(),
@@ -380,7 +393,7 @@ sub parse_bash_array_assignment {
my @tokens = $self->expect('(');
while (defined(my $token = $self->next_token())) {
push(@tokens, $token);
- last if $token eq ')';
+ last if $token->[0] eq ')';
}
return @tokens;
}
@@ -398,29 +411,31 @@ sub parse_cmd {
my $self = shift @_;
my $cmd = $self->next_token();
return () unless defined($cmd);
- return $cmd if $cmd eq "\n";
+ return $cmd if $cmd->[0] eq "\n";
my $token;
my @tokens = $cmd;
- if ($cmd eq '!') {
+ if ($cmd->[0] eq '!') {
push(@tokens, $self->parse_cmd());
return @tokens;
- } elsif (my $f = $compound{$cmd}) {
+ } elsif (my $f = $compound{$cmd->[0]}) {
push(@tokens, $self->$f());
- } elsif (defined($token = $self->peek()) && $token eq '(') {
- if ($cmd !~ /\w=$/) {
+ } elsif (defined($token = $self->peek()) && $token->[0] eq '(') {
+ if ($cmd->[0] !~ /\w=$/) {
push(@tokens, $self->parse_func());
return @tokens;
}
- $tokens[-1] .= join(' ', $self->parse_bash_array_assignment());
+ my @array = $self->parse_bash_array_assignment();
+ $tokens[-1]->[0] .= join(' ', map {$_->[0]} @array);
+ $tokens[-1]->[2] = $array[$#array][2] if @array;
}
while (defined(my $token = $self->next_token())) {
$self->untoken($token), last if $self->stop_at($token);
push(@tokens, $token);
- last if $token =~ /^(?:[;&\n|]|&&|\|\|)$/;
+ last if $token->[0] =~ /^(?:[;&\n|]|&&|\|\|)$/;
}
- push(@tokens, $self->next_token()) if $tokens[-1] ne "\n" && defined($token = $self->peek()) && $token eq "\n";
+ push(@tokens, $self->next_token()) if $tokens[-1]->[0] ne "\n" && defined($token = $self->peek()) && $token->[0] eq "\n";
return @tokens;
}
@@ -453,11 +468,18 @@ package TestParser;
use base 'ShellParser';
+sub new {
+ my $class = shift @_;
+ my $self = $class->SUPER::new(@_);
+ $self->{problems} = [];
+ return $self;
+}
+
sub find_non_nl {
my $tokens = shift @_;
my $n = shift @_;
$n = $#$tokens if !defined($n);
- $n-- while $n >= 0 && $$tokens[$n] eq "\n";
+ $n-- while $n >= 0 && $$tokens[$n]->[0] eq "\n";
return $n;
}
@@ -467,7 +489,7 @@ sub ends_with {
for my $needle (reverse(@$needles)) {
return undef if $n < 0;
$n = find_non_nl($tokens, $n), next if $needle eq "\n";
- return undef if $$tokens[$n] !~ $needle;
+ return undef if $$tokens[$n]->[0] !~ $needle;
$n--;
}
return 1;
@@ -486,13 +508,13 @@ sub parse_loop_body {
my $self = shift @_;
my @tokens = $self->SUPER::parse_loop_body(@_);
# did loop signal failure via "|| return" or "|| exit"?
- return @tokens if !@tokens || grep(/^(?:return|exit|\$\?)$/, @tokens);
+ return @tokens if !@tokens || grep {$_->[0] =~ /^(?:return|exit|\$\?)$/} @tokens;
# did loop upstream of a pipe signal failure via "|| echo 'impossible
# text'" as the final command in the loop body?
return @tokens if ends_with(\@tokens, [qr/^\|\|$/, "\n", qr/^echo$/, qr/^.+$/]);
# flag missing "return/exit" handling explicit failure in loop body
my $n = find_non_nl(\@tokens);
- splice(@tokens, $n + 1, 0, '?!LOOP?!');
+ push(@{$self->{problems}}, ['LOOP', $tokens[$n]]);
return @tokens;
}
@@ -505,8 +527,13 @@ my @safe_endings = (
sub accumulate {
my ($self, $tokens, $cmd) = @_;
+ my $problems = $self->{problems};
+
+ # no previous command to check for missing "&&"
goto DONE unless @$tokens;
- goto DONE if @$cmd == 1 && $$cmd[0] eq "\n";
+
+ # new command is empty line; can't yet check if previous is missing "&&"
+ goto DONE if @$cmd == 1 && $$cmd[0]->[0] eq "\n";
# did previous command end with "&&", "|", "|| return" or similar?
goto DONE if match_ending($tokens, \@safe_endings);
@@ -514,20 +541,20 @@ sub accumulate {
# if this command handles "$?" specially, then okay for previous
# command to be missing "&&"
for my $token (@$cmd) {
- goto DONE if $token =~ /\$\?/;
+ goto DONE if $token->[0] =~ /\$\?/;
}
# if this command is "false", "return 1", or "exit 1" (which signal
# failure explicitly), then okay for all preceding commands to be
# missing "&&"
- if ($$cmd[0] =~ /^(?:false|return|exit)$/) {
- @$tokens = grep(!/^\?!AMP\?!$/, @$tokens);
+ if ($$cmd[0]->[0] =~ /^(?:false|return|exit)$/) {
+ @$problems = grep {$_->[0] ne 'AMP'} @$problems;
goto DONE;
}
# flag missing "&&" at end of previous command
my $n = find_non_nl($tokens);
- splice(@$tokens, $n + 1, 0, '?!AMP?!') unless $n < 0;
+ push(@$problems, ['AMP', $tokens->[$n]]) unless $n < 0;
DONE:
$self->SUPER::accumulate($tokens, $cmd);
@@ -553,7 +580,7 @@ sub new {
# composition of multiple strings and non-string character runs; for instance,
# `"test body"` unwraps to `test body`; `word"a b"42'c d'` to `worda b42c d`
sub unwrap {
- my $token = @_ ? shift @_ : $_;
+ my $token = (@_ ? shift @_ : $_)->[0];
# simple case: 'sqstring' or "dqstring"
return $token if $token =~ s/^'([^']*)'$/$1/;
return $token if $token =~ s/^"([^"]*)"$/$1/;
@@ -584,13 +611,25 @@ sub check_test {
$self->{ntests}++;
my $parser = TestParser->new(\$body);
my @tokens = $parser->parse();
- return unless $emit_all || grep(/\?![^?]+\?!/, @tokens);
+ my $problems = $parser->{problems};
+ return unless $emit_all || @$problems;
my $c = main::fd_colors(1);
- my $checked = join(' ', @tokens);
- $checked =~ s/^\n//;
- $checked =~ s/^ //mg;
- $checked =~ s/ $//mg;
+ my $lineno = $_[1]->[3];
+ my $start = 0;
+ my $checked = '';
+ for (sort {$a->[1]->[2] <=> $b->[1]->[2]} @$problems) {
+ my ($label, $token) = @$_;
+ my $pos = $token->[2];
+ $checked .= substr($body, $start, $pos - $start) . " ?!$label?! ";
+ $start = $pos;
+ }
+ $checked .= substr($body, $start);
+ $checked =~ s/^/$lineno++ . ' '/mge;
+ $checked =~ s/^\d+ \n//;
+ $checked =~ s/(\s) \?!/$1?!/mg;
+ $checked =~ s/\?! (\s)/?!$1/mg;
$checked =~ s/(\?![^?]+\?!)/$c->{rev}$c->{red}$1$c->{reset}/mg;
+ $checked =~ s/^\d+/$c->{dim}$&$c->{reset}/mg;
$checked .= "\n" unless $checked =~ /\n$/;
push(@{$self->{output}}, "$c->{blue}# chainlint: $title$c->{reset}\n$checked");
}
@@ -598,9 +637,9 @@ sub check_test {
sub parse_cmd {
my $self = shift @_;
my @tokens = $self->SUPER::parse_cmd();
- return @tokens unless @tokens && $tokens[0] =~ /^test_expect_(?:success|failure)$/;
+ return @tokens unless @tokens && $tokens[0]->[0] =~ /^test_expect_(?:success|failure)$/;
my $n = $#tokens;
- $n-- while $n >= 0 && $tokens[$n] =~ /^(?:[;&\n|]|&&|\|\|)$/;
+ $n-- while $n >= 0 && $tokens[$n]->[0] =~ /^(?:[;&\n|]|&&|\|\|)$/;
$self->check_test($tokens[1], $tokens[2]) if $n == 2; # title body
$self->check_test($tokens[2], $tokens[3]) if $n > 2; # prereq title body
return @tokens;
@@ -622,25 +661,39 @@ if (eval {require Time::HiRes; Time::HiRes->import(); 1;}) {
# thread and ignore %ENV changes in subthreads.
$ENV{TERM} = $ENV{USER_TERM} if $ENV{USER_TERM};
-my @NOCOLORS = (bold => '', rev => '', reset => '', blue => '', green => '', red => '');
+my @NOCOLORS = (bold => '', rev => '', dim => '', reset => '', blue => '', green => '', red => '');
my %COLORS = ();
sub get_colors {
return \%COLORS if %COLORS;
- if (exists($ENV{NO_COLOR}) ||
- system("tput sgr0 >/dev/null 2>&1") != 0 ||
- system("tput bold >/dev/null 2>&1") != 0 ||
- system("tput rev >/dev/null 2>&1") != 0 ||
- system("tput setaf 1 >/dev/null 2>&1") != 0) {
+ if (exists($ENV{NO_COLOR})) {
%COLORS = @NOCOLORS;
return \%COLORS;
}
- %COLORS = (bold => `tput bold`,
- rev => `tput rev`,
- reset => `tput sgr0`,
- blue => `tput setaf 4`,
- green => `tput setaf 2`,
- red => `tput setaf 1`);
- chomp(%COLORS);
+ if ($ENV{TERM} =~ /xterm|xterm-\d+color|xterm-new|xterm-direct|nsterm|nsterm-\d+color|nsterm-direct/) {
+ %COLORS = (bold => "\e[1m",
+ rev => "\e[7m",
+ dim => "\e[2m",
+ reset => "\e[0m",
+ blue => "\e[34m",
+ green => "\e[32m",
+ red => "\e[31m");
+ return \%COLORS;
+ }
+ if (system("tput sgr0 >/dev/null 2>&1") == 0 &&
+ system("tput bold >/dev/null 2>&1") == 0 &&
+ system("tput rev >/dev/null 2>&1") == 0 &&
+ system("tput dim >/dev/null 2>&1") == 0 &&
+ system("tput setaf 1 >/dev/null 2>&1") == 0) {
+ %COLORS = (bold => `tput bold`,
+ rev => `tput rev`,
+ dim => `tput dim`,
+ reset => `tput sgr0`,
+ blue => `tput setaf 4`,
+ green => `tput setaf 2`,
+ red => `tput setaf 1`);
+ return \%COLORS;
+ }
+ %COLORS = @NOCOLORS;
return \%COLORS;
}
@@ -656,7 +709,7 @@ sub ncores {
# Windows
return $ENV{NUMBER_OF_PROCESSORS} if exists($ENV{NUMBER_OF_PROCESSORS});
# Linux / MSYS2 / Cygwin / WSL
- do { local @ARGV='/proc/cpuinfo'; return scalar(grep(/^processor\s*:/, <>)); } if -r '/proc/cpuinfo';
+ do { local @ARGV='/proc/cpuinfo'; return scalar(grep(/^processor[\s\d]*:/, <>)); } if -r '/proc/cpuinfo';
# macOS & BSD
return qx/sysctl -n hw.ncpu/ if $^O =~ /(?:^darwin$|bsd)/;
return 1;
diff --git a/t/chainlint/block-comment.expect b/t/chainlint/block-comment.expect
index d10b2eeaf2..df2beea888 100644
--- a/t/chainlint/block-comment.expect
+++ b/t/chainlint/block-comment.expect
@@ -1,6 +1,8 @@
(
{
+ # show a
echo a &&
+ # show b
echo b
}
)
diff --git a/t/chainlint/case-comment.expect b/t/chainlint/case-comment.expect
index 1e4b054bda..641c157b98 100644
--- a/t/chainlint/case-comment.expect
+++ b/t/chainlint/case-comment.expect
@@ -1,7 +1,10 @@
(
case "$x" in
+ # found foo
x) foo ;;
+ # found other
*)
+ # treat it as bar
bar
;;
esac
diff --git a/t/chainlint/close-subshell.expect b/t/chainlint/close-subshell.expect
index 0f87db9ae6..2192a2870a 100644
--- a/t/chainlint/close-subshell.expect
+++ b/t/chainlint/close-subshell.expect
@@ -15,7 +15,8 @@
) | wuzzle &&
(
bop
-) | fazz fozz &&
+) | fazz \
+ fozz &&
(
bup
) |
diff --git a/t/chainlint/comment.expect b/t/chainlint/comment.expect
index f76fde1ffb..a68f1f9d7c 100644
--- a/t/chainlint/comment.expect
+++ b/t/chainlint/comment.expect
@@ -1,4 +1,8 @@
(
+ # comment 1
nothing &&
+ # comment 2
something
+ # comment 3
+ # comment 4
)
diff --git a/t/chainlint/double-here-doc.expect b/t/chainlint/double-here-doc.expect
index 75477bb1ad..cd584a4357 100644
--- a/t/chainlint/double-here-doc.expect
+++ b/t/chainlint/double-here-doc.expect
@@ -1,2 +1,12 @@
-run_sub_test_lib_test_err run-inv-range-start "--run invalid range start" --run="a-5" <<-EOF &&
-check_sub_test_lib_test_err run-inv-range-start <<-EOF_OUT 3 <<-EOF_ERR
+run_sub_test_lib_test_err run-inv-range-start \
+ "--run invalid range start" \
+ --run="a-5" <<-\EOF &&
+test_expect_success "passing test #1" "true"
+test_done
+EOF
+check_sub_test_lib_test_err run-inv-range-start \
+ <<-\EOF_OUT 3<<-EOF_ERR
+> FATAL: Unexpected exit with code 1
+EOF_OUT
+> error: --run: invalid non-numeric in range start: ${SQ}a-5${SQ}
+EOF_ERR
diff --git a/t/chainlint/empty-here-doc.expect b/t/chainlint/empty-here-doc.expect
index f42f2d41ba..e8733c97c6 100644
--- a/t/chainlint/empty-here-doc.expect
+++ b/t/chainlint/empty-here-doc.expect
@@ -1,3 +1,4 @@
git ls-tree $tree path > current &&
-cat > expected <<EOF &&
+cat > expected <<\EOF &&
+EOF
test_output
diff --git a/t/chainlint/for-loop.expect b/t/chainlint/for-loop.expect
index a5810c9bdd..d65c82129a 100644
--- a/t/chainlint/for-loop.expect
+++ b/t/chainlint/for-loop.expect
@@ -2,7 +2,9 @@
for i in a b c
do
echo $i ?!AMP?!
- cat <<-EOF ?!LOOP?!
+ cat <<-\EOF ?!LOOP?!
+ bar
+ EOF
done ?!AMP?!
for i in a b c; do
echo $i &&
diff --git a/t/chainlint/here-doc-close-subshell.expect b/t/chainlint/here-doc-close-subshell.expect
index 2af9ced71c..7d9c2b5607 100644
--- a/t/chainlint/here-doc-close-subshell.expect
+++ b/t/chainlint/here-doc-close-subshell.expect
@@ -1,2 +1,4 @@
(
- cat <<-INPUT)
+ cat <<-\INPUT)
+ fizz
+ INPUT
diff --git a/t/chainlint/here-doc-indent-operator.expect b/t/chainlint/here-doc-indent-operator.expect
index fb6cf7285d..f92a7ce999 100644
--- a/t/chainlint/here-doc-indent-operator.expect
+++ b/t/chainlint/here-doc-indent-operator.expect
@@ -1,5 +1,11 @@
-cat > expect <<-EOF &&
+cat >expect <<- EOF &&
+header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0
+num_commits: $1
+chunks: oid_fanout oid_lookup commit_metadata generation_data bloom_indexes bloom_data
+EOF
-cat > expect <<-EOF ?!AMP?!
+cat >expect << -EOF ?!AMP?!
+this is not indented
+-EOF
cleanup
diff --git a/t/chainlint/here-doc-multi-line-command-subst.expect b/t/chainlint/here-doc-multi-line-command-subst.expect
index f8b3aa73c4..b7364c82c8 100644
--- a/t/chainlint/here-doc-multi-line-command-subst.expect
+++ b/t/chainlint/here-doc-multi-line-command-subst.expect
@@ -1,5 +1,8 @@
(
- x=$(bobble <<-END &&
+ x=$(bobble <<-\END &&
+ fossil
+ vegetable
+ END
wiffle) ?!AMP?!
echo $x
)
diff --git a/t/chainlint/here-doc-multi-line-string.expect b/t/chainlint/here-doc-multi-line-string.expect
index be64b26869..6c13bdcbfb 100644
--- a/t/chainlint/here-doc-multi-line-string.expect
+++ b/t/chainlint/here-doc-multi-line-string.expect
@@ -1,5 +1,7 @@
(
- cat <<-TXT && echo "multi-line
+ cat <<-\TXT && echo "multi-line
string" ?!AMP?!
+ fizzle
+ TXT
bap
)
diff --git a/t/chainlint/here-doc.expect b/t/chainlint/here-doc.expect
index 110059ba58..1df3f78282 100644
--- a/t/chainlint/here-doc.expect
+++ b/t/chainlint/here-doc.expect
@@ -1,7 +1,25 @@
-boodle wobba gorgo snoot wafta snurb <<EOF &&
+boodle wobba \
+ gorgo snoot \
+ wafta snurb <<EOF &&
+quoth the raven,
+nevermore...
+EOF
cat <<-Arbitrary_Tag_42 >foo &&
+snoz
+boz
+woz
+Arbitrary_Tag_42
-cat <<zump >boo &&
+cat <<"zump" >boo &&
+snoz
+boz
+woz
+zump
-horticulture <<EOF
+horticulture <<\EOF
+gomez
+morticia
+wednesday
+pugsly
+EOF
diff --git a/t/chainlint/if-then-else.expect b/t/chainlint/if-then-else.expect
index 44d86c3597..cbaaf857d4 100644
--- a/t/chainlint/if-then-else.expect
+++ b/t/chainlint/if-then-else.expect
@@ -8,7 +8,9 @@
echo foo
else
echo foo &&
- cat <<-EOF
+ cat <<-\EOF
+ bar
+ EOF
fi ?!AMP?!
echo poodle
) &&
diff --git a/t/chainlint/incomplete-line.expect b/t/chainlint/incomplete-line.expect
index ffac8f9018..134d3a14f5 100644
--- a/t/chainlint/incomplete-line.expect
+++ b/t/chainlint/incomplete-line.expect
@@ -1,4 +1,10 @@
-line 1 line 2 line 3 line 4 &&
+line 1 \
+line 2 \
+line 3 \
+line 4 &&
(
- line 5 line 6 line 7 line 8
+ line 5 \
+ line 6 \
+ line 7 \
+ line 8
)
diff --git a/t/chainlint/inline-comment.expect b/t/chainlint/inline-comment.expect
index dd0dace077..6bad218530 100644
--- a/t/chainlint/inline-comment.expect
+++ b/t/chainlint/inline-comment.expect
@@ -1,6 +1,6 @@
(
- foobar &&
- barfoo ?!AMP?!
+ foobar && # comment 1
+ barfoo ?!AMP?! # wrong position for &&
flibble "not a # comment"
) &&
diff --git a/t/chainlint/loop-detect-status.expect b/t/chainlint/loop-detect-status.expect
index 0ad23bb35e..24da9e86d5 100644
--- a/t/chainlint/loop-detect-status.expect
+++ b/t/chainlint/loop-detect-status.expect
@@ -2,7 +2,7 @@
do
printf "Generating blob $i/$blobcount\r" >& 2 &&
printf "blob\nmark :$i\ndata $blobsize\n" &&
-
+ #test-tool genrandom $i $blobsize &&
printf "%-${blobsize}s" $i &&
echo "M 100644 :$i $i" >> commit &&
i=$(($i+1)) ||
diff --git a/t/chainlint/nested-here-doc.expect b/t/chainlint/nested-here-doc.expect
index e3bef63f75..29b3832a98 100644
--- a/t/chainlint/nested-here-doc.expect
+++ b/t/chainlint/nested-here-doc.expect
@@ -1,7 +1,30 @@
cat <<ARBITRARY >foop &&
+naddle
+fub <<EOF
+ nozzle
+ noodle
+EOF
+formp
+ARBITRARY
(
- cat <<-INPUT_END &&
- cat <<-EOT ?!AMP?!
+ cat <<-\INPUT_END &&
+ fish are mice
+ but geese go slow
+ data <<EOF
+ perl is lerp
+ and nothing else
+ EOF
+ toink
+ INPUT_END
+
+ cat <<-\EOT ?!AMP?!
+ text goes here
+ data <<EOF
+ data goes here
+ EOF
+ more test here
+ EOT
+
foobar
)
diff --git a/t/chainlint/nested-subshell-comment.expect b/t/chainlint/nested-subshell-comment.expect
index be4b27a305..9138cf386d 100644
--- a/t/chainlint/nested-subshell-comment.expect
+++ b/t/chainlint/nested-subshell-comment.expect
@@ -2,6 +2,8 @@
foo &&
(
bar &&
+ # bottles wobble while fiddles gobble
+ # minor numbers of cows (or do they?)
baz &&
snaff
) ?!AMP?!
diff --git a/t/chainlint/subshell-here-doc.expect b/t/chainlint/subshell-here-doc.expect
index 029d129299..52789278d1 100644
--- a/t/chainlint/subshell-here-doc.expect
+++ b/t/chainlint/subshell-here-doc.expect
@@ -1,10 +1,30 @@
(
- echo wobba gorgo snoot wafta snurb <<-EOF &&
+ echo wobba \
+ gorgo snoot \
+ wafta snurb <<-EOF &&
+ quoth the raven,
+ nevermore...
+ EOF
+
cat <<EOF >bip ?!AMP?!
- echo <<-EOF >bop
+ fish fly high
+EOF
+
+ echo <<-\EOF >bop
+ gomez
+ morticia
+ wednesday
+ pugsly
+ EOF
) &&
(
- cat <<-ARBITRARY >bup &&
- cat <<-ARBITRARY3 >bup3 &&
+ cat <<-\ARBITRARY >bup &&
+ glink
+ FIZZ
+ ARBITRARY
+ cat <<-"ARBITRARY3" >bup3 &&
+ glink
+ FIZZ
+ ARBITRARY3
meep
)
diff --git a/t/chainlint/t7900-subtree.expect b/t/chainlint/t7900-subtree.expect
index 69167da2f2..71b3b3bc20 100644
--- a/t/chainlint/t7900-subtree.expect
+++ b/t/chainlint/t7900-subtree.expect
@@ -4,12 +4,16 @@ sub2
sub3
sub4" &&
chks_sub=$(cat <<TXT | sed "s,^,sub dir/,"
+$chks
+TXT
) &&
chkms="main-sub1
main-sub2
main-sub3
main-sub4" &&
chkms_sub=$(cat <<TXT | sed "s,^,sub dir/,"
+$chkms
+TXT
) &&
subfiles=$(git ls-files) &&
check_equal "$subfiles" "$chkms
diff --git a/t/chainlint/while-loop.expect b/t/chainlint/while-loop.expect
index f272aa21fe..1f5eaea0fd 100644
--- a/t/chainlint/while-loop.expect
+++ b/t/chainlint/while-loop.expect
@@ -2,7 +2,9 @@
while true
do
echo foo ?!AMP?!
- cat <<-EOF ?!LOOP?!
+ cat <<-\EOF ?!LOOP?!
+ bar
+ EOF
done ?!AMP?!
while true; do
echo foo &&
diff --git a/t/helper/test-cache-tree.c b/t/helper/test-cache-tree.c
new file mode 100644
index 0000000000..9159a17301
--- /dev/null
+++ b/t/helper/test-cache-tree.c
@@ -0,0 +1,65 @@
+#define USE_THE_INDEX_VARIABLE
+#include "test-tool.h"
+#include "cache.h"
+#include "tree.h"
+#include "cache-tree.h"
+#include "parse-options.h"
+
+static char const * const test_cache_tree_usage[] = {
+ N_("test-tool cache-tree <options> (control|prime|update)"),
+ NULL
+};
+
+int cmd__cache_tree(int argc, const char **argv)
+{
+ struct object_id oid;
+ struct tree *tree;
+ int empty = 0;
+ int invalidate_qty = 0;
+ int i;
+
+ struct option options[] = {
+ OPT_BOOL(0, "empty", &empty,
+ N_("clear the cache tree before each iteration")),
+ OPT_INTEGER_F(0, "invalidate", &invalidate_qty,
+ N_("number of entries in the cache tree to invalidate (default 0)"),
+ PARSE_OPT_NONEG),
+ OPT_END()
+ };
+
+ setup_git_directory();
+
+ argc = parse_options(argc, argv, NULL, options, test_cache_tree_usage, 0);
+
+ if (repo_read_index(the_repository) < 0)
+ die(_("unable to read index file"));
+
+ oidcpy(&oid, &the_index.cache_tree->oid);
+ tree = parse_tree_indirect(&oid);
+ if (!tree)
+ die(_("not a tree object: %s"), oid_to_hex(&oid));
+
+ if (empty) {
+ /* clear the cache tree & allocate a new one */
+ cache_tree_free(&the_index.cache_tree);
+ the_index.cache_tree = cache_tree();
+ } else if (invalidate_qty) {
+ /* invalidate the specified number of unique paths */
+ float f_interval = (float)the_index.cache_nr / invalidate_qty;
+ int interval = f_interval < 1.0 ? 1 : (int)f_interval;
+ for (i = 0; i < invalidate_qty && i * interval < the_index.cache_nr; i++)
+ cache_tree_invalidate_path(&the_index, the_index.cache[i * interval]->name);
+ }
+
+ if (argc != 1)
+ usage_with_options(test_cache_tree_usage, options);
+ else if (!strcmp(argv[0], "prime"))
+ prime_cache_tree(the_repository, &the_index, tree);
+ else if (!strcmp(argv[0], "update"))
+ cache_tree_update(&the_index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR);
+ /* use "control" subcommand to specify no-op */
+ else if (!!strcmp(argv[0], "control"))
+ die(_("Unhandled subcommand '%s'"), argv[0]);
+
+ return 0;
+}
diff --git a/t/helper/test-dump-cache-tree.c b/t/helper/test-dump-cache-tree.c
index 0d6d7f1ecb..454f17b1a0 100644
--- a/t/helper/test-dump-cache-tree.c
+++ b/t/helper/test-dump-cache-tree.c
@@ -1,3 +1,4 @@
+#define USE_THE_INDEX_VARIABLE
#include "test-tool.h"
#include "cache.h"
#include "tree.h"
@@ -62,12 +63,12 @@ int cmd__dump_cache_tree(int ac, const char **av)
int ret;
setup_git_directory();
- if (read_cache() < 0)
+ if (repo_read_index(the_repository) < 0)
die("unable to read index file");
istate = the_index;
istate.cache_tree = another;
cache_tree_update(&istate, WRITE_TREE_DRY_RUN);
- ret = dump_cache_tree(active_cache_tree, another, "");
+ ret = dump_cache_tree(the_index.cache_tree, another, "");
cache_tree_free(&another);
return ret;
diff --git a/t/helper/test-dump-split-index.c b/t/helper/test-dump-split-index.c
index a209880eb3..0ea97b8407 100644
--- a/t/helper/test-dump-split-index.c
+++ b/t/helper/test-dump-split-index.c
@@ -1,3 +1,4 @@
+#define USE_THE_INDEX_VARIABLE
#include "test-tool.h"
#include "cache.h"
#include "split-index.h"
diff --git a/t/helper/test-dump-untracked-cache.c b/t/helper/test-dump-untracked-cache.c
index 99010614f6..6d53683f13 100644
--- a/t/helper/test-dump-untracked-cache.c
+++ b/t/helper/test-dump-untracked-cache.c
@@ -1,4 +1,4 @@
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "test-tool.h"
#include "cache.h"
#include "dir.h"
@@ -51,7 +51,7 @@ int cmd__dump_untracked_cache(int ac, const char **av)
xsetenv("GIT_CONFIG_VALUE_0", "keep", 1);
setup_git_directory();
- if (read_cache() < 0)
+ if (repo_read_index(the_repository) < 0)
die("unable to read index file");
uc = the_index.untracked;
if (!uc) {
diff --git a/t/helper/test-fast-rebase.c b/t/helper/test-fast-rebase.c
index 45665ec19a..efc82dd80c 100644
--- a/t/helper/test-fast-rebase.c
+++ b/t/helper/test-fast-rebase.c
@@ -10,7 +10,7 @@
* refactoring is the better route).
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "test-tool.h"
#include "cache-tree.h"
@@ -123,7 +123,7 @@ int cmd__fast_rebase(int argc, const char **argv)
die(_("Cannot read HEAD"));
assert(oideq(&onto->object.oid, &head));
- hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
+ repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR);
if (repo_read_index(the_repository) < 0)
BUG("Could not read index");
diff --git a/t/helper/test-lazy-init-name-hash.c b/t/helper/test-lazy-init-name-hash.c
index cd1b4c9736..ab86c14c8b 100644
--- a/t/helper/test-lazy-init-name-hash.c
+++ b/t/helper/test-lazy-init-name-hash.c
@@ -1,3 +1,4 @@
+#define USE_THE_INDEX_VARIABLE
#include "test-tool.h"
#include "cache.h"
#include "parse-options.h"
@@ -32,7 +33,7 @@ static void dump_run(void)
struct dir_entry *dir;
struct cache_entry *ce;
- read_cache();
+ repo_read_index(the_repository);
if (single) {
test_lazy_init_name_hash(&the_index, 0);
} else {
@@ -49,7 +50,7 @@ static void dump_run(void)
ent /* member name */)
printf("name %08x %s\n", ce->ent.hash, ce->name);
- discard_cache();
+ discard_index(&the_index);
}
/*
@@ -66,7 +67,7 @@ static uint64_t time_runs(int try_threaded)
for (i = 0; i < count; i++) {
t0 = getnanotime();
- read_cache();
+ repo_read_index(the_repository);
t1 = getnanotime();
nr_threads_used = test_lazy_init_name_hash(&the_index, try_threaded);
t2 = getnanotime();
@@ -89,7 +90,7 @@ static uint64_t time_runs(int try_threaded)
the_index.cache_nr);
fflush(stdout);
- discard_cache();
+ discard_index(&the_index);
}
avg = sum / count;
@@ -113,9 +114,9 @@ static void analyze_run(void)
int i;
int nr;
- read_cache();
+ repo_read_index(the_repository);
cache_nr_limit = the_index.cache_nr;
- discard_cache();
+ discard_index(&the_index);
nr = analyze;
while (1) {
@@ -128,23 +129,23 @@ static void analyze_run(void)
nr = cache_nr_limit;
for (i = 0; i < count; i++) {
- read_cache();
+ repo_read_index(the_repository);
the_index.cache_nr = nr; /* cheap truncate of index */
t1s = getnanotime();
test_lazy_init_name_hash(&the_index, 0);
t2s = getnanotime();
sum_single += (t2s - t1s);
the_index.cache_nr = cache_nr_limit;
- discard_cache();
+ discard_index(&the_index);
- read_cache();
+ repo_read_index(the_repository);
the_index.cache_nr = nr; /* cheap truncate of index */
t1m = getnanotime();
nr_threads_used = test_lazy_init_name_hash(&the_index, 1);
t2m = getnanotime();
sum_multi += (t2m - t1m);
the_index.cache_nr = cache_nr_limit;
- discard_cache();
+ discard_index(&the_index);
if (!nr_threads_used)
printf(" [size %8d] [single %f] non-threaded code path used\n",
diff --git a/t/helper/test-read-cache.c b/t/helper/test-read-cache.c
index b736ef1642..23e9e27109 100644
--- a/t/helper/test-read-cache.c
+++ b/t/helper/test-read-cache.c
@@ -1,3 +1,4 @@
+#define USE_THE_INDEX_VARIABLE
#include "test-tool.h"
#include "cache.h"
#include "config.h"
@@ -20,7 +21,7 @@ int cmd__read_cache(int argc, const char **argv)
git_config(git_default_config, NULL);
for (i = 0; i < cnt; i++) {
- read_cache();
+ repo_read_index(the_repository);
if (name) {
int pos;
@@ -33,7 +34,7 @@ int cmd__read_cache(int argc, const char **argv)
ce_uptodate(the_index.cache[pos]) ? "" : " not");
write_file(name, "%d\n", i);
}
- discard_cache();
+ discard_index(&the_index);
}
return 0;
}
diff --git a/t/helper/test-scrap-cache-tree.c b/t/helper/test-scrap-cache-tree.c
index 026c802479..a26107ed70 100644
--- a/t/helper/test-scrap-cache-tree.c
+++ b/t/helper/test-scrap-cache-tree.c
@@ -1,3 +1,4 @@
+#define USE_THE_INDEX_VARIABLE
#include "test-tool.h"
#include "cache.h"
#include "lockfile.h"
@@ -9,11 +10,11 @@ int cmd__scrap_cache_tree(int ac, const char **av)
struct lock_file index_lock = LOCK_INIT;
setup_git_directory();
- hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR);
- if (read_cache() < 0)
+ repo_hold_locked_index(the_repository, &index_lock, LOCK_DIE_ON_ERROR);
+ if (repo_read_index(the_repository) < 0)
die("unable to read index file");
- cache_tree_free(&active_cache_tree);
- active_cache_tree = NULL;
+ cache_tree_free(&the_index.cache_tree);
+ the_index.cache_tree = NULL;
if (write_locked_index(&the_index, &index_lock, COMMIT_LOCK))
die("unable to write index file");
return 0;
diff --git a/t/helper/test-sha1.c b/t/helper/test-sha1.c
index d860c387c3..71fe5c6145 100644
--- a/t/helper/test-sha1.c
+++ b/t/helper/test-sha1.c
@@ -5,3 +5,11 @@ int cmd__sha1(int ac, const char **av)
{
return cmd_hash_impl(ac, av, GIT_HASH_SHA1);
}
+
+int cmd__sha1_is_sha1dc(int argc UNUSED, const char **argv UNUSED)
+{
+#ifdef platform_SHA_IS_SHA1DC
+ return 0;
+#endif
+ return 1;
+}
diff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c
index b7d117cd55..e060cc6226 100644
--- a/t/helper/test-submodule.c
+++ b/t/helper/test-submodule.c
@@ -111,10 +111,94 @@ static int cmd__submodule_resolve_relative_url(int argc, const char **argv)
return 0;
}
+static int cmd__submodule_config_list(int argc, const char **argv)
+{
+ struct option options[] = {
+ OPT_END()
+ };
+ const char *const usage[] = {
+ "test-tool submodule config-list <key>",
+ NULL
+ };
+ argc = parse_options(argc, argv, "test-tools", options, usage,
+ PARSE_OPT_KEEP_ARGV0);
+
+ setup_git_directory();
+
+ if (argc == 2)
+ return print_config_from_gitmodules(the_repository, argv[1]);
+ usage_with_options(usage, options);
+}
+
+static int cmd__submodule_config_set(int argc, const char **argv)
+{
+ struct option options[] = {
+ OPT_END()
+ };
+ const char *const usage[] = {
+ "test-tool submodule config-set <key> <value>",
+ NULL
+ };
+ argc = parse_options(argc, argv, "test-tools", options, usage,
+ PARSE_OPT_KEEP_ARGV0);
+
+ setup_git_directory();
+
+ /* Equivalent to ACTION_SET in builtin/config.c */
+ if (argc == 3) {
+ if (!is_writing_gitmodules_ok())
+ die("please make sure that the .gitmodules file is in the working tree");
+
+ return config_set_in_gitmodules_file_gently(argv[1], argv[2]);
+ }
+ usage_with_options(usage, options);
+}
+
+static int cmd__submodule_config_unset(int argc, const char **argv)
+{
+ struct option options[] = {
+ OPT_END()
+ };
+ const char *const usage[] = {
+ "test-tool submodule config-unset <key>",
+ NULL
+ };
+
+ setup_git_directory();
+
+ if (argc == 2) {
+ if (!is_writing_gitmodules_ok())
+ die("please make sure that the .gitmodules file is in the working tree");
+ return config_set_in_gitmodules_file_gently(argv[1], NULL);
+ }
+ usage_with_options(usage, options);
+}
+
+static int cmd__submodule_config_writeable(int argc, const char **argv)
+{
+ struct option options[] = {
+ OPT_END()
+ };
+ const char *const usage[] = {
+ "test-tool submodule config-writeable",
+ NULL
+ };
+ setup_git_directory();
+
+ if (argc == 1)
+ return is_writing_gitmodules_ok() ? 0 : -1;
+
+ usage_with_options(usage, options);
+}
+
static struct test_cmd cmds[] = {
{ "check-name", cmd__submodule_check_name },
{ "is-active", cmd__submodule_is_active },
{ "resolve-relative-url", cmd__submodule_resolve_relative_url},
+ { "config-list", cmd__submodule_config_list },
+ { "config-set", cmd__submodule_config_set },
+ { "config-unset", cmd__submodule_config_unset },
+ { "config-writeable", cmd__submodule_config_writeable },
};
int cmd__submodule(int argc, const char **argv)
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index 01cda9358d..7eb1a26a30 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -14,6 +14,7 @@ static struct test_cmd cmds[] = {
{ "bitmap", cmd__bitmap },
{ "bloom", cmd__bloom },
{ "bundle-uri", cmd__bundle_uri },
+ { "cache-tree", cmd__cache_tree },
{ "chmtime", cmd__chmtime },
{ "config", cmd__config },
{ "crontab", cmd__crontab },
@@ -73,6 +74,7 @@ static struct test_cmd cmds[] = {
{ "scrap-cache-tree", cmd__scrap_cache_tree },
{ "serve-v2", cmd__serve_v2 },
{ "sha1", cmd__sha1 },
+ { "sha1-is-sha1dc", cmd__sha1_is_sha1dc },
{ "sha256", cmd__sha256 },
{ "sigchain", cmd__sigchain },
{ "simple-ipc", cmd__simple_ipc },
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
index ca2948066f..2e20a16eb8 100644
--- a/t/helper/test-tool.h
+++ b/t/helper/test-tool.h
@@ -1,13 +1,13 @@
#ifndef TEST_TOOL_H
#define TEST_TOOL_H
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
#include "git-compat-util.h"
int cmd__advise_if_enabled(int argc, const char **argv);
int cmd__bitmap(int argc, const char **argv);
int cmd__bloom(int argc, const char **argv);
int cmd__bundle_uri(int argc, const char **argv);
+int cmd__cache_tree(int argc, const char **argv);
int cmd__chmtime(int argc, const char **argv);
int cmd__config(int argc, const char **argv);
int cmd__crontab(int argc, const char **argv);
@@ -66,6 +66,7 @@ int cmd__run_command(int argc, const char **argv);
int cmd__scrap_cache_tree(int argc, const char **argv);
int cmd__serve_v2(int argc, const char **argv);
int cmd__sha1(int argc, const char **argv);
+int cmd__sha1_is_sha1dc(int argc, const char **argv);
int cmd__oid_array(int argc, const char **argv);
int cmd__sha256(int argc, const char **argv);
int cmd__sigchain(int argc, const char **argv);
diff --git a/t/helper/test-write-cache.c b/t/helper/test-write-cache.c
index 8837717d36..7d45cd61e8 100644
--- a/t/helper/test-write-cache.c
+++ b/t/helper/test-write-cache.c
@@ -1,3 +1,4 @@
+#define USE_THE_INDEX_VARIABLE
#include "test-tool.h"
#include "cache.h"
#include "lockfile.h"
@@ -9,9 +10,10 @@ int cmd__write_cache(int argc, const char **argv)
if (argc == 2)
cnt = strtol(argv[1], NULL, 0);
setup_git_directory();
- read_cache();
+ repo_read_index(the_repository);
for (i = 0; i < cnt; i++) {
- hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR);
+ repo_hold_locked_index(the_repository, &index_lock,
+ LOCK_DIE_ON_ERROR);
if (write_locked_index(&the_index, &index_lock, COMMIT_LOCK))
die("unable to write index file");
}
diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh
index 1f6b9b08d1..608949ea80 100644
--- a/t/lib-httpd.sh
+++ b/t/lib-httpd.sh
@@ -65,7 +65,8 @@ done
for DEFAULT_HTTPD_MODULE_PATH in '/usr/libexec/apache2' \
'/usr/lib/apache2/modules' \
'/usr/lib64/httpd/modules' \
- '/usr/lib/httpd/modules'
+ '/usr/lib/httpd/modules' \
+ '/usr/libexec/httpd'
do
if test -d "$DEFAULT_HTTPD_MODULE_PATH"
then
@@ -174,6 +175,11 @@ prepare_httpd() {
fi
}
+enable_http2 () {
+ HTTPD_PARA="$HTTPD_PARA -DHTTP2"
+ test_set_prereq HTTP2
+}
+
start_httpd() {
prepare_httpd >&3 2>&4
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index 706799391b..0294739a77 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -29,6 +29,11 @@ ErrorLog error.log
LoadModule setenvif_module modules/mod_setenvif.so
</IfModule>
+<IfDefine HTTP2>
+LoadModule http2_module modules/mod_http2.so
+Protocols h2c
+</IfDefine>
+
<IfVersion < 2.4>
LockFile accept.lock
</IfVersion>
@@ -64,12 +69,20 @@ LockFile accept.lock
<IfModule !mod_access_compat.c>
LoadModule access_compat_module modules/mod_access_compat.so
</IfModule>
-<IfModule !mod_mpm_prefork.c>
- LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
-</IfModule>
<IfModule !mod_unixd.c>
LoadModule unixd_module modules/mod_unixd.so
</IfModule>
+
+<IfDefine HTTP2>
+<IfModule !mod_mpm_event.c>
+ LoadModule mpm_event_module modules/mod_mpm_event.so
+</IfModule>
+</IfDefine>
+<IfDefine !HTTP2>
+<IfModule !mod_mpm_prefork.c>
+ LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
+</IfModule>
+</IfDefine>
</IfVersion>
PassEnv GIT_VALGRIND
diff --git a/t/perf/p0006-read-tree-checkout.sh b/t/perf/p0006-read-tree-checkout.sh
index c481c012d2..325566e18e 100755
--- a/t/perf/p0006-read-tree-checkout.sh
+++ b/t/perf/p0006-read-tree-checkout.sh
@@ -49,6 +49,14 @@ test_perf "read-tree br_base br_ballast ($nr_files)" '
git read-tree -n -m br_base br_ballast
'
+test_perf "read-tree br_ballast_plus_1 ($nr_files)" '
+ # Run read-tree 100 times for clearer performance results & comparisons
+ for i in $(test_seq 100)
+ do
+ git read-tree -n -m br_ballast_plus_1 || return 1
+ done
+'
+
test_perf "switch between br_base br_ballast ($nr_files)" '
git checkout -q br_base &&
git checkout -q br_ballast
diff --git a/t/perf/p0090-cache-tree.sh b/t/perf/p0090-cache-tree.sh
new file mode 100755
index 0000000000..a8eabca2c4
--- /dev/null
+++ b/t/perf/p0090-cache-tree.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+test_description="Tests performance of cache tree update operations"
+
+. ./perf-lib.sh
+
+test_perf_large_repo
+test_checkout_worktree
+
+count=100
+
+test_expect_success 'setup cache tree' '
+ git write-tree
+'
+
+test_cache_tree () {
+ test_perf "$1, $3" "
+ for i in \$(test_seq $count)
+ do
+ test-tool cache-tree $4 $2
+ done
+ "
+}
+
+test_cache_tree_update_functions () {
+ test_cache_tree 'no-op' 'control' "$1" "$2"
+ test_cache_tree 'prime_cache_tree' 'prime' "$1" "$2"
+ test_cache_tree 'cache_tree_update' 'update' "$1" "$2"
+}
+
+test_cache_tree_update_functions "clean" ""
+test_cache_tree_update_functions "invalidate 2" "--invalidate 2"
+test_cache_tree_update_functions "invalidate 50" "--invalidate 50"
+test_cache_tree_update_functions "empty" "--empty"
+
+test_done
diff --git a/t/perf/p7102-reset.sh b/t/perf/p7102-reset.sh
new file mode 100755
index 0000000000..9b039e8691
--- /dev/null
+++ b/t/perf/p7102-reset.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+test_description='performance of reset'
+. ./perf-lib.sh
+
+test_perf_default_repo
+test_checkout_worktree
+
+test_perf 'reset --hard with change in tree' '
+ base=$(git rev-parse HEAD) &&
+ test_commit --no-tag A &&
+ new=$(git rev-parse HEAD) &&
+
+ for i in $(test_seq 10)
+ do
+ git reset --hard $new &&
+ git reset --hard $base || return $?
+ done
+'
+
+test_done
diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh
index f7ee2f2ff0..d0284fe2d7 100755
--- a/t/t0003-attributes.sh
+++ b/t/t0003-attributes.sh
@@ -376,4 +376,63 @@ test_expect_success SYMLINKS 'symlinks not respected in-tree' '
test_i18ngrep "unable to access.*gitattributes" err
'
+test_expect_success 'large attributes line ignored in tree' '
+ test_when_finished "rm .gitattributes" &&
+ printf "path %02043d" 1 >.gitattributes &&
+ git check-attr --all path >actual 2>err &&
+ echo "warning: ignoring overly long attributes line 1" >expect &&
+ test_cmp expect err &&
+ test_must_be_empty actual
+'
+
+test_expect_success 'large attributes line ignores trailing content in tree' '
+ test_when_finished "rm .gitattributes" &&
+ # older versions of Git broke lines at 2048 bytes; the 2045 bytes
+ # of 0-padding here is accounting for the three bytes of "a 1", which
+ # would knock "trailing" to the "next" line, where it would be
+ # erroneously parsed.
+ printf "a %02045dtrailing attribute\n" 1 >.gitattributes &&
+ git check-attr --all trailing >actual 2>err &&
+ echo "warning: ignoring overly long attributes line 1" >expect &&
+ test_cmp expect err &&
+ test_must_be_empty actual
+'
+
+test_expect_success EXPENSIVE 'large attributes file ignored in tree' '
+ test_when_finished "rm .gitattributes" &&
+ dd if=/dev/zero of=.gitattributes bs=101M count=1 2>/dev/null &&
+ git check-attr --all path >/dev/null 2>err &&
+ echo "warning: ignoring overly large gitattributes file ${SQ}.gitattributes${SQ}" >expect &&
+ test_cmp expect err
+'
+
+test_expect_success 'large attributes line ignored in index' '
+ test_when_finished "git update-index --remove .gitattributes" &&
+ blob=$(printf "path %02043d" 1 | git hash-object -w --stdin) &&
+ git update-index --add --cacheinfo 100644,$blob,.gitattributes &&
+ git check-attr --cached --all path >actual 2>err &&
+ echo "warning: ignoring overly long attributes line 1" >expect &&
+ test_cmp expect err &&
+ test_must_be_empty actual
+'
+
+test_expect_success 'large attributes line ignores trailing content in index' '
+ test_when_finished "git update-index --remove .gitattributes" &&
+ blob=$(printf "a %02045dtrailing attribute\n" 1 | git hash-object -w --stdin) &&
+ git update-index --add --cacheinfo 100644,$blob,.gitattributes &&
+ git check-attr --cached --all trailing >actual 2>err &&
+ echo "warning: ignoring overly long attributes line 1" >expect &&
+ test_cmp expect err &&
+ test_must_be_empty actual
+'
+
+test_expect_success EXPENSIVE 'large attributes file ignored in index' '
+ test_when_finished "git update-index --remove .gitattributes" &&
+ blob=$(dd if=/dev/zero bs=101M count=1 2>/dev/null | git hash-object -w --stdin) &&
+ git update-index --add --cacheinfo 100644,$blob,.gitattributes &&
+ git check-attr --cached --all path >/dev/null 2>err &&
+ echo "warning: ignoring overly large gitattributes blob ${SQ}.gitattributes${SQ}" >expect &&
+ test_cmp expect err
+'
+
test_done
diff --git a/t/t0013-sha1dc.sh b/t/t0013-sha1dc.sh
index 9ad76080aa..5324047689 100755
--- a/t/t0013-sha1dc.sh
+++ b/t/t0013-sha1dc.sh
@@ -6,9 +6,11 @@ TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
TEST_DATA="$TEST_DIRECTORY/t0013"
-if test -z "$DC_SHA1"
+test_lazy_prereq SHA1_IS_SHA1DC 'test-tool sha1-is-sha1dc'
+
+if ! test_have_prereq SHA1_IS_SHA1DC
then
- skip_all='skipping sha1 collision tests, DC_SHA1 not set'
+ skip_all='skipping sha1 collision tests, not using sha1collisiondetection'
test_done
fi
diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh
index 5cc62306e3..7d7ecfd571 100755
--- a/t/t0040-parse-options.sh
+++ b/t/t0040-parse-options.sh
@@ -709,4 +709,16 @@ test_expect_success 'subcommands are incompatible with KEEP_DASHDASH unless in c
grep ^BUG err
'
+test_expect_success 'negative magnitude' '
+ test_must_fail test-tool parse-options --magnitude -1 >out 2>err &&
+ grep "non-negative integer" err &&
+ test_must_be_empty out
+'
+
+test_expect_success 'magnitude with units but no numbers' '
+ test_must_fail test-tool parse-options --magnitude m >out 2>err &&
+ grep "non-negative integer" err &&
+ test_must_be_empty out
+'
+
test_done
diff --git a/t/t0061-run-command.sh b/t/t0061-run-command.sh
index 7b5423eebd..e2411f6a9b 100755
--- a/t/t0061-run-command.sh
+++ b/t/t0061-run-command.sh
@@ -130,7 +130,8 @@ World
EOF
test_expect_success 'run_command runs in parallel with more jobs available than tasks' '
- test-tool run-command run-command-parallel 5 sh -c "printf \"%s\n%s\n\" Hello World" 2>actual &&
+ test-tool run-command run-command-parallel 5 sh -c "printf \"%s\n%s\n\" Hello World" >out 2>actual &&
+ test_must_be_empty out &&
test_cmp expect actual
'
@@ -141,7 +142,8 @@ test_expect_success 'run_command runs ungrouped in parallel with more jobs avail
'
test_expect_success 'run_command runs in parallel with as many jobs as tasks' '
- test-tool run-command run-command-parallel 4 sh -c "printf \"%s\n%s\n\" Hello World" 2>actual &&
+ test-tool run-command run-command-parallel 4 sh -c "printf \"%s\n%s\n\" Hello World" >out 2>actual &&
+ test_must_be_empty out &&
test_cmp expect actual
'
@@ -152,7 +154,8 @@ test_expect_success 'run_command runs ungrouped in parallel with as many jobs as
'
test_expect_success 'run_command runs in parallel with more tasks than jobs available' '
- test-tool run-command run-command-parallel 3 sh -c "printf \"%s\n%s\n\" Hello World" 2>actual &&
+ test-tool run-command run-command-parallel 3 sh -c "printf \"%s\n%s\n\" Hello World" >out 2>actual &&
+ test_must_be_empty out &&
test_cmp expect actual
'
@@ -172,7 +175,8 @@ asking for a quick stop
EOF
test_expect_success 'run_command is asked to abort gracefully' '
- test-tool run-command run-command-abort 3 false 2>actual &&
+ test-tool run-command run-command-abort 3 false >out 2>actual &&
+ test_must_be_empty out &&
test_cmp expect actual
'
@@ -187,7 +191,8 @@ no further jobs available
EOF
test_expect_success 'run_command outputs ' '
- test-tool run-command run-command-no-jobs 3 sh -c "printf \"%s\n%s\n\" Hello World" 2>actual &&
+ test-tool run-command run-command-no-jobs 3 sh -c "printf \"%s\n%s\n\" Hello World" >out 2>actual &&
+ test_must_be_empty out &&
test_cmp expect actual
'
diff --git a/t/t0066-dir-iterator.sh b/t/t0066-dir-iterator.sh
index 63a1a45cd3..04b811622b 100755
--- a/t/t0066-dir-iterator.sh
+++ b/t/t0066-dir-iterator.sh
@@ -110,7 +110,9 @@ test_expect_success SYMLINKS 'setup dirs with symlinks' '
mkdir -p dir5/a/c &&
ln -s ../c dir5/a/b/d &&
ln -s ../ dir5/a/b/e &&
- ln -s ../../ dir5/a/b/f
+ ln -s ../../ dir5/a/b/f &&
+
+ ln -s dir4 dir6
'
test_expect_success SYMLINKS 'dir-iterator should not follow symlinks by default' '
@@ -146,4 +148,27 @@ test_expect_success SYMLINKS 'dir-iterator should follow symlinks w/ follow flag
test_cmp expected-follow-sorted-output actual-follow-sorted-output
'
+test_expect_success SYMLINKS 'dir-iterator does not resolve top-level symlinks' '
+ test_must_fail test-tool dir-iterator ./dir6 >out &&
+
+ grep "ENOTDIR" out
+'
+
+test_expect_success SYMLINKS 'dir-iterator resolves top-level symlinks w/ follow flag' '
+ cat >expected-follow-sorted-output <<-EOF &&
+ [d] (a) [a] ./dir6/a
+ [d] (a/f) [f] ./dir6/a/f
+ [d] (a/f/c) [c] ./dir6/a/f/c
+ [d] (b) [b] ./dir6/b
+ [d] (b/c) [c] ./dir6/b/c
+ [f] (a/d) [d] ./dir6/a/d
+ [f] (a/e) [e] ./dir6/a/e
+ EOF
+
+ test-tool dir-iterator --follow-symlinks ./dir6 >out &&
+ sort out >actual-follow-sorted-output &&
+
+ test_cmp expected-follow-sorted-output actual-follow-sorted-output
+'
+
test_done
diff --git a/t/t0068-for-each-repo.sh b/t/t0068-for-each-repo.sh
index 4675e85251..c6e0d65563 100755
--- a/t/t0068-for-each-repo.sh
+++ b/t/t0068-for-each-repo.sh
@@ -8,9 +8,11 @@ test_expect_success 'run based on configured value' '
git init one &&
git init two &&
git init three &&
+ git init ~/four &&
git -C two commit --allow-empty -m "DID NOT RUN" &&
git config run.key "$TRASH_DIRECTORY/one" &&
git config --add run.key "$TRASH_DIRECTORY/three" &&
+ git config --add run.key "~/four" &&
git for-each-repo --config=run.key commit --allow-empty -m "ran" &&
git -C one log -1 --pretty=format:%s >message &&
grep ran message &&
@@ -18,12 +20,16 @@ test_expect_success 'run based on configured value' '
! grep ran message &&
git -C three log -1 --pretty=format:%s >message &&
grep ran message &&
+ git -C ~/four log -1 --pretty=format:%s >message &&
+ grep ran message &&
git for-each-repo --config=run.key -- commit --allow-empty -m "ran again" &&
git -C one log -1 --pretty=format:%s >message &&
grep again message &&
git -C two log -1 --pretty=format:%s >message &&
! grep again message &&
git -C three log -1 --pretty=format:%s >message &&
+ grep again message &&
+ git -C ~/four log -1 --pretty=format:%s >message &&
grep again message
'
diff --git a/t/t0211-trace2-perf.sh b/t/t0211-trace2-perf.sh
index 0b3436e8ca..b4e9135118 100755
--- a/t/t0211-trace2-perf.sh
+++ b/t/t0211-trace2-perf.sh
@@ -203,7 +203,7 @@ test_expect_success 'stopwatch timer test/test1' '
have_timer_event "main" "timer" "test" "test1" 5 actual
'
-test_expect_success 'stopwatch timer test/test2' '
+test_expect_success PTHREAD 'stopwatch timer test/test2' '
test_when_finished "rm trace.perf actual" &&
test_config_global trace2.perfBrief 1 &&
test_config_global trace2.perfTarget "$(pwd)/trace.perf" &&
@@ -249,7 +249,7 @@ test_expect_success 'global counter test/test1' '
have_counter_event "main" "counter" "test" "test1" 15 actual
'
-test_expect_success 'global counter test/test2' '
+test_expect_success PTHREAD 'global counter test/test2' '
test_when_finished "rm trace.perf actual" &&
test_config_global trace2.perfBrief 1 &&
test_config_global trace2.perfTarget "$(pwd)/trace.perf" &&
diff --git a/t/t1022-read-tree-partial-clone.sh b/t/t1022-read-tree-partial-clone.sh
index a9953b6a71..da53971635 100755
--- a/t/t1022-read-tree-partial-clone.sh
+++ b/t/t1022-read-tree-partial-clone.sh
@@ -19,7 +19,7 @@ test_expect_success 'read-tree in partial clone prefetches in one batch' '
git -C server config uploadpack.allowfilter 1 &&
git -C server config uploadpack.allowanysha1inwant 1 &&
git clone --bare --filter=blob:none "file://$(pwd)/server" client &&
- GIT_TRACE_PACKET="$(pwd)/trace" git -C client read-tree $TREE &&
+ GIT_TRACE_PACKET="$(pwd)/trace" git -C client read-tree $TREE $TREE &&
# "done" marks the end of negotiation (once per fetch). Expect that
# only one fetch occurs.
diff --git a/t/t1050-large.sh b/t/t1050-large.sh
index 4f3aa17c99..c71932b024 100755
--- a/t/t1050-large.sh
+++ b/t/t1050-large.sh
@@ -5,6 +5,12 @@ test_description='adding and checking out large blobs'
. ./test-lib.sh
+test_expect_success 'core.bigFileThreshold must be non-negative' '
+ test_must_fail git -c core.bigFileThreshold=-1 rev-parse >out 2>err &&
+ grep "bad numeric config value" err &&
+ test_must_be_empty out
+'
+
test_expect_success setup '
# clone does not allow us to pass core.bigfilethreshold to
# new repos, so set core.bigfilethreshold globally
diff --git a/t/t1091-sparse-checkout-builtin.sh b/t/t1091-sparse-checkout-builtin.sh
index b563d6c263..627267be15 100755
--- a/t/t1091-sparse-checkout-builtin.sh
+++ b/t/t1091-sparse-checkout-builtin.sh
@@ -238,7 +238,7 @@ test_expect_success 'cone mode: match patterns' '
test_expect_success 'cone mode: warn on bad pattern' '
test_when_finished mv sparse-checkout repo/.git/info/ &&
cp repo/.git/info/sparse-checkout . &&
- echo "!/deep/deeper/*" >>repo/.git/info/sparse-checkout &&
+ echo "!/deep/deeper/*/" >>repo/.git/info/sparse-checkout &&
git -C repo read-tree -mu HEAD 2>err &&
test_i18ngrep "unrecognized negative pattern" err
'
@@ -667,6 +667,15 @@ test_expect_success 'pattern-checks: starting "*"' '
check_read_tree_errors repo "a deep" "disabling cone pattern matching"
'
+test_expect_success 'pattern-checks: non directory pattern' '
+ cat >repo/.git/info/sparse-checkout <<-\EOF &&
+ /deep/deeper1/a
+ EOF
+ check_read_tree_errors repo deep "disabling cone pattern matching" &&
+ check_files repo/deep deeper1 &&
+ check_files repo/deep/deeper1 a
+'
+
test_expect_success 'pattern-checks: contained glob characters' '
for c in "[a]" "\\" "?" "*"
do
diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index c6661e61af..2575279ab8 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -2228,6 +2228,12 @@ test_expect_success '--type rejects unknown specifiers' '
test_i18ngrep "unrecognized --type argument" error
'
+test_expect_success '--type=int requires at least one digit' '
+ test_must_fail git config --type int --default m some.key >out 2>error &&
+ grep "bad numeric config value" error &&
+ test_must_be_empty out
+'
+
test_expect_success '--replace-all does not invent newlines' '
q_to_tab >.git/config <<-\EOF &&
[abc]key
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index ace4556788..de0f6d5e7f 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -999,4 +999,28 @@ test_expect_success 'fsck error and recovery on invalid object type' '
)
'
+test_expect_success 'fsck error on gitattributes with excessive line lengths' '
+ blob=$(printf "pattern %02048d" 1 | git hash-object -w --stdin) &&
+ test_when_finished "remove_object $blob" &&
+ tree=$(printf "100644 blob %s\t%s\n" $blob .gitattributes | git mktree) &&
+ test_when_finished "remove_object $tree" &&
+ cat >expected <<-EOF &&
+ error in blob $blob: gitattributesLineLength: .gitattributes has too long lines to parse
+ EOF
+ test_must_fail git fsck --no-dangling >actual 2>&1 &&
+ test_cmp expected actual
+'
+
+test_expect_success 'fsck error on gitattributes with excessive size' '
+ blob=$(test-tool genzeros $((100 * 1024 * 1024 + 1)) | git hash-object -w --stdin) &&
+ test_when_finished "remove_object $blob" &&
+ tree=$(printf "100644 blob %s\t%s\n" $blob .gitattributes | git mktree) &&
+ test_when_finished "remove_object $tree" &&
+ cat >expected <<-EOF &&
+ error in blob $blob: gitattributesLarge: .gitattributes too large to parse
+ EOF
+ test_must_fail git fsck --no-dangling >actual 2>&1 &&
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t1800-hook.sh b/t/t1800-hook.sh
index 43fcb7c0bf..2ef3579fa7 100755
--- a/t/t1800-hook.sh
+++ b/t/t1800-hook.sh
@@ -95,7 +95,7 @@ test_expect_success 'git hook run -- out-of-repo runs excluded' '
test_expect_success 'git -c core.hooksPath=<PATH> hook run' '
mkdir my-hooks &&
write_script my-hooks/test-hook <<-\EOF &&
- echo Hook ran $1 >>actual
+ echo Hook ran $1
EOF
cat >expect <<-\EOF &&
diff --git a/t/t3104-ls-tree-format.sh b/t/t3104-ls-tree-format.sh
index 383896667b..805b30f403 100755
--- a/t/t3104-ls-tree-format.sh
+++ b/t/t3104-ls-tree-format.sh
@@ -36,6 +36,12 @@ test_ls_tree_format () {
'
}
+test_expect_success "ls-tree --format='%(path) %(path) %(path)' HEAD top-file" '
+ git ls-tree --format="%(path) %(path) %(path)" HEAD top-file.t >actual &&
+ echo top-file.t top-file.t top-file.t >expect &&
+ test_cmp expect actual
+'
+
test_ls_tree_format \
"%(objectmode) %(objecttype) %(objectname)%x09%(path)" \
""
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 7f605f865b..5a169b68d6 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -279,6 +279,42 @@ test_expect_success 'git branch -M and -C fail on detached HEAD' '
test_cmp expect err
'
+test_expect_success 'git branch -d on orphan HEAD (merged)' '
+ test_when_finished git checkout main &&
+ git checkout --orphan orphan &&
+ test_when_finished "rm -rf .git/objects/commit-graph*" &&
+ git commit-graph write --reachable &&
+ git branch --track to-delete main &&
+ git branch -d to-delete
+'
+
+test_expect_success 'git branch -d on orphan HEAD (merged, graph)' '
+ test_when_finished git checkout main &&
+ git checkout --orphan orphan &&
+ git branch --track to-delete main &&
+ git branch -d to-delete
+'
+
+test_expect_success 'git branch -d on orphan HEAD (unmerged)' '
+ test_when_finished git checkout main &&
+ git checkout --orphan orphan &&
+ test_when_finished "git branch -D to-delete" &&
+ git branch to-delete main &&
+ test_must_fail git branch -d to-delete 2>err &&
+ grep "not fully merged" err
+'
+
+test_expect_success 'git branch -d on orphan HEAD (unmerged, graph)' '
+ test_when_finished git checkout main &&
+ git checkout --orphan orphan &&
+ test_when_finished "git branch -D to-delete" &&
+ git branch to-delete main &&
+ test_when_finished "rm -rf .git/objects/commit-graph*" &&
+ git commit-graph write --reachable &&
+ test_must_fail git branch -d to-delete 2>err &&
+ grep "not fully merged" err
+'
+
test_expect_success 'git branch -v -d t should work' '
git branch t &&
git rev-parse --verify refs/heads/t &&
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 4f5abb5ad2..462cefd25d 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -1964,6 +1964,113 @@ test_expect_success 'respect user edits to update-ref steps' '
test_cmp_rev HEAD refs/heads/no-conflict-branch
'
+test_expect_success '--update-refs: all update-ref lines removed' '
+ git checkout -b test-refs-not-removed no-conflict-branch &&
+ git branch -f base HEAD~4 &&
+ git branch -f first HEAD~3 &&
+ git branch -f second HEAD~3 &&
+ git branch -f third HEAD~1 &&
+ git branch -f tip &&
+
+ test_commit test-refs-not-removed &&
+ git commit --amend --fixup first &&
+
+ git rev-parse first second third tip no-conflict-branch >expect-oids &&
+
+ (
+ set_cat_todo_editor &&
+ test_must_fail git rebase -i --update-refs base >todo.raw &&
+ sed -e "/^update-ref/d" <todo.raw >todo
+ ) &&
+ (
+ set_replace_editor todo &&
+ git rebase -i --update-refs base
+ ) &&
+
+ # Ensure refs are not deleted and their OIDs have not changed
+ git rev-parse first second third tip no-conflict-branch >actual-oids &&
+ test_cmp expect-oids actual-oids
+'
+
+test_expect_success '--update-refs: all update-ref lines removed, then some re-added' '
+ git checkout -b test-refs-not-removed2 no-conflict-branch &&
+ git branch -f base HEAD~4 &&
+ git branch -f first HEAD~3 &&
+ git branch -f second HEAD~3 &&
+ git branch -f third HEAD~1 &&
+ git branch -f tip &&
+
+ test_commit test-refs-not-removed2 &&
+ git commit --amend --fixup first &&
+
+ git rev-parse first second third >expect-oids &&
+
+ (
+ set_cat_todo_editor &&
+ test_must_fail git rebase -i \
+ --autosquash --update-refs \
+ base >todo.raw &&
+ sed -e "/^update-ref/d" <todo.raw >todo
+ ) &&
+
+ # Add a break to the end of the todo so we can edit later
+ echo "break" >>todo &&
+
+ (
+ set_replace_editor todo &&
+ git rebase -i --autosquash --update-refs base &&
+ echo "update-ref refs/heads/tip" >todo &&
+ git rebase --edit-todo &&
+ git rebase --continue
+ ) &&
+
+ # Ensure first/second/third are unchanged, but tip is updated
+ git rev-parse first second third >actual-oids &&
+ test_cmp expect-oids actual-oids &&
+ test_cmp_rev HEAD tip
+'
+
+test_expect_success '--update-refs: --edit-todo with no update-ref lines' '
+ git checkout -b test-refs-not-removed3 no-conflict-branch &&
+ git branch -f base HEAD~4 &&
+ git branch -f first HEAD~3 &&
+ git branch -f second HEAD~3 &&
+ git branch -f third HEAD~1 &&
+ git branch -f tip &&
+
+ test_commit test-refs-not-removed3 &&
+ git commit --amend --fixup first &&
+
+ git rev-parse first second third tip no-conflict-branch >expect-oids &&
+
+ (
+ set_cat_todo_editor &&
+ test_must_fail git rebase -i \
+ --autosquash --update-refs \
+ base >todo.raw &&
+ sed -e "/^update-ref/d" <todo.raw >todo
+ ) &&
+
+ # Add a break to the beginning of the todo so we can resume with no
+ # update-ref lines
+ echo "break" >todo.new &&
+ cat todo >>todo.new &&
+
+ (
+ set_replace_editor todo.new &&
+ git rebase -i --autosquash --update-refs base &&
+
+ # Make no changes when editing so update-refs is still empty
+ cat todo >todo.new &&
+ git rebase --edit-todo &&
+ git rebase --continue
+ ) &&
+
+ # Ensure refs are not deleted and their OIDs have not changed
+ git rev-parse first second third tip no-conflict-branch >actual-oids &&
+ test_cmp expect-oids actual-oids
+'
+
test_expect_success '--update-refs: check failed ref update' '
git checkout -B update-refs-error no-conflict-branch &&
git branch -f base HEAD~4 &&
diff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh
index f351701fec..fa2a06c19f 100755
--- a/t/t3430-rebase-merges.sh
+++ b/t/t3430-rebase-merges.sh
@@ -138,6 +138,23 @@ test_expect_success '`reset` refuses to overwrite untracked files' '
git rebase --abort
'
+test_expect_success '`reset` rejects trees' '
+ test_when_finished "test_might_fail git rebase --abort" &&
+ test_must_fail env GIT_SEQUENCE_EDITOR="echo reset A^{tree} >" \
+ git rebase -i B C >out 2>err &&
+ grep "object .* is a tree" err &&
+ test_must_be_empty out
+'
+
+test_expect_success '`reset` only looks for labels under refs/rewritten/' '
+ test_when_finished "test_might_fail git rebase --abort" &&
+ git branch refs/rewritten/my-label A &&
+ test_must_fail env GIT_SEQUENCE_EDITOR="echo reset my-label >" \
+ git rebase -i B C >out 2>err &&
+ grep "could not resolve ${SQ}my-label${SQ}" err &&
+ test_must_be_empty out
+'
+
test_expect_success 'failed `merge -C` writes patch (may be rescheduled, too)' '
test_when_finished "test_might_fail git rebase --abort" &&
git checkout -b conflicting-merge A &&
diff --git a/t/t3920-crlf-messages.sh b/t/t3920-crlf-messages.sh
index 4c661d4d54..67fd2345af 100755
--- a/t/t3920-crlf-messages.sh
+++ b/t/t3920-crlf-messages.sh
@@ -12,7 +12,7 @@ create_crlf_ref () {
cat >.crlf-orig-$branch.txt &&
cat .crlf-orig-$branch.txt | append_cr >.crlf-message-$branch.txt &&
grep 'Subject' .crlf-orig-$branch.txt | tr '\n' ' ' | sed 's/[ ]*$//' | tr -d '\n' >.crlf-subject-$branch.txt &&
- grep 'Body' .crlf-message-$branch.txt >.crlf-body-$branch.txt || true &&
+ grep 'Body' .crlf-orig-$branch.txt | append_cr >.crlf-body-$branch.txt &&
LIB_CRLF_BRANCHES="${LIB_CRLF_BRANCHES} ${branch}" &&
test_tick &&
hash=$(git commit-tree HEAD^{tree} -p HEAD -F .crlf-message-${branch}.txt) &&
diff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh
index 7cb9909293..787605ce3f 100755
--- a/t/t4023-diff-rename-typechange.sh
+++ b/t/t4023-diff-rename-typechange.sh
@@ -52,8 +52,8 @@ test_expect_success setup '
'
test_expect_success 'cross renames to be detected for regular files' '
-
- git diff-tree five six -r --name-status -B -M | sort >actual &&
+ git diff-tree five six -r --name-status -B -M >out &&
+ sort out >actual &&
{
echo "R100 foo bar" &&
echo "R100 bar foo"
@@ -63,8 +63,8 @@ test_expect_success 'cross renames to be detected for regular files' '
'
test_expect_success 'cross renames to be detected for typechange' '
-
- git diff-tree one two -r --name-status -B -M | sort >actual &&
+ git diff-tree one two -r --name-status -B -M >out &&
+ sort out >actual &&
{
echo "R100 foo bar" &&
echo "R100 bar foo"
@@ -74,8 +74,8 @@ test_expect_success 'cross renames to be detected for typechange' '
'
test_expect_success 'moves and renames' '
-
- git diff-tree three four -r --name-status -B -M | sort >actual &&
+ git diff-tree three four -r --name-status -B -M >out &&
+ sort out >actual &&
{
# see -B -M (#6) in t4008
echo "C100 foo bar" &&
diff --git a/t/t4045-diff-relative.sh b/t/t4045-diff-relative.sh
index fab351b48a..5e1bbb57e7 100755
--- a/t/t4045-diff-relative.sh
+++ b/t/t4045-diff-relative.sh
@@ -162,6 +162,35 @@ check_diff_relative_option subdir file2 true --no-relative --relative
check_diff_relative_option . file2 false --no-relative --relative=subdir
check_diff_relative_option . file2 true --no-relative --relative=subdir
+test_expect_success 'external diff with --relative' '
+ test_when_finished "git reset --hard" &&
+ echo changed >file1 &&
+ echo changed >subdir/file2 &&
+
+ write_script mydiff <<-\EOF &&
+ # hacky pretend diff; the goal here is just to make sure we got
+ # passed sensible input that we _could_ diff, without relying on
+ # the specific output of a system diff tool.
+ echo "diff a/$1 b/$1" &&
+ echo "--- a/$1" &&
+ echo "+++ b/$1" &&
+ echo "@@ -1 +0,0 @@" &&
+ sed "s/^/-/" "$2" &&
+ sed "s/^/+/" "$5"
+ EOF
+
+ cat >expect <<-\EOF &&
+ diff a/file2 b/file2
+ --- a/file2
+ +++ b/file2
+ @@ -1 +0,0 @@
+ -other content
+ +changed
+ EOF
+ GIT_EXTERNAL_DIFF=./mydiff git diff --relative=subdir >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'setup diff --relative unmerged' '
test_commit zero file0 &&
test_commit base subdir/file0 &&
diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh
index d0f3edef54..65ac7df2d7 100755
--- a/t/t4115-apply-symlink.sh
+++ b/t/t4115-apply-symlink.sh
@@ -45,4 +45,85 @@ test_expect_success 'apply --index symlink patch' '
'
+test_expect_success 'symlink setup' '
+ ln -s .git symlink &&
+ git add symlink &&
+ git commit -m "add symlink"
+'
+
+test_expect_success SYMLINKS 'symlink escape when creating new files' '
+ test_when_finished "git reset --hard && git clean -dfx" &&
+
+ cat >patch <<-EOF &&
+ diff --git a/symlink b/renamed-symlink
+ similarity index 100%
+ rename from symlink
+ rename to renamed-symlink
+ --
+ diff --git /dev/null b/renamed-symlink/create-me
+ new file mode 100644
+ index 0000000..039727e
+ --- /dev/null
+ +++ b/renamed-symlink/create-me
+ @@ -0,0 +1,1 @@
+ +busted
+ EOF
+
+ test_must_fail git apply patch 2>stderr &&
+ cat >expected_stderr <<-EOF &&
+ error: affected file ${SQ}renamed-symlink/create-me${SQ} is beyond a symbolic link
+ EOF
+ test_cmp expected_stderr stderr &&
+ ! test_path_exists .git/create-me
+'
+
+test_expect_success SYMLINKS 'symlink escape when modifying file' '
+ test_when_finished "git reset --hard && git clean -dfx" &&
+ touch .git/modify-me &&
+
+ cat >patch <<-EOF &&
+ diff --git a/symlink b/renamed-symlink
+ similarity index 100%
+ rename from symlink
+ rename to renamed-symlink
+ --
+ diff --git a/renamed-symlink/modify-me b/renamed-symlink/modify-me
+ index 1111111..2222222 100644
+ --- a/renamed-symlink/modify-me
+ +++ b/renamed-symlink/modify-me
+ @@ -0,0 +1,1 @@
+ +busted
+ EOF
+
+ test_must_fail git apply patch 2>stderr &&
+ cat >expected_stderr <<-EOF &&
+ error: renamed-symlink/modify-me: No such file or directory
+ EOF
+ test_cmp expected_stderr stderr &&
+ test_must_be_empty .git/modify-me
+'
+
+test_expect_success SYMLINKS 'symlink escape when deleting file' '
+ test_when_finished "git reset --hard && git clean -dfx && rm .git/delete-me" &&
+ touch .git/delete-me &&
+
+ cat >patch <<-EOF &&
+ diff --git a/symlink b/renamed-symlink
+ similarity index 100%
+ rename from symlink
+ rename to renamed-symlink
+ --
+ diff --git a/renamed-symlink/delete-me b/renamed-symlink/delete-me
+ deleted file mode 100644
+ index 1111111..0000000 100644
+ EOF
+
+ test_must_fail git apply patch 2>stderr &&
+ cat >expected_stderr <<-EOF &&
+ error: renamed-symlink/delete-me: No such file or directory
+ EOF
+ test_cmp expected_stderr stderr &&
+ test_path_is_file .git/delete-me
+'
+
test_done
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index e448ef2928..3e7ad9d5de 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -156,7 +156,7 @@ test_expect_success 'NUL termination with --reflog --pretty=oneline' '
for r in $revs
do
git show -s --pretty=oneline "$r" >raw &&
- cat raw | lf_to_nul || exit 1
+ cat raw | lf_to_nul || return 1
done >expect &&
# the trailing NUL is already produced so we do not need to
# output another one
@@ -1018,4 +1018,80 @@ test_expect_success '%(describe:abbrev=...) vs git describe --abbrev=...' '
test_cmp expect actual
'
+test_expect_success 'log --pretty with space stealing' '
+ printf mm0 >expect &&
+ git log -1 --pretty="format:mm%>>|(1)%x30" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log --pretty with invalid padding format' '
+ printf "%s%%<(20" "$(git rev-parse HEAD)" >expect &&
+ git log -1 --pretty="format:%H%<(20" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log --pretty with magical wrapping directives' '
+ commit_id=$(git commit-tree HEAD^{tree} -m "describe me") &&
+ git tag describe-me $commit_id &&
+ printf "\n(tag:\ndescribe-me)%%+w(2)" >expect &&
+ git log -1 --pretty="format:%w(1)%+d%+w(2)" $commit_id >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success SIZE_T_IS_64BIT 'log --pretty with overflowing wrapping directive' '
+ printf "%%w(2147483649,1,1)0" >expect &&
+ git log -1 --pretty="format:%w(2147483649,1,1)%x30" >actual &&
+ test_cmp expect actual &&
+ printf "%%w(1,2147483649,1)0" >expect &&
+ git log -1 --pretty="format:%w(1,2147483649,1)%x30" >actual &&
+ test_cmp expect actual &&
+ printf "%%w(1,1,2147483649)0" >expect &&
+ git log -1 --pretty="format:%w(1,1,2147483649)%x30" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success SIZE_T_IS_64BIT 'log --pretty with overflowing padding directive' '
+ printf "%%<(2147483649)0" >expect &&
+ git log -1 --pretty="format:%<(2147483649)%x30" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log --pretty with padding and preceding control chars' '
+ printf "\20\20 0" >expect &&
+ git log -1 --pretty="format:%x10%x10%>|(4)%x30" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log --pretty truncation with control chars' '
+ test_commit "$(printf "\20\20\20\20xxxx")" file contents commit-with-control-chars &&
+ printf "\20\20\20\20x.." >expect &&
+ git log -1 --pretty="format:%<(3,trunc)%s" commit-with-control-chars >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message' '
+ # We only assert that this command does not crash. This needs to be
+ # executed with the address sanitizer to demonstrate failure.
+ git log -1 --pretty="format:%>(2147483646)%x41%41%>(2147483646)%x41" >/dev/null
+'
+
+test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'set up huge commit' '
+ test-tool genzeros 2147483649 | tr "\000" "1" >expect &&
+ huge_commit=$(git commit-tree -F expect HEAD^{tree})
+'
+
+test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message' '
+ git log -1 --format="%B%<(1)%x30" $huge_commit >actual &&
+ echo 0 >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message does not cause allocation failure' '
+ test_must_fail git log -1 --format="%<(1)%B" $huge_commit 2>error &&
+ cat >expect <<-EOF &&
+ fatal: number too large to represent as int on this platform: 2147483649
+ EOF
+ test_cmp expect error
+'
+
test_done
diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh
index ac9e4d0928..c6540e822f 100755
--- a/t/t4211-line-log.sh
+++ b/t/t4211-line-log.sh
@@ -315,4 +315,26 @@ test_expect_success 'line-log with --before' '
test_cmp expect actual
'
+test_expect_success 'setup tests for zero-width regular expressions' '
+ cat >expect <<-EOF
+ Modify func1() in file.c
+ Add func1() and func2() in file.c
+ EOF
+'
+
+test_expect_success 'zero-width regex $ matches any function name' '
+ git log --format="%s" --no-patch "-L:$:file.c" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'zero-width regex ^ matches any function name' '
+ git log --format="%s" --no-patch "-L:^:file.c" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'zero-width regex .* matches any function name' '
+ git log --format="%s" --no-patch "-L:.*:file.c" >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh
index 8ae314af58..d65a5f94b4 100755
--- a/t/t5304-prune.sh
+++ b/t/t5304-prune.sh
@@ -29,6 +29,14 @@ test_expect_success setup '
git gc
'
+test_expect_success 'bare repo prune is quiet without $GIT_DIR/objects/pack' '
+ git clone -q --shared --template= --bare . bare.git &&
+ rmdir bare.git/objects/pack &&
+ git --git-dir=bare.git prune --no-progress 2>prune.err &&
+ test_must_be_empty prune.err &&
+ rm -r bare.git prune.err
+'
+
test_expect_success 'prune stale packs' '
orig_pack=$(echo .git/objects/pack/*.pack) &&
>.git/objects/tmp_1.pack &&
diff --git a/t/t5314-pack-cycle-detection.sh b/t/t5314-pack-cycle-detection.sh
index 73a241743a..82734b9a3c 100755
--- a/t/t5314-pack-cycle-detection.sh
+++ b/t/t5314-pack-cycle-detection.sh
@@ -63,13 +63,16 @@ TEST_PASSES_SANITIZE_LEAK=true
# Note that the two variants of "file" must be similar enough to convince git
# to create the delta.
make_pack () {
- {
- printf '%s\n' "-$(git rev-parse $2)"
- printf '%s dummy\n' "$(git rev-parse $1:dummy)"
- printf '%s file\n' "$(git rev-parse $1:file)"
- } |
- git pack-objects --stdout |
- git index-pack --stdin --fix-thin
+ ln1=$(git rev-parse "$2") &&
+ ln2=$(git rev-parse "$1:dummy") &&
+ ln3=$(git rev-parse "$1:file") &&
+ cat >list <<-EOF
+ -$ln1
+ $ln2 dummy
+ $ln3 file
+ EOF
+ git pack-objects --stdout <list >pack &&
+ git index-pack --stdin --fix-thin <pack
}
test_expect_success 'setup' '
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 4f2bfaf005..98a27a2948 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -1858,19 +1858,19 @@ test_expect_success 'push with config push.useBitmaps' '
git checkout main &&
test_unconfig push.useBitmaps &&
GIT_TRACE2_EVENT="$PWD/default" \
- git push testrepo main:test &&
+ git push --quiet testrepo main:test &&
test_subcommand git pack-objects --all-progress-implied --revs --stdout \
--thin --delta-base-offset -q <default &&
test_config push.useBitmaps true &&
GIT_TRACE2_EVENT="$PWD/true" \
- git push testrepo main:test2 &&
+ git push --quiet testrepo main:test2 &&
test_subcommand git pack-objects --all-progress-implied --revs --stdout \
--thin --delta-base-offset -q <true &&
test_config push.useBitmaps false &&
GIT_TRACE2_EVENT="$PWD/false" \
- git push testrepo main:test3 &&
+ git push --quiet testrepo main:test3 &&
test_subcommand git pack-objects --all-progress-implied --revs --stdout \
--thin --delta-base-offset -q --no-use-bitmap-index <false
'
diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh
index 75da8acf8f..b9546ef8e5 100755
--- a/t/t5526-fetch-submodules.sh
+++ b/t/t5526-fetch-submodules.sh
@@ -178,6 +178,7 @@ test_expect_success "submodule.recurse option triggers recursive fetch" '
'
test_expect_success "fetch --recurse-submodules -j2 has the same output behaviour" '
+ test_when_finished "rm -f trace.out" &&
add_submodule_commits &&
(
cd downstream &&
@@ -705,15 +706,22 @@ test_expect_success "'fetch.recurseSubmodules=on-demand' works also without .git
test_expect_success 'fetching submodules respects parallel settings' '
git config fetch.recurseSubmodules true &&
+ test_when_finished "rm -f downstream/trace.out" &&
(
cd downstream &&
GIT_TRACE=$(pwd)/trace.out git fetch &&
grep "1 tasks" trace.out &&
+ >trace.out &&
+
GIT_TRACE=$(pwd)/trace.out git fetch --jobs 7 &&
grep "7 tasks" trace.out &&
+ >trace.out &&
+
git config submodule.fetchJobs 8 &&
GIT_TRACE=$(pwd)/trace.out git fetch &&
grep "8 tasks" trace.out &&
+ >trace.out &&
+
GIT_TRACE=$(pwd)/trace.out git fetch --jobs 9 &&
grep "9 tasks" trace.out &&
>trace.out &&
diff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh
index 3f58b515ce..302e4cbdba 100755
--- a/t/t5531-deep-submodule-push.sh
+++ b/t/t5531-deep-submodule-push.sh
@@ -512,6 +512,56 @@ test_expect_success 'push only unpushed submodules recursively' '
test_cmp expected_pub actual_pub
'
+setup_subsub () {
+ git init upstream &&
+ git init upstream/sub &&
+ git init upstream/sub/deepsub &&
+ test_commit -C upstream/sub/deepsub innermost &&
+ git -C upstream/sub submodule add ./deepsub deepsub &&
+ git -C upstream/sub commit -m middle &&
+ git -C upstream submodule add ./sub sub &&
+ git -C upstream commit -m outermost &&
+
+ git -c protocol.file.allow=always clone --recurse-submodules upstream downstream &&
+ git -C downstream/sub/deepsub checkout -b downstream-branch &&
+ git -C downstream/sub checkout -b downstream-branch &&
+ git -C downstream checkout -b downstream-branch
+}
+
+new_downstream_commits () {
+ test_commit -C downstream/sub/deepsub new-innermost &&
+ git -C downstream/sub add deepsub &&
+ git -C downstream/sub commit -m new-middle &&
+ git -C downstream add sub &&
+ git -C downstream commit -m new-outermost
+}
+
+test_expect_success 'push with push.recurseSubmodules=only on superproject' '
+ test_when_finished rm -rf upstream downstream &&
+ setup_subsub &&
+ new_downstream_commits &&
+ git -C downstream config push.recurseSubmodules only &&
+ git -C downstream push origin downstream-branch &&
+
+ test_must_fail git -C upstream rev-parse refs/heads/downstream-branch &&
+ git -C upstream/sub rev-parse refs/heads/downstream-branch &&
+ test_must_fail git -C upstream/sub/deepsub rev-parse refs/heads/downstream-branch
+'
+
+test_expect_success 'push with push.recurseSubmodules=only on superproject and top-level submodule' '
+ test_when_finished rm -rf upstream downstream &&
+ setup_subsub &&
+ new_downstream_commits &&
+ git -C downstream config push.recurseSubmodules only &&
+ git -C downstream/sub config push.recurseSubmodules only &&
+ git -C downstream push origin downstream-branch 2> err &&
+
+ test_must_fail git -C upstream rev-parse refs/heads/downstream-branch &&
+ git -C upstream/sub rev-parse refs/heads/downstream-branch &&
+ git -C upstream/sub/deepsub rev-parse refs/heads/downstream-branch &&
+ grep "recursing into submodule with push.recurseSubmodules=only; using on-demand instead" err
+'
+
test_expect_success 'push propagating the remotes name to a submodule' '
git -C work remote add origin ../pub.git &&
git -C work remote add pub ../pub.git &&
diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh
index 64c6c9f59e..bc0719a4fc 100755
--- a/t/t5551-http-fetch-smart.sh
+++ b/t/t5551-http-fetch-smart.sh
@@ -1,13 +1,19 @@
#!/bin/sh
-test_description='test smart fetching over http via http-backend'
+: ${HTTP_PROTO:=HTTP}
+test_description="test smart fetching over http via http-backend ($HTTP_PROTO)"
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-httpd.sh
+test "$HTTP_PROTO" = "HTTP/2" && enable_http2
start_httpd
+test_expect_success HTTP2 'enable client-side http/2' '
+ git config --global http.version HTTP/2
+'
+
test_expect_success 'setup repository' '
git config push.default matching &&
echo content >file &&
@@ -347,7 +353,10 @@ test_expect_success CMDLINE_LIMIT \
test_expect_success 'large fetch-pack requests can be sent using chunked encoding' '
GIT_TRACE_CURL=true git -c http.postbuffer=65536 \
clone --bare "$HTTPD_URL/smart/repo.git" split.git 2>err &&
- grep "^=> Send header: Transfer-Encoding: chunked" err
+ {
+ test_have_prereq HTTP2 ||
+ grep "^=> Send header: Transfer-Encoding: chunked" err
+ }
'
test_expect_success 'test allowreachablesha1inwant' '
diff --git a/t/t5559-http-fetch-smart-http2.sh b/t/t5559-http-fetch-smart-http2.sh
new file mode 100755
index 0000000000..9eece71c2c
--- /dev/null
+++ b/t/t5559-http-fetch-smart-http2.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+HTTP_PROTO=HTTP/2
+. ./t5551-http-fetch-smart.sh
diff --git a/t/t5604-clone-reference.sh b/t/t5604-clone-reference.sh
index 2734e37e88..7ccebb40c3 100755
--- a/t/t5604-clone-reference.sh
+++ b/t/t5604-clone-reference.sh
@@ -344,4 +344,20 @@ test_expect_success SYMLINKS 'clone repo with symlinked or unknown files at obje
test_must_be_empty T--shared.objects-symlinks.raw
'
+test_expect_success SYMLINKS 'clone repo with symlinked objects directory' '
+ test_when_finished "rm -fr sensitive malicious" &&
+
+ mkdir -p sensitive &&
+ echo "secret" >sensitive/file &&
+
+ git init malicious &&
+ rm -fr malicious/.git/objects &&
+ ln -s "$(pwd)/sensitive" ./malicious/.git/objects &&
+
+ test_must_fail git clone --local malicious clone 2>err &&
+
+ test_path_is_missing clone &&
+ grep "failed to start iterator over" err
+'
+
test_done
diff --git a/t/t5619-clone-local-ambiguous-transport.sh b/t/t5619-clone-local-ambiguous-transport.sh
new file mode 100755
index 0000000000..cce62bf78d
--- /dev/null
+++ b/t/t5619-clone-local-ambiguous-transport.sh
@@ -0,0 +1,70 @@
+#!/bin/sh
+
+test_description='test local clone with ambiguous transport'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY/lib-httpd.sh"
+
+if ! test_have_prereq SYMLINKS
+then
+ skip_all='skipping test, symlink support unavailable'
+ test_done
+fi
+
+start_httpd
+
+REPO="$HTTPD_DOCUMENT_ROOT_PATH/sub.git"
+URI="$HTTPD_URL/dumb/sub.git"
+
+test_expect_success 'setup' '
+ mkdir -p sensitive &&
+ echo "secret" >sensitive/secret &&
+
+ git init --bare "$REPO" &&
+ test_commit_bulk -C "$REPO" --ref=main 1 &&
+
+ git -C "$REPO" update-ref HEAD main &&
+ git -C "$REPO" update-server-info &&
+
+ git init malicious &&
+ (
+ cd malicious &&
+
+ git submodule add "$URI" &&
+
+ mkdir -p repo/refs &&
+ touch repo/refs/.gitkeep &&
+ printf "ref: refs/heads/a" >repo/HEAD &&
+ ln -s "$(cd .. && pwd)/sensitive" repo/objects &&
+
+ mkdir -p "$HTTPD_URL/dumb" &&
+ ln -s "../../../.git/modules/sub/../../../repo/" "$URI" &&
+
+ git add . &&
+ git commit -m "initial commit"
+ ) &&
+
+ # Delete all of the references in our malicious submodule to
+ # avoid the client attempting to checkout any objects (which
+ # will be missing, and thus will cause the clone to fail before
+ # we can trigger the exploit).
+ git -C "$REPO" for-each-ref --format="delete %(refname)" >in &&
+ git -C "$REPO" update-ref --stdin <in &&
+ git -C "$REPO" update-server-info
+'
+
+test_expect_success 'ambiguous transport does not lead to arbitrary file-inclusion' '
+ git clone malicious clone &&
+ test_must_fail git -C clone submodule update --init 2>err &&
+
+ test_path_is_missing clone/.git/modules/sub/objects/secret &&
+ # We would actually expect "transport .file. not allowed" here,
+ # but due to quirks of the URL detection in Git, we mis-parse
+ # the absolute path as a bogus URL and die before that step.
+ #
+ # This works for now, and if we ever fix the URL detection, it
+ # is OK to change this to detect the transport error.
+ grep "protocol .* is not supported" err
+'
+
+test_done
diff --git a/t/t6018-rev-list-glob.sh b/t/t6018-rev-list-glob.sh
index e1abc5c2b3..aabf590dda 100755
--- a/t/t6018-rev-list-glob.sh
+++ b/t/t6018-rev-list-glob.sh
@@ -187,6 +187,46 @@ test_expect_success 'rev-parse --exclude=ref with --remotes=glob' '
compare rev-parse "--exclude=upstream/x --remotes=upstream/*" "upstream/one upstream/two"
'
+for section in receive uploadpack
+do
+ test_expect_success "rev-parse --exclude-hidden=$section with --all" '
+ compare "-c transfer.hideRefs=refs/remotes/ rev-parse" "--branches --tags" "--exclude-hidden=$section --all"
+ '
+
+ test_expect_success "rev-parse --exclude-hidden=$section with --all" '
+ compare "-c transfer.hideRefs=refs/heads/subspace/ rev-parse" "--exclude=refs/heads/subspace/* --all" "--exclude-hidden=$section --all"
+ '
+
+ test_expect_success "rev-parse --exclude-hidden=$section with --glob" '
+ compare "-c transfer.hideRefs=refs/heads/subspace/ rev-parse" "--exclude=refs/heads/subspace/* --glob=refs/heads/*" "--exclude-hidden=$section --glob=refs/heads/*"
+ '
+
+ test_expect_success "rev-parse --exclude-hidden=$section can be passed once per pseudo-ref" '
+ compare "-c transfer.hideRefs=refs/remotes/ rev-parse" "--branches --tags --branches --tags" "--exclude-hidden=$section --all --exclude-hidden=$section --all"
+ '
+
+ test_expect_success "rev-parse --exclude-hidden=$section can only be passed once per pseudo-ref" '
+ echo "fatal: --exclude-hidden= passed more than once" >expected &&
+ test_must_fail git rev-parse --exclude-hidden=$section --exclude-hidden=$section 2>err &&
+ test_cmp expected err
+ '
+
+ for pseudoopt in branches tags remotes
+ do
+ test_expect_success "rev-parse --exclude-hidden=$section fails with --$pseudoopt" '
+ echo "error: --exclude-hidden cannot be used together with --$pseudoopt" >expected &&
+ test_must_fail git rev-parse --exclude-hidden=$section --$pseudoopt 2>err &&
+ test_cmp expected err
+ '
+
+ test_expect_success "rev-parse --exclude-hidden=$section fails with --$pseudoopt=pattern" '
+ echo "error: --exclude-hidden cannot be used together with --$pseudoopt" >expected &&
+ test_must_fail git rev-parse --exclude-hidden=$section --$pseudoopt=pattern 2>err &&
+ test_cmp expected err
+ '
+ done
+done
+
test_expect_success 'rev-list --exclude=glob with --branches=glob' '
compare rev-list "--exclude=subspace-* --branches=sub*" "subspace/one subspace/two"
'
diff --git a/t/t6020-bundle-misc.sh b/t/t6020-bundle-misc.sh
index 833205125a..3a1cf30b1d 100755
--- a/t/t6020-bundle-misc.sh
+++ b/t/t6020-bundle-misc.sh
@@ -11,6 +11,13 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-bundle.sh
+for cmd in create verify list-heads unbundle
+do
+ test_expect_success "usage: git bundle $cmd needs an argument" '
+ test_expect_code 129 git bundle $cmd
+ '
+done
+
# Create a commit or tag and set the variable with the object ID.
test_commit_setvar () {
notick=
diff --git a/t/t6021-rev-list-exclude-hidden.sh b/t/t6021-rev-list-exclude-hidden.sh
new file mode 100755
index 0000000000..32b2b09413
--- /dev/null
+++ b/t/t6021-rev-list-exclude-hidden.sh
@@ -0,0 +1,163 @@
+#!/bin/sh
+
+test_description='git rev-list --exclude-hidden test'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ test_commit_bulk --id=commit --ref=refs/heads/branch 1 &&
+ COMMIT=$(git rev-parse refs/heads/branch) &&
+ test_commit_bulk --id=tag --ref=refs/tags/lightweight 1 &&
+ TAG=$(git rev-parse refs/tags/lightweight) &&
+ test_commit_bulk --id=hidden --ref=refs/hidden/commit 1 &&
+ HIDDEN=$(git rev-parse refs/hidden/commit) &&
+ test_commit_bulk --id=namespace --ref=refs/namespaces/namespace/refs/namespaced/commit 1 &&
+ NAMESPACE=$(git rev-parse refs/namespaces/namespace/refs/namespaced/commit)
+'
+
+test_expect_success 'invalid section' '
+ echo "fatal: unsupported section for hidden refs: unsupported" >expected &&
+ test_must_fail git rev-list --exclude-hidden=unsupported 2>err &&
+ test_cmp expected err
+'
+
+for section in receive uploadpack
+do
+ test_expect_success "$section: passed multiple times" '
+ echo "fatal: --exclude-hidden= passed more than once" >expected &&
+ test_must_fail git rev-list --exclude-hidden=$section --exclude-hidden=$section 2>err &&
+ test_cmp expected err
+ '
+
+ test_expect_success "$section: without hiddenRefs" '
+ git rev-list --exclude-hidden=$section --all >out &&
+ cat >expected <<-EOF &&
+ $NAMESPACE
+ $HIDDEN
+ $TAG
+ $COMMIT
+ EOF
+ test_cmp expected out
+ '
+
+ test_expect_success "$section: hidden via transfer.hideRefs" '
+ git -c transfer.hideRefs=refs/hidden/ rev-list --exclude-hidden=$section --all >out &&
+ cat >expected <<-EOF &&
+ $NAMESPACE
+ $TAG
+ $COMMIT
+ EOF
+ test_cmp expected out
+ '
+
+ test_expect_success "$section: hidden via $section.hideRefs" '
+ git -c $section.hideRefs=refs/hidden/ rev-list --exclude-hidden=$section --all >out &&
+ cat >expected <<-EOF &&
+ $NAMESPACE
+ $TAG
+ $COMMIT
+ EOF
+ test_cmp expected out
+ '
+
+ test_expect_success "$section: respects both transfer.hideRefs and $section.hideRefs" '
+ git -c transfer.hideRefs=refs/tags/ -c $section.hideRefs=refs/hidden/ rev-list --exclude-hidden=$section --all >out &&
+ cat >expected <<-EOF &&
+ $NAMESPACE
+ $COMMIT
+ EOF
+ test_cmp expected out
+ '
+
+ test_expect_success "$section: negation without hidden refs marks everything as uninteresting" '
+ git rev-list --all --exclude-hidden=$section --not --all >out &&
+ test_must_be_empty out
+ '
+
+ test_expect_success "$section: negation with hidden refs marks them as interesting" '
+ git -c transfer.hideRefs=refs/hidden/ rev-list --all --exclude-hidden=$section --not --all >out &&
+ cat >expected <<-EOF &&
+ $HIDDEN
+ EOF
+ test_cmp expected out
+ '
+
+ test_expect_success "$section: hidden refs and excludes work together" '
+ git -c transfer.hideRefs=refs/hidden/ rev-list --exclude=refs/tags/* --exclude-hidden=$section --all >out &&
+ cat >expected <<-EOF &&
+ $NAMESPACE
+ $COMMIT
+ EOF
+ test_cmp expected out
+ '
+
+ test_expect_success "$section: excluded hidden refs get reset" '
+ git -c transfer.hideRefs=refs/ rev-list --exclude-hidden=$section --all --all >out &&
+ cat >expected <<-EOF &&
+ $NAMESPACE
+ $HIDDEN
+ $TAG
+ $COMMIT
+ EOF
+ test_cmp expected out
+ '
+
+ test_expect_success "$section: excluded hidden refs can be used with multiple pseudo-refs" '
+ git -c transfer.hideRefs=refs/ rev-list --exclude-hidden=$section --all --exclude-hidden=$section --all >out &&
+ test_must_be_empty out
+ '
+
+ test_expect_success "$section: works with --glob" '
+ git -c transfer.hideRefs=refs/hidden/ rev-list --exclude-hidden=$section --glob=refs/h* >out &&
+ cat >expected <<-EOF &&
+ $COMMIT
+ EOF
+ test_cmp expected out
+ '
+
+ test_expect_success "$section: operates on stripped refs by default" '
+ GIT_NAMESPACE=namespace git -c transfer.hideRefs=refs/namespaced/ rev-list --exclude-hidden=$section --all >out &&
+ cat >expected <<-EOF &&
+ $HIDDEN
+ $TAG
+ $COMMIT
+ EOF
+ test_cmp expected out
+ '
+
+ test_expect_success "$section: does not hide namespace by default" '
+ GIT_NAMESPACE=namespace git -c transfer.hideRefs=refs/namespaces/namespace/ rev-list --exclude-hidden=$section --all >out &&
+ cat >expected <<-EOF &&
+ $NAMESPACE
+ $HIDDEN
+ $TAG
+ $COMMIT
+ EOF
+ test_cmp expected out
+ '
+
+ test_expect_success "$section: can operate on unstripped refs" '
+ GIT_NAMESPACE=namespace git -c transfer.hideRefs=^refs/namespaces/namespace/ rev-list --exclude-hidden=$section --all >out &&
+ cat >expected <<-EOF &&
+ $HIDDEN
+ $TAG
+ $COMMIT
+ EOF
+ test_cmp expected out
+ '
+
+ for pseudoopt in remotes branches tags
+ do
+ test_expect_success "$section: fails with --$pseudoopt" '
+ test_must_fail git rev-list --exclude-hidden=$section --$pseudoopt 2>err &&
+ test_i18ngrep "error: --exclude-hidden cannot be used together with --$pseudoopt" err
+ '
+
+ test_expect_success "$section: fails with --$pseudoopt=pattern" '
+ test_must_fail git rev-list --exclude-hidden=$section --$pseudoopt=pattern 2>err &&
+ test_i18ngrep "error: --exclude-hidden cannot be used together with --$pseudoopt" err
+ '
+ done
+done
+
+test_done
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 83931d482f..6dbbe62eb2 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -266,6 +266,16 @@ test_expect_success '"git bisect run" simple case' '
git bisect reset
'
+# We want to make sure no arguments has been eaten
+test_expect_success '"git bisect run" simple case' '
+ git bisect start &&
+ git bisect good $HASH1 &&
+ git bisect bad $HASH4 &&
+ git bisect run printf "%s %s\n" reset --bisect-skip >my_bisect_log.txt &&
+ grep -e "reset --bisect-skip" my_bisect_log.txt &&
+ git bisect reset
+'
+
# We want to automatically find the commit that
# added "Ciao" into hello.
test_expect_success '"git bisect run" with more complex "git bisect start"' '
diff --git a/t/t6102-rev-list-unexpected-objects.sh b/t/t6102-rev-list-unexpected-objects.sh
index 4a9a4436e2..9350b5fd2c 100755
--- a/t/t6102-rev-list-unexpected-objects.sh
+++ b/t/t6102-rev-list-unexpected-objects.sh
@@ -121,8 +121,8 @@ test_expect_success 'setup unexpected non-blob tag' '
tag=$(git hash-object -w --literally -t tag broken-tag)
'
-test_expect_success 'TODO (should fail!): traverse unexpected non-blob tag (lone)' '
- git rev-list --objects $tag
+test_expect_success 'traverse unexpected non-blob tag (lone)' '
+ test_must_fail git rev-list --objects $tag
'
test_expect_success 'traverse unexpected non-blob tag (seen)' '
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index a989aafaf5..eae6a46ef3 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -579,6 +579,16 @@ test_expect_success 'status should be "modified" after submodule commit' '
grep "^+$rev2" list
'
+test_expect_success '"submodule --cached" command forms should be identical' '
+ git submodule status --cached >expect &&
+
+ git submodule --cached >actual &&
+ test_cmp expect actual &&
+
+ git submodule --cached status >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'the --cached sha1 should be rev1' '
git submodule --cached status >list &&
grep "^+$rev1" list
diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 59bd150166..8d7b234beb 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -154,6 +154,11 @@ test_expect_success 'use "submodule foreach" to checkout 2nd level submodule' '
)
'
+test_expect_success 'usage: foreach -- --not-an-option' '
+ test_expect_code 1 git submodule foreach -- --not-an-option &&
+ test_expect_code 1 git -C clone2 submodule foreach -- --not-an-option
+'
+
test_expect_success 'use "foreach --recursive" to checkout all submodules' '
(
cd clone2 &&
diff --git a/t/t7411-submodule-config.sh b/t/t7411-submodule-config.sh
index c583c4e373..c0167944ab 100755
--- a/t/t7411-submodule-config.sh
+++ b/t/t7411-submodule-config.sh
@@ -137,44 +137,44 @@ test_expect_success 'error in history in fetchrecursesubmodule lets continue' '
)
'
-test_expect_success 'reading submodules config from the working tree with "submodule--helper config"' '
+test_expect_success 'reading submodules config from the working tree' '
(cd super &&
echo "../submodule" >expect &&
- git submodule--helper config submodule.submodule.url >actual &&
+ test-tool submodule config-list submodule.submodule.url >actual &&
test_cmp expect actual
)
'
-test_expect_success 'unsetting submodules config from the working tree with "submodule--helper config --unset"' '
+test_expect_success 'unsetting submodules config from the working tree' '
(cd super &&
- git submodule--helper config --unset submodule.submodule.url &&
- git submodule--helper config submodule.submodule.url >actual &&
+ test-tool submodule config-unset submodule.submodule.url &&
+ test-tool submodule config-list submodule.submodule.url >actual &&
test_must_be_empty actual
)
'
-test_expect_success 'writing submodules config with "submodule--helper config"' '
+test_expect_success 'writing submodules config' '
(cd super &&
echo "new_url" >expect &&
- git submodule--helper config submodule.submodule.url "new_url" &&
- git submodule--helper config submodule.submodule.url >actual &&
+ test-tool submodule config-set submodule.submodule.url "new_url" &&
+ test-tool submodule config-list submodule.submodule.url >actual &&
test_cmp expect actual
)
'
-test_expect_success 'overwriting unstaged submodules config with "submodule--helper config"' '
+test_expect_success 'overwriting unstaged submodules config' '
test_when_finished "git -C super checkout .gitmodules" &&
(cd super &&
echo "newer_url" >expect &&
- git submodule--helper config submodule.submodule.url "newer_url" &&
- git submodule--helper config submodule.submodule.url >actual &&
+ test-tool submodule config-set submodule.submodule.url "newer_url" &&
+ test-tool submodule config-list submodule.submodule.url >actual &&
test_cmp expect actual
)
'
test_expect_success 'writeable .gitmodules when it is in the working tree' '
- git -C super submodule--helper config --check-writeable
+ test-tool -C super submodule config-writeable
'
test_expect_success 'writeable .gitmodules when it is nowhere in the repository' '
@@ -183,7 +183,7 @@ test_expect_success 'writeable .gitmodules when it is nowhere in the repository'
(cd super &&
git rm .gitmodules &&
git commit -m "remove .gitmodules from the current branch" &&
- git submodule--helper config --check-writeable
+ test-tool submodule config-writeable
)
'
@@ -191,7 +191,7 @@ test_expect_success 'non-writeable .gitmodules when it is in the index but not i
test_when_finished "git -C super checkout .gitmodules" &&
(cd super &&
rm -f .gitmodules &&
- test_must_fail git submodule--helper config --check-writeable
+ test_must_fail test-tool submodule config-writeable
)
'
@@ -200,7 +200,7 @@ test_expect_success 'non-writeable .gitmodules when it is in the current branch
test_when_finished "git -C super reset --hard $ORIG" &&
(cd super &&
git rm .gitmodules &&
- test_must_fail git submodule--helper config --check-writeable
+ test_must_fail test-tool submodule config-writeable
)
'
@@ -208,11 +208,11 @@ test_expect_success 'reading submodules config from the index when .gitmodules i
ORIG=$(git -C super rev-parse HEAD) &&
test_when_finished "git -C super reset --hard $ORIG" &&
(cd super &&
- git submodule--helper config submodule.submodule.url "staged_url" &&
+ test-tool submodule config-set submodule.submodule.url "staged_url" &&
git add .gitmodules &&
rm -f .gitmodules &&
echo "staged_url" >expect &&
- git submodule--helper config submodule.submodule.url >actual &&
+ test-tool submodule config-list submodule.submodule.url >actual &&
test_cmp expect actual
)
'
@@ -223,7 +223,7 @@ test_expect_success 'reading submodules config from the current branch when .git
(cd super &&
git rm .gitmodules &&
echo "../submodule" >expect &&
- git submodule--helper config submodule.submodule.url >actual &&
+ test-tool submodule config-list submodule.submodule.url >actual &&
test_cmp expect actual
)
'
diff --git a/t/t7418-submodule-sparse-gitmodules.sh b/t/t7418-submodule-sparse-gitmodules.sh
index d5874200fd..dde11ecce8 100755
--- a/t/t7418-submodule-sparse-gitmodules.sh
+++ b/t/t7418-submodule-sparse-gitmodules.sh
@@ -50,12 +50,12 @@ test_expect_success 'sparse checkout setup which hides .gitmodules' '
test_expect_success 'reading gitmodules config file when it is not checked out' '
echo "../submodule" >expect &&
- git -C super submodule--helper config submodule.submodule.url >actual &&
+ test-tool -C super submodule config-list submodule.submodule.url >actual &&
test_cmp expect actual
'
test_expect_success 'not writing gitmodules config file when it is not checked out' '
- test_must_fail git -C super submodule--helper config submodule.submodule.url newurl &&
+ test_must_fail test-tool -C super submodule config-set submodule.submodule.url newurl &&
test_path_is_missing super/.gitmodules
'
diff --git a/t/t7422-submodule-output.sh b/t/t7422-submodule-output.sh
new file mode 100755
index 0000000000..ab946ec940
--- /dev/null
+++ b/t/t7422-submodule-output.sh
@@ -0,0 +1,170 @@
+#!/bin/sh
+
+test_description='submodule --cached, --quiet etc. output'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-t3100.sh
+
+setup_sub () {
+ local d="$1" &&
+ shift &&
+ git $@ clone . "$d" &&
+ git $@ submodule add ./"$d"
+}
+
+normalize_status () {
+ sed -e 's/-g[0-9a-f]*/-gHASH/'
+}
+
+test_expect_success 'setup' '
+ test_commit A &&
+ test_commit B &&
+ setup_sub S &&
+ setup_sub S.D &&
+ setup_sub S.C &&
+ setup_sub S.C.D &&
+ setup_sub X &&
+ git add S* &&
+ test_commit C &&
+
+ # recursive in X/
+ git -C X pull &&
+ GIT_ALLOW_PROTOCOL=file git -C X submodule update --init &&
+
+ # dirty
+ for d in S.D X/S.D
+ do
+ echo dirty >"$d"/A.t || return 1
+ done &&
+
+ # commit (for --cached)
+ for d in S.C* X/S.C*
+ do
+ git -C "$d" reset --hard A || return 1
+ done &&
+
+ # dirty
+ for d in S*.D X/S*.D
+ do
+ echo dirty >"$d/C2.t" || return 1
+ done &&
+
+ for ref in A B C
+ do
+ # Not different with SHA-1 and SHA-256, just (ab)using
+ # test_oid_cache as a variable bag to avoid using
+ # $(git rev-parse ...).
+ oid=$(git rev-parse $ref) &&
+ test_oid_cache <<-EOF || return 1
+ $ref sha1:$oid
+ $ref sha256:$oid
+ EOF
+ done
+'
+
+for opts in "" "status"
+do
+ test_expect_success "git submodule $opts" '
+ sed -e "s/^>//" >expect <<-EOF &&
+ > $(test_oid B) S (B)
+ >+$(test_oid A) S.C (A)
+ >+$(test_oid A) S.C.D (A)
+ > $(test_oid B) S.D (B)
+ >+$(test_oid C) X (C)
+ EOF
+ git submodule $opts >actual.raw &&
+ normalize_status <actual.raw >actual &&
+ test_cmp expect actual
+ '
+done
+
+for opts in \
+ "status --recursive"
+do
+ test_expect_success "git submodule $opts" '
+ sed -e "s/^>//" >expect <<-EOF &&
+ > $(test_oid B) S (B)
+ >+$(test_oid A) S.C (A)
+ >+$(test_oid A) S.C.D (A)
+ > $(test_oid B) S.D (B)
+ >+$(test_oid C) X (C)
+ > $(test_oid B) X/S (B)
+ >+$(test_oid A) X/S.C (A)
+ >+$(test_oid A) X/S.C.D (A)
+ > $(test_oid B) X/S.D (B)
+ > $(test_oid B) X/X (B)
+ EOF
+ git submodule $opts >actual.raw &&
+ normalize_status <actual.raw >actual &&
+ test_cmp expect actual
+ '
+done
+
+for opts in \
+ "--quiet" \
+ "--quiet status" \
+ "status --quiet"
+do
+ test_expect_success "git submodule $opts" '
+ git submodule $opts >out &&
+ test_must_be_empty out
+ '
+done
+
+for opts in \
+ "--cached" \
+ "--cached status" \
+ "status --cached"
+do
+ test_expect_success "git submodule $opts" '
+ sed -e "s/^>//" >expect <<-EOF &&
+ > $(test_oid B) S (B)
+ >+$(test_oid B) S.C (B)
+ >+$(test_oid B) S.C.D (B)
+ > $(test_oid B) S.D (B)
+ >+$(test_oid B) X (B)
+ EOF
+ git submodule $opts >actual.raw &&
+ normalize_status <actual.raw >actual &&
+ test_cmp expect actual
+ '
+done
+
+for opts in \
+ "--cached --quiet" \
+ "--cached --quiet status" \
+ "--cached status --quiet" \
+ "--quiet status --cached" \
+ "status --cached --quiet"
+do
+ test_expect_success "git submodule $opts" '
+ git submodule $opts >out &&
+ test_must_be_empty out
+ '
+done
+
+for opts in \
+ "status --cached --recursive" \
+ "--cached status --recursive"
+do
+ test_expect_success "git submodule $opts" '
+ sed -e "s/^>//" >expect <<-EOF &&
+ > $(test_oid B) S (B)
+ >+$(test_oid B) S.C (B)
+ >+$(test_oid B) S.C.D (B)
+ > $(test_oid B) S.D (B)
+ >+$(test_oid B) X (B)
+ > $(test_oid B) X/S (B)
+ >+$(test_oid B) X/S.C (B)
+ >+$(test_oid B) X/S.C.D (B)
+ > $(test_oid B) X/S.D (B)
+ > $(test_oid B) X/X (B)
+ EOF
+ git submodule $opts >actual.raw &&
+ normalize_status <actual.raw >actual &&
+ test_cmp expect actual
+ '
+done
+
+test_done
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 7c3f6ed994..060e145957 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -105,7 +105,7 @@ verify_mergeheads () {
test_write_lines "$@" >mergehead.expected &&
while read sha1 rest
do
- git rev-parse $sha1
+ git rev-parse $sha1 || return 1
done <.git/MERGE_HEAD >mergehead.actual &&
test_cmp mergehead.expected mergehead.actual
}
diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh
index 8cc64729ad..7b957022f1 100755
--- a/t/t7610-mergetool.sh
+++ b/t/t7610-mergetool.sh
@@ -33,7 +33,7 @@ test_expect_success 'setup' '
git add foo &&
git commit -m "Add foo"
) &&
- git submodule add git://example.com/submod submod &&
+ git submodule add file:///dev/null submod &&
git add file1 "spaced name" file1[1-4] subdir/file3 .gitmodules submod &&
git commit -m "add initial versions" &&
@@ -614,7 +614,7 @@ test_expect_success 'submodule in subdirectory' '
)
) &&
test_when_finished "rm -rf subdir/subdir_module" &&
- git submodule add git://example.com/subsubmodule subdir/subdir_module &&
+ git submodule add file:///dev/null subdir/subdir_module &&
git add subdir/subdir_module &&
git commit -m "add submodule in subdirectory" &&
diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh
index 5be483bf88..4aabe98139 100755
--- a/t/t7700-repack.sh
+++ b/t/t7700-repack.sh
@@ -90,6 +90,22 @@ test_expect_success 'loose objects in alternate ODB are not repacked' '
test_has_duplicate_object false
'
+test_expect_success SYMLINKS '--local keeps packs when alternate is objectdir ' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ test_commit -C repo A &&
+ (
+ cd repo &&
+ git repack -a &&
+ ls .git/objects/pack/*.pack >../expect &&
+ ln -s objects .git/alt_objects &&
+ echo "$(pwd)/.git/alt_objects" >.git/objects/info/alternates &&
+ git repack -a -d -l &&
+ ls .git/objects/pack/*.pack >../actual
+ ) &&
+ test_cmp expect actual
+'
+
test_expect_success 'packed obs in alt ODB are repacked even when local repo is packless' '
mkdir alt_objects/pack &&
mv .git/objects/pack/* alt_objects/pack &&
@@ -543,4 +559,125 @@ test_expect_success '-n overrides repack.updateServerInfo=true' '
test_server_info_missing
'
+test_expect_success '--expire-to stores pruned objects (now)' '
+ git init expire-to-now &&
+ (
+ cd expire-to-now &&
+
+ git branch -M main &&
+
+ test_commit base &&
+
+ git checkout -b cruft &&
+ test_commit --no-tag cruft &&
+
+ git rev-list --objects --no-object-names main..cruft >moved.raw &&
+ sort moved.raw >moved.want &&
+
+ git rev-list --all --objects --no-object-names >expect.raw &&
+ sort expect.raw >expect &&
+
+ git checkout main &&
+ git branch -D cruft &&
+ git reflog expire --all --expire=all &&
+
+ git init --bare expired.git &&
+ git repack -d \
+ --cruft --cruft-expiration="now" \
+ --expire-to="expired.git/objects/pack/pack" &&
+
+ expired="$(ls expired.git/objects/pack/pack-*.idx)" &&
+ test_path_is_file "${expired%.idx}.mtimes" &&
+
+ # Since the `--cruft-expiration` is "now", the effective
+ # behavior is to move _all_ unreachable objects out to
+ # the location in `--expire-to`.
+ git show-index <$expired >expired.raw &&
+ cut -d" " -f2 expired.raw | sort >expired.objects &&
+ git rev-list --all --objects --no-object-names \
+ >remaining.objects &&
+
+ # ...in other words, the combined contents of this
+ # repository and expired.git should be the same as the
+ # set of objects we started with.
+ cat expired.objects remaining.objects | sort >actual &&
+ test_cmp expect actual &&
+
+ # The "moved" objects (i.e., those in expired.git)
+ # should be the same as the cruft objects which were
+ # expired in the previous step.
+ test_cmp moved.want expired.objects
+ )
+'
+
+test_expect_success '--expire-to stores pruned objects (5.minutes.ago)' '
+ git init expire-to-5.minutes.ago &&
+ (
+ cd expire-to-5.minutes.ago &&
+
+ git branch -M main &&
+
+ test_commit base &&
+
+ # Create two classes of unreachable objects, one which
+ # is older than 5 minutes (stale), and another which is
+ # newer (recent).
+ for kind in stale recent
+ do
+ git checkout -b $kind main &&
+ test_commit --no-tag $kind || return 1
+ done &&
+
+ git rev-list --objects --no-object-names main..stale >in &&
+ stale="$(git pack-objects $objdir/pack/pack <in)" &&
+ mtime="$(test-tool chmtime --get =-600 $objdir/pack/pack-$stale.pack)" &&
+
+ # expect holds the set of objects we expect to find in
+ # this repository after repacking
+ git rev-list --objects --no-object-names recent >expect.raw &&
+ sort expect.raw >expect &&
+
+ # moved.want holds the set of objects we expect to find
+ # in expired.git
+ git rev-list --objects --no-object-names main..stale >out &&
+ sort out >moved.want &&
+
+ git checkout main &&
+ git branch -D stale recent &&
+ git reflog expire --all --expire=all &&
+ git prune-packed &&
+
+ git init --bare expired.git &&
+ git repack -d \
+ --cruft --cruft-expiration=5.minutes.ago \
+ --expire-to="expired.git/objects/pack/pack" &&
+
+ # Some of the remaining objects in this repository are
+ # unreachable, so use `cat-file --batch-all-objects`
+ # instead of `rev-list` to get their names
+ git cat-file --batch-all-objects --batch-check="%(objectname)" \
+ >remaining.objects &&
+ sort remaining.objects >actual &&
+ test_cmp expect actual &&
+
+ (
+ cd expired.git &&
+
+ expired="$(ls objects/pack/pack-*.mtimes)" &&
+ test-tool pack-mtimes $(basename $expired) >out &&
+ cut -d" " -f1 out | sort >../moved.got &&
+
+ # Ensure that there are as many objects with the
+ # expected mtime as were moved to expired.git.
+ #
+ # In other words, ensure that the recorded
+ # mtimes of any moved objects was written
+ # correctly.
+ grep " $mtime$" out >matching &&
+ test_line_count = $(wc -l <../moved.want) matching
+ ) &&
+ test_cmp moved.want moved.got
+ )
+'
+
test_done
diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh
index 96bdd42045..823331e44a 100755
--- a/t/t7900-maintenance.sh
+++ b/t/t7900-maintenance.sh
@@ -500,9 +500,28 @@ test_expect_success 'register and unregister' '
git config --global --get-all maintenance.repo >actual &&
test_cmp before actual &&
+ git config --file ./other --add maintenance.repo /existing1 &&
+ git config --file ./other --add maintenance.repo /existing2 &&
+ git config --file ./other --get-all maintenance.repo >before &&
+
+ git maintenance register --config-file ./other &&
+ test_cmp_config false maintenance.auto &&
+ git config --file ./other --get-all maintenance.repo >between &&
+ cp before expect &&
+ pwd >>expect &&
+ test_cmp expect between &&
+
+ git maintenance unregister --config-file ./other &&
+ git config --file ./other --get-all maintenance.repo >actual &&
+ test_cmp before actual &&
+
test_must_fail git maintenance unregister 2>err &&
grep "is not registered" err &&
- git maintenance unregister --force
+ git maintenance unregister --force &&
+
+ test_must_fail git maintenance unregister --config-file ./other 2>err &&
+ grep "is not registered" err &&
+ git maintenance unregister --config-file ./other --force
'
test_expect_success !MINGW 'register and unregister with regex metacharacters' '
diff --git a/t/t9210-scalar.sh b/t/t9210-scalar.sh
index be51a8bb7a..25f500cf68 100755
--- a/t/t9210-scalar.sh
+++ b/t/t9210-scalar.sh
@@ -166,6 +166,20 @@ test_expect_success 'scalar reconfigure' '
test true = "$(git -C one/src config core.preloadIndex)"
'
+test_expect_success '`reconfigure -a` removes stale config entries' '
+ git init stale/src &&
+ scalar register stale &&
+ scalar list >scalar.repos &&
+ grep stale scalar.repos &&
+
+ grep -v stale scalar.repos >expect &&
+
+ rm -rf stale &&
+ scalar reconfigure -a &&
+ scalar list >scalar.repos &&
+ test_cmp expect scalar.repos
+'
+
test_expect_success 'scalar delete without enlistment shows a usage' '
test_expect_code 129 scalar delete
'