diff options
Diffstat (limited to 't')
554 files changed, 19012 insertions, 4902 deletions
diff --git a/t/.gitattributes b/t/.gitattributes index 9930e28351..b9cea1795d 100644 --- a/t/.gitattributes +++ b/t/.gitattributes @@ -22,3 +22,4 @@ t[0-9][0-9][0-9][0-9]/* -whitespace /t7500/* eol=lf /t8005/*.txt eol=lf /t9*/*.dump eol=lf +/t0040*.sh whitespace=-indent-with-non-tab diff --git a/t/Makefile b/t/Makefile index 882782a519..3e00cdd801 100644 --- a/t/Makefile +++ b/t/Makefile @@ -44,8 +44,8 @@ CHAINLINT = '$(PERL_PATH_SQ)' chainlint.pl # `test-chainlint` (which is a dependency of `test-lint`, `test` and `prove`) # checks all tests in all scripts via a single invocation, so tell individual -# scripts not to "chainlint" themselves -CHAINLINTSUPPRESS = GIT_TEST_CHAIN_LINT=0 && export GIT_TEST_CHAIN_LINT && +# scripts not to run the external "chainlint.pl" script themselves +CHAINLINTSUPPRESS = GIT_TEST_EXT_CHAIN_LINT=0 && export GIT_TEST_EXT_CHAIN_LINT && all: $(DEFAULT_TEST_TARGET) @@ -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 && \ @@ -140,9 +140,7 @@ aggregate-results-and-cleanup: $(T) $(MAKE) clean aggregate-results: - for f in '$(TEST_RESULTS_DIRECTORY_SQ)'/t*-*.counts; do \ - echo "$$f"; \ - done | '$(SHELL_PATH_SQ)' ./aggregate-results.sh + @'$(SHELL_PATH_SQ)' ./aggregate-results.sh '$(TEST_RESULTS_DIRECTORY_SQ)' valgrind: $(MAKE) GIT_TEST_OPTS="$(GIT_TEST_OPTS) --valgrind" @@ -442,6 +442,10 @@ GIT_TEST_INDEX_VERSION=<n> exercises the index read/write code path for the index version specified. Can be set to any valid version (currently 2, 3, or 4). +GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL=<boolean> if enabled will +use the boundary-based bitmap traversal algorithm. See the documentation +of `pack.useBitmapBoundaryTraversal` for more details. + GIT_TEST_PACK_SPARSE=<boolean> if disabled will default the pack-objects builtin to use the non-sparse object walk. This can still be overridden by the --sparse command-line argument. @@ -449,10 +453,6 @@ the --sparse command-line argument. GIT_TEST_PRELOAD_INDEX=<boolean> exercises the preload-index code path by overriding the minimum number of cache entries required per thread. -GIT_TEST_ADD_I_USE_BUILTIN=<boolean>, when false, disables the -built-in version of git add -i. See 'add.interactive.useBuiltin' in -git-config(1). - GIT_TEST_INDEX_THREADS=<n> enables exercising the multi-threaded loading of the index for the whole test suite by bypassing the default number of cache entries and thread minimums. Setting this to 1 will make the @@ -479,7 +479,7 @@ GIT_TEST_DEFAULT_HASH=<hash-algo> specifies which hash algorithm to use in the test scripts. Recognized values for <hash-algo> are "sha1" and "sha256". -GIT_TEST_WRITE_REV_INDEX=<boolean>, when true enables the +GIT_TEST_NO_WRITE_REV_INDEX=<boolean>, when true disables the 'pack.writeReverseIndex' setting. GIT_TEST_SPARSE_INDEX=<boolean>, when true enables index writes to use the @@ -1102,6 +1102,12 @@ see test-lib-functions.sh for the full list and their options. the symbolic link in the file system and a part that does; then only the latter part need be protected by a SYMLINKS prerequisite (see below). + - test_path_is_executable + + This tests whether a file is executable and prints an error message + if not. This must be used only under the POSIXPERM prerequisite + (see below). + - test_oid_init This function loads facts and useful object IDs related to the hash diff --git a/t/aggregate-results.sh b/t/aggregate-results.sh index 7f2b83bdc8..6e3bcc4aec 100755 --- a/t/aggregate-results.sh +++ b/t/aggregate-results.sh @@ -8,7 +8,7 @@ broken=0 total=0 missing_prereq= -while read file +for file in "$1"/t*-*.counts do while read type value do diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index f1b9a6ce4d..5e21e84f38 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -72,6 +72,32 @@ test_expect_success 'blame 1 author' ' check_count A 2 ' +test_expect_success 'blame working copy' ' + test_when_finished "git restore file" && + echo "1A quick brown fox jumps over the" >file && + echo "another lazy dog" >>file && + check_count A 1 "Not Committed Yet" 1 +' + +test_expect_success 'blame with --contents' ' + check_count --contents=file A 2 +' + +test_expect_success 'blame with --contents in a bare repo' ' + git clone --bare . bare-contents.git && + ( + cd bare-contents.git && + echo "1A quick brown fox jumps over the" >contents && + check_count --contents=contents A 1 + ) +' + +test_expect_success 'blame with --contents changed' ' + echo "1A quick brown fox jumps over the" >contents && + echo "another lazy dog" >>contents && + check_count --contents=contents A 1 "External file (--contents)" 1 +' + test_expect_success 'blame in a bare repo without starting commit' ' git clone --bare . bare.git && ( @@ -98,6 +124,10 @@ test_expect_success 'blame 2 authors' ' check_count A 2 B 2 ' +test_expect_success 'blame with --contents and revision' ' + check_count -h testTag --contents=file A 2 "External file (--contents)" 2 +' + test_expect_success 'setup B1 lines (branch1)' ' git checkout -b branch1 main && echo "3A slow green fox jumps into the" >>file && diff --git a/t/chainlint.pl b/t/chainlint.pl index 976db4b8a0..556ee91a15 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,9 +76,12 @@ 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"); + $$token[0] = $indented ? "\t$tag" : "$tag"; + push(@{$self->{heretags}}, $token); return "<<$indented$tag"; } @@ -95,7 +99,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 +119,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 +127,7 @@ sub scan_dqstring { } die("internal error scanning dq-string '$c'\n"); } + $self->{lineno} += () = $s =~ /\n/sg; return $s; } @@ -135,6 +142,7 @@ sub scan_balanced { $depth--; last if $depth == 0; } + $self->{lineno} += () = $s =~ /\n/sg; return $s; } @@ -149,7 +157,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 +169,19 @@ sub swallow_heredocs { my $b = $self->{buff}; my $tags = $self->{heretags}; while (my $tag = shift @$tags) { - my $indent = $tag =~ s/^\t// ? '\\s*' : ''; - $$b =~ /(?:\G|\n)$indent\Q$tag\E(?:\n|\z)/gc; + my $start = pos($$b); + my $indent = $$tag[0] =~ s/^\t// ? '\\s*' : ''; + $$b =~ /(?:\G|\n)$indent\Q$$tag[0]\E(?:\n|\z)/gc; + if (pos($$b) > $start) { + my $body = substr($$b, $start, pos($$b) - $start); + $self->{lineno} += () = $body =~ /\n/sg; + next; + } + push(@{$self->{parser}->{problems}}, ['UNCLOSED-HEREDOC', $tag]); + $$b =~ /(?:\G|\n).*\z/gc; # consume rest of input + my $body = substr($$b, $start, pos($$b) - $start); + $self->{lineno} += () = $body =~ /\n/sg; + last; } } @@ -170,34 +189,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 +261,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 +277,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 +300,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 +315,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 +337,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 +361,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 +402,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 +420,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 +477,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 +498,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 +517,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 +536,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 +550,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 +589,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 +620,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 +646,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 +670,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 +718,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/unclosed-here-doc-indent.expect b/t/chainlint/unclosed-here-doc-indent.expect new file mode 100644 index 0000000000..7c30a1a024 --- /dev/null +++ b/t/chainlint/unclosed-here-doc-indent.expect @@ -0,0 +1,4 @@ +command_which_is_run && +cat >expect <<-\EOF ?!UNCLOSED-HEREDOC?! && +we forget to end the here-doc +command_which_is_gobbled diff --git a/t/chainlint/unclosed-here-doc-indent.test b/t/chainlint/unclosed-here-doc-indent.test new file mode 100644 index 0000000000..5c841a9dfd --- /dev/null +++ b/t/chainlint/unclosed-here-doc-indent.test @@ -0,0 +1,4 @@ +command_which_is_run && +cat >expect <<-\EOF && +we forget to end the here-doc +command_which_is_gobbled diff --git a/t/chainlint/unclosed-here-doc.expect b/t/chainlint/unclosed-here-doc.expect new file mode 100644 index 0000000000..d65e50f78d --- /dev/null +++ b/t/chainlint/unclosed-here-doc.expect @@ -0,0 +1,7 @@ +command_which_is_run && +cat >expect <<\EOF ?!UNCLOSED-HEREDOC?! && + we try to end the here-doc below, + but the indentation throws us off + since the operator is not "<<-". + EOF +command_which_is_gobbled diff --git a/t/chainlint/unclosed-here-doc.test b/t/chainlint/unclosed-here-doc.test new file mode 100644 index 0000000000..69d3786c34 --- /dev/null +++ b/t/chainlint/unclosed-here-doc.test @@ -0,0 +1,7 @@ +command_which_is_run && +cat >expect <<\EOF && + we try to end the here-doc below, + but the indentation throws us off + since the operator is not "<<-". + EOF +command_which_is_gobbled 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/check-non-portable-shell.pl b/t/check-non-portable-shell.pl index fd3303552b..dd8107cd7d 100755 --- a/t/check-non-portable-shell.pl +++ b/t/check-non-portable-shell.pl @@ -45,6 +45,7 @@ while (<>) { /\bhead\s+-c\b/ and err 'head -c is not portable (use test_copy_bytes BYTES <file >out)'; /(?:\$\(seq|^\s*seq\b)/ and err 'seq is not portable (use test_seq)'; /\bgrep\b.*--file\b/ and err 'grep --file FILE is not portable (use grep -f FILE)'; + /\b[ef]grep\b/ and err 'egrep/fgrep obsolescent (use grep -E/-F)'; /\bexport\s+[A-Za-z0-9_]*=/ and err '"export FOO=bar" is not portable (use FOO=bar && export FOO)'; /^\s*([A-Z0-9_]+=(\w*|(["']).*?\3)\s+)+(\w+)/ and exists($func{$4}) and err '"FOO=bar shell_func" assignment extends beyond "shell_func"'; diff --git a/t/helper/test-advise.c b/t/helper/test-advise.c index cb881139f7..8a3fd0009a 100644 --- a/t/helper/test-advise.c +++ b/t/helper/test-advise.c @@ -1,7 +1,7 @@ #include "test-tool.h" -#include "cache.h" #include "advice.h" #include "config.h" +#include "setup.h" int cmd__advise_if_enabled(int argc, const char **argv) { diff --git a/t/helper/test-bitmap.c b/t/helper/test-bitmap.c index ff35f5999b..af43ee1cb5 100644 --- a/t/helper/test-bitmap.c +++ b/t/helper/test-bitmap.c @@ -1,6 +1,7 @@ #include "test-tool.h" -#include "cache.h" +#include "git-compat-util.h" #include "pack-bitmap.h" +#include "setup.h" static int bitmap_list_commits(void) { diff --git a/t/helper/test-bloom.c b/t/helper/test-bloom.c index 6c900ca668..aabe31d724 100644 --- a/t/helper/test-bloom.c +++ b/t/helper/test-bloom.c @@ -1,7 +1,9 @@ -#include "git-compat-util.h" -#include "bloom.h" #include "test-tool.h" +#include "bloom.h" +#include "hex.h" #include "commit.h" +#include "repository.h" +#include "setup.h" static struct bloom_filter_settings settings = DEFAULT_BLOOM_FILTER_SETTINGS; diff --git a/t/helper/test-bundle-uri.c b/t/helper/test-bundle-uri.c new file mode 100644 index 0000000000..475058592d --- /dev/null +++ b/t/helper/test-bundle-uri.c @@ -0,0 +1,137 @@ +#include "test-tool.h" +#include "parse-options.h" +#include "bundle-uri.h" +#include "gettext.h" +#include "strbuf.h" +#include "string-list.h" +#include "transport.h" +#include "ref-filter.h" +#include "remote.h" +#include "refs.h" + +enum input_mode { + KEY_VALUE_PAIRS, + CONFIG_FILE, +}; + +static int cmd__bundle_uri_parse(int argc, const char **argv, enum input_mode mode) +{ + const char *key_value_usage[] = { + "test-tool bundle-uri parse-key-values <input>", + NULL + }; + const char *config_usage[] = { + "test-tool bundle-uri parse-config <input>", + NULL + }; + const char **usage = key_value_usage; + struct option options[] = { + OPT_END(), + }; + struct strbuf sb = STRBUF_INIT; + struct bundle_list list; + int err = 0; + FILE *fp; + + if (mode == CONFIG_FILE) + usage = config_usage; + + argc = parse_options(argc, argv, NULL, options, usage, + PARSE_OPT_STOP_AT_NON_OPTION); + + init_bundle_list(&list); + + list.baseURI = xstrdup("<uri>"); + + switch (mode) { + case KEY_VALUE_PAIRS: + if (argc != 1) + goto usage; + fp = fopen(argv[0], "r"); + if (!fp) + die("failed to open '%s'", argv[0]); + while (strbuf_getline(&sb, fp) != EOF) { + if (bundle_uri_parse_line(&list, sb.buf)) + err = error("bad line: '%s'", sb.buf); + } + fclose(fp); + break; + + case CONFIG_FILE: + if (argc != 1) + goto usage; + err = bundle_uri_parse_config_format("<uri>", argv[0], &list); + break; + } + strbuf_release(&sb); + + print_bundle_list(stdout, &list); + + clear_bundle_list(&list); + + return !!err; + +usage: + usage_with_options(usage, options); +} + +static int cmd_ls_remote(int argc, const char **argv) +{ + const char *dest; + struct remote *remote; + struct transport *transport; + int status = 0; + + dest = argc > 1 ? argv[1] : NULL; + + remote = remote_get(dest); + if (!remote) { + if (dest) + die(_("bad repository '%s'"), dest); + die(_("no remote configured to get bundle URIs from")); + } + if (!remote->url_nr) + die(_("remote '%s' has no configured URL"), dest); + + transport = transport_get(remote, NULL); + if (transport_get_remote_bundle_uri(transport) < 0) { + error(_("could not get the bundle-uri list")); + status = 1; + goto cleanup; + } + + print_bundle_list(stdout, transport->bundles); + +cleanup: + if (transport_disconnect(transport)) + return 1; + return status; +} + +int cmd__bundle_uri(int argc, const char **argv) +{ + const char *usage[] = { + "test-tool bundle-uri <subcommand> [<options>]", + NULL + }; + struct option options[] = { + OPT_END(), + }; + + argc = parse_options(argc, argv, NULL, options, usage, + PARSE_OPT_STOP_AT_NON_OPTION | + PARSE_OPT_KEEP_ARGV0); + if (argc == 1) + goto usage; + + if (!strcmp(argv[1], "parse-key-values")) + return cmd__bundle_uri_parse(argc - 1, argv + 1, KEY_VALUE_PAIRS); + if (!strcmp(argv[1], "parse-config")) + return cmd__bundle_uri_parse(argc - 1, argv + 1, CONFIG_FILE); + if (!strcmp(argv[1], "ls-remote")) + return cmd_ls_remote(argc - 1, argv + 1); + error("there is no test-tool bundle-uri tool '%s'", argv[1]); + +usage: + usage_with_options(usage, options); +} diff --git a/t/helper/test-cache-tree.c b/t/helper/test-cache-tree.c new file mode 100644 index 0000000000..e7236392c8 --- /dev/null +++ b/t/helper/test-cache-tree.c @@ -0,0 +1,69 @@ +#define USE_THE_INDEX_VARIABLE +#include "test-tool.h" +#include "gettext.h" +#include "hex.h" +#include "tree.h" +#include "cache-tree.h" +#include "parse-options.h" +#include "read-cache-ll.h" +#include "repository.h" +#include "setup.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-chmtime.c b/t/helper/test-chmtime.c index dc28890a18..0e5538833a 100644 --- a/t/helper/test-chmtime.c +++ b/t/helper/test-chmtime.c @@ -94,7 +94,7 @@ int cmd__chmtime(int argc, const char **argv) if (timespec_arg(argv[i], &set_time, &set_eq)) { ++i; } else { - if (get == 0) { + if (get == 0 && verbose == 0) { fprintf(stderr, "Not a base-10 integer: %s\n", argv[i] + 1); goto usage; } diff --git a/t/helper/test-config.c b/t/helper/test-config.c index 4ba9eb6560..ed444ca4c2 100644 --- a/t/helper/test-config.c +++ b/t/helper/test-config.c @@ -1,6 +1,6 @@ #include "test-tool.h" -#include "cache.h" #include "config.h" +#include "setup.h" #include "string-list.h" /* @@ -14,6 +14,8 @@ * get_value_multi -> prints all values for the entered key in increasing order * of priority * + * get -> print return value for the entered key + * * get_int -> print integer value for the entered key or die * * get_bool -> print bool value for the entered key or die @@ -30,6 +32,9 @@ * iterate -> iterate over all values using git_config(), and print some * data for each * + * git_config_int -> iterate over all values using git_config() and print the + * integer value for the entered key or die + * * Examples: * * To print the value with highest priority for key "foo.bAr Baz.rock": @@ -37,8 +42,11 @@ * */ -static int iterate_cb(const char *var, const char *value, void *data UNUSED) +static int iterate_cb(const char *var, const char *value, + const struct config_context *ctx, + void *data UNUSED) { + const struct key_value_info *kvi = ctx->kvi; static int nr; if (nr++) @@ -46,15 +54,29 @@ static int iterate_cb(const char *var, const char *value, void *data UNUSED) printf("key=%s\n", var); printf("value=%s\n", value ? value : "(null)"); - printf("origin=%s\n", current_config_origin_type()); - printf("name=%s\n", current_config_name()); - printf("lno=%d\n", current_config_line()); - printf("scope=%s\n", config_scope_name(current_config_scope())); + printf("origin=%s\n", config_origin_type_name(kvi->origin_type)); + printf("name=%s\n", kvi->filename ? kvi->filename : ""); + printf("lno=%d\n", kvi->linenr); + printf("scope=%s\n", config_scope_name(kvi->scope)); return 0; } -static int early_config_cb(const char *var, const char *value, void *vdata) +static int parse_int_cb(const char *var, const char *value, + const struct config_context *ctx, void *data) +{ + const char *key_to_match = data; + + if (!strcmp(key_to_match, var)) { + int parsed = git_config_int(value, value, ctx->kvi); + printf("%d\n", parsed); + } + return 0; +} + +static int early_config_cb(const char *var, const char *value, + const struct config_context *ctx UNUSED, + void *vdata) { const char *key = vdata; @@ -95,8 +117,7 @@ int cmd__config(int argc, const char **argv) goto exit1; } } else if (argc == 3 && !strcmp(argv[1], "get_value_multi")) { - strptr = git_config_get_value_multi(argv[2]); - if (strptr) { + if (!git_config_get_value_multi(argv[2], &strptr)) { for (i = 0; i < strptr->nr; i++) { v = strptr->items[i].string; if (!v) @@ -109,6 +130,26 @@ int cmd__config(int argc, const char **argv) printf("Value not found for \"%s\"\n", argv[2]); goto exit1; } + } else if (argc == 3 && !strcmp(argv[1], "get")) { + int ret; + + if (!(ret = git_config_get(argv[2]))) + goto exit0; + else if (ret == 1) + printf("Value not found for \"%s\"\n", argv[2]); + else if (ret == -CONFIG_INVALID_KEY) + printf("Key \"%s\" is invalid\n", argv[2]); + else if (ret == -CONFIG_NO_SECTION_OR_NAME) + printf("Key \"%s\" has no section\n", argv[2]); + else + /* + * A normal caller should just check "ret < + * 0", but for our own tests let's BUG() if + * our whitelist of git_config_parse_key() + * return values isn't exhaustive. + */ + BUG("Key \"%s\" has unknown return %d", argv[2], ret); + goto exit1; } else if (argc == 3 && !strcmp(argv[1], "get_int")) { if (!git_config_get_int(argv[2], &val)) { printf("%d\n", val); @@ -141,7 +182,7 @@ int cmd__config(int argc, const char **argv) goto exit2; } } - if (!git_configset_get_value(&cs, argv[2], &v)) { + if (!git_configset_get_value(&cs, argv[2], &v, NULL)) { if (!v) printf("(NULL)\n"); else @@ -159,8 +200,7 @@ int cmd__config(int argc, const char **argv) goto exit2; } } - strptr = git_configset_get_value_multi(&cs, argv[2]); - if (strptr) { + if (!git_configset_get_value_multi(&cs, argv[2], &strptr)) { for (i = 0; i < strptr->nr; i++) { v = strptr->items[i].string; if (!v) @@ -176,6 +216,9 @@ int cmd__config(int argc, const char **argv) } else if (!strcmp(argv[1], "iterate")) { git_config(iterate_cb, NULL); goto exit0; + } else if (argc == 3 && !strcmp(argv[1], "git_config_int")) { + git_config(parse_int_cb, (void *) argv[2]); + goto exit0; } die("%s: Please check the syntax and the function name", argv[0]); diff --git a/t/helper/test-crontab.c b/t/helper/test-crontab.c index e6c1b1e22b..597027a96e 100644 --- a/t/helper/test-crontab.c +++ b/t/helper/test-crontab.c @@ -1,5 +1,4 @@ #include "test-tool.h" -#include "cache.h" /* * Usage: test-tool crontab <file> -l|<input> diff --git a/t/helper/test-ctype.c b/t/helper/test-ctype.c index 92c4c2313e..e5659df40b 100644 --- a/t/helper/test-ctype.c +++ b/t/helper/test-ctype.c @@ -1,5 +1,4 @@ #include "test-tool.h" -#include "cache.h" static int rc; @@ -11,9 +10,14 @@ static void report_error(const char *class, int ch) static int is_in(const char *s, int ch) { - /* We can't find NUL using strchr. It's classless anyway. */ + /* + * We can't find NUL using strchr. Accept it as the first + * character in the spec -- there are no empty classes. + */ if (ch == '\0') - return 0; + return ch == *s; + if (*s == '\0') + s++; return !!strchr(s, ch); } @@ -23,13 +27,29 @@ static int is_in(const char *s, int ch) if (is_in(s, i) != t(i)) \ report_error(#t, i); \ } \ + if (t(EOF)) \ + report_error(#t, EOF); \ } #define DIGIT "0123456789" #define LOWER "abcdefghijklmnopqrstuvwxyz" #define UPPER "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define PUNCT "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" +#define ASCII \ + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \ + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \ + "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" \ + "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" \ + "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" \ + "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" \ + "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" \ + "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" +#define CNTRL \ + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \ + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \ + "\x7f" -int cmd__ctype(int argc, const char **argv) +int cmd__ctype(int argc UNUSED, const char **argv UNUSED) { TEST_CLASS(isdigit, DIGIT); TEST_CLASS(isspace, " \n\r\t"); @@ -38,6 +58,13 @@ int cmd__ctype(int argc, const char **argv) TEST_CLASS(is_glob_special, "*?[\\"); TEST_CLASS(is_regex_special, "$()*+.?[\\^{|"); TEST_CLASS(is_pathspec_magic, "!\"#%&',-/:;<=>@_`~"); + TEST_CLASS(isascii, ASCII); + TEST_CLASS(islower, LOWER); + TEST_CLASS(isupper, UPPER); + TEST_CLASS(iscntrl, CNTRL); + TEST_CLASS(ispunct, PUNCT); + TEST_CLASS(isxdigit, DIGIT "abcdefABCDEF"); + TEST_CLASS(isprint, LOWER UPPER DIGIT PUNCT " "); return rc; } diff --git a/t/helper/test-date.c b/t/helper/test-date.c index 45951b1df8..0683d46574 100644 --- a/t/helper/test-date.c +++ b/t/helper/test-date.c @@ -1,6 +1,6 @@ #include "test-tool.h" -#include "cache.h" #include "date.h" +#include "trace.h" static const char *usage_msg = "\n" " test-tool date relative [time_t]...\n" @@ -81,7 +81,7 @@ static void parse_approxidate(const char **argv) { for (; *argv; argv++) { timestamp_t t; - t = approxidate_relative(*argv); + t = approxidate(*argv); printf("%s -> %s\n", *argv, show_date(t, 0, DATE_MODE(ISO8601))); } } @@ -90,7 +90,7 @@ static void parse_approx_timestamp(const char **argv) { for (; *argv; argv++) { timestamp_t t; - t = approxidate_relative(*argv); + t = approxidate(*argv); printf("%s -> %"PRItime"\n", *argv, t); } } @@ -104,7 +104,7 @@ static void getnanos(const char **argv) printf("%lf\n", seconds); } -int cmd__date(int argc, const char **argv) +int cmd__date(int argc UNUSED, const char **argv) { const char *x; diff --git a/t/helper/test-delta.c b/t/helper/test-delta.c index b15481ea59..6bc787a474 100644 --- a/t/helper/test-delta.c +++ b/t/helper/test-delta.c @@ -11,7 +11,6 @@ #include "test-tool.h" #include "git-compat-util.h" #include "delta.h" -#include "cache.h" static const char usage_str[] = "test-tool delta (-d|-p) <from_file> <data_file> <out_file>"; diff --git a/t/helper/test-dir-iterator.c b/t/helper/test-dir-iterator.c index 659b6bfa81..6b297bd753 100644 --- a/t/helper/test-dir-iterator.c +++ b/t/helper/test-dir-iterator.c @@ -15,7 +15,7 @@ static const char *error_name(int error_number) /* * usage: - * tool-test dir-iterator [--follow-symlinks] [--pedantic] directory_path + * tool-test dir-iterator [--pedantic] directory_path */ int cmd__dir_iterator(int argc, const char **argv) { @@ -24,9 +24,7 @@ int cmd__dir_iterator(int argc, const char **argv) int iter_status; for (++argv, --argc; *argv && starts_with(*argv, "--"); ++argv, --argc) { - if (strcmp(*argv, "--follow-symlinks") == 0) - flags |= DIR_ITERATOR_FOLLOW_SYMLINKS; - else if (strcmp(*argv, "--pedantic") == 0) + if (strcmp(*argv, "--pedantic") == 0) flags |= DIR_ITERATOR_PEDANTIC; else die("invalid option '%s'", *argv); diff --git a/t/helper/test-drop-caches.c b/t/helper/test-drop-caches.c index e37396dd9c..73e551cfc2 100644 --- a/t/helper/test-drop-caches.c +++ b/t/helper/test-drop-caches.c @@ -155,7 +155,7 @@ static int cmd_dropcaches(void) #endif -int cmd__drop_caches(int argc, const char **argv) +int cmd__drop_caches(int argc UNUSED, const char **argv UNUSED) { cmd_sync(); return cmd_dropcaches(); diff --git a/t/helper/test-dump-cache-tree.c b/t/helper/test-dump-cache-tree.c index 0d6d7f1ecb..c38f546e4f 100644 --- a/t/helper/test-dump-cache-tree.c +++ b/t/helper/test-dump-cache-tree.c @@ -1,8 +1,12 @@ +#define USE_THE_INDEX_VARIABLE #include "test-tool.h" -#include "cache.h" +#include "hash.h" +#include "hex.h" #include "tree.h" #include "cache-tree.h" - +#include "read-cache-ll.h" +#include "repository.h" +#include "setup.h" static void dump_one(struct cache_tree *it, const char *pfx, const char *x) { @@ -55,19 +59,19 @@ static int dump_cache_tree(struct cache_tree *it, return errs; } -int cmd__dump_cache_tree(int ac, const char **av) +int cmd__dump_cache_tree(int ac UNUSED, const char **av UNUSED) { struct index_state istate; struct cache_tree *another = cache_tree(); 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-fsmonitor.c b/t/helper/test-dump-fsmonitor.c index 975f0ac890..4f215fea02 100644 --- a/t/helper/test-dump-fsmonitor.c +++ b/t/helper/test-dump-fsmonitor.c @@ -1,7 +1,9 @@ #include "test-tool.h" -#include "cache.h" +#include "read-cache-ll.h" +#include "repository.h" +#include "setup.h" -int cmd__dump_fsmonitor(int ac, const char **av) +int cmd__dump_fsmonitor(int ac UNUSED, const char **av UNUSED) { struct index_state *istate = the_repository->index; int i; diff --git a/t/helper/test-dump-split-index.c b/t/helper/test-dump-split-index.c index a209880eb3..f29d18ef94 100644 --- a/t/helper/test-dump-split-index.c +++ b/t/helper/test-dump-split-index.c @@ -1,14 +1,18 @@ +#define USE_THE_INDEX_VARIABLE #include "test-tool.h" -#include "cache.h" +#include "hex.h" +#include "read-cache-ll.h" +#include "repository.h" +#include "setup.h" #include "split-index.h" #include "ewah/ewok.h" -static void show_bit(size_t pos, void *data) +static void show_bit(size_t pos, void *data UNUSED) { printf(" %d", (int)pos); } -int cmd__dump_split_index(int ac, const char **av) +int cmd__dump_split_index(int ac UNUSED, const char **av) { struct split_index *si; int i; diff --git a/t/helper/test-dump-untracked-cache.c b/t/helper/test-dump-untracked-cache.c index 99010614f6..b4af9712fe 100644 --- a/t/helper/test-dump-untracked-cache.c +++ b/t/helper/test-dump-untracked-cache.c @@ -1,7 +1,10 @@ -#define USE_THE_INDEX_COMPATIBILITY_MACROS +#define USE_THE_INDEX_VARIABLE #include "test-tool.h" -#include "cache.h" #include "dir.h" +#include "hex.h" +#include "read-cache-ll.h" +#include "repository.h" +#include "setup.h" static int compare_untracked(const void *a_, const void *b_) { @@ -40,7 +43,7 @@ static void dump(struct untracked_cache_dir *ucd, struct strbuf *base) strbuf_setlen(base, len); } -int cmd__dump_untracked_cache(int ac, const char **av) +int cmd__dump_untracked_cache(int ac UNUSED, const char **av UNUSED) { struct untracked_cache *uc; struct strbuf base = STRBUF_INIT; @@ -51,7 +54,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-env-helper.c b/t/helper/test-env-helper.c new file mode 100644 index 0000000000..66c88b8ff3 --- /dev/null +++ b/t/helper/test-env-helper.c @@ -0,0 +1,100 @@ +#include "test-tool.h" +#include "config.h" +#include "parse-options.h" + +static char const * const env__helper_usage[] = { + "test-tool env-helper --type=[bool|ulong] <options> <env-var>", + NULL +}; + +enum cmdmode { + ENV_HELPER_TYPE_BOOL = 1, + ENV_HELPER_TYPE_ULONG +}; + +static int option_parse_type(const struct option *opt, const char *arg, + int unset) +{ + enum cmdmode *cmdmode = opt->value; + + BUG_ON_OPT_NEG(unset); + + if (!strcmp(arg, "bool")) + *cmdmode = ENV_HELPER_TYPE_BOOL; + else if (!strcmp(arg, "ulong")) + *cmdmode = ENV_HELPER_TYPE_ULONG; + else + die("unrecognized --type argument, %s", arg); + + return 0; +} + +int cmd__env_helper(int argc, const char **argv) +{ + int exit_code = 0; + const char *env_variable = NULL; + const char *env_default = NULL; + int ret; + int ret_int, default_int; + unsigned long ret_ulong, default_ulong; + enum cmdmode cmdmode = 0; + struct option opts[] = { + OPT_CALLBACK_F(0, "type", &cmdmode, "type", + "value is given this type", PARSE_OPT_NONEG, + option_parse_type), + OPT_STRING(0, "default", &env_default, "value", + "default for git_env_*(...) to fall back on"), + OPT_BOOL(0, "exit-code", &exit_code, + "be quiet only use git_env_*() value as exit code"), + OPT_END(), + }; + + argc = parse_options(argc, argv, NULL, opts, env__helper_usage, + PARSE_OPT_KEEP_UNKNOWN_OPT); + if (env_default && !*env_default) + usage_with_options(env__helper_usage, opts); + if (!cmdmode) + usage_with_options(env__helper_usage, opts); + if (argc != 1) + usage_with_options(env__helper_usage, opts); + env_variable = argv[0]; + + switch (cmdmode) { + case ENV_HELPER_TYPE_BOOL: + if (env_default) { + default_int = git_parse_maybe_bool(env_default); + if (default_int == -1) { + error("option `--default' expects a boolean value with `--type=bool`, not `%s`", + env_default); + usage_with_options(env__helper_usage, opts); + } + } else { + default_int = 0; + } + ret_int = git_env_bool(env_variable, default_int); + if (!exit_code) + puts(ret_int ? "true" : "false"); + ret = ret_int; + break; + case ENV_HELPER_TYPE_ULONG: + if (env_default) { + if (!git_parse_ulong(env_default, &default_ulong)) { + error("option `--default' expects an unsigned long value with `--type=ulong`, not `%s`", + env_default); + usage_with_options(env__helper_usage, opts); + } + } else { + default_ulong = 0; + } + ret_ulong = git_env_ulong(env_variable, default_ulong); + if (!exit_code) + printf("%lu\n", ret_ulong); + ret = ret_ulong; + break; + default: + BUG("unknown <type> value"); + break; + } + + return !ret; +} diff --git a/t/helper/test-example-decorate.c b/t/helper/test-example-decorate.c index b9d1200eb9..2ed910adaa 100644 --- a/t/helper/test-example-decorate.c +++ b/t/helper/test-example-decorate.c @@ -1,9 +1,10 @@ #include "test-tool.h" -#include "cache.h" +#include "git-compat-util.h" #include "object.h" #include "decorate.h" +#include "repository.h" -int cmd__example_decorate(int argc, const char **argv) +int cmd__example_decorate(int argc UNUSED, const char **argv UNUSED) { struct decoration n; struct object_id one_oid = { {1} }; diff --git a/t/helper/test-fake-ssh.c b/t/helper/test-fake-ssh.c index 12beee99ad..27323cb367 100644 --- a/t/helper/test-fake-ssh.c +++ b/t/helper/test-fake-ssh.c @@ -8,7 +8,7 @@ int cmd_main(int argc, const char **argv) struct strbuf buf = STRBUF_INIT; FILE *f; int i; - const char *child_argv[] = { NULL, NULL }; + struct child_process cmd = CHILD_PROCESS_INIT; /* First, print all parameters into $TRASH_DIRECTORY/ssh-output */ if (!trash_directory) @@ -17,6 +17,7 @@ int cmd_main(int argc, const char **argv) f = fopen(buf.buf, "w"); if (!f) die("Could not write to %s", buf.buf); + strbuf_release(&buf); for (i = 0; i < argc; i++) fprintf(f, "%s%s", i > 0 ? " " : "", i > 0 ? argv[i] : "ssh:"); fprintf(f, "\n"); @@ -25,6 +26,7 @@ int cmd_main(int argc, const char **argv) /* Now, evaluate the *last* parameter */ if (argc < 2) return 0; - child_argv[0] = argv[argc - 1]; - return run_command_v_opt(child_argv, RUN_USING_SHELL); + cmd.use_shell = 1; + strvec_push(&cmd.args, argv[argc - 1]); + return run_command(&cmd); } diff --git a/t/helper/test-fast-rebase.c b/t/helper/test-fast-rebase.c index 45665ec19a..cac20a72b3 100644 --- a/t/helper/test-fast-rebase.c +++ b/t/helper/test-fast-rebase.c @@ -10,22 +10,29 @@ * refactoring is the better route). */ -#define USE_THE_INDEX_COMPATIBILITY_MACROS +#define USE_THE_INDEX_VARIABLE #include "test-tool.h" - #include "cache-tree.h" #include "commit.h" +#include "environment.h" +#include "gettext.h" +#include "hash.h" +#include "hex.h" #include "lockfile.h" #include "merge-ort.h" +#include "object-name.h" +#include "read-cache-ll.h" #include "refs.h" #include "revision.h" #include "sequencer.h" +#include "setup.h" #include "strvec.h" #include "tree.h" static const char *short_commit_name(struct commit *commit) { - return find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV); + return repo_find_unique_abbrev(the_repository, &commit->object.oid, + DEFAULT_ABBREV); } static struct commit *peel_committish(const char *name) @@ -33,10 +40,11 @@ static struct commit *peel_committish(const char *name) struct object *obj; struct object_id oid; - if (get_oid(name, &oid)) + if (repo_get_oid(the_repository, name, &oid)) return NULL; obj = parse_object(the_repository, &oid); - return (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT); + return (struct commit *)repo_peel_to_type(the_repository, name, 0, obj, + OBJ_COMMIT); } static char *get_author(const char *message) @@ -63,7 +71,8 @@ static struct commit *create_commit(struct tree *tree, struct commit_extra_header *extra; struct strbuf msg = STRBUF_INIT; const char *out_enc = get_commit_output_encoding(); - const char *message = logmsg_reencode(based_on, NULL, out_enc); + const char *message = repo_logmsg_reencode(the_repository, based_on, + NULL, out_enc); const char *orig_message = NULL; const char *exclude_gpgsig[] = { "gpgsig", NULL }; @@ -119,11 +128,11 @@ int cmd__fast_rebase(int argc, const char **argv) strbuf_addf(&branch_name, "refs/heads/%s", argv[4]); /* Sanity check */ - if (get_oid("HEAD", &head)) + if (repo_get_oid(the_repository, "HEAD", &head)) 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"); @@ -154,7 +163,7 @@ int cmd__fast_rebase(int argc, const char **argv) memset(&result, 0, sizeof(result)); merge_opt.show_rename_progress = 1; merge_opt.branch1 = "HEAD"; - head_tree = get_commit_tree(onto); + head_tree = repo_get_commit_tree(the_repository, onto); result.tree = head_tree; last_commit = onto; while ((commit = get_revision(&revs))) { @@ -165,8 +174,8 @@ int cmd__fast_rebase(int argc, const char **argv) assert(commit->parents && !commit->parents->next); base = commit->parents->item; - next_tree = get_commit_tree(commit); - base_tree = get_commit_tree(base); + next_tree = repo_get_commit_tree(the_repository, commit); + base_tree = repo_get_commit_tree(the_repository, base); merge_opt.branch2 = short_commit_name(commit); merge_opt.ancestor = xstrfmt("parent of %s", merge_opt.branch2); diff --git a/t/helper/test-fsmonitor-client.c b/t/helper/test-fsmonitor-client.c index 54a4856c48..8280984d08 100644 --- a/t/helper/test-fsmonitor-client.c +++ b/t/helper/test-fsmonitor-client.c @@ -4,14 +4,16 @@ */ #include "test-tool.h" -#include "cache.h" #include "parse-options.h" #include "fsmonitor-ipc.h" +#include "read-cache-ll.h" +#include "repository.h" +#include "setup.h" #include "thread-utils.h" #include "trace2.h" #ifndef HAVE_FSMONITOR_DAEMON_BACKEND -int cmd__fsmonitor_client(int argc, const char **argv) +int cmd__fsmonitor_client(int argc UNUSED, const char **argv UNUSED) { die("fsmonitor--daemon not available on this platform"); } diff --git a/t/helper/test-genzeros.c b/t/helper/test-genzeros.c index 8ca988d621..47af843b68 100644 --- a/t/helper/test-genzeros.c +++ b/t/helper/test-genzeros.c @@ -17,15 +17,16 @@ int cmd__genzeros(int argc, const char **argv) /* Writing out individual NUL bytes is slow... */ while (count < 0) - if (write(1, zeros, ARRAY_SIZE(zeros)) < 0) - return -1; + if (xwrite(1, zeros, ARRAY_SIZE(zeros)) < 0) + die_errno("write error"); while (count > 0) { - n = write(1, zeros, count < ARRAY_SIZE(zeros) ? - count : ARRAY_SIZE(zeros)); + n = xwrite(1, zeros, + count < ARRAY_SIZE(zeros) + ? count : ARRAY_SIZE(zeros)); if (n < 0) - return -1; + die_errno("write error"); count -= n; } diff --git a/t/helper/test-hash-speed.c b/t/helper/test-hash-speed.c index f40d9ad0c2..b235da594f 100644 --- a/t/helper/test-hash-speed.c +++ b/t/helper/test-hash-speed.c @@ -1,5 +1,5 @@ #include "test-tool.h" -#include "cache.h" +#include "hash-ll.h" #define NUM_SECONDS 3 diff --git a/t/helper/test-hash.c b/t/helper/test-hash.c index 5860dab0ff..45d829c908 100644 --- a/t/helper/test-hash.c +++ b/t/helper/test-hash.c @@ -1,5 +1,5 @@ #include "test-tool.h" -#include "cache.h" +#include "hex.h" int cmd_hash_impl(int ac, const char **av, int algo) { diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c index 36ff07bd4b..0eb0b3d49c 100644 --- a/t/helper/test-hashmap.c +++ b/t/helper/test-hashmap.c @@ -2,6 +2,7 @@ #include "git-compat-util.h" #include "hashmap.h" #include "strbuf.h" +#include "string-list.h" struct test_entry { @@ -150,6 +151,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds) */ int cmd__hashmap(int argc, const char **argv) { + struct string_list parts = STRING_LIST_INIT_NODUP; struct strbuf line = STRBUF_INIT; int icase; struct hashmap map = HASHMAP_INIT(test_entry_cmp, &icase); @@ -159,21 +161,26 @@ int cmd__hashmap(int argc, const char **argv) /* process commands from stdin */ while (strbuf_getline(&line, stdin) != EOF) { - char *cmd, *p1 = NULL, *p2 = NULL; + char *cmd, *p1, *p2; unsigned int hash = 0; struct test_entry *entry; /* break line into command and up to two parameters */ - cmd = strtok(line.buf, DELIM); + string_list_setlen(&parts, 0); + string_list_split_in_place(&parts, line.buf, DELIM, 2); + string_list_remove_empty_items(&parts, 0); + /* ignore empty lines */ - if (!cmd || *cmd == '#') + if (!parts.nr) + continue; + if (!*parts.items[0].string || *parts.items[0].string == '#') continue; - p1 = strtok(NULL, DELIM); - if (p1) { + cmd = parts.items[0].string; + p1 = parts.nr >= 1 ? parts.items[1].string : NULL; + p2 = parts.nr >= 2 ? parts.items[2].string : NULL; + if (p1) hash = icase ? strihash(p1) : strhash(p1); - p2 = strtok(NULL, DELIM); - } if (!strcmp("add", cmd) && p1 && p2) { @@ -260,6 +267,7 @@ int cmd__hashmap(int argc, const char **argv) } } + string_list_clear(&parts, 0); strbuf_release(&line); hashmap_clear_and_free(&map, struct test_entry, ent); return 0; diff --git a/t/helper/test-hexdump.c b/t/helper/test-hexdump.c index 811e89c1bc..05f55eca21 100644 --- a/t/helper/test-hexdump.c +++ b/t/helper/test-hexdump.c @@ -4,7 +4,7 @@ /* * Read stdin and print a hexdump to stdout. */ -int cmd__hexdump(int argc, const char **argv) +int cmd__hexdump(int argc UNUSED, const char **argv UNUSED) { char buf[1024]; ssize_t i, len; diff --git a/t/helper/test-index-version.c b/t/helper/test-index-version.c deleted file mode 100644 index fcd10968cc..0000000000 --- a/t/helper/test-index-version.c +++ /dev/null @@ -1,15 +0,0 @@ -#include "test-tool.h" -#include "cache.h" - -int cmd__index_version(int argc, const char **argv) -{ - struct cache_header hdr; - int version; - - memset(&hdr,0,sizeof(hdr)); - if (read(0, &hdr, sizeof(hdr)) != sizeof(hdr)) - return 0; - version = ntohl(hdr.hdr_version); - printf("%d\n", version); - return 0; -} diff --git a/t/helper/test-json-writer.c b/t/helper/test-json-writer.c index 8c3edacc00..afe393f597 100644 --- a/t/helper/test-json-writer.c +++ b/t/helper/test-json-writer.c @@ -1,6 +1,6 @@ #include "test-tool.h" -#include "cache.h" #include "json-writer.h" +#include "string-list.h" static const char *expect_obj1 = "{\"a\":\"abc\",\"b\":42,\"c\":true}"; static const char *expect_obj2 = "{\"a\":-1,\"b\":2147483647,\"c\":0}"; @@ -395,35 +395,41 @@ static int unit_tests(void) return 0; } -static void get_s(int line_nr, char **s_in) +struct line { + struct string_list *parts; + size_t consumed_nr; + int nr; +}; + +static void get_s(struct line *line, char **s_in) { - *s_in = strtok(NULL, " "); - if (!*s_in) - die("line[%d]: expected: <s>", line_nr); + if (line->consumed_nr > line->parts->nr) + die("line[%d]: expected: <s>", line->nr); + *s_in = line->parts->items[line->consumed_nr++].string; } -static void get_i(int line_nr, intmax_t *s_in) +static void get_i(struct line *line, intmax_t *s_in) { char *s; char *endptr; - get_s(line_nr, &s); + get_s(line, &s); *s_in = strtol(s, &endptr, 10); if (*endptr || errno == ERANGE) - die("line[%d]: invalid integer value", line_nr); + die("line[%d]: invalid integer value", line->nr); } -static void get_d(int line_nr, double *s_in) +static void get_d(struct line *line, double *s_in) { char *s; char *endptr; - get_s(line_nr, &s); + get_s(line, &s); *s_in = strtod(s, &endptr); if (*endptr || errno == ERANGE) - die("line[%d]: invalid float value", line_nr); + die("line[%d]: invalid float value", line->nr); } static int pretty; @@ -454,6 +460,7 @@ static char *get_trimmed_line(char *buf, int buf_size) static int scripted(void) { + struct string_list parts = STRING_LIST_INIT_NODUP; struct json_writer jw = JSON_WRITER_INIT; char buf[MAX_LINE_LENGTH]; char *line; @@ -471,66 +478,77 @@ static int scripted(void) die("expected first line to be 'object' or 'array'"); while ((line = get_trimmed_line(buf, MAX_LINE_LENGTH)) != NULL) { + struct line state = { 0 }; char *verb; char *key; char *s_value; intmax_t i_value; double d_value; - line_nr++; + state.parts = &parts; + state.nr = ++line_nr; + + /* break line into command and zero or more tokens */ + string_list_setlen(&parts, 0); + string_list_split_in_place(&parts, line, " ", -1); + string_list_remove_empty_items(&parts, 0); + + /* ignore empty lines */ + if (!parts.nr || !*parts.items[0].string) + continue; - verb = strtok(line, " "); + verb = parts.items[state.consumed_nr++].string; if (!strcmp(verb, "end")) { jw_end(&jw); } else if (!strcmp(verb, "object-string")) { - get_s(line_nr, &key); - get_s(line_nr, &s_value); + get_s(&state, &key); + get_s(&state, &s_value); jw_object_string(&jw, key, s_value); } else if (!strcmp(verb, "object-int")) { - get_s(line_nr, &key); - get_i(line_nr, &i_value); + get_s(&state, &key); + get_i(&state, &i_value); jw_object_intmax(&jw, key, i_value); } else if (!strcmp(verb, "object-double")) { - get_s(line_nr, &key); - get_i(line_nr, &i_value); - get_d(line_nr, &d_value); + get_s(&state, &key); + get_i(&state, &i_value); + get_d(&state, &d_value); jw_object_double(&jw, key, i_value, d_value); } else if (!strcmp(verb, "object-true")) { - get_s(line_nr, &key); + get_s(&state, &key); jw_object_true(&jw, key); } else if (!strcmp(verb, "object-false")) { - get_s(line_nr, &key); + get_s(&state, &key); jw_object_false(&jw, key); } else if (!strcmp(verb, "object-null")) { - get_s(line_nr, &key); + get_s(&state, &key); jw_object_null(&jw, key); } else if (!strcmp(verb, "object-object")) { - get_s(line_nr, &key); + get_s(&state, &key); jw_object_inline_begin_object(&jw, key); } else if (!strcmp(verb, "object-array")) { - get_s(line_nr, &key); + get_s(&state, &key); jw_object_inline_begin_array(&jw, key); } else if (!strcmp(verb, "array-string")) { - get_s(line_nr, &s_value); + get_s(&state, &s_value); jw_array_string(&jw, s_value); } else if (!strcmp(verb, "array-int")) { - get_i(line_nr, &i_value); + get_i(&state, &i_value); jw_array_intmax(&jw, i_value); } else if (!strcmp(verb, "array-double")) { - get_i(line_nr, &i_value); - get_d(line_nr, &d_value); + get_i(&state, &i_value); + get_d(&state, &d_value); jw_array_double(&jw, i_value, d_value); } else if (!strcmp(verb, "array-true")) @@ -553,6 +571,7 @@ static int scripted(void) printf("%s\n", jw.json.buf); jw_release(&jw); + string_list_clear(&parts, 0); return 0; } diff --git a/t/helper/test-lazy-init-name-hash.c b/t/helper/test-lazy-init-name-hash.c index cd1b4c9736..187a115d57 100644 --- a/t/helper/test-lazy-init-name-hash.c +++ b/t/helper/test-lazy-init-name-hash.c @@ -1,6 +1,12 @@ +#define USE_THE_INDEX_VARIABLE #include "test-tool.h" -#include "cache.h" +#include "environment.h" +#include "name-hash.h" #include "parse-options.h" +#include "read-cache-ll.h" +#include "repository.h" +#include "setup.h" +#include "trace.h" static int single; static int multi; @@ -32,7 +38,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 +55,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 +72,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 +95,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 +119,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 +134,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-match-trees.c b/t/helper/test-match-trees.c index 4079fdee06..d0db5ff26f 100644 --- a/t/helper/test-match-trees.c +++ b/t/helper/test-match-trees.c @@ -1,17 +1,21 @@ #include "test-tool.h" -#include "cache.h" +#include "hex.h" +#include "match-trees.h" +#include "object-name.h" +#include "repository.h" +#include "setup.h" #include "tree.h" -int cmd__match_trees(int ac, const char **av) +int cmd__match_trees(int ac UNUSED, const char **av) { struct object_id hash1, hash2, shifted; struct tree *one, *two; setup_git_directory(); - if (get_oid(av[1], &hash1)) + if (repo_get_oid(the_repository, av[1], &hash1)) die("cannot parse %s as an object name", av[1]); - if (get_oid(av[2], &hash2)) + if (repo_get_oid(the_repository, av[2], &hash2)) die("cannot parse %s as an object name", av[2]); one = parse_tree_indirect(&hash1); if (!one) diff --git a/t/helper/test-mergesort.c b/t/helper/test-mergesort.c index 335e5bb3a9..42ccc87051 100644 --- a/t/helper/test-mergesort.c +++ b/t/helper/test-mergesort.c @@ -1,6 +1,7 @@ #include "test-tool.h" -#include "cache.h" +#include "mem-pool.h" #include "mergesort.h" +#include "strbuf.h" static uint32_t minstd_rand(uint32_t *state) { diff --git a/t/helper/test-oid-array.c b/t/helper/test-oid-array.c index d1324d086a..aafe398ef0 100644 --- a/t/helper/test-oid-array.c +++ b/t/helper/test-oid-array.c @@ -1,14 +1,16 @@ #include "test-tool.h" -#include "cache.h" +#include "hex.h" #include "oid-array.h" +#include "setup.h" +#include "strbuf.h" -static int print_oid(const struct object_id *oid, void *data) +static int print_oid(const struct object_id *oid, void *data UNUSED) { puts(oid_to_hex(oid)); return 0; } -int cmd__oid_array(int argc, const char **argv) +int cmd__oid_array(int argc UNUSED, const char **argv UNUSED) { struct oid_array array = OID_ARRAY_INIT; struct strbuf line = STRBUF_INIT; diff --git a/t/helper/test-oidmap.c b/t/helper/test-oidmap.c index 0acf99931e..bd30244a54 100644 --- a/t/helper/test-oidmap.c +++ b/t/helper/test-oidmap.c @@ -1,7 +1,11 @@ #include "test-tool.h" -#include "cache.h" +#include "hex.h" +#include "object-name.h" #include "oidmap.h" +#include "repository.h" +#include "setup.h" #include "strbuf.h" +#include "string-list.h" /* key is an oid and value is a name (could be a refname for example) */ struct test_entry { @@ -21,8 +25,9 @@ struct test_entry { * iterate -> oidkey1 namevalue1\noidkey2 namevalue2\n... * */ -int cmd__oidmap(int argc, const char **argv) +int cmd__oidmap(int argc UNUSED, const char **argv UNUSED) { + struct string_list parts = STRING_LIST_INIT_NODUP; struct strbuf line = STRBUF_INIT; struct oidmap map = OIDMAP_INIT; @@ -33,23 +38,28 @@ int cmd__oidmap(int argc, const char **argv) /* process commands from stdin */ while (strbuf_getline(&line, stdin) != EOF) { - char *cmd, *p1 = NULL, *p2 = NULL; + char *cmd, *p1, *p2; struct test_entry *entry; struct object_id oid; /* break line into command and up to two parameters */ - cmd = strtok(line.buf, DELIM); + string_list_setlen(&parts, 0); + string_list_split_in_place(&parts, line.buf, DELIM, 2); + string_list_remove_empty_items(&parts, 0); + /* ignore empty lines */ - if (!cmd || *cmd == '#') + if (!parts.nr) + continue; + if (!*parts.items[0].string || *parts.items[0].string == '#') continue; - p1 = strtok(NULL, DELIM); - if (p1) - p2 = strtok(NULL, DELIM); + cmd = parts.items[0].string; + p1 = parts.nr >= 1 ? parts.items[1].string : NULL; + p2 = parts.nr >= 2 ? parts.items[2].string : NULL; if (!strcmp("put", cmd) && p1 && p2) { - if (get_oid(p1, &oid)) { + if (repo_get_oid(the_repository, p1, &oid)) { printf("Unknown oid: %s\n", p1); continue; } @@ -67,7 +77,7 @@ int cmd__oidmap(int argc, const char **argv) } else if (!strcmp("get", cmd) && p1) { - if (get_oid(p1, &oid)) { + if (repo_get_oid(the_repository, p1, &oid)) { printf("Unknown oid: %s\n", p1); continue; } @@ -80,7 +90,7 @@ int cmd__oidmap(int argc, const char **argv) } else if (!strcmp("remove", cmd) && p1) { - if (get_oid(p1, &oid)) { + if (repo_get_oid(the_repository, p1, &oid)) { printf("Unknown oid: %s\n", p1); continue; } @@ -106,6 +116,7 @@ int cmd__oidmap(int argc, const char **argv) } } + string_list_clear(&parts, 0); strbuf_release(&line); oidmap_free(&map, 1); return 0; diff --git a/t/helper/test-oidtree.c b/t/helper/test-oidtree.c index d48a409f4e..c7a1d4c642 100644 --- a/t/helper/test-oidtree.c +++ b/t/helper/test-oidtree.c @@ -1,14 +1,16 @@ #include "test-tool.h" -#include "cache.h" +#include "hex.h" #include "oidtree.h" +#include "setup.h" +#include "strbuf.h" -static enum cb_next print_oid(const struct object_id *oid, void *data) +static enum cb_next print_oid(const struct object_id *oid, void *data UNUSED) { puts(oid_to_hex(oid)); return CB_CONTINUE; } -int cmd__oidtree(int argc, const char **argv) +int cmd__oidtree(int argc UNUSED, const char **argv UNUSED) { struct oidtree ot; struct strbuf line = STRBUF_INIT; diff --git a/t/helper/test-online-cpus.c b/t/helper/test-online-cpus.c index 8cb0d53840..47dc211711 100644 --- a/t/helper/test-online-cpus.c +++ b/t/helper/test-online-cpus.c @@ -2,7 +2,7 @@ #include "git-compat-util.h" #include "thread-utils.h" -int cmd__online_cpus(int argc, const char **argv) +int cmd__online_cpus(int argc UNUSED, const char **argv UNUSED) { printf("%d\n", online_cpus()); return 0; diff --git a/t/helper/test-pack-mtimes.c b/t/helper/test-pack-mtimes.c index f7b79daf4c..67a964ef90 100644 --- a/t/helper/test-pack-mtimes.c +++ b/t/helper/test-pack-mtimes.c @@ -1,9 +1,10 @@ -#include "git-compat-util.h" #include "test-tool.h" +#include "hex.h" #include "strbuf.h" -#include "object-store.h" +#include "object-store-ll.h" #include "packfile.h" #include "pack-mtimes.h" +#include "setup.h" static void dump_mtimes(struct packed_git *p) { diff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c index 506835521a..a4f6e24b0c 100644 --- a/t/helper/test-parse-options.c +++ b/t/helper/test-parse-options.c @@ -1,6 +1,6 @@ #include "test-tool.h" -#include "cache.h" #include "parse-options.h" +#include "strbuf.h" #include "string-list.h" #include "trace2.h" @@ -133,6 +133,8 @@ int cmd__parse_options(int argc, const char **argv) OPT_STRING(0, "st", &string, "st", "get another string (pervert ordering)"), OPT_STRING('o', NULL, &string, "str", "get another string"), OPT_NOOP_NOARG(0, "obsolete"), + OPT_SET_INT_F(0, "longhelp", &integer, "help text of this entry\n" + "spans multiple lines", 0, PARSE_OPT_NONEG), OPT_STRING_LIST(0, "list", &list, "str", "add str to list"), OPT_GROUP("Magic arguments"), OPT_NUMBER_CALLBACK(&integer, "set integer to NUM", @@ -263,14 +265,14 @@ int cmd__parse_options_flags(int argc, const char **argv) return parse_options_flags__cmd(argc, argv, test_flags); } -static int subcmd_one(int argc, const char **argv, const char *prefix) +static int subcmd_one(int argc, const char **argv, const char *prefix UNUSED) { printf("fn: subcmd_one\n"); print_args(argc, argv); return 0; } -static int subcmd_two(int argc, const char **argv, const char *prefix) +static int subcmd_two(int argc, const char **argv, const char *prefix UNUSED) { printf("fn: subcmd_two\n"); print_args(argc, argv); diff --git a/t/helper/test-parse-pathspec-file.c b/t/helper/test-parse-pathspec-file.c index b3e08cef4b..89ecefd1cd 100644 --- a/t/helper/test-parse-pathspec-file.c +++ b/t/helper/test-parse-pathspec-file.c @@ -1,12 +1,11 @@ #include "test-tool.h" #include "parse-options.h" #include "pathspec.h" -#include "gettext.h" int cmd__parse_pathspec_file(int argc, const char **argv) { struct pathspec pathspec; - const char *pathspec_from_file = NULL; + char *pathspec_from_file = NULL; int pathspec_file_nul = 0, i; static const char *const usage[] = { @@ -29,5 +28,6 @@ int cmd__parse_pathspec_file(int argc, const char **argv) printf("%s\n", pathspec.items[i].original); clear_pathspec(&pathspec); + free(pathspec_from_file); return 0; } diff --git a/t/helper/test-partial-clone.c b/t/helper/test-partial-clone.c index 3f102cfddd..910a128614 100644 --- a/t/helper/test-partial-clone.c +++ b/t/helper/test-partial-clone.c @@ -1,7 +1,8 @@ -#include "cache.h" #include "test-tool.h" +#include "hex.h" #include "repository.h" -#include "object-store.h" +#include "object-store-ll.h" +#include "setup.h" /* * Prints the size of the object corresponding to the given hash in a specific diff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c index d20e1b7a18..70396fa384 100644 --- a/t/helper/test-path-utils.c +++ b/t/helper/test-path-utils.c @@ -1,6 +1,11 @@ #include "test-tool.h" -#include "cache.h" +#include "abspath.h" +#include "environment.h" +#include "path.h" +#include "read-cache-ll.h" +#include "setup.h" #include "string-list.h" +#include "trace.h" #include "utf8.h" /* @@ -8,7 +13,8 @@ * GIT_CEILING_DIRECTORIES. If the path is unusable for some reason, * die with an explanation. */ -static int normalize_ceiling_entry(struct string_list_item *item, void *unused) +static int normalize_ceiling_entry(struct string_list_item *item, + void *data UNUSED) { char *ceil = item->string; diff --git a/t/helper/test-pcre2-config.c b/t/helper/test-pcre2-config.c index 5258fdddba..5d0b2a2e10 100644 --- a/t/helper/test-pcre2-config.c +++ b/t/helper/test-pcre2-config.c @@ -1,5 +1,4 @@ #include "test-tool.h" -#include "cache.h" #include "grep.h" int cmd__pcre2_config(int argc, const char **argv) diff --git a/t/helper/test-pkt-line.c b/t/helper/test-pkt-line.c index c5e052e537..f4d134a145 100644 --- a/t/helper/test-pkt-line.c +++ b/t/helper/test-pkt-line.c @@ -1,6 +1,7 @@ -#include "cache.h" +#include "git-compat-util.h" #include "test-tool.h" #include "pkt-line.h" +#include "write-or-die.h" static void pack_line(const char *line) { diff --git a/t/helper/test-prio-queue.c b/t/helper/test-prio-queue.c index 133b5e6f4a..f0bf255f5f 100644 --- a/t/helper/test-prio-queue.c +++ b/t/helper/test-prio-queue.c @@ -1,8 +1,7 @@ #include "test-tool.h" -#include "cache.h" #include "prio-queue.h" -static int intcmp(const void *va, const void *vb, void *data) +static int intcmp(const void *va, const void *vb, void *data UNUSED) { const int *a = va, *b = vb; return *a - *b; @@ -17,7 +16,7 @@ static void show(int *v) free(v); } -int cmd__prio_queue(int argc, const char **argv) +int cmd__prio_queue(int argc UNUSED, const char **argv) { struct prio_queue pq = { intcmp }; diff --git a/t/helper/test-proc-receive.c b/t/helper/test-proc-receive.c index cc08506cf0..f30022d222 100644 --- a/t/helper/test-proc-receive.c +++ b/t/helper/test-proc-receive.c @@ -1,12 +1,13 @@ -#include "cache.h" +#include "test-tool.h" #include "connect.h" +#include "hex.h" #include "parse-options.h" #include "pkt-line.h" +#include "setup.h" #include "sigchain.h" -#include "test-tool.h" static const char *proc_receive_usage[] = { - "test-tool proc-receive [<options>...]", + "test-tool proc-receive [<options>]", NULL }; diff --git a/t/helper/test-progress.c b/t/helper/test-progress.c index 6cc9735b60..66acb6a06c 100644 --- a/t/helper/test-progress.c +++ b/t/helper/test-progress.c @@ -19,7 +19,6 @@ */ #define GIT_TEST_PROGRESS_ONLY #include "test-tool.h" -#include "gettext.h" #include "parse-options.h" #include "progress.h" #include "strbuf.h" diff --git a/t/helper/test-reach.c b/t/helper/test-reach.c index 2f65c7f6a5..3e173399a0 100644 --- a/t/helper/test-reach.c +++ b/t/helper/test-reach.c @@ -1,10 +1,13 @@ #include "test-tool.h" -#include "cache.h" #include "commit.h" #include "commit-reach.h" #include "config.h" +#include "gettext.h" +#include "hex.h" +#include "object-name.h" #include "parse-options.h" #include "ref-filter.h" +#include "setup.h" #include "string-list.h" #include "tag.h" @@ -57,7 +60,7 @@ int cmd__reach(int ac, const char **av) if (buf.len < 3) continue; - if (get_oid_committish(buf.buf + 2, &oid)) + if (repo_get_oid_committish(the_repository, buf.buf + 2, &oid)) die("failed to resolve %s", buf.buf + 2); orig = parse_object(r, &oid); @@ -106,13 +109,17 @@ int cmd__reach(int ac, const char **av) if (!strcmp(av[1], "ref_newer")) printf("%s(A,B):%d\n", av[1], ref_newer(&oid_A, &oid_B)); else if (!strcmp(av[1], "in_merge_bases")) - printf("%s(A,B):%d\n", av[1], in_merge_bases(A, B)); + printf("%s(A,B):%d\n", av[1], + repo_in_merge_bases(the_repository, A, B)); else if (!strcmp(av[1], "in_merge_bases_many")) - printf("%s(A,X):%d\n", av[1], in_merge_bases_many(A, X_nr, X_array)); + printf("%s(A,X):%d\n", av[1], + repo_in_merge_bases_many(the_repository, A, X_nr, X_array)); else if (!strcmp(av[1], "is_descendant_of")) printf("%s(A,X):%d\n", av[1], repo_is_descendant_of(r, A, X)); else if (!strcmp(av[1], "get_merge_bases_many")) { - struct commit_list *list = get_merge_bases_many(A, X_nr, X_array); + struct commit_list *list = repo_get_merge_bases_many(the_repository, + A, X_nr, + X_array); printf("%s(A,X):\n", av[1]); print_sorted_commit_ids(list); } else if (!strcmp(av[1], "reduce_heads")) { @@ -131,7 +138,7 @@ int cmd__reach(int ac, const char **av) printf("%s(X,_,_,0,0):%d\n", av[1], can_all_from_reach_with_flag(&X_obj, 2, 4, 0, 0)); } else if (!strcmp(av[1], "commit_contains")) { - struct ref_filter filter; + struct ref_filter filter = REF_FILTER_INIT; struct contains_cache cache; init_contains_cache(&cache); diff --git a/t/helper/test-read-cache.c b/t/helper/test-read-cache.c index b736ef1642..1acd362346 100644 --- a/t/helper/test-read-cache.c +++ b/t/helper/test-read-cache.c @@ -1,6 +1,9 @@ +#define USE_THE_INDEX_VARIABLE #include "test-tool.h" -#include "cache.h" #include "config.h" +#include "read-cache-ll.h" +#include "repository.h" +#include "setup.h" int cmd__read_cache(int argc, const char **argv) { @@ -20,7 +23,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 +36,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-read-graph.c b/t/helper/test-read-graph.c index 98b73bb8f2..8c7a83f578 100644 --- a/t/helper/test-read-graph.c +++ b/t/helper/test-read-graph.c @@ -1,11 +1,11 @@ #include "test-tool.h" -#include "cache.h" #include "commit-graph.h" #include "repository.h" -#include "object-store.h" +#include "object-store-ll.h" #include "bloom.h" +#include "setup.h" -int cmd__read_graph(int argc, const char **argv) +int cmd__read_graph(int argc UNUSED, const char **argv UNUSED) { struct commit_graph *graph = NULL; struct object_directory *odb; diff --git a/t/helper/test-read-midx.c b/t/helper/test-read-midx.c index 27072ba94d..e9a444ddba 100644 --- a/t/helper/test-read-midx.c +++ b/t/helper/test-read-midx.c @@ -1,9 +1,11 @@ #include "test-tool.h" -#include "cache.h" +#include "hex.h" #include "midx.h" #include "repository.h" -#include "object-store.h" +#include "object-store-ll.h" #include "pack-bitmap.h" +#include "packfile.h" +#include "setup.h" static int read_midx_file(const char *object_dir, int show_objects) { diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c index ae8a5648da..48552e6a9e 100644 --- a/t/helper/test-ref-store.c +++ b/t/helper/test-ref-store.c @@ -1,9 +1,13 @@ #include "test-tool.h" -#include "cache.h" +#include "hex.h" #include "refs.h" +#include "setup.h" #include "worktree.h" -#include "object-store.h" +#include "object-store-ll.h" +#include "path.h" #include "repository.h" +#include "strbuf.h" +#include "revision.h" struct flag_definition { const char *name; @@ -115,8 +119,16 @@ static struct flag_definition pack_flags[] = { FLAG_DEF(PACK_REFS_PRUNE), static int cmd_pack_refs(struct ref_store *refs, const char **argv) { unsigned int flags = arg_flags(*argv++, "flags", pack_flags); + static struct ref_exclusions exclusions = REF_EXCLUSIONS_INIT; + static struct string_list included_refs = STRING_LIST_INIT_NODUP; + struct pack_refs_opts pack_opts = { .flags = flags, + .exclusions = &exclusions, + .includes = &included_refs }; - return refs_pack_refs(refs, flags); + if (pack_opts.flags & PACK_REFS_ALL) + string_list_append(pack_opts.includes, "*"); + + return refs_pack_refs(refs, &pack_opts); } static int cmd_create_symref(struct ref_store *refs, const char **argv) @@ -174,6 +186,15 @@ static int cmd_for_each_ref(struct ref_store *refs, const char **argv) return refs_for_each_ref_in(refs, prefix, each_ref, NULL); } +static int cmd_for_each_ref__exclude(struct ref_store *refs, const char **argv) +{ + const char *prefix = notnull(*argv++, "prefix"); + const char **exclude_patterns = argv; + + return refs_for_each_fullref_in(refs, prefix, exclude_patterns, each_ref, + NULL); +} + static int cmd_resolve_ref(struct ref_store *refs, const char **argv) { struct object_id oid = *null_oid(); @@ -200,7 +221,8 @@ static int cmd_verify_ref(struct ref_store *refs, const char **argv) return ret; } -static int cmd_for_each_reflog(struct ref_store *refs, const char **argv) +static int cmd_for_each_reflog(struct ref_store *refs, + const char **argv UNUSED) { return refs_for_each_reflog(refs, each_ref, NULL); } @@ -255,11 +277,6 @@ static int cmd_delete_reflog(struct ref_store *refs, const char **argv) return refs_delete_reflog(refs, refname); } -static int cmd_reflog_expire(struct ref_store *refs, const char **argv) -{ - die("not supported yet"); -} - static int cmd_delete_ref(struct ref_store *refs, const char **argv) { const char *msg = notnull(*argv++, "msg"); @@ -305,6 +322,7 @@ static struct command commands[] = { { "delete-refs", cmd_delete_refs }, { "rename-ref", cmd_rename_ref }, { "for-each-ref", cmd_for_each_ref }, + { "for-each-ref--exclude", cmd_for_each_ref__exclude }, { "resolve-ref", cmd_resolve_ref }, { "verify-ref", cmd_verify_ref }, { "for-each-reflog", cmd_for_each_reflog }, @@ -313,7 +331,6 @@ static struct command commands[] = { { "reflog-exists", cmd_reflog_exists }, { "create-reflog", cmd_create_reflog }, { "delete-reflog", cmd_delete_reflog }, - { "reflog-expire", cmd_reflog_expire }, /* * backend transaction functions can't be tested separately */ @@ -322,7 +339,7 @@ static struct command commands[] = { { NULL, NULL } }; -int cmd__ref_store(int argc, const char **argv) +int cmd__ref_store(int argc UNUSED, const char **argv) { struct ref_store *refs; const char *func; diff --git a/t/helper/test-reftable.c b/t/helper/test-reftable.c index 1f0a28cbb6..00237ef0d9 100644 --- a/t/helper/test-reftable.c +++ b/t/helper/test-reftable.c @@ -1,3 +1,4 @@ +#include "reftable/system.h" #include "reftable/reftable-tests.h" #include "test-tool.h" diff --git a/t/helper/test-repository.c b/t/helper/test-repository.c index 56f0e3c1be..4cd8a952e5 100644 --- a/t/helper/test-repository.c +++ b/t/helper/test-repository.c @@ -1,11 +1,13 @@ #include "test-tool.h" -#include "cache.h" #include "commit-graph.h" #include "commit.h" #include "config.h" -#include "object-store.h" +#include "environment.h" +#include "hex.h" +#include "object-store-ll.h" #include "object.h" #include "repository.h" +#include "setup.h" #include "tree.h" static void test_parse_commit_in_graph(const char *gitdir, const char *worktree, diff --git a/t/helper/test-revision-walking.c b/t/helper/test-revision-walking.c index 4a45d5bac2..f346951bc2 100644 --- a/t/helper/test-revision-walking.c +++ b/t/helper/test-revision-walking.c @@ -9,17 +9,19 @@ */ #include "test-tool.h" -#include "cache.h" #include "commit.h" #include "diff.h" +#include "repository.h" #include "revision.h" +#include "setup.h" static void print_commit(struct commit *commit) { struct strbuf sb = STRBUF_INIT; struct pretty_print_context ctx = {0}; ctx.date_mode.type = DATE_NORMAL; - format_commit_message(commit, " %m %s", &sb, &ctx); + repo_format_commit_message(the_repository, commit, " %m %s", &sb, + &ctx); printf("%s\n", sb.buf); strbuf_release(&sb); } diff --git a/t/helper/test-run-command.c b/t/helper/test-run-command.c index c9283b47af..c0ed8722c8 100644 --- a/t/helper/test-run-command.c +++ b/t/helper/test-run-command.c @@ -9,8 +9,6 @@ */ #include "test-tool.h" -#include "git-compat-util.h" -#include "cache.h" #include "run-command.h" #include "strvec.h" #include "strbuf.h" @@ -18,13 +16,12 @@ #include "string-list.h" #include "thread-utils.h" #include "wildmatch.h" -#include "gettext.h" static int number_callbacks; static int parallel_next(struct child_process *cp, struct strbuf *err, void *cb, - void **task_cb) + void **task_cb UNUSED) { struct child_process *d = cb; if (number_callbacks >= 4) @@ -40,10 +37,10 @@ static int parallel_next(struct child_process *cp, return 1; } -static int no_job(struct child_process *cp, +static int no_job(struct child_process *cp UNUSED, struct strbuf *err, - void *cb, - void **task_cb) + void *cb UNUSED, + void **task_cb UNUSED) { if (err) strbuf_addstr(err, "no further jobs available\n"); @@ -52,10 +49,10 @@ static int no_job(struct child_process *cp, return 0; } -static int task_finished(int result, +static int task_finished(int result UNUSED, struct strbuf *err, - void *pp_cb, - void *pp_task_cb) + void *pp_cb UNUSED, + void *pp_task_cb UNUSED) { if (err) strbuf_addstr(err, "asking for a quick stop\n"); @@ -136,7 +133,7 @@ static const char * const testsuite_usage[] = { static int testsuite(int argc, const char **argv) { struct testsuite suite = TESTSUITE_INIT; - int max_jobs = 1, i, ret; + int max_jobs = 1, i, ret = 0; DIR *dir; struct dirent *d; struct option options[] = { @@ -152,6 +149,12 @@ static int testsuite(int argc, const char **argv) "write JUnit-style XML files"), OPT_END() }; + struct run_process_parallel_opts opts = { + .get_next_task = next_test, + .start_failure = test_failed, + .task_finished = test_finished, + .data = &suite, + }; argc = parse_options(argc, argv, NULL, options, testsuite_usage, PARSE_OPT_STOP_AT_NON_OPTION); @@ -192,8 +195,8 @@ static int testsuite(int argc, const char **argv) fprintf(stderr, "Running %"PRIuMAX" tests (%d at a time)\n", (uintmax_t)suite.tests.nr, max_jobs); - ret = run_processes_parallel(max_jobs, next_test, test_failed, - test_finished, &suite); + opts.processes = max_jobs; + run_processes_parallel(&opts); if (suite.failed.nr > 0) { ret = 1; @@ -206,7 +209,7 @@ static int testsuite(int argc, const char **argv) string_list_clear(&suite.tests, 0); string_list_clear(&suite.failed, 0); - return !!ret; + return ret; } static uint64_t my_random_next = 1234; @@ -381,13 +384,17 @@ int cmd__run_command(int argc, const char **argv) { struct child_process proc = CHILD_PROCESS_INIT; int jobs; + int ret; + struct run_process_parallel_opts opts = { + .data = &proc, + }; if (argc > 1 && !strcmp(argv[1], "testsuite")) - exit(testsuite(argc - 1, argv + 1)); + return testsuite(argc - 1, argv + 1); if (!strcmp(argv[1], "inherited-handle")) - exit(inherit_handle(argv[0])); + return inherit_handle(argv[0]); if (!strcmp(argv[1], "inherited-handle-child")) - exit(inherit_handle_child()); + return inherit_handle_child(); if (argc >= 2 && !strcmp(argv[1], "quote-stress-test")) return !!quote_stress_test(argc - 1, argv + 1); @@ -404,41 +411,52 @@ int cmd__run_command(int argc, const char **argv) argv += 2; argc -= 2; } - if (argc < 3) - return 1; + if (argc < 3) { + ret = 1; + goto cleanup; + } strvec_pushv(&proc.args, (const char **)argv + 2); if (!strcmp(argv[1], "start-command-ENOENT")) { - if (start_command(&proc) < 0 && errno == ENOENT) - return 0; + if (start_command(&proc) < 0 && errno == ENOENT) { + ret = 0; + goto cleanup; + } fprintf(stderr, "FAIL %s\n", argv[1]); return 1; } - if (!strcmp(argv[1], "run-command")) - exit(run_command(&proc)); + if (!strcmp(argv[1], "run-command")) { + ret = run_command(&proc); + goto cleanup; + } if (!strcmp(argv[1], "--ungroup")) { argv += 1; argc -= 1; - run_processes_parallel_ungroup = 1; + opts.ungroup = 1; } jobs = atoi(argv[2]); strvec_clear(&proc.args); strvec_pushv(&proc.args, (const char **)argv + 3); - if (!strcmp(argv[1], "run-command-parallel")) - exit(run_processes_parallel(jobs, parallel_next, - NULL, NULL, &proc)); - - if (!strcmp(argv[1], "run-command-abort")) - exit(run_processes_parallel(jobs, parallel_next, - NULL, task_finished, &proc)); - - if (!strcmp(argv[1], "run-command-no-jobs")) - exit(run_processes_parallel(jobs, no_job, - NULL, task_finished, &proc)); - - fprintf(stderr, "check usage\n"); - return 1; + if (!strcmp(argv[1], "run-command-parallel")) { + opts.get_next_task = parallel_next; + } else if (!strcmp(argv[1], "run-command-abort")) { + opts.get_next_task = parallel_next; + opts.task_finished = task_finished; + } else if (!strcmp(argv[1], "run-command-no-jobs")) { + opts.get_next_task = no_job; + opts.task_finished = task_finished; + } else { + ret = 1; + fprintf(stderr, "check usage\n"); + goto cleanup; + } + opts.processes = jobs; + run_processes_parallel(&opts); + ret = 0; +cleanup: + child_process_clear(&proc); + return ret; } diff --git a/t/helper/test-scrap-cache-tree.c b/t/helper/test-scrap-cache-tree.c index 026c802479..0a816a96e2 100644 --- a/t/helper/test-scrap-cache-tree.c +++ b/t/helper/test-scrap-cache-tree.c @@ -1,19 +1,22 @@ +#define USE_THE_INDEX_VARIABLE #include "test-tool.h" -#include "cache.h" #include "lockfile.h" +#include "read-cache-ll.h" +#include "repository.h" +#include "setup.h" #include "tree.h" #include "cache-tree.h" -int cmd__scrap_cache_tree(int ac, const char **av) +int cmd__scrap_cache_tree(int ac UNUSED, const char **av UNUSED) { 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-serve-v2.c b/t/helper/test-serve-v2.c index 824e5c0a95..054cbcf5d8 100644 --- a/t/helper/test-serve-v2.c +++ b/t/helper/test-serve-v2.c @@ -1,7 +1,8 @@ #include "test-tool.h" -#include "cache.h" +#include "gettext.h" #include "parse-options.h" #include "serve.h" +#include "setup.h" static char const * const serve_usage[] = { N_("test-tool serve-v2 [<options>]"), diff --git a/t/helper/test-sha1.c b/t/helper/test-sha1.c index d860c387c3..dcb7f6c003 100644 --- a/t/helper/test-sha1.c +++ b/t/helper/test-sha1.c @@ -1,7 +1,15 @@ #include "test-tool.h" -#include "cache.h" +#include "hash-ll.h" 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-sha256.c b/t/helper/test-sha256.c index 0ac6a99d5f..08cf149001 100644 --- a/t/helper/test-sha256.c +++ b/t/helper/test-sha256.c @@ -1,5 +1,5 @@ #include "test-tool.h" -#include "cache.h" +#include "hash-ll.h" int cmd__sha256(int ac, const char **av) { diff --git a/t/helper/test-sigchain.c b/t/helper/test-sigchain.c index d013bccdda..2d5ecf7383 100644 --- a/t/helper/test-sigchain.c +++ b/t/helper/test-sigchain.c @@ -1,5 +1,4 @@ #include "test-tool.h" -#include "cache.h" #include "sigchain.h" #define X(f) \ @@ -14,7 +13,7 @@ X(two) X(three) #undef X -int cmd__sigchain(int argc, const char **argv) +int cmd__sigchain(int argc UNUSED, const char **argv UNUSED) { sigchain_push(SIGTERM, one); sigchain_push(SIGTERM, two); diff --git a/t/helper/test-simple-ipc.c b/t/helper/test-simple-ipc.c index 28365ff85b..3d1436da59 100644 --- a/t/helper/test-simple-ipc.c +++ b/t/helper/test-simple-ipc.c @@ -3,13 +3,14 @@ */ #include "test-tool.h" -#include "cache.h" +#include "gettext.h" #include "strbuf.h" #include "simple-ipc.h" #include "parse-options.h" #include "thread-utils.h" #include "strvec.h" #include "run-command.h" +#include "trace2.h" #ifndef SUPPORTS_SIMPLE_IPC int cmd__simple_ipc(int argc, const char **argv) diff --git a/t/helper/test-strcmp-offset.c b/t/helper/test-strcmp-offset.c index 44e4a6d143..d8473cf2fc 100644 --- a/t/helper/test-strcmp-offset.c +++ b/t/helper/test-strcmp-offset.c @@ -1,7 +1,7 @@ #include "test-tool.h" -#include "cache.h" +#include "read-cache-ll.h" -int cmd__strcmp_offset(int argc, const char **argv) +int cmd__strcmp_offset(int argc UNUSED, const char **argv) { int result; size_t offset; diff --git a/t/helper/test-string-list.c b/t/helper/test-string-list.c index 2123dda85b..e2aad611d1 100644 --- a/t/helper/test-string-list.c +++ b/t/helper/test-string-list.c @@ -1,5 +1,5 @@ #include "test-tool.h" -#include "cache.h" +#include "strbuf.h" #include "string-list.h" /* @@ -62,7 +62,7 @@ int cmd__string_list(int argc, const char **argv) struct string_list list = STRING_LIST_INIT_NODUP; int i; char *s = xstrdup(argv[2]); - int delim = *argv[3]; + const char *delim = argv[3]; int maxsplit = atoi(argv[4]); i = string_list_split_in_place(&list, s, delim, maxsplit); @@ -111,7 +111,7 @@ int cmd__string_list(int argc, const char **argv) */ if (sb.len && sb.buf[sb.len - 1] == '\n') strbuf_setlen(&sb, sb.len - 1); - string_list_split_in_place(&list, sb.buf, '\n', -1); + string_list_split_in_place(&list, sb.buf, "\n", -1); string_list_sort(&list); diff --git a/t/helper/test-submodule-config.c b/t/helper/test-submodule-config.c index 22a41c4092..9df2f03ac8 100644 --- a/t/helper/test-submodule-config.c +++ b/t/helper/test-submodule-config.c @@ -1,10 +1,13 @@ #include "test-tool.h" -#include "cache.h" #include "config.h" +#include "hash.h" +#include "object-name.h" +#include "repository.h" +#include "setup.h" #include "submodule-config.h" #include "submodule.h" -static void die_usage(int argc, const char **argv, const char *msg) +static void die_usage(int argc UNUSED, const char **argv, const char *msg) { fprintf(stderr, "%s\n", msg); fprintf(stderr, "Usage: %s [<commit> <submodulepath>] ...\n", argv[0]); @@ -42,7 +45,7 @@ int cmd__submodule_config(int argc, const char **argv) if (commit[0] == '\0') oidclr(&commit_oid); - else if (get_oid(commit, &commit_oid) < 0) + else if (repo_get_oid(the_repository, commit, &commit_oid) < 0) die_usage(argc, argv, "Commit not found."); if (lookup_name) { diff --git a/t/helper/test-submodule-nested-repo-config.c b/t/helper/test-submodule-nested-repo-config.c index dc1c14bde3..ecd40ded99 100644 --- a/t/helper/test-submodule-nested-repo-config.c +++ b/t/helper/test-submodule-nested-repo-config.c @@ -1,4 +1,6 @@ #include "test-tool.h" +#include "repository.h" +#include "setup.h" #include "submodule-config.h" static void die_usage(const char **argv, const char *msg) diff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c index b7d117cd55..356e0a26c5 100644 --- a/t/helper/test-submodule.c +++ b/t/helper/test-submodule.c @@ -1,8 +1,9 @@ #include "test-tool.h" #include "test-tool-utils.h" -#include "cache.h" #include "parse-options.h" #include "remote.h" +#include "repository.h" +#include "setup.h" #include "submodule-config.h" #include "submodule.h" @@ -111,10 +112,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 UNUSED) +{ + 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-subprocess.c b/t/helper/test-subprocess.c index ff22f2fa2c..c344f1694d 100644 --- a/t/helper/test-subprocess.c +++ b/t/helper/test-subprocess.c @@ -1,6 +1,6 @@ #include "test-tool.h" -#include "cache.h" #include "run-command.h" +#include "setup.h" int cmd__subprocess(int argc, const char **argv) { diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c index d1d013bcd9..621ac3dd10 100644 --- a/t/helper/test-tool.c +++ b/t/helper/test-tool.c @@ -13,6 +13,8 @@ static struct test_cmd cmds[] = { { "advise", cmd__advise_if_enabled }, { "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 }, @@ -26,6 +28,7 @@ static struct test_cmd cmds[] = { { "dump-fsmonitor", cmd__dump_fsmonitor }, { "dump-split-index", cmd__dump_split_index }, { "dump-untracked-cache", cmd__dump_untracked_cache }, + { "env-helper", cmd__env_helper }, { "example-decorate", cmd__example_decorate }, { "fast-rebase", cmd__fast_rebase }, { "fsmonitor-client", cmd__fsmonitor_client }, @@ -35,7 +38,6 @@ static struct test_cmd cmds[] = { { "hashmap", cmd__hashmap }, { "hash-speed", cmd__hash_speed }, { "hexdump", cmd__hexdump }, - { "index-version", cmd__index_version }, { "json-writer", cmd__json_writer }, { "lazy-init-name-hash", cmd__lazy_init_name_hash }, { "match-trees", cmd__match_trees }, @@ -72,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 6b46b6444b..a641c3a81d 100644 --- a/t/helper/test-tool.h +++ b/t/helper/test-tool.h @@ -1,12 +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); @@ -21,6 +22,7 @@ int cmd__dump_fsmonitor(int argc, const char **argv); int cmd__dump_split_index(int argc, const char **argv); int cmd__dump_untracked_cache(int argc, const char **argv); int cmd__dump_reftable(int argc, const char **argv); +int cmd__env_helper(int argc, const char **argv); int cmd__example_decorate(int argc, const char **argv); int cmd__fast_rebase(int argc, const char **argv); int cmd__fsmonitor_client(int argc, const char **argv); @@ -30,7 +32,6 @@ int cmd__getcwd(int argc, const char **argv); int cmd__hashmap(int argc, const char **argv); int cmd__hash_speed(int argc, const char **argv); int cmd__hexdump(int argc, const char **argv); -int cmd__index_version(int argc, const char **argv); int cmd__json_writer(int argc, const char **argv); int cmd__lazy_init_name_hash(int argc, const char **argv); int cmd__match_trees(int argc, const char **argv); @@ -65,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-trace2.c b/t/helper/test-trace2.c index a714130ece..d5ca0046c8 100644 --- a/t/helper/test-trace2.c +++ b/t/helper/test-trace2.c @@ -1,9 +1,10 @@ #include "test-tool.h" -#include "cache.h" #include "strvec.h" #include "run-command.h" #include "exec-cmd.h" #include "config.h" +#include "repository.h" +#include "trace2.h" typedef int(fn_unit_test)(int argc, const char **argv); @@ -44,7 +45,7 @@ static int get_i(int *p_value, const char *data) * [] "def_param" events for all of the "interesting" pre-defined * config settings. */ -static int ut_001return(int argc, const char **argv) +static int ut_001return(int argc UNUSED, const char **argv) { int rc; @@ -64,7 +65,7 @@ static int ut_001return(int argc, const char **argv) * [] "def_param" events for all of the "interesting" pre-defined * config settings. */ -static int ut_002exit(int argc, const char **argv) +static int ut_002exit(int argc UNUSED, const char **argv) { int rc; @@ -132,6 +133,7 @@ static int ut_003error(int argc, const char **argv) */ static int ut_004child(int argc, const char **argv) { + struct child_process cmd = CHILD_PROCESS_INIT; int result; /* @@ -141,7 +143,8 @@ static int ut_004child(int argc, const char **argv) if (!argc) return 0; - result = run_command_v_opt(argv, 0); + strvec_pushv(&cmd.args, argv); + result = run_command(&cmd); exit(result); } @@ -198,7 +201,7 @@ static int ut_006data(int argc, const char **argv) return 0; } -static int ut_007BUG(int argc, const char **argv) +static int ut_007BUG(int argc UNUSED, const char **argv UNUSED) { /* * Exercise BUG() to ensure that the message is printed to trace2. @@ -206,7 +209,7 @@ static int ut_007BUG(int argc, const char **argv) BUG("the bug message"); } -static int ut_008bug(int argc, const char **argv) +static int ut_008bug(int argc UNUSED, const char **argv UNUSED) { bug("a bug message"); bug("another bug message"); @@ -214,7 +217,7 @@ static int ut_008bug(int argc, const char **argv) return 0; } -static int ut_009bug_BUG(int argc, const char **argv) +static int ut_009bug_BUG(int argc UNUSED, const char **argv UNUSED) { bug("a bug message"); bug("another bug message"); @@ -222,13 +225,194 @@ static int ut_009bug_BUG(int argc, const char **argv) return 0; } -static int ut_010bug_BUG(int argc, const char **argv) +static int ut_010bug_BUG(int argc UNUSED, const char **argv UNUSED) { bug("a %s message", "bug"); BUG("a %s message", "BUG"); } /* + * Single-threaded timer test. Create several intervals using the + * TEST1 timer. The test script can verify that an aggregate Trace2 + * "timer" event is emitted indicating that we started+stopped the + * timer the requested number of times. + */ +static int ut_100timer(int argc, const char **argv) +{ + const char *usage_error = + "expect <count> <ms_delay>"; + + int count = 0; + int delay = 0; + int k; + + if (argc != 2) + die("%s", usage_error); + if (get_i(&count, argv[0])) + die("%s", usage_error); + if (get_i(&delay, argv[1])) + die("%s", usage_error); + + for (k = 0; k < count; k++) { + trace2_timer_start(TRACE2_TIMER_ID_TEST1); + sleep_millisec(delay); + trace2_timer_stop(TRACE2_TIMER_ID_TEST1); + } + + return 0; +} + +struct ut_101_data { + int count; + int delay; +}; + +static void *ut_101timer_thread_proc(void *_ut_101_data) +{ + struct ut_101_data *data = _ut_101_data; + int k; + + trace2_thread_start("ut_101"); + + for (k = 0; k < data->count; k++) { + trace2_timer_start(TRACE2_TIMER_ID_TEST2); + sleep_millisec(data->delay); + trace2_timer_stop(TRACE2_TIMER_ID_TEST2); + } + + trace2_thread_exit(); + return NULL; +} + +/* + * Multi-threaded timer test. Create several threads that each create + * several intervals using the TEST2 timer. The test script can verify + * that an individual Trace2 "th_timer" events for each thread and an + * aggregate "timer" event are generated. + */ +static int ut_101timer(int argc, const char **argv) +{ + const char *usage_error = + "expect <count> <ms_delay> <threads>"; + + struct ut_101_data data = { 0, 0 }; + int nr_threads = 0; + int k; + pthread_t *pids = NULL; + + if (argc != 3) + die("%s", usage_error); + if (get_i(&data.count, argv[0])) + die("%s", usage_error); + if (get_i(&data.delay, argv[1])) + die("%s", usage_error); + if (get_i(&nr_threads, argv[2])) + die("%s", usage_error); + + CALLOC_ARRAY(pids, nr_threads); + + for (k = 0; k < nr_threads; k++) { + if (pthread_create(&pids[k], NULL, ut_101timer_thread_proc, &data)) + die("failed to create thread[%d]", k); + } + + for (k = 0; k < nr_threads; k++) { + if (pthread_join(pids[k], NULL)) + die("failed to join thread[%d]", k); + } + + free(pids); + + return 0; +} + +/* + * Single-threaded counter test. Add several values to the TEST1 counter. + * The test script can verify that the final sum is reported in the "counter" + * event. + */ +static int ut_200counter(int argc, const char **argv) +{ + const char *usage_error = + "expect <v1> [<v2> [...]]"; + int value; + int k; + + if (argc < 1) + die("%s", usage_error); + + for (k = 0; k < argc; k++) { + if (get_i(&value, argv[k])) + die("invalid value[%s] -- %s", + argv[k], usage_error); + trace2_counter_add(TRACE2_COUNTER_ID_TEST1, value); + } + + return 0; +} + +/* + * Multi-threaded counter test. Create seveal threads that each increment + * the TEST2 global counter. The test script can verify that an individual + * "th_counter" event is generated with a partial sum for each thread and + * that a final aggregate "counter" event is generated. + */ + +struct ut_201_data { + int v1; + int v2; +}; + +static void *ut_201counter_thread_proc(void *_ut_201_data) +{ + struct ut_201_data *data = _ut_201_data; + + trace2_thread_start("ut_201"); + + trace2_counter_add(TRACE2_COUNTER_ID_TEST2, data->v1); + trace2_counter_add(TRACE2_COUNTER_ID_TEST2, data->v2); + + trace2_thread_exit(); + return NULL; +} + +static int ut_201counter(int argc, const char **argv) +{ + const char *usage_error = + "expect <v1> <v2> <threads>"; + + struct ut_201_data data = { 0, 0 }; + int nr_threads = 0; + int k; + pthread_t *pids = NULL; + + if (argc != 3) + die("%s", usage_error); + if (get_i(&data.v1, argv[0])) + die("%s", usage_error); + if (get_i(&data.v2, argv[1])) + die("%s", usage_error); + if (get_i(&nr_threads, argv[2])) + die("%s", usage_error); + + CALLOC_ARRAY(pids, nr_threads); + + for (k = 0; k < nr_threads; k++) { + if (pthread_create(&pids[k], NULL, ut_201counter_thread_proc, &data)) + die("failed to create thread[%d]", k); + } + + for (k = 0; k < nr_threads; k++) { + if (pthread_join(pids[k], NULL)) + die("failed to join thread[%d]", k); + } + + free(pids); + + return 0; +} + +/* * Usage: * test-tool trace2 <ut_name_1> <ut_usage_1> * test-tool trace2 <ut_name_2> <ut_usage_2> @@ -248,6 +432,12 @@ static struct unit_test ut_table[] = { { ut_008bug, "008bug", "" }, { ut_009bug_BUG, "009bug_BUG","" }, { ut_010bug_BUG, "010bug_BUG","" }, + + { ut_100timer, "100timer", "<count> <ms_delay>" }, + { ut_101timer, "101timer", "<count> <ms_delay> <threads>" }, + + { ut_200counter, "200counter", "<v1> [<v2> [<v3> [...]]]" }, + { ut_201counter, "201counter", "<v1> <v2> <threads>" }, }; /* clang-format on */ diff --git a/t/helper/test-userdiff.c b/t/helper/test-userdiff.c index a2b56b9cae..0ce31ce59f 100644 --- a/t/helper/test-userdiff.c +++ b/t/helper/test-userdiff.c @@ -1,5 +1,5 @@ #include "test-tool.h" -#include "cache.h" +#include "setup.h" #include "userdiff.h" #include "config.h" @@ -12,7 +12,9 @@ static int driver_cb(struct userdiff_driver *driver, return 0; } -static int cmd__userdiff_config(const char *var, const char *value, void *cb UNUSED) +static int cmd__userdiff_config(const char *var, const char *value, + const struct config_context *ctx UNUSED, + void *cb UNUSED) { if (userdiff_config(var, value) < 0) return -1; diff --git a/t/helper/test-wildmatch.c b/t/helper/test-wildmatch.c index 2c103d1824..b4ff5f986a 100644 --- a/t/helper/test-wildmatch.c +++ b/t/helper/test-wildmatch.c @@ -1,5 +1,5 @@ #include "test-tool.h" -#include "cache.h" +#include "wildmatch.h" int cmd__wildmatch(int argc, const char **argv) { diff --git a/t/helper/test-write-cache.c b/t/helper/test-write-cache.c index 8837717d36..f084034d38 100644 --- a/t/helper/test-write-cache.c +++ b/t/helper/test-write-cache.c @@ -1,6 +1,9 @@ +#define USE_THE_INDEX_VARIABLE #include "test-tool.h" -#include "cache.h" #include "lockfile.h" +#include "read-cache-ll.h" +#include "repository.h" +#include "setup.h" int cmd__write_cache(int argc, const char **argv) { @@ -9,9 +12,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/helper/test-xml-encode.c b/t/helper/test-xml-encode.c index a648bbd961..b2f330d1a4 100644 --- a/t/helper/test-xml-encode.c +++ b/t/helper/test-xml-encode.c @@ -6,7 +6,7 @@ static const char *utf8_replace_character = "�"; * Encodes (possibly incorrect) UTF-8 on <stdin> to <stdout>, to be embedded * in an XML file. */ -int cmd__xml_encode(int argc, const char **argv) +int cmd__xml_encode(int argc UNUSED, const char **argv UNUSED) { unsigned char buf[1024], tmp[4], *tmp2 = NULL; ssize_t cur = 0, len = 1, remaining = 0; diff --git a/t/interop/interop-lib.sh b/t/interop/interop-lib.sh index 3e0a2911d4..62f4481b6e 100644 --- a/t/interop/interop-lib.sh +++ b/t/interop/interop-lib.sh @@ -68,7 +68,7 @@ generate_wrappers () { wrap_git .bin/git.a "$DIR_A" && wrap_git .bin/git.b "$DIR_B" && write_script .bin/git <<-\EOF && - echo >&2 fatal: test tried to run generic git + echo >&2 fatal: test tried to run generic git: $* exit 1 EOF PATH=$(pwd)/.bin:$PATH diff --git a/t/lib-bundle-uri-protocol.sh b/t/lib-bundle-uri-protocol.sh new file mode 100644 index 0000000000..a4a1af8d02 --- /dev/null +++ b/t/lib-bundle-uri-protocol.sh @@ -0,0 +1,216 @@ +# Set up and run tests of the 'bundle-uri' command in protocol v2 +# +# The test that includes this script should set BUNDLE_URI_PROTOCOL +# to one of "file", "git", or "http". + +BUNDLE_URI_TEST_PARENT= +BUNDLE_URI_TEST_URI= +BUNDLE_URI_TEST_BUNDLE_URI= +case "$BUNDLE_URI_PROTOCOL" in +file) + BUNDLE_URI_PARENT=file_parent + BUNDLE_URI_REPO_URI="file://$PWD/file_parent" + BUNDLE_URI_BUNDLE_URI="$BUNDLE_URI_REPO_URI/fake.bdl" + test_set_prereq BUNDLE_URI_FILE + ;; +git) + . "$TEST_DIRECTORY"/lib-git-daemon.sh + start_git_daemon --export-all --enable=receive-pack + BUNDLE_URI_PARENT="$GIT_DAEMON_DOCUMENT_ROOT_PATH/parent" + BUNDLE_URI_REPO_URI="$GIT_DAEMON_URL/parent" + BUNDLE_URI_BUNDLE_URI="https://example.com/fake.bdl" + test_set_prereq BUNDLE_URI_GIT + ;; +http) + . "$TEST_DIRECTORY"/lib-httpd.sh + start_httpd + BUNDLE_URI_PARENT="$HTTPD_DOCUMENT_ROOT_PATH/http_parent" + BUNDLE_URI_REPO_URI="$HTTPD_URL/smart/http_parent" + BUNDLE_URI_BUNDLE_URI="https://example.com/fake.bdl" + test_set_prereq BUNDLE_URI_HTTP + ;; +*) + BUG "Need to pass valid BUNDLE_URI_PROTOCOL (was \"$BUNDLE_URI_PROTOCOL\")" + ;; +esac + +test_expect_success "setup protocol v2 $BUNDLE_URI_PROTOCOL:// tests" ' + git init "$BUNDLE_URI_PARENT" && + test_commit -C "$BUNDLE_URI_PARENT" one && + git -C "$BUNDLE_URI_PARENT" config uploadpack.advertiseBundleURIs true +' + +case "$BUNDLE_URI_PROTOCOL" in +http) + test_expect_success "setup config for $BUNDLE_URI_PROTOCOL:// tests" ' + git -C "$BUNDLE_URI_PARENT" config http.receivepack true + ' + ;; +*) + ;; +esac +BUNDLE_URI_BUNDLE_URI_ESCAPED=$(echo "$BUNDLE_URI_BUNDLE_URI" | test_uri_escape) + +test_expect_success "connect with $BUNDLE_URI_PROTOCOL:// using protocol v2: no bundle-uri" ' + test_when_finished "rm -f log" && + test_when_finished "git -C \"$BUNDLE_URI_PARENT\" config uploadpack.advertiseBundleURIs true" && + git -C "$BUNDLE_URI_PARENT" config uploadpack.advertiseBundleURIs false && + + GIT_TRACE_PACKET="$PWD/log" \ + git \ + -c protocol.version=2 \ + ls-remote --symref "$BUNDLE_URI_REPO_URI" \ + >actual 2>err && + + # Server responded using protocol v2 + grep "< version 2" log && + + ! grep bundle-uri log +' + +test_expect_success "connect with $BUNDLE_URI_PROTOCOL:// using protocol v2: have bundle-uri" ' + test_when_finished "rm -f log" && + + GIT_TRACE_PACKET="$PWD/log" \ + git \ + -c protocol.version=2 \ + ls-remote --symref "$BUNDLE_URI_REPO_URI" \ + >actual 2>err && + + # Server responded using protocol v2 + grep "< version 2" log && + + # Server advertised bundle-uri capability + grep "< bundle-uri" log +' + +test_expect_success "clone with $BUNDLE_URI_PROTOCOL:// using protocol v2: request bundle-uris" ' + test_when_finished "rm -rf log* cloned*" && + + GIT_TRACE_PACKET="$PWD/log" \ + git \ + -c transfer.bundleURI=false \ + -c protocol.version=2 \ + clone "$BUNDLE_URI_REPO_URI" cloned \ + >actual 2>err && + + # Server responded using protocol v2 + grep "< version 2" log && + + # Server advertised bundle-uri capability + grep "< bundle-uri" log && + + # Client did not issue bundle-uri command + ! grep "> command=bundle-uri" log && + + GIT_TRACE_PACKET="$PWD/log" \ + git \ + -c transfer.bundleURI=true \ + -c protocol.version=2 \ + clone "$BUNDLE_URI_REPO_URI" cloned2 \ + >actual 2>err && + + # Server responded using protocol v2 + grep "< version 2" log && + + # Server advertised bundle-uri capability + grep "< bundle-uri" log && + + # Client issued bundle-uri command + grep "> command=bundle-uri" log && + + GIT_TRACE_PACKET="$PWD/log3" \ + git \ + -c transfer.bundleURI=true \ + -c protocol.version=2 \ + clone --bundle-uri="$BUNDLE_URI_BUNDLE_URI" \ + "$BUNDLE_URI_REPO_URI" cloned3 \ + >actual 2>err && + + # Server responded using protocol v2 + grep "< version 2" log3 && + + # Server advertised bundle-uri capability + grep "< bundle-uri" log3 && + + # Client did not issue bundle-uri command (--bundle-uri override) + ! grep "> command=bundle-uri" log3 +' + +# The remaining tests will all assume transfer.bundleURI=true +# +# This test can be removed when transfer.bundleURI is enabled by default. +test_expect_success 'enable transfer.bundleURI for remaining tests' ' + git config --global transfer.bundleURI true +' + +test_expect_success "test bundle-uri with $BUNDLE_URI_PROTOCOL:// using protocol v2" ' + test_config -C "$BUNDLE_URI_PARENT" \ + bundle.only.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED" && + + # All data about bundle URIs + cat >expect <<-EOF && + [bundle] + version = 1 + mode = all + [bundle "only"] + uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED + EOF + + test-tool bundle-uri \ + ls-remote \ + "$BUNDLE_URI_REPO_URI" \ + >actual && + test_cmp_config_output expect actual +' + +test_expect_success "test bundle-uri with $BUNDLE_URI_PROTOCOL:// using protocol v2 and extra data" ' + test_config -C "$BUNDLE_URI_PARENT" \ + bundle.only.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED" && + + # Extra data should be ignored + test_config -C "$BUNDLE_URI_PARENT" bundle.only.extra bogus && + + # All data about bundle URIs + cat >expect <<-EOF && + [bundle] + version = 1 + mode = all + [bundle "only"] + uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED + EOF + + test-tool bundle-uri \ + ls-remote \ + "$BUNDLE_URI_REPO_URI" \ + >actual && + test_cmp_config_output expect actual +' + +test_expect_success "test bundle-uri with $BUNDLE_URI_PROTOCOL:// using protocol v2 with list" ' + test_config -C "$BUNDLE_URI_PARENT" \ + bundle.bundle1.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED-1.bdl" && + test_config -C "$BUNDLE_URI_PARENT" \ + bundle.bundle2.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED-2.bdl" && + test_config -C "$BUNDLE_URI_PARENT" \ + bundle.bundle3.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED-3.bdl" && + + # All data about bundle URIs + cat >expect <<-EOF && + [bundle] + version = 1 + mode = all + [bundle "bundle1"] + uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED-1.bdl + [bundle "bundle2"] + uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED-2.bdl + [bundle "bundle3"] + uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED-3.bdl + EOF + + test-tool bundle-uri \ + ls-remote \ + "$BUNDLE_URI_REPO_URI" \ + >actual && + test_cmp_config_output expect actual +' diff --git a/t/lib-commit-graph.sh b/t/lib-commit-graph.sh index 5d79e1a4e9..89b26676fb 100755 --- a/t/lib-commit-graph.sh +++ b/t/lib-commit-graph.sh @@ -14,24 +14,37 @@ graph_git_two_modes() { test_cmp expect output } +# graph_git_behavior <name> <directory> <branch> <compare> +# +# Ensures that a handful of traversal operations produce the same +# results with and without the commit-graph in use. +# +# NOTE: it is a bug to call this function with <directory> containing +# any characters in $IFS. graph_git_behavior() { MSG=$1 DIR=$2 BRANCH=$3 COMPARE=$4 test_expect_success "check normal git operations: $MSG" ' - cd "$TRASH_DIRECTORY/$DIR" && - graph_git_two_modes "log --oneline $BRANCH" && - graph_git_two_modes "log --topo-order $BRANCH" && - graph_git_two_modes "log --graph $COMPARE..$BRANCH" && - graph_git_two_modes "branch -vv" && - graph_git_two_modes "merge-base -a $BRANCH $COMPARE" + graph_git_two_modes "${DIR:+-C $DIR} log --oneline $BRANCH" && + graph_git_two_modes "${DIR:+-C $DIR} log --topo-order $BRANCH" && + graph_git_two_modes "${DIR:+-C $DIR} log --graph $COMPARE..$BRANCH" && + graph_git_two_modes "${DIR:+-C $DIR} branch -vv" && + graph_git_two_modes "${DIR:+-C $DIR} merge-base -a $BRANCH $COMPARE" ' } graph_read_expect() { OPTIONAL="" NUM_CHUNKS=3 + DIR="." + if test "$1" = -C + then + shift + DIR="$1" + shift + fi if test -n "$2" then OPTIONAL=" $2" @@ -47,12 +60,15 @@ graph_read_expect() { then OPTIONS=" read_generation_data" fi - cat >expect <<- EOF + cat >"$DIR/expect" <<-EOF header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0 num_commits: $1 chunks: oid_fanout oid_lookup commit_metadata$OPTIONAL options:$OPTIONS EOF - test-tool read-graph >output && - test_cmp expect output + ( + cd "$DIR" && + test-tool read-graph >output && + test_cmp expect output + ) } diff --git a/t/lib-credential.sh b/t/lib-credential.sh index 5ea8bc9f1d..15fc9a31e2 100644 --- a/t/lib-credential.sh +++ b/t/lib-credential.sh @@ -43,6 +43,13 @@ helper_test_clean() { reject $1 https example.com store-user reject $1 https example.com user1 reject $1 https example.com user2 + reject $1 https example.com user-expiry + reject $1 https example.com user-expiry-overwrite + reject $1 https example.com user4 + reject $1 https example.com user-distinct-pass + reject $1 https example.com user-overwrite + reject $1 https example.com user-erase1 + reject $1 https example.com user-erase2 reject $1 http path.tld user reject $1 https timeout.tld user reject $1 https sso.tld @@ -166,6 +173,49 @@ helper_test() { EOF ' + test_expect_success "helper ($HELPER) overwrites on store" ' + check approve $HELPER <<-\EOF && + protocol=https + host=example.com + username=user-overwrite + password=pass1 + EOF + check approve $HELPER <<-\EOF && + protocol=https + host=example.com + username=user-overwrite + password=pass2 + EOF + check fill $HELPER <<-\EOF && + protocol=https + host=example.com + username=user-overwrite + -- + protocol=https + host=example.com + username=user-overwrite + password=pass2 + EOF + check reject $HELPER <<-\EOF && + protocol=https + host=example.com + username=user-overwrite + password=pass2 + EOF + check fill $HELPER <<-\EOF + protocol=https + host=example.com + username=user-overwrite + -- + protocol=https + host=example.com + username=user-overwrite + password=askpass-password + -- + askpass: Password for '\''https://user-overwrite@example.com'\'': + EOF + ' + test_expect_success "helper ($HELPER) can forget host" ' check reject $HELPER <<-\EOF && protocol=https @@ -220,6 +270,31 @@ helper_test() { EOF ' + test_expect_success "helper ($HELPER) does not erase a password distinct from input" ' + check approve $HELPER <<-\EOF && + protocol=https + host=example.com + username=user-distinct-pass + password=pass1 + EOF + check reject $HELPER <<-\EOF && + protocol=https + host=example.com + username=user-distinct-pass + password=pass2 + EOF + check fill $HELPER <<-\EOF + protocol=https + host=example.com + username=user-distinct-pass + -- + protocol=https + host=example.com + username=user-distinct-pass + password=pass1 + EOF + ' + test_expect_success "helper ($HELPER) can forget user" ' check reject $HELPER <<-\EOF && protocol=https @@ -270,6 +345,66 @@ helper_test() { password= EOF ' + + test_expect_success "helper ($HELPER) erases all matching credentials" ' + check approve $HELPER <<-\EOF && + protocol=https + host=example.com + username=user-erase1 + password=pass1 + EOF + check approve $HELPER <<-\EOF && + protocol=https + host=example.com + username=user-erase2 + password=pass1 + EOF + check reject $HELPER <<-\EOF && + protocol=https + host=example.com + EOF + check fill $HELPER <<-\EOF + protocol=https + host=example.com + -- + protocol=https + host=example.com + username=askpass-username + password=askpass-password + -- + askpass: Username for '\''https://example.com'\'': + askpass: Password for '\''https://askpass-username@example.com'\'': + EOF + ' + + : ${GIT_TEST_LONG_CRED_BUFFER:=1024} + # 23 bytes accounts for "wwwauth[]=basic realm=" plus NUL + LONG_VALUE_LEN=$((GIT_TEST_LONG_CRED_BUFFER - 23)) + LONG_VALUE=$(perl -e 'print "a" x shift' $LONG_VALUE_LEN) + + test_expect_success "helper ($HELPER) not confused by long header" ' + check approve $HELPER <<-\EOF && + protocol=https + host=victim.example.com + username=user + password=to-be-stolen + EOF + + check fill $HELPER <<-EOF + protocol=https + host=badguy.example.com + wwwauth[]=basic realm=${LONG_VALUE}host=victim.example.com + -- + protocol=https + host=badguy.example.com + username=askpass-username + password=askpass-password + wwwauth[]=basic realm=${LONG_VALUE}host=victim.example.com + -- + askpass: Username for '\''https://badguy.example.com'\'': + askpass: Password for '\''https://askpass-username@badguy.example.com'\'': + EOF + ' } helper_test_timeout() { @@ -298,6 +433,110 @@ helper_test_timeout() { ' } +helper_test_password_expiry_utc() { + HELPER=$1 + + test_expect_success "helper ($HELPER) stores password_expiry_utc" ' + check approve $HELPER <<-\EOF + protocol=https + host=example.com + username=user-expiry + password=pass + password_expiry_utc=9999999999 + EOF + ' + + test_expect_success "helper ($HELPER) gets password_expiry_utc" ' + check fill $HELPER <<-\EOF + protocol=https + host=example.com + username=user-expiry + -- + protocol=https + host=example.com + username=user-expiry + password=pass + password_expiry_utc=9999999999 + -- + EOF + ' + + test_expect_success "helper ($HELPER) overwrites when password_expiry_utc changes" ' + check approve $HELPER <<-\EOF && + protocol=https + host=example.com + username=user-expiry-overwrite + password=pass1 + password_expiry_utc=9999999998 + EOF + check approve $HELPER <<-\EOF && + protocol=https + host=example.com + username=user-expiry-overwrite + password=pass2 + password_expiry_utc=9999999999 + EOF + check fill $HELPER <<-\EOF && + protocol=https + host=example.com + username=user-expiry-overwrite + -- + protocol=https + host=example.com + username=user-expiry-overwrite + password=pass2 + password_expiry_utc=9999999999 + EOF + check reject $HELPER <<-\EOF && + protocol=https + host=example.com + username=user-expiry-overwrite + password=pass2 + EOF + check fill $HELPER <<-\EOF + protocol=https + host=example.com + username=user-expiry-overwrite + -- + protocol=https + host=example.com + username=user-expiry-overwrite + password=askpass-password + -- + askpass: Password for '\''https://user-expiry-overwrite@example.com'\'': + EOF + ' +} + +helper_test_oauth_refresh_token() { + HELPER=$1 + + test_expect_success "helper ($HELPER) stores oauth_refresh_token" ' + check approve $HELPER <<-\EOF + protocol=https + host=example.com + username=user4 + password=pass + oauth_refresh_token=xyzzy + EOF + ' + + test_expect_success "helper ($HELPER) gets oauth_refresh_token" ' + check fill $HELPER <<-\EOF + protocol=https + host=example.com + username=user4 + -- + protocol=https + host=example.com + username=user4 + password=pass + oauth_refresh_token=xyzzy + -- + EOF + ' +} + write_script askpass <<\EOF echo >&2 askpass: $* what=$(echo $1 | cut -d" " -f1 | tr A-Z a-z | tr -cd a-z) diff --git a/t/lib-diff-alternative.sh b/t/lib-diff-alternative.sh index 8d1e408bb5..c4dc2d46dc 100644 --- a/t/lib-diff-alternative.sh +++ b/t/lib-diff-alternative.sh @@ -105,10 +105,67 @@ index $file1..$file2 100644 } EOF + cat >expect_diffstat <<EOF + file1 => file2 | 21 ++++++++++----------- + 1 file changed, 10 insertions(+), 11 deletions(-) +EOF + STRATEGY=$1 + test_expect_success "setup attributes files for tests with $STRATEGY" ' + git checkout -b master && + echo "file* diff=driver" >.gitattributes && + git add file1 file2 .gitattributes && + git commit -m "adding files" && + git checkout -b branchA && + echo "file* diff=driverA" >.gitattributes && + git add .gitattributes && + git commit -m "adding driverA as diff driver" && + git checkout master && + git clone --bare --no-local . bare.git + ' + + test_expect_success "$STRATEGY diff from attributes" ' + test_must_fail git -c diff.driver.algorithm=$STRATEGY diff --no-index file1 file2 > output && + test_cmp expect output + ' + + test_expect_success "diff from attributes with bare repo with source" ' + git -C bare.git --attr-source=branchA -c diff.driver.algorithm=myers \ + -c diff.driverA.algorithm=$STRATEGY \ + diff HEAD:file1 HEAD:file2 >output && + test_cmp expect output + ' + + test_expect_success "diff from attributes with bare repo with invalid source" ' + test_must_fail git -C bare.git --attr-source=invalid-branch diff \ + HEAD:file1 HEAD:file2 + ' + + test_expect_success "$STRATEGY diff from attributes has valid diffstat" ' + echo "file* diff=driver" >.gitattributes && + git config diff.driver.algorithm "$STRATEGY" && + test_must_fail git diff --stat --no-index file1 file2 > output && + test_cmp expect_diffstat output + ' + test_expect_success "$STRATEGY diff" ' - test_must_fail git diff --no-index "--$STRATEGY" file1 file2 > output && + test_must_fail git diff --no-index "--diff-algorithm=$STRATEGY" file1 file2 > output && + test_cmp expect output + ' + + test_expect_success "$STRATEGY diff command line precedence before attributes" ' + echo "file* diff=driver" >.gitattributes && + git config diff.driver.algorithm myers && + test_must_fail git diff --no-index "--diff-algorithm=$STRATEGY" file1 file2 > output && + test_cmp expect output + ' + + test_expect_success "$STRATEGY diff attributes precedence before config" ' + git config diff.algorithm default && + echo "file* diff=driver" >.gitattributes && + git config diff.driver.algorithm "$STRATEGY" && + test_must_fail git diff --no-index file1 file2 > output && test_cmp expect output ' diff --git a/t/lib-gpg.sh b/t/lib-gpg.sh index 114785586a..83b83c9abb 100644 --- a/t/lib-gpg.sh +++ b/t/lib-gpg.sh @@ -45,6 +45,28 @@ test_lazy_prereq GPG ' "$TEST_DIRECTORY"/lib-gpg/keyring.gpg && gpg --homedir "${GNUPGHOME}" --import-ownertrust \ "$TEST_DIRECTORY"/lib-gpg/ownertrust && + gpg --homedir "${GNUPGHOME}" --update-trustdb && + gpg --homedir "${GNUPGHOME}" </dev/null >/dev/null \ + --sign -u committer@example.com + ;; + esac +' + +test_lazy_prereq GPG2 ' + gpg_version=$(gpg --version 2>&1) + test $? != 127 || exit 1 + + case "$gpg_version" in + "gpg (GnuPG) "[01].*) + say "This test requires a GPG version >= v2.0.0" + exit 1 + ;; + *) + (gpgconf --kill all || : ) && + gpg --homedir "${GNUPGHOME}" --import \ + "$TEST_DIRECTORY"/lib-gpg/keyring.gpg && + gpg --homedir "${GNUPGHOME}" --import-ownertrust \ + "$TEST_DIRECTORY"/lib-gpg/ownertrust && gpg --homedir "${GNUPGHOME}" </dev/null >/dev/null \ --sign -u committer@example.com ;; @@ -135,8 +157,9 @@ test_lazy_prereq GPGSSH ' ' test_lazy_prereq GPGSSH_VERIFYTIME ' + test_have_prereq GPGSSH && # Check if ssh-keygen has a verify-time option by passing an invalid date to it - ssh-keygen -Overify-time=INVALID -Y check-novalidate -s doesnotmatter 2>&1 | grep -q -F "Invalid \"verify-time\"" && + ssh-keygen -Overify-time=INVALID -Y check-novalidate -n "git" -s doesnotmatter 2>&1 | grep -q -F "Invalid \"verify-time\"" && # Set up keys with key lifetimes ssh-keygen -t ed25519 -N "" -C "timeboxed valid key" -f "${GPGSSH_KEY_TIMEBOXEDVALID}" >/dev/null && diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh index 1f6b9b08d1..2fb1b2ae56 100644 --- a/t/lib-httpd.sh +++ b/t/lib-httpd.sh @@ -25,6 +25,7 @@ # LIB_HTTPD_DAV enable DAV # LIB_HTTPD_SVN enable SVN at given location (e.g. "svn") # LIB_HTTPD_SSL enable SSL +# LIB_HTTPD_PROXY enable proxy # # Copyright (c) 2008 Clemens Buchacher <drizzd@aon.at> # @@ -65,7 +66,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 @@ -98,16 +100,19 @@ then fi HTTPD_VERSION=$($LIB_HTTPD_PATH -v | \ - sed -n 's/^Server version: Apache\/\([0-9]*\)\..*$/\1/p; q') + sed -n 's/^Server version: Apache\/\([0-9.]*\).*$/\1/p; q') +HTTPD_VERSION_MAJOR=$(echo $HTTPD_VERSION | cut -d. -f1) +HTTPD_VERSION_MINOR=$(echo $HTTPD_VERSION | cut -d. -f2) -if test -n "$HTTPD_VERSION" +if test -n "$HTTPD_VERSION_MAJOR" then if test -z "$LIB_HTTPD_MODULE_PATH" then - if ! test $HTTPD_VERSION -ge 2 + if ! test "$HTTPD_VERSION_MAJOR" -eq 2 || + ! test "$HTTPD_VERSION_MINOR" -ge 4 then test_skip_or_die GIT_TEST_HTTPD \ - "at least Apache version 2 is required" + "at least Apache version 2.4 is required" fi if ! test -d "$DEFAULT_HTTPD_MODULE_PATH" then @@ -129,6 +134,7 @@ install_script () { prepare_httpd() { mkdir -p "$HTTPD_DOCUMENT_ROOT_PATH" cp "$TEST_PATH"/passwd "$HTTPD_ROOT_PATH" + cp "$TEST_PATH"/proxy-passwd "$HTTPD_ROOT_PATH" install_script incomplete-length-upload-pack-v2-http.sh install_script incomplete-body-upload-pack-v2-http.sh install_script error-no-report.sh @@ -136,6 +142,7 @@ prepare_httpd() { install_script error-smart-http.sh install_script error.sh install_script apply-one-time-perl.sh + install_script nph-custom-auth.sh ln -s "$LIB_HTTPD_MODULE_PATH" "$HTTPD_ROOT_PATH/modules" @@ -172,6 +179,30 @@ prepare_httpd() { export LIB_HTTPD_SVN LIB_HTTPD_SVNPATH fi fi + + if test -n "$LIB_HTTPD_PROXY" + then + HTTPD_PARA="$HTTPD_PARA -DPROXY" + fi +} + +enable_http2 () { + HTTPD_PARA="$HTTPD_PARA -DHTTP2" + test_set_prereq HTTP2 +} + +enable_cgipassauth () { + # We are looking for 2.4.13 or more recent. Since we only support + # 2.4 and up, no need to check for older major/minor. + if test "$HTTPD_VERSION_MAJOR" = 2 && + test "$HTTPD_VERSION_MINOR" = 4 && + test "$(echo $HTTPD_VERSION | cut -d. -f3)" -lt 13 + then + echo >&4 "apache $HTTPD_VERSION too old for CGIPassAuth" + return + fi + HTTPD_PARA="$HTTPD_PARA -DUSE_CGIPASSAUTH" + test_set_prereq CGIPASSAUTH } start_httpd() { @@ -211,8 +242,12 @@ test_http_push_nonff () { git commit -a -m path2 --amend && test_must_fail git push -v origin >output 2>&1 && - (cd "$REMOTE_REPO" && - test $HEAD = $(git rev-parse --verify HEAD)) + ( + cd "$REMOTE_REPO" && + echo "$HEAD" >expect && + git rev-parse --verify HEAD >actual && + test_cmp expect actual + ) ' test_expect_success 'non-fast-forward push show ref status' ' @@ -274,11 +309,11 @@ expect_askpass() { none) ;; pass) - echo "askpass: Password for 'http://$2@$dest': " + echo "askpass: Password for '$HTTPD_PROTO://$2@$dest': " ;; both) - echo "askpass: Username for 'http://$dest': " - echo "askpass: Password for 'http://$2@$dest': " + echo "askpass: Username for '$HTTPD_PROTO://$dest': " + echo "askpass: Password for '$HTTPD_PROTO://$2@$dest': " ;; *) false diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf index 706799391b..a22d138605 100644 --- a/t/lib-httpd/apache.conf +++ b/t/lib-httpd/apache.conf @@ -29,17 +29,11 @@ ErrorLog error.log LoadModule setenvif_module modules/mod_setenvif.so </IfModule> -<IfVersion < 2.4> -LockFile accept.lock -</IfVersion> - -<IfVersion < 2.1> -<IfModule !mod_auth.c> - LoadModule auth_module modules/mod_auth.so -</IfModule> -</IfVersion> +<IfDefine HTTP2> +LoadModule http2_module modules/mod_http2.so +Protocols h2 h2c +</IfDefine> -<IfVersion >= 2.1> <IfModule !mod_auth_basic.c> LoadModule auth_basic_module modules/mod_auth_basic.so </IfModule> @@ -52,9 +46,23 @@ LockFile accept.lock <IfModule !mod_authz_host.c> LoadModule authz_host_module modules/mod_authz_host.so </IfModule> -</IfVersion> -<IfVersion >= 2.4> +<IfDefine PROXY> +<IfModule !mod_proxy.c> + LoadModule proxy_module modules/mod_proxy.so +</IfModule> +<IfModule !mod_proxy_http.c> + LoadModule proxy_http_module modules/mod_proxy_http.so +</IfModule> +ProxyRequests On +<Proxy "*"> + AuthType Basic + AuthName "proxy-auth" + AuthUserFile proxy-passwd + Require valid-user +</Proxy> +</IfDefine> + <IfModule !mod_authn_core.c> LoadModule authn_core_module modules/mod_authn_core.so </IfModule> @@ -64,13 +72,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> -</IfVersion> + +<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> PassEnv GIT_VALGRIND PassEnv GIT_VALGRIND_OPTIONS @@ -86,6 +101,8 @@ PassEnv LC_ALL Alias /dumb/ www/ Alias /auth/dumb/ www/auth/dumb/ +SetEnv PERL_PATH ${PERL_PATH} + <LocationMatch /smart/> SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH} SetEnv GIT_HTTP_EXPORT_ALL @@ -110,6 +127,10 @@ Alias /auth/dumb/ www/auth/dumb/ Header set Set-Cookie name=value </LocationMatch> <LocationMatch /smart_headers/> + <RequireAll> + Require expr %{HTTP:x-magic-one} == 'abra' + Require expr %{HTTP:x-magic-two} == 'cadabra' + </RequireAll> SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH} SetEnv GIT_HTTP_EXPORT_ALL </LocationMatch> @@ -122,6 +143,13 @@ Alias /auth/dumb/ www/auth/dumb/ SetEnv GIT_HTTP_EXPORT_ALL SetEnv GIT_PROTOCOL </LocationMatch> +<LocationMatch /custom_auth/> + SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH} + SetEnv GIT_HTTP_EXPORT_ALL + <IfDefine USE_CGIPASSAUTH> + CGIPassAuth on + </IfDefine> +</LocationMatch> ScriptAlias /smart/incomplete_length/git-upload-pack incomplete-length-upload-pack-v2-http.sh/ ScriptAlias /smart/incomplete_body/git-upload-pack incomplete-body-upload-pack-v2-http.sh/ ScriptAlias /smart/no_report/git-receive-pack error-no-report.sh/ @@ -131,6 +159,7 @@ ScriptAlias /broken_smart/ broken-smart-http.sh/ ScriptAlias /error_smart/ error-smart-http.sh/ ScriptAlias /error/ error.sh/ ScriptAliasMatch /one_time_perl/(.*) apply-one-time-perl.sh/$1 +ScriptAliasMatch /custom_auth/(.*) nph-custom-auth.sh/$1 <Directory ${GIT_EXEC_PATH}> Options FollowSymlinks </Directory> @@ -192,18 +221,6 @@ RewriteRule ^/intern-redir/(.*)/foo$ /smart/$1 [PT] RewriteRule ^/redir-objects/(.*/info/refs)$ /dumb/$1 [PT] RewriteRule ^/redir-objects/(.*/objects/.*)$ /dumb/$1 [R=301] -# Apache 2.2 does not understand <RequireAll>, so we use RewriteCond. -# And as RewriteCond does not allow testing for non-matches, we match -# the desired case first (one has abra, two has cadabra), and let it -# pass by marking the RewriteRule as [L], "last rule, do not process -# any other matching RewriteRules after this"), and then have another -# RewriteRule that matches all other cases and lets them fail via '[F]', -# "fail the request". -RewriteCond %{HTTP:x-magic-one} =abra -RewriteCond %{HTTP:x-magic-two} =cadabra -RewriteRule ^/smart_headers/.* - [L] -RewriteRule ^/smart_headers/.* - [F] - <IfDefine SSL> LoadModule ssl_module modules/mod_ssl.so @@ -212,7 +229,6 @@ SSLCertificateKeyFile httpd.pem SSLRandomSeed startup file:/dev/urandom 512 SSLRandomSeed connect file:/dev/urandom 512 SSLSessionCache none -SSLMutex file:ssl_mutex SSLEngine On </IfDefine> diff --git a/t/lib-httpd/apply-one-time-perl.sh b/t/lib-httpd/apply-one-time-perl.sh index 09a0abdff7..d7f9fed6ae 100644 --- a/t/lib-httpd/apply-one-time-perl.sh +++ b/t/lib-httpd/apply-one-time-perl.sh @@ -13,7 +13,7 @@ then export LC_ALL "$GIT_EXEC_PATH/git-http-backend" >out - perl -pe "$(cat one-time-perl)" out >out_modified + "$PERL_PATH" -pe "$(cat one-time-perl)" out >out_modified if cmp -s out out_modified then diff --git a/t/lib-httpd/nph-custom-auth.sh b/t/lib-httpd/nph-custom-auth.sh new file mode 100644 index 0000000000..f5345e775e --- /dev/null +++ b/t/lib-httpd/nph-custom-auth.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +VALID_CREDS_FILE=custom-auth.valid +CHALLENGE_FILE=custom-auth.challenge + +# +# If $VALID_CREDS_FILE exists in $HTTPD_ROOT_PATH, consider each line as a valid +# credential for the current request. Each line in the file is considered a +# valid HTTP Authorization header value. For example: +# +# Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== +# +# If $CHALLENGE_FILE exists in $HTTPD_ROOT_PATH, output the contents as headers +# in a 401 response if no valid authentication credentials were included in the +# request. For example: +# +# WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0 +# WWW-Authenticate: Basic realm="example.com" +# + +if test -n "$HTTP_AUTHORIZATION" && \ + grep -Fqsx "${HTTP_AUTHORIZATION}" "$VALID_CREDS_FILE" +then + # Note that although git-http-backend returns a status line, it + # does so using a CGI 'Status' header. Because this script is an + # No Parsed Headers (NPH) script, we must return a real HTTP + # status line. + # This is only a test script, so we don't bother to check for + # the actual status from git-http-backend and always return 200. + echo 'HTTP/1.1 200 OK' + exec "$GIT_EXEC_PATH"/git-http-backend +fi + +echo 'HTTP/1.1 401 Authorization Required' +if test -f "$CHALLENGE_FILE" +then + cat "$CHALLENGE_FILE" +fi +echo diff --git a/t/lib-httpd/proxy-passwd b/t/lib-httpd/proxy-passwd new file mode 100644 index 0000000000..77c25138e0 --- /dev/null +++ b/t/lib-httpd/proxy-passwd @@ -0,0 +1 @@ +proxuser:2x7tAukjAED5M diff --git a/t/lib-httpd/ssl.cnf b/t/lib-httpd/ssl.cnf index 6dab2579cb..812e8253f0 100644 --- a/t/lib-httpd/ssl.cnf +++ b/t/lib-httpd/ssl.cnf @@ -1,7 +1,7 @@ RANDFILE = $ENV::RANDFILE_PATH [ req ] -default_bits = 1024 +default_bits = 2048 distinguished_name = req_distinguished_name prompt = no [ req_distinguished_name ] diff --git a/t/lib-patch-mode.sh b/t/lib-patch-mode.sh index cfd76bf987..89ca1f7805 100644 --- a/t/lib-patch-mode.sh +++ b/t/lib-patch-mode.sh @@ -29,8 +29,12 @@ set_and_save_state () { # verify_state <path> <expected-worktree-content> <expected-index-content> verify_state () { - test "$(cat "$1")" = "$2" && - test "$(git show :"$1")" = "$3" + echo "$2" >expect && + test_cmp expect "$1" && + + echo "$3" >expect && + git show :"$1" >actual && + test_cmp expect actual } # verify_saved_state <path> @@ -46,5 +50,6 @@ save_head () { } verify_saved_head () { - test "$(cat _head)" = "$(git rev-parse HEAD)" + git rev-parse HEAD >actual && + test_cmp _head actual } diff --git a/t/lib-rebase.sh b/t/lib-rebase.sh index b57541356b..11d2dc9fe3 100644 --- a/t/lib-rebase.sh +++ b/t/lib-rebase.sh @@ -8,18 +8,21 @@ # - check that non-commit messages have a certain line count with $EXPECT_COUNT # - check the commit count in the commit message header with $EXPECT_HEADER_COUNT # - rewrite a rebase -i script as directed by $FAKE_LINES. -# $FAKE_LINES consists of a sequence of words separated by spaces. -# The following word combinations are possible: +# $FAKE_LINES consists of a sequence of words separated by spaces; +# spaces inside the words are encoded as underscores. +# The following words are possible: # -# "<lineno>" -- add a "pick" line with the SHA1 taken from the -# specified line. +# "<cmd>" -- override the command for the next line specification. Can be +# "pick", "squash", "fixup[_-(c|C)]", "edit", "reword", "drop", +# "merge[_-(c|C)_<rev>]", or "bad" for an invalid command. # -# "<cmd> <lineno>" -- add a line with the specified command -# ("pick", "squash", "fixup"|"fixup_-C"|"fixup_-c", "edit", "reword" or "drop") -# and the SHA1 taken from the specified line. +# "<lineno>" -- add a command, using the specified line as a template. +# If the command has not been overridden, the line will be copied +# verbatim, usually resulting in a "pick" line. # -# "_" -- add a space, like "fixup_-C" implies "fixup -C" and -# "exec_cmd_with_args" add an "exec cmd with args" line. +# "fakesha" -- add a command ("pick" by default), using a fake SHA1. +# +# "exec_[command...]", "break" -- add the specified command. # # "#" -- Add a comment line. # @@ -49,7 +52,7 @@ set_fake_editor () { action=\& for line in $FAKE_LINES; do case $line in - pick|p|squash|s|fixup|f|edit|e|reword|r|drop|d|label|l|reset|r|merge|m) + pick|p|squash|s|fixup|f|edit|e|reword|r|drop|d|label|l|reset|t|merge|m) action="$line";; exec_*|x_*|break|b) echo "$line" | sed 's/_/ /g' >> "$1";; @@ -60,11 +63,11 @@ set_fake_editor () { ">") echo >> "$1";; bad) - action="badcmd";; + action="pickled";; fakesha) test \& != "$action" || action=pick echo "$action XXXXXXX False commit" >> "$1" - action=pick;; + action=\&;; *) sed -n "${line}s/^[a-z][a-z]*/$action/p" < "$1".tmp >> "$1" action=\&;; @@ -211,6 +214,9 @@ check_reworded_commits () { # usage: set_replace_editor <file> # # Replace the todo file with the exact contents of the given file. +# N.B. sets GIT_SEQUENCE_EDITOR rather than EDITOR so it can be +# combined with set_fake_editor to reword commits and replace the +# todo list set_replace_editor () { cat >script <<-\EOF && cat FILENAME >"$1" @@ -219,6 +225,7 @@ set_replace_editor () { cat "$1" EOF - sed -e "s/FILENAME/$1/g" <script | write_script fake-editor.sh && - test_set_editor "$(pwd)/fake-editor.sh" + sed -e "s/FILENAME/$1/g" script | + write_script fake-sequence-editor.sh && + test_set_sequence_editor "$(pwd)/fake-sequence-editor.sh" } diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh index 2d31fcfda1..9acb0d5d19 100644 --- a/t/lib-submodule-update.sh +++ b/t/lib-submodule-update.sh @@ -168,20 +168,16 @@ replace_gitfile_with_git_dir () { # Note that this only supports submodules at the root level of the # superproject, with the default name, i.e. same as its path. test_git_directory_is_unchanged () { - ( - cd ".git/modules/$1" && - # does core.worktree point at the right place? - test "$(git config core.worktree)" = "../../../$1" && - # remove it temporarily before comparing, as - # "$1/.git/config" lacks it... - git config --unset core.worktree - ) && + # does core.worktree point at the right place? + echo "../../../$1" >expect && + git -C ".git/modules/$1" config core.worktree >actual && + test_cmp expect actual && + # remove it temporarily before comparing, as + # "$1/.git/config" lacks it... + git -C ".git/modules/$1" config --unset core.worktree && diff -r ".git/modules/$1" "$1/.git" && - ( - # ... and then restore. - cd ".git/modules/$1" && - git config core.worktree "../../../$1" - ) + # ... and then restore. + git -C ".git/modules/$1" config core.worktree "../../../$1" } test_git_directory_exists () { @@ -189,7 +185,9 @@ test_git_directory_exists () { if test -f sub1/.git then # does core.worktree point at the right place? - test "$(git -C .git/modules/$1 config core.worktree)" = "../../../$1" + echo "../../../$1" >expect && + git -C ".git/modules/$1" config core.worktree >actual && + test_cmp expect actual fi } @@ -804,7 +802,7 @@ test_submodule_recursing_with_args_common () { git branch -t no_submodule origin/no_submodule && $command no_submodule && test_superproject_content origin/no_submodule && - ! test_path_is_dir sub1 && + test_path_is_missing sub1 && test_must_fail git config -f .git/modules/sub1/config core.worktree && test_must_fail git config -f .git/modules/sub1/modules/sub2/config core.worktree ) 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/p1500-graph-walks.sh b/t/perf/p1500-graph-walks.sh new file mode 100755 index 0000000000..e14e7620cc --- /dev/null +++ b/t/perf/p1500-graph-walks.sh @@ -0,0 +1,50 @@ +#!/bin/sh + +test_description='Commit walk performance tests' +. ./perf-lib.sh + +test_perf_large_repo + +test_expect_success 'setup' ' + git for-each-ref --format="%(refname)" "refs/heads/*" "refs/tags/*" >allrefs && + sort -r allrefs | head -n 50 >refs && + for ref in $(cat refs) + do + git branch -f ref-$ref $ref && + echo ref-$ref || + return 1 + done >branches && + for ref in $(cat refs) + do + git tag -f tag-$ref $ref && + echo tag-$ref || + return 1 + done >tags && + git commit-graph write --reachable +' + +test_perf 'ahead-behind counts: git for-each-ref' ' + git for-each-ref --format="%(ahead-behind:HEAD)" --stdin <refs +' + +test_perf 'ahead-behind counts: git branch' ' + xargs git branch -l --format="%(ahead-behind:HEAD)" <branches +' + +test_perf 'ahead-behind counts: git tag' ' + xargs git tag -l --format="%(ahead-behind:HEAD)" <tags +' + +test_perf 'contains: git for-each-ref --merged' ' + git for-each-ref --merged=HEAD --stdin <refs +' + +test_perf 'contains: git branch --merged' ' + xargs git branch --merged=HEAD <branches +' + +test_perf 'contains: git tag --merged' ' + xargs git tag --merged=HEAD <tags +' + +test_done diff --git a/t/perf/p2000-sparse-operations.sh b/t/perf/p2000-sparse-operations.sh index fce8151d41..39e92b0841 100755 --- a/t/perf/p2000-sparse-operations.sh +++ b/t/perf/p2000-sparse-operations.sh @@ -43,6 +43,7 @@ test_expect_success 'setup repo and indexes' ' done && git sparse-checkout init --cone && + git tag -a v1.0 -m "Final" && git sparse-checkout set $SPARSE_CONE && git checkout -b wide $OLD_COMMIT && @@ -124,5 +125,15 @@ test_perf_on_all git read-tree -mu HEAD test_perf_on_all git checkout-index -f --all test_perf_on_all git update-index --add --remove $SPARSE_CONE/a test_perf_on_all "git rm -f $SPARSE_CONE/a && git checkout HEAD -- $SPARSE_CONE/a" +test_perf_on_all git grep --cached bogus -- "f2/f1/f1/*" +test_perf_on_all git write-tree +test_perf_on_all git describe --dirty +test_perf_on_all 'echo >>new && git describe --dirty' +test_perf_on_all git diff-files +test_perf_on_all git diff-files -- $SPARSE_CONE/a +test_perf_on_all git diff-tree HEAD +test_perf_on_all git diff-tree HEAD -- $SPARSE_CONE/a +test_perf_on_all "git worktree add ../temp && git worktree remove ../temp" +test_perf_on_all git check-attr -a -- $SPARSE_CONE/a test_done diff --git a/t/perf/p5312-pack-bitmaps-revs.sh b/t/perf/p5312-pack-bitmaps-revs.sh index 0684b690af..ceec60656b 100755 --- a/t/perf/p5312-pack-bitmaps-revs.sh +++ b/t/perf/p5312-pack-bitmaps-revs.sh @@ -12,8 +12,7 @@ test_lookup_pack_bitmap () { test_perf_large_repo test_expect_success 'setup bitmap config' ' - git config pack.writebitmaps true && - git config pack.writeReverseIndex true + git config pack.writebitmaps true ' # we need to create the tag up front such that it is covered by the repack and 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/perf/p7822-grep-perl-character.sh b/t/perf/p7822-grep-perl-character.sh new file mode 100755 index 0000000000..87009c60df --- /dev/null +++ b/t/perf/p7822-grep-perl-character.sh @@ -0,0 +1,42 @@ +#!/bin/sh + +test_description="git-grep's perl regex + +If GIT_PERF_GREP_THREADS is set to a list of threads (e.g. '1 4 8' +etc.) we will test the patterns under those numbers of threads. +" + +. ./perf-lib.sh + +test_perf_large_repo +test_checkout_worktree + +if test -n "$GIT_PERF_GREP_THREADS" +then + test_set_prereq PERF_GREP_ENGINES_THREADS +fi + +for pattern in \ + '\\bhow' \ + '\\bÆvar' \ + '\\d+ \\bÆvar' \ + '\\bBelón\\b' \ + '\\w{12}\\b' +do + echo '$pattern' >pat + if ! test_have_prereq PERF_GREP_ENGINES_THREADS + then + test_perf "grep -P '$pattern'" --prereq PCRE " + git -P grep -f pat || : + " + else + for threads in $GIT_PERF_GREP_THREADS + do + test_perf "grep -P '$pattern' with $threads threads" --prereq PTHREADS,PCRE " + git -c grep.threads=$threads -P grep -f pat || : + " + done + fi +done + +test_done diff --git a/t/perf/run b/t/perf/run index 33da4d2aba..34115edec3 100755 --- a/t/perf/run +++ b/t/perf/run @@ -232,10 +232,10 @@ then ) elif test -n "$GIT_PERF_SUBSECTION" then - egrep "^$GIT_PERF_SUBSECTION\$" "$TEST_RESULTS_DIR"/run_subsections.names >/dev/null || + grep -E "^$GIT_PERF_SUBSECTION\$" "$TEST_RESULTS_DIR"/run_subsections.names >/dev/null || die "subsection '$GIT_PERF_SUBSECTION' not found in '$GIT_PERF_CONFIG_FILE'" - egrep "^$GIT_PERF_SUBSECTION\$" "$TEST_RESULTS_DIR"/run_subsections.names | while read -r subsec + grep -E "^$GIT_PERF_SUBSECTION\$" "$TEST_RESULTS_DIR"/run_subsections.names | while read -r subsec do ( GIT_PERF_SUBSECTION="$subsec" diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 502b4bcf9e..6e300be2ac 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -815,7 +815,8 @@ test_expect_success 'test_oid provides sane info by default' ' grep "^00*\$" actual && rawsz="$(test_oid rawsz)" && hexsz="$(test_oid hexsz)" && - test "$hexsz" -eq $(wc -c <actual) && + # +1 accounts for the trailing newline + test $(( $hexsz + 1)) -eq $(wc -c <actual) && test $(( $rawsz * 2)) -eq "$hexsz" ' @@ -826,7 +827,7 @@ test_expect_success 'test_oid can look up data for SHA-1' ' grep "^00*\$" actual && rawsz="$(test_oid rawsz)" && hexsz="$(test_oid hexsz)" && - test $(wc -c <actual) -eq 40 && + test $(wc -c <actual) -eq 41 && test "$rawsz" -eq 20 && test "$hexsz" -eq 40 ' @@ -838,7 +839,7 @@ test_expect_success 'test_oid can look up data for SHA-256' ' grep "^00*\$" actual && rawsz="$(test_oid rawsz)" && hexsz="$(test_oid hexsz)" && - test $(wc -c <actual) -eq 64 && + test $(wc -c <actual) -eq 65 && test "$rawsz" -eq 32 && test "$hexsz" -eq 64 ' @@ -1013,7 +1014,7 @@ test_expect_success 'validate object ID for a known tree' ' ' test_expect_success 'showing tree with git ls-tree' ' - git ls-tree $tree >current + git ls-tree $tree >current ' test_expect_success 'git ls-tree output for a known tree' ' diff --git a/t/t0001-init.sh b/t/t0001-init.sh index d479303efa..30a6edca1d 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -598,9 +598,14 @@ test_expect_success 'invalid default branch name' ' test_expect_success 'branch -m with the initial branch' ' git init rename-initial && git -C rename-initial branch -m renamed && - test renamed = $(git -C rename-initial symbolic-ref --short HEAD) && + echo renamed >expect && + git -C rename-initial symbolic-ref --short HEAD >actual && + test_cmp expect actual && + git -C rename-initial branch -m renamed again && - test again = $(git -C rename-initial symbolic-ref --short HEAD) + echo again >expect && + git -C rename-initial symbolic-ref --short HEAD >actual && + test_cmp expect actual ' test_done diff --git a/t/t0002-gitfile.sh b/t/t0002-gitfile.sh index 26eaca095a..e013d38f48 100755 --- a/t/t0002-gitfile.sh +++ b/t/t0002-gitfile.sh @@ -33,7 +33,9 @@ test_expect_success 'bad setup: invalid .git file path' ' test_expect_success 'final setup + check rev-parse --git-dir' ' echo "gitdir: $REAL" >.git && - test "$REAL" = "$(git rev-parse --git-dir)" + echo "$REAL" >expect && + git rev-parse --git-dir >actual && + test_cmp expect actual ' test_expect_success 'check hash-object' ' diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh index d0284fe2d7..26e082f05b 100755 --- a/t/t0003-attributes.sh +++ b/t/t0003-attributes.sh @@ -25,7 +25,24 @@ attr_check_quote () { git check-attr test -- "$path" >actual && echo "\"$quoted_path\": test: $expect" >expect && test_cmp expect actual +} + +attr_check_source () { + path="$1" expect="$2" source="$3" git_opts="$4" && + + echo "$path: test: $expect" >expect && + git $git_opts check-attr --source $source test -- "$path" >actual 2>err && + test_cmp expect actual && + test_must_be_empty err && + + git $git_opts --attr-source="$source" check-attr test -- "$path" >actual 2>err && + test_cmp expect actual && + test_must_be_empty err + + GIT_ATTR_SOURCE="$source" git $git_opts check-attr test -- "$path" >actual 2>err && + test_cmp expect actual && + test_must_be_empty err } test_expect_success 'open-quoted pathname' ' @@ -33,7 +50,6 @@ test_expect_success 'open-quoted pathname' ' attr_check a unspecified ' - test_expect_success 'setup' ' mkdir -p a/b/d a/c b && ( @@ -80,12 +96,23 @@ test_expect_success 'setup' ' EOF ' +test_expect_success 'setup branches' ' + mkdir -p foo/bar && + test_commit --printf "add .gitattributes" foo/bar/.gitattributes \ + "f test=f\na/i test=n\n" tag-1 && + test_commit --printf "add .gitattributes" foo/bar/.gitattributes \ + "g test=g\na/i test=m\n" tag-2 && + rm foo/bar/.gitattributes +' + test_expect_success 'command line checks' ' test_must_fail git check-attr && test_must_fail git check-attr -- && test_must_fail git check-attr test && test_must_fail git check-attr test -- && test_must_fail git check-attr -- f && + test_must_fail git check-attr --source && + test_must_fail git check-attr --source not-a-valid-ref && echo "f" | test_must_fail git check-attr --stdin && echo "f" | test_must_fail git check-attr --stdin -- f && echo "f" | test_must_fail git check-attr --stdin test -- f && @@ -203,9 +230,12 @@ test_expect_success 'attribute test: read paths from stdin' ' test_cmp expect actual ' -test_expect_success 'attribute test: --all option' ' +test_expect_success 'setup --all option' ' grep -v unspecified <expect-all | sort >specified-all && - sed -e "s/:.*//" <expect-all | uniq >stdin-all && + sed -e "s/:.*//" <expect-all | uniq >stdin-all +' + +test_expect_success 'attribute test: --all option' ' git check-attr --stdin --all <stdin-all >tmp && sort tmp >actual && test_cmp specified-all actual @@ -284,6 +314,15 @@ test_expect_success 'using --git-dir and --work-tree' ' ) ' +test_expect_success 'using --source' ' + attr_check_source foo/bar/f f tag-1 && + attr_check_source foo/bar/a/i n tag-1 && + attr_check_source foo/bar/f unspecified tag-2 && + attr_check_source foo/bar/a/i m tag-2 && + attr_check_source foo/bar/g g tag-2 && + attr_check_source foo/bar/g unspecified tag-1 +' + test_expect_success 'setup bare' ' git clone --template= --bare . bare.git ' @@ -303,6 +342,18 @@ test_expect_success 'bare repository: check that .gitattribute is ignored' ' ) ' +test_expect_success 'bare repository: with --source' ' + ( + cd bare.git && + attr_check_source foo/bar/f f tag-1 && + attr_check_source foo/bar/a/i n tag-1 && + attr_check_source foo/bar/f unspecified tag-2 && + attr_check_source foo/bar/a/i m tag-2 && + attr_check_source foo/bar/g g tag-2 && + attr_check_source foo/bar/g unspecified tag-1 + ) +' + test_expect_success 'bare repository: check that --cached honors index' ' ( cd bare.git && @@ -400,7 +451,7 @@ test_expect_success 'large attributes line ignores trailing content in tree' ' 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 && + dd if=/dev/zero of=.gitattributes bs=1048576 count=101 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 @@ -428,7 +479,7 @@ test_expect_success 'large attributes line ignores trailing content in index' ' 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) && + blob=$(dd if=/dev/zero bs=1048576 count=101 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 && diff --git a/t/t0006-date.sh b/t/t0006-date.sh index 2490162071..e18b160286 100755 --- a/t/t0006-date.sh +++ b/t/t0006-date.sh @@ -88,6 +88,13 @@ check_parse 2008-02-14 bad check_parse '2008-02-14 20:30:45' '2008-02-14 20:30:45 +0000' check_parse '2008-02-14 20:30:45 -0500' '2008-02-14 20:30:45 -0500' check_parse '2008.02.14 20:30:45 -0500' '2008-02-14 20:30:45 -0500' +check_parse '20080214T20:30:45' '2008-02-14 20:30:45 +0000' +check_parse '20080214T20:30' '2008-02-14 20:30:00 +0000' +check_parse '20080214T20' '2008-02-14 20:00:00 +0000' +check_parse '20080214T203045' '2008-02-14 20:30:45 +0000' +check_parse '20080214T2030' '2008-02-14 20:30:00 +0000' +check_parse '20080214T000000.20' '2008-02-14 00:00:00 +0000' +check_parse '20080214T00:00:00.20' '2008-02-14 00:00:00 +0000' check_parse '20080214T203045-04:00' '2008-02-14 20:30:45 -0400' check_parse '20080214T203045 -04:00' '2008-02-14 20:30:45 -0400' check_parse '20080214T203045.019-04:00' '2008-02-14 20:30:45 -0400' @@ -99,6 +106,7 @@ check_parse '2008-02-14 20:30:45 -05' '2008-02-14 20:30:45 -0500' check_parse '2008-02-14 20:30:45 -:30' '2008-02-14 20:30:45 +0000' check_parse '2008-02-14 20:30:45 -05:00' '2008-02-14 20:30:45 -0500' check_parse '2008-02-14 20:30:45' '2008-02-14 20:30:45 -0500' EST5 +check_parse 'Thu, 7 Apr 2005 15:14:13 -0700' '2005-04-07 15:14:13 -0700' check_approxidate() { echo "$1 -> $2 +0000" >expect diff --git a/t/t0007-git-var.sh b/t/t0007-git-var.sh index e56f4b9ac5..ff4fd9348c 100755 --- a/t/t0007-git-var.sh +++ b/t/t0007-git-var.sh @@ -5,6 +5,12 @@ test_description='basic sanity checks for git var' TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh +sane_unset_all_editors () { + sane_unset GIT_EDITOR && + sane_unset VISUAL && + sane_unset EDITOR +} + test_expect_success 'get GIT_AUTHOR_IDENT' ' test_tick && echo "$GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE" >expect && @@ -47,6 +53,178 @@ test_expect_success 'get GIT_DEFAULT_BRANCH with configuration' ' ) ' +test_expect_success 'get GIT_EDITOR without configuration' ' + ( + sane_unset_all_editors && + test_expect_code 1 git var GIT_EDITOR >out && + test_must_be_empty out + ) +' + +test_expect_success 'get GIT_EDITOR with configuration' ' + test_config core.editor foo && + ( + sane_unset_all_editors && + echo foo >expect && + git var GIT_EDITOR >actual && + test_cmp expect actual + ) +' + +test_expect_success 'get GIT_EDITOR with environment variable GIT_EDITOR' ' + ( + sane_unset_all_editors && + echo bar >expect && + GIT_EDITOR=bar git var GIT_EDITOR >actual && + test_cmp expect actual + ) +' + +test_expect_success 'get GIT_EDITOR with environment variable EDITOR' ' + ( + sane_unset_all_editors && + echo bar >expect && + EDITOR=bar git var GIT_EDITOR >actual && + test_cmp expect actual + ) +' + +test_expect_success 'get GIT_EDITOR with configuration and environment variable GIT_EDITOR' ' + test_config core.editor foo && + ( + sane_unset_all_editors && + echo bar >expect && + GIT_EDITOR=bar git var GIT_EDITOR >actual && + test_cmp expect actual + ) +' + +test_expect_success 'get GIT_EDITOR with configuration and environment variable EDITOR' ' + test_config core.editor foo && + ( + sane_unset_all_editors && + echo foo >expect && + EDITOR=bar git var GIT_EDITOR >actual && + test_cmp expect actual + ) +' + +test_expect_success 'get GIT_SEQUENCE_EDITOR without configuration' ' + ( + sane_unset GIT_SEQUENCE_EDITOR && + git var GIT_EDITOR >expect && + git var GIT_SEQUENCE_EDITOR >actual && + test_cmp expect actual + ) +' + +test_expect_success 'get GIT_SEQUENCE_EDITOR with configuration' ' + test_config sequence.editor foo && + ( + sane_unset GIT_SEQUENCE_EDITOR && + echo foo >expect && + git var GIT_SEQUENCE_EDITOR >actual && + test_cmp expect actual + ) +' + +test_expect_success 'get GIT_SEQUENCE_EDITOR with environment variable' ' + ( + sane_unset GIT_SEQUENCE_EDITOR && + echo bar >expect && + GIT_SEQUENCE_EDITOR=bar git var GIT_SEQUENCE_EDITOR >actual && + test_cmp expect actual + ) +' + +test_expect_success 'get GIT_SEQUENCE_EDITOR with configuration and environment variable' ' + test_config sequence.editor foo && + ( + sane_unset GIT_SEQUENCE_EDITOR && + echo bar >expect && + GIT_SEQUENCE_EDITOR=bar git var GIT_SEQUENCE_EDITOR >actual && + test_cmp expect actual + ) +' + +test_expect_success POSIXPERM 'GIT_SHELL_PATH points to a valid executable' ' + shellpath=$(git var GIT_SHELL_PATH) && + test_path_is_executable "$shellpath" +' + +# We know in this environment that our shell will be one of a few fixed values +# that all end in "sh". +test_expect_success MINGW 'GIT_SHELL_PATH points to a suitable shell' ' + shellpath=$(git var GIT_SHELL_PATH) && + case "$shellpath" in + *sh) ;; + *) return 1;; + esac +' + +test_expect_success 'GIT_ATTR_SYSTEM produces expected output' ' + test_must_fail env GIT_ATTR_NOSYSTEM=1 git var GIT_ATTR_SYSTEM && + ( + sane_unset GIT_ATTR_NOSYSTEM && + systempath=$(git var GIT_ATTR_SYSTEM) && + test "$systempath" != "" + ) +' + +test_expect_success 'GIT_ATTR_GLOBAL points to the correct location' ' + TRASHDIR="$(test-tool path-utils normalize_path_copy "$(pwd)")" && + globalpath=$(XDG_CONFIG_HOME="$TRASHDIR/.config" git var GIT_ATTR_GLOBAL) && + test "$globalpath" = "$TRASHDIR/.config/git/attributes" && + ( + sane_unset XDG_CONFIG_HOME && + globalpath=$(HOME="$TRASHDIR" git var GIT_ATTR_GLOBAL) && + test "$globalpath" = "$TRASHDIR/.config/git/attributes" + ) +' + +test_expect_success 'GIT_CONFIG_SYSTEM points to the correct location' ' + TRASHDIR="$(test-tool path-utils normalize_path_copy "$(pwd)")" && + test_must_fail env GIT_CONFIG_NOSYSTEM=1 git var GIT_CONFIG_SYSTEM && + ( + sane_unset GIT_CONFIG_NOSYSTEM && + systempath=$(git var GIT_CONFIG_SYSTEM) && + test "$systempath" != "" && + systempath=$(GIT_CONFIG_SYSTEM=/dev/null git var GIT_CONFIG_SYSTEM) && + if test_have_prereq MINGW + then + test "$systempath" = "nul" + else + test "$systempath" = "/dev/null" + fi && + systempath=$(GIT_CONFIG_SYSTEM="$TRASHDIR/gitconfig" git var GIT_CONFIG_SYSTEM) && + test "$systempath" = "$TRASHDIR/gitconfig" + ) +' + +test_expect_success 'GIT_CONFIG_GLOBAL points to the correct location' ' + TRASHDIR="$(test-tool path-utils normalize_path_copy "$(pwd)")" && + HOME="$TRASHDIR" XDG_CONFIG_HOME="$TRASHDIR/foo" git var GIT_CONFIG_GLOBAL >actual && + echo "$TRASHDIR/foo/git/config" >expected && + echo "$TRASHDIR/.gitconfig" >>expected && + test_cmp expected actual && + ( + sane_unset XDG_CONFIG_HOME && + HOME="$TRASHDIR" git var GIT_CONFIG_GLOBAL >actual && + echo "$TRASHDIR/.config/git/config" >expected && + echo "$TRASHDIR/.gitconfig" >>expected && + test_cmp expected actual && + globalpath=$(GIT_CONFIG_GLOBAL=/dev/null git var GIT_CONFIG_GLOBAL) && + if test_have_prereq MINGW + then + test "$globalpath" = "nul" + else + test "$globalpath" = "/dev/null" + fi && + globalpath=$(GIT_CONFIG_GLOBAL="$TRASHDIR/gitconfig" git var GIT_CONFIG_GLOBAL) && + test "$globalpath" = "$TRASHDIR/gitconfig" + ) +' + # For git var -l, we check only a representative variable; # testing the whole output would make our test too brittle with # respect to unrelated changes in the test suite's environment. @@ -64,8 +242,39 @@ test_expect_success 'git var -l lists config' ' test_cmp expect actual.bare ' +test_expect_success 'git var -l lists multiple global configs' ' + TRASHDIR="$(test-tool path-utils normalize_path_copy "$(pwd)")" && + HOME="$TRASHDIR" XDG_CONFIG_HOME="$TRASHDIR/foo" git var -l >actual && + grep "^GIT_CONFIG_GLOBAL=" actual >filtered && + echo "GIT_CONFIG_GLOBAL=$TRASHDIR/foo/git/config" >expected && + echo "GIT_CONFIG_GLOBAL=$TRASHDIR/.gitconfig" >>expected && + test_cmp expected filtered +' + +test_expect_success 'git var -l does not split multiline editors' ' + ( + GIT_EDITOR="!f() { + echo Hello! + }; f" && + export GIT_EDITOR && + echo "GIT_EDITOR=$GIT_EDITOR" >expected && + git var -l >var && + sed -n -e "/^GIT_EDITOR/,\$p" var | head -n 3 >actual && + test_cmp expected actual + ) +' + test_expect_success 'listing and asking for variables are exclusive' ' test_must_fail git var -l GIT_COMMITTER_IDENT ' +test_expect_success '`git var -l` works even without HOME' ' + ( + XDG_CONFIG_HOME= && + export XDG_CONFIG_HOME && + unset HOME && + git var -l + ) +' + 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/t0017-env-helper.sh b/t/t0017-env-helper.sh index 2e42fba956..fc14ba091c 100755 --- a/t/t0017-env-helper.sh +++ b/t/t0017-env-helper.sh @@ -1,87 +1,87 @@ #!/bin/sh -test_description='test env--helper' +test_description='test test-tool env-helper' TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh -test_expect_success 'env--helper usage' ' - test_must_fail git env--helper && - test_must_fail git env--helper --type=bool && - test_must_fail git env--helper --type=ulong && - test_must_fail git env--helper --type=bool && - test_must_fail git env--helper --type=bool --default && - test_must_fail git env--helper --type=bool --default= && - test_must_fail git env--helper --defaultxyz +test_expect_success 'test-tool env-helper usage' ' + test_must_fail test-tool env-helper && + test_must_fail test-tool env-helper --type=bool && + test_must_fail test-tool env-helper --type=ulong && + test_must_fail test-tool env-helper --type=bool && + test_must_fail test-tool env-helper --type=bool --default && + test_must_fail test-tool env-helper --type=bool --default= && + test_must_fail test-tool env-helper --defaultxyz ' -test_expect_success 'env--helper bad default values' ' - test_must_fail git env--helper --type=bool --default=1xyz MISSING && - test_must_fail git env--helper --type=ulong --default=1xyz MISSING +test_expect_success 'test-tool env-helper bad default values' ' + test_must_fail test-tool env-helper --type=bool --default=1xyz MISSING && + test_must_fail test-tool env-helper --type=ulong --default=1xyz MISSING ' -test_expect_success 'env--helper --type=bool' ' +test_expect_success 'test-tool env-helper --type=bool' ' # Test various --default bool values echo true >expected && - git env--helper --type=bool --default=1 MISSING >actual && + test-tool env-helper --type=bool --default=1 MISSING >actual && test_cmp expected actual && - git env--helper --type=bool --default=yes MISSING >actual && + test-tool env-helper --type=bool --default=yes MISSING >actual && test_cmp expected actual && - git env--helper --type=bool --default=true MISSING >actual && + test-tool env-helper --type=bool --default=true MISSING >actual && test_cmp expected actual && echo false >expected && - test_must_fail git env--helper --type=bool --default=0 MISSING >actual && + test_must_fail test-tool env-helper --type=bool --default=0 MISSING >actual && test_cmp expected actual && - test_must_fail git env--helper --type=bool --default=no MISSING >actual && + test_must_fail test-tool env-helper --type=bool --default=no MISSING >actual && test_cmp expected actual && - test_must_fail git env--helper --type=bool --default=false MISSING >actual && + test_must_fail test-tool env-helper --type=bool --default=false MISSING >actual && test_cmp expected actual && # No output with --exit-code - git env--helper --type=bool --default=true --exit-code MISSING >actual.out 2>actual.err && + test-tool env-helper --type=bool --default=true --exit-code MISSING >actual.out 2>actual.err && test_must_be_empty actual.out && test_must_be_empty actual.err && - test_must_fail git env--helper --type=bool --default=false --exit-code MISSING >actual.out 2>actual.err && + test_must_fail test-tool env-helper --type=bool --default=false --exit-code MISSING >actual.out 2>actual.err && test_must_be_empty actual.out && test_must_be_empty actual.err && # Existing variable - EXISTS=true git env--helper --type=bool --default=false --exit-code EXISTS >actual.out 2>actual.err && + EXISTS=true test-tool env-helper --type=bool --default=false --exit-code EXISTS >actual.out 2>actual.err && test_must_be_empty actual.out && test_must_be_empty actual.err && test_must_fail \ env EXISTS=false \ - git env--helper --type=bool --default=true --exit-code EXISTS >actual.out 2>actual.err && + test-tool env-helper --type=bool --default=true --exit-code EXISTS >actual.out 2>actual.err && test_must_be_empty actual.out && test_must_be_empty actual.err ' -test_expect_success 'env--helper --type=ulong' ' +test_expect_success 'test-tool env-helper --type=ulong' ' echo 1234567890 >expected && - git env--helper --type=ulong --default=1234567890 MISSING >actual.out 2>actual.err && + test-tool env-helper --type=ulong --default=1234567890 MISSING >actual.out 2>actual.err && test_cmp expected actual.out && test_must_be_empty actual.err && echo 0 >expected && - test_must_fail git env--helper --type=ulong --default=0 MISSING >actual && + test_must_fail test-tool env-helper --type=ulong --default=0 MISSING >actual && test_cmp expected actual && - git env--helper --type=ulong --default=1234567890 --exit-code MISSING >actual.out 2>actual.err && + test-tool env-helper --type=ulong --default=1234567890 --exit-code MISSING >actual.out 2>actual.err && test_must_be_empty actual.out && test_must_be_empty actual.err && - EXISTS=1234567890 git env--helper --type=ulong --default=0 EXISTS --exit-code >actual.out 2>actual.err && + EXISTS=1234567890 test-tool env-helper --type=ulong --default=0 EXISTS --exit-code >actual.out 2>actual.err && test_must_be_empty actual.out && test_must_be_empty actual.err && echo 1234567890 >expected && - EXISTS=1234567890 git env--helper --type=ulong --default=0 EXISTS >actual.out 2>actual.err && + EXISTS=1234567890 test-tool env-helper --type=ulong --default=0 EXISTS >actual.out 2>actual.err && test_cmp expected actual.out && test_must_be_empty actual.err ' -test_expect_success 'env--helper reads config thanks to trace2' ' +test_expect_success 'test-tool env-helper reads config thanks to trace2' ' mkdir home && git config -f home/.gitconfig include.path cycle && git config -f home/cycle include.path .gitconfig && @@ -93,7 +93,7 @@ test_expect_success 'env--helper reads config thanks to trace2' ' test_must_fail \ env HOME="$(pwd)/home" GIT_TEST_ENV_HELPER=true \ - git -C cycle env--helper --type=bool --default=0 --exit-code GIT_TEST_ENV_HELPER 2>err && + test-tool -C cycle env-helper --type=bool --default=0 --exit-code GIT_TEST_ENV_HELPER 2>err && grep "exceeded maximum include depth" err ' diff --git a/t/t0020-crlf.sh b/t/t0020-crlf.sh index 35cc8c3b39..81946e87cc 100755 --- a/t/t0020-crlf.sh +++ b/t/t0020-crlf.sh @@ -125,7 +125,7 @@ test_expect_success 'update with autocrlf=input' ' munge_cr append dir/two && git update-index -- one dir/two && differs=$(git diff-index --cached HEAD) && - verbose test -z "$differs" + test -z "$differs" ' @@ -138,7 +138,7 @@ test_expect_success 'update with autocrlf=true' ' munge_cr append dir/two && git update-index -- one dir/two && differs=$(git diff-index --cached HEAD) && - verbose test -z "$differs" + test -z "$differs" ' @@ -153,7 +153,7 @@ test_expect_success 'checkout with autocrlf=true' ' test "$one" = $(git hash-object --stdin <one) && test "$two" = $(git hash-object --stdin <dir/two) && differs=$(git diff-index --cached HEAD) && - verbose test -z "$differs" + test -z "$differs" ' test_expect_success 'checkout with autocrlf=input' ' @@ -167,7 +167,7 @@ test_expect_success 'checkout with autocrlf=input' ' test "$one" = $(git hash-object --stdin <one) && test "$two" = $(git hash-object --stdin <dir/two) && differs=$(git diff-index --cached HEAD) && - verbose test -z "$differs" + test -z "$differs" ' test_expect_success 'apply patch (autocrlf=input)' ' @@ -177,7 +177,7 @@ test_expect_success 'apply patch (autocrlf=input)' ' git read-tree --reset -u HEAD && git apply patch.file && - verbose test "$patched" = "$(git hash-object --stdin <one)" + test "$patched" = "$(git hash-object --stdin <one)" ' test_expect_success 'apply patch --cached (autocrlf=input)' ' @@ -187,7 +187,7 @@ test_expect_success 'apply patch --cached (autocrlf=input)' ' git read-tree --reset -u HEAD && git apply --cached patch.file && - verbose test "$patched" = $(git rev-parse :one) + test "$patched" = $(git rev-parse :one) ' test_expect_success 'apply patch --index (autocrlf=input)' ' @@ -197,8 +197,8 @@ test_expect_success 'apply patch --index (autocrlf=input)' ' git read-tree --reset -u HEAD && git apply --index patch.file && - verbose test "$patched" = $(git rev-parse :one) && - verbose test "$patched" = $(git hash-object --stdin <one) + test "$patched" = $(git rev-parse :one) && + test "$patched" = $(git hash-object --stdin <one) ' test_expect_success 'apply patch (autocrlf=true)' ' @@ -208,7 +208,7 @@ test_expect_success 'apply patch (autocrlf=true)' ' git read-tree --reset -u HEAD && git apply patch.file && - verbose test "$patched" = "$(remove_cr <one | git hash-object --stdin)" + test "$patched" = "$(remove_cr <one | git hash-object --stdin)" ' test_expect_success 'apply patch --cached (autocrlf=true)' ' @@ -218,7 +218,7 @@ test_expect_success 'apply patch --cached (autocrlf=true)' ' git read-tree --reset -u HEAD && git apply --cached patch.file && - verbose test "$patched" = $(git rev-parse :one) + test "$patched" = $(git rev-parse :one) ' test_expect_success 'apply patch --index (autocrlf=true)' ' @@ -228,8 +228,8 @@ test_expect_success 'apply patch --index (autocrlf=true)' ' git read-tree --reset -u HEAD && git apply --index patch.file && - verbose test "$patched" = $(git rev-parse :one) && - verbose test "$patched" = "$(remove_cr <one | git hash-object --stdin)" + test "$patched" = $(git rev-parse :one) && + test "$patched" = "$(remove_cr <one | git hash-object --stdin)" ' test_expect_success '.gitattributes says two is binary' ' @@ -240,7 +240,7 @@ test_expect_success '.gitattributes says two is binary' ' git read-tree --reset -u HEAD && ! has_cr dir/two && - verbose has_cr one && + has_cr one && ! has_cr three ' @@ -259,8 +259,8 @@ test_expect_success '.gitattributes says two and three are text' ' echo "t* crlf" >.gitattributes && git read-tree --reset -u HEAD && - verbose has_cr dir/two && - verbose has_cr three + has_cr dir/two && + has_cr three ' test_expect_success 'in-tree .gitattributes (1)' ' @@ -273,7 +273,7 @@ test_expect_success 'in-tree .gitattributes (1)' ' git read-tree --reset -u HEAD && ! has_cr one && - verbose has_cr three + has_cr three ' test_expect_success 'in-tree .gitattributes (2)' ' @@ -283,7 +283,7 @@ test_expect_success 'in-tree .gitattributes (2)' ' git checkout-index -f -q -u -a && ! has_cr one && - verbose has_cr three + has_cr three ' test_expect_success 'in-tree .gitattributes (3)' ' @@ -294,7 +294,7 @@ test_expect_success 'in-tree .gitattributes (3)' ' git checkout-index -u one dir/two three && ! has_cr one && - verbose has_cr three + has_cr three ' test_expect_success 'in-tree .gitattributes (4)' ' @@ -305,7 +305,7 @@ test_expect_success 'in-tree .gitattributes (4)' ' git checkout-index -u .gitattributes && ! has_cr one && - verbose has_cr three + has_cr three ' test_expect_success 'checkout with existing .gitattributes' ' diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh index abecd75e4e..46abbeed68 100755 --- a/t/t0021-conversion.sh +++ b/t/t0021-conversion.sh @@ -8,8 +8,8 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . ./test-lib.sh . "$TEST_DIRECTORY"/lib-terminal.sh -TEST_ROOT="$PWD" -PATH=$TEST_ROOT:$PATH +PATH=$PWD:$PATH +TEST_ROOT="$(pwd)" write_script <<\EOF "$TEST_ROOT/rot13.sh" tr \ diff --git a/t/t0023-crlf-am.sh b/t/t0023-crlf-am.sh index f9bbb91f64..575805513a 100755 --- a/t/t0023-crlf-am.sh +++ b/t/t0023-crlf-am.sh @@ -2,6 +2,7 @@ test_description='Test am with auto.crlf' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh cat >patchfile <<\EOF diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh index a94ac1eae3..2f57c8669c 100755 --- a/t/t0027-auto-crlf.sh +++ b/t/t0027-auto-crlf.sh @@ -70,7 +70,8 @@ create_NNO_MIX_files () { cp CRLF ${pfx}_CRLF.txt && cp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt && cp LF_mix_CR ${pfx}_LF_mix_CR.txt && - cp CRLF_nul ${pfx}_CRLF_nul.txt + cp CRLF_nul ${pfx}_CRLF_nul.txt || + return 1 done done done @@ -101,7 +102,8 @@ commit_check_warn () { do fname=${pfx}_$f.txt && cp $f $fname && - git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err" + git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err" || + return 1 done && git commit -m "core.autocrlf $crlf" && check_warning "$lfname" ${pfx}_LF.err && @@ -121,15 +123,19 @@ commit_chk_wrnNNO () { lfmixcr=$1 ; shift crlfnul=$1 ; shift pfx=NNO_attr_${attr}_aeol_${aeol}_${crlf} - #Commit files on top of existing file - create_gitattributes "$attr" $aeol && - for f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul - do - fname=${pfx}_$f.txt && - cp $f $fname && - printf Z >>"$fname" && - git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err" - done + + test_expect_success 'setup commit NNO files' ' + #Commit files on top of existing file + create_gitattributes "$attr" $aeol && + for f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul + do + fname=${pfx}_$f.txt && + cp $f $fname && + printf Z >>"$fname" && + git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err" || + return 1 + done + ' test_expect_success "commit NNO files crlf=$crlf attr=$attr LF" ' check_warning "$lfwarn" ${pfx}_LF.err @@ -163,15 +169,19 @@ commit_MIX_chkwrn () { lfmixcr=$1 ; shift crlfnul=$1 ; shift pfx=MIX_attr_${attr}_aeol_${aeol}_${crlf} - #Commit file with CLRF_mix_LF on top of existing file - create_gitattributes "$attr" $aeol && - for f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul - do - fname=${pfx}_$f.txt && - cp CRLF_mix_LF $fname && - printf Z >>"$fname" && - git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err" - done + + test_expect_success 'setup commit file with mixed EOL' ' + #Commit file with CLRF_mix_LF on top of existing file + create_gitattributes "$attr" $aeol && + for f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul + do + fname=${pfx}_$f.txt && + cp CRLF_mix_LF $fname && + printf Z >>"$fname" && + git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err" || + return 1 + done + ' test_expect_success "commit file with mixed EOL onto LF crlf=$crlf attr=$attr" ' check_warning "$lfwarn" ${pfx}_LF.err @@ -289,17 +299,17 @@ checkout_files () { lfmixcrlf=$1 ; shift lfmixcr=$1 ; shift crlfnul=$1 ; shift - create_gitattributes "$attr" $ident $aeol && - git config core.autocrlf $crlf && + test_expect_success "setup config for checkout attr=$attr ident=$ident aeol=$aeol core.autocrlf=$crlf" ' + create_gitattributes "$attr" $ident $aeol && + git config core.autocrlf $crlf + ' pfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ && for f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul do - rm crlf_false_attr__$f.txt && - if test -z "$ceol"; then - git checkout -- crlf_false_attr__$f.txt - else - git -c core.eol=$ceol checkout -- crlf_false_attr__$f.txt - fi + test_expect_success "setup $f checkout ${ceol:+ with -c core.eol=$ceol}" ' + rm -f crlf_false_attr__$f.txt && + git ${ceol:+-c core.eol=$ceol} checkout -- crlf_false_attr__$f.txt + ' done test_expect_success "ls-files --eol attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol" ' diff --git a/t/t0030-stripspace.sh b/t/t0030-stripspace.sh index 0a5713c524..d1b3be8725 100755 --- a/t/t0030-stripspace.sh +++ b/t/t0030-stripspace.sh @@ -17,396 +17,378 @@ printf_git_stripspace () { printf "$1" | git stripspace } -test_expect_success \ - 'long lines without spaces should be unchanged' ' - echo "$ttt" >expect && - git stripspace <expect >actual && - test_cmp expect actual && - - echo "$ttt$ttt" >expect && - git stripspace <expect >actual && - test_cmp expect actual && - - echo "$ttt$ttt$ttt" >expect && - git stripspace <expect >actual && - test_cmp expect actual && - - echo "$ttt$ttt$ttt$ttt" >expect && - git stripspace <expect >actual && - test_cmp expect actual +test_expect_success 'long lines without spaces should be unchanged' ' + echo "$ttt" >expect && + git stripspace <expect >actual && + test_cmp expect actual && + + echo "$ttt$ttt" >expect && + git stripspace <expect >actual && + test_cmp expect actual && + + echo "$ttt$ttt$ttt" >expect && + git stripspace <expect >actual && + test_cmp expect actual && + + echo "$ttt$ttt$ttt$ttt" >expect && + git stripspace <expect >actual && + test_cmp expect actual ' -test_expect_success \ - 'lines with spaces at the beginning should be unchanged' ' - echo "$sss$ttt" >expect && - git stripspace <expect >actual && - test_cmp expect actual && +test_expect_success 'lines with spaces at the beginning should be unchanged' ' + echo "$sss$ttt" >expect && + git stripspace <expect >actual && + test_cmp expect actual && - echo "$sss$sss$ttt" >expect && - git stripspace <expect >actual && - test_cmp expect actual && + echo "$sss$sss$ttt" >expect && + git stripspace <expect >actual && + test_cmp expect actual && - echo "$sss$sss$sss$ttt" >expect && - git stripspace <expect >actual && - test_cmp expect actual + echo "$sss$sss$sss$ttt" >expect && + git stripspace <expect >actual && + test_cmp expect actual ' -test_expect_success \ - 'lines with intermediate spaces should be unchanged' ' - echo "$ttt$sss$ttt" >expect && - git stripspace <expect >actual && - test_cmp expect actual && +test_expect_success 'lines with intermediate spaces should be unchanged' ' + echo "$ttt$sss$ttt" >expect && + git stripspace <expect >actual && + test_cmp expect actual && - echo "$ttt$sss$sss$ttt" >expect && - git stripspace <expect >actual && - test_cmp expect actual + echo "$ttt$sss$sss$ttt" >expect && + git stripspace <expect >actual && + test_cmp expect actual ' -test_expect_success \ - 'consecutive blank lines should be unified' ' - printf "$ttt\n\n$ttt\n" > expect && - printf "$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual && - test_cmp expect actual && +test_expect_success 'consecutive blank lines should be unified' ' + printf "$ttt\n\n$ttt\n" > expect && + printf "$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt$ttt\n\n$ttt\n" > expect && - printf "$ttt$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt$ttt\n\n$ttt\n" > expect && + printf "$ttt$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt$ttt$ttt\n\n$ttt\n" > expect && - printf "$ttt$ttt$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt$ttt$ttt\n\n$ttt\n" > expect && + printf "$ttt$ttt$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt\n\n$ttt\n" > expect && - printf "$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt\n\n$ttt\n" > expect && + printf "$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt\n\n$ttt$ttt\n" > expect && - printf "$ttt\n\n\n\n\n$ttt$ttt\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt\n\n$ttt$ttt\n" > expect && + printf "$ttt\n\n\n\n\n$ttt$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt\n\n$ttt$ttt$ttt\n" > expect && - printf "$ttt\n\n\n\n\n$ttt$ttt$ttt\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt\n\n$ttt$ttt$ttt\n" > expect && + printf "$ttt\n\n\n\n\n$ttt$ttt$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt\n\n$ttt\n" > expect && - printf "$ttt\n\t\n \n\n \t\t\n$ttt\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt\n\n$ttt\n" > expect && + printf "$ttt\n\t\n \n\n \t\t\n$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt$ttt\n\n$ttt\n" > expect && - printf "$ttt$ttt\n\t\n \n\n \t\t\n$ttt\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt$ttt\n\n$ttt\n" > expect && + printf "$ttt$ttt\n\t\n \n\n \t\t\n$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt$ttt$ttt\n\n$ttt\n" > expect && - printf "$ttt$ttt$ttt\n\t\n \n\n \t\t\n$ttt\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt$ttt$ttt\n\n$ttt\n" > expect && + printf "$ttt$ttt$ttt\n\t\n \n\n \t\t\n$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt\n\n$ttt\n" > expect && - printf "$ttt\n\t\n \n\n \t\t\n$ttt\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt\n\n$ttt\n" > expect && + printf "$ttt\n\t\n \n\n \t\t\n$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt\n\n$ttt$ttt\n" > expect && - printf "$ttt\n\t\n \n\n \t\t\n$ttt$ttt\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt\n\n$ttt$ttt\n" > expect && + printf "$ttt\n\t\n \n\n \t\t\n$ttt$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt\n\n$ttt$ttt$ttt\n" > expect && - printf "$ttt\n\t\n \n\n \t\t\n$ttt$ttt$ttt\n" | git stripspace >actual && - test_cmp expect actual + printf "$ttt\n\n$ttt$ttt$ttt\n" > expect && + printf "$ttt\n\t\n \n\n \t\t\n$ttt$ttt$ttt\n" | git stripspace >actual && + test_cmp expect actual ' -test_expect_success \ - 'only consecutive blank lines should be completely removed' ' +test_expect_success 'only consecutive blank lines should be completely removed' ' + printf "\n" | git stripspace >actual && + test_must_be_empty actual && - printf "\n" | git stripspace >actual && - test_must_be_empty actual && + printf "\n\n\n" | git stripspace >actual && + test_must_be_empty actual && - printf "\n\n\n" | git stripspace >actual && - test_must_be_empty actual && + printf "$sss\n$sss\n$sss\n" | git stripspace >actual && + test_must_be_empty actual && - printf "$sss\n$sss\n$sss\n" | git stripspace >actual && - test_must_be_empty actual && + printf "$sss$sss\n$sss\n\n" | git stripspace >actual && + test_must_be_empty actual && - printf "$sss$sss\n$sss\n\n" | git stripspace >actual && - test_must_be_empty actual && + printf "\n$sss\n$sss$sss\n" | git stripspace >actual && + test_must_be_empty actual && - printf "\n$sss\n$sss$sss\n" | git stripspace >actual && - test_must_be_empty actual && + printf "$sss$sss$sss$sss\n\n\n" | git stripspace >actual && + test_must_be_empty actual && - printf "$sss$sss$sss$sss\n\n\n" | git stripspace >actual && - test_must_be_empty actual && + printf "\n$sss$sss$sss$sss\n\n" | git stripspace >actual && + test_must_be_empty actual && - printf "\n$sss$sss$sss$sss\n\n" | git stripspace >actual && - test_must_be_empty actual && - - printf "\n\n$sss$sss$sss$sss\n" | git stripspace >actual && - test_must_be_empty actual + printf "\n\n$sss$sss$sss$sss\n" | git stripspace >actual && + test_must_be_empty actual ' -test_expect_success \ - 'consecutive blank lines at the beginning should be removed' ' - printf "$ttt\n" > expect && - printf "\n$ttt\n" | git stripspace >actual && - test_cmp expect actual && +test_expect_success 'consecutive blank lines at the beginning should be removed' ' + printf "$ttt\n" > expect && + printf "\n$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt\n" > expect && - printf "\n\n\n$ttt\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt\n" > expect && + printf "\n\n\n$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt$ttt\n" > expect && - printf "\n\n\n$ttt$ttt\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt$ttt\n" > expect && + printf "\n\n\n$ttt$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt$ttt$ttt\n" > expect && - printf "\n\n\n$ttt$ttt$ttt\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt$ttt$ttt\n" > expect && + printf "\n\n\n$ttt$ttt$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt$ttt$ttt$ttt\n" > expect && - printf "\n\n\n$ttt$ttt$ttt$ttt\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt$ttt$ttt$ttt\n" > expect && + printf "\n\n\n$ttt$ttt$ttt$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt\n" > expect && + printf "$ttt\n" > expect && - printf "$sss\n$sss\n$sss\n$ttt\n" | git stripspace >actual && - test_cmp expect actual && + printf "$sss\n$sss\n$sss\n$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "\n$sss\n$sss$sss\n$ttt\n" | git stripspace >actual && - test_cmp expect actual && + printf "\n$sss\n$sss$sss\n$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "$sss$sss\n$sss\n\n$ttt\n" | git stripspace >actual && - test_cmp expect actual && + printf "$sss$sss\n$sss\n\n$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "$sss$sss$sss\n\n\n$ttt\n" | git stripspace >actual && - test_cmp expect actual && + printf "$sss$sss$sss\n\n\n$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "\n$sss$sss$sss\n\n$ttt\n" | git stripspace >actual && - test_cmp expect actual && + printf "\n$sss$sss$sss\n\n$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "\n\n$sss$sss$sss\n$ttt\n" | git stripspace >actual && - test_cmp expect actual + printf "\n\n$sss$sss$sss\n$ttt\n" | git stripspace >actual && + test_cmp expect actual ' -test_expect_success \ - 'consecutive blank lines at the end should be removed' ' - printf "$ttt\n" > expect && - printf "$ttt\n\n" | git stripspace >actual && - test_cmp expect actual && +test_expect_success 'consecutive blank lines at the end should be removed' ' + printf "$ttt\n" > expect && + printf "$ttt\n\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt\n" > expect && - printf "$ttt\n\n\n\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt\n" > expect && + printf "$ttt\n\n\n\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt$ttt\n" > expect && - printf "$ttt$ttt\n\n\n\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt$ttt\n" > expect && + printf "$ttt$ttt\n\n\n\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt$ttt$ttt\n" > expect && - printf "$ttt$ttt$ttt\n\n\n\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt$ttt$ttt\n" > expect && + printf "$ttt$ttt$ttt\n\n\n\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt$ttt$ttt$ttt\n" > expect && - printf "$ttt$ttt$ttt$ttt\n\n\n\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt$ttt$ttt$ttt\n" > expect && + printf "$ttt$ttt$ttt$ttt\n\n\n\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt\n" > expect && + printf "$ttt\n" > expect && - printf "$ttt\n$sss\n$sss\n$sss\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt\n$sss\n$sss\n$sss\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt\n\n$sss\n$sss$sss\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt\n\n$sss\n$sss$sss\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt\n$sss$sss\n$sss\n\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt\n$sss$sss\n$sss\n\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt\n$sss$sss$sss\n\n\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt\n$sss$sss$sss\n\n\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt\n\n$sss$sss$sss\n\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt\n\n$sss$sss$sss\n\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt\n\n\n$sss$sss$sss\n" | git stripspace >actual && - test_cmp expect actual + printf "$ttt\n\n\n$sss$sss$sss\n" | git stripspace >actual && + test_cmp expect actual ' -test_expect_success \ - 'text without newline at end should end with newline' ' - test_stdout_line_count -gt 0 printf_git_stripspace "$ttt" && - test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt" && - test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$ttt" && - test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$ttt$ttt" +test_expect_success 'text without newline at end should end with newline' ' + test_stdout_line_count -gt 0 printf_git_stripspace "$ttt" && + test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt" && + test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$ttt" && + test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$ttt$ttt" ' # text plus spaces at the end: -test_expect_success \ - 'text plus spaces without newline at end should end with newline' ' - test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$sss" && - test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$sss" && - test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$ttt$sss" && - test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$sss$sss" && - test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$sss$sss" && - test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$sss$sss$sss" +test_expect_success 'text plus spaces without newline at end should end with newline' ' + test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$sss" && + test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$sss" && + test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$ttt$sss" && + test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$sss$sss" && + test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$ttt$sss$sss" && + test_stdout_line_count -gt 0 printf_git_stripspace "$ttt$sss$sss$sss" ' -test_expect_success \ - 'text plus spaces without newline at end should not show spaces' ' - printf "$ttt$sss" | git stripspace >tmp && - ! grep " " tmp >/dev/null && - printf "$ttt$ttt$sss" | git stripspace >tmp && - ! grep " " tmp >/dev/null && - printf "$ttt$ttt$ttt$sss" | git stripspace >tmp && - ! grep " " tmp >/dev/null && - printf "$ttt$sss$sss" | git stripspace >tmp && - ! grep " " tmp >/dev/null && - printf "$ttt$ttt$sss$sss" | git stripspace >tmp && - ! grep " " tmp >/dev/null && - printf "$ttt$sss$sss$sss" | git stripspace >tmp && - ! grep " " tmp >/dev/null +test_expect_success 'text plus spaces without newline at end should not show spaces' ' + printf "$ttt$sss" | git stripspace >tmp && + ! grep " " tmp >/dev/null && + printf "$ttt$ttt$sss" | git stripspace >tmp && + ! grep " " tmp >/dev/null && + printf "$ttt$ttt$ttt$sss" | git stripspace >tmp && + ! grep " " tmp >/dev/null && + printf "$ttt$sss$sss" | git stripspace >tmp && + ! grep " " tmp >/dev/null && + printf "$ttt$ttt$sss$sss" | git stripspace >tmp && + ! grep " " tmp >/dev/null && + printf "$ttt$sss$sss$sss" | git stripspace >tmp && + ! grep " " tmp >/dev/null ' -test_expect_success \ - 'text plus spaces without newline should show the correct lines' ' - printf "$ttt\n" >expect && - printf "$ttt$sss" | git stripspace >actual && - test_cmp expect actual && +test_expect_success 'text plus spaces without newline should show the correct lines' ' + printf "$ttt\n" >expect && + printf "$ttt$sss" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt\n" >expect && - printf "$ttt$sss$sss" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt\n" >expect && + printf "$ttt$sss$sss" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt\n" >expect && - printf "$ttt$sss$sss$sss" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt\n" >expect && + printf "$ttt$sss$sss$sss" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt$ttt\n" >expect && - printf "$ttt$ttt$sss" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt$ttt\n" >expect && + printf "$ttt$ttt$sss" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt$ttt\n" >expect && - printf "$ttt$ttt$sss$sss" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt$ttt\n" >expect && + printf "$ttt$ttt$sss$sss" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt$ttt$ttt\n" >expect && - printf "$ttt$ttt$ttt$sss" | git stripspace >actual && - test_cmp expect actual + printf "$ttt$ttt$ttt\n" >expect && + printf "$ttt$ttt$ttt$sss" | git stripspace >actual && + test_cmp expect actual ' -test_expect_success \ - 'text plus spaces at end should not show spaces' ' - echo "$ttt$sss" | git stripspace >tmp && - ! grep " " tmp >/dev/null && - echo "$ttt$ttt$sss" | git stripspace >tmp && - ! grep " " tmp >/dev/null && - echo "$ttt$ttt$ttt$sss" | git stripspace >tmp && - ! grep " " tmp >/dev/null && - echo "$ttt$sss$sss" | git stripspace >tmp && - ! grep " " tmp >/dev/null && - echo "$ttt$ttt$sss$sss" | git stripspace >tmp && - ! grep " " tmp >/dev/null && - echo "$ttt$sss$sss$sss" | git stripspace >tmp && - ! grep " " tmp >/dev/null +test_expect_success 'text plus spaces at end should not show spaces' ' + echo "$ttt$sss" | git stripspace >tmp && + ! grep " " tmp >/dev/null && + echo "$ttt$ttt$sss" | git stripspace >tmp && + ! grep " " tmp >/dev/null && + echo "$ttt$ttt$ttt$sss" | git stripspace >tmp && + ! grep " " tmp >/dev/null && + echo "$ttt$sss$sss" | git stripspace >tmp && + ! grep " " tmp >/dev/null && + echo "$ttt$ttt$sss$sss" | git stripspace >tmp && + ! grep " " tmp >/dev/null && + echo "$ttt$sss$sss$sss" | git stripspace >tmp && + ! grep " " tmp >/dev/null ' -test_expect_success \ - 'text plus spaces at end should be cleaned and newline must remain' ' - echo "$ttt" >expect && - echo "$ttt$sss" | git stripspace >actual && - test_cmp expect actual && +test_expect_success 'text plus spaces at end should be cleaned and newline must remain' ' + echo "$ttt" >expect && + echo "$ttt$sss" | git stripspace >actual && + test_cmp expect actual && - echo "$ttt" >expect && - echo "$ttt$sss$sss" | git stripspace >actual && - test_cmp expect actual && + echo "$ttt" >expect && + echo "$ttt$sss$sss" | git stripspace >actual && + test_cmp expect actual && - echo "$ttt" >expect && - echo "$ttt$sss$sss$sss" | git stripspace >actual && - test_cmp expect actual && + echo "$ttt" >expect && + echo "$ttt$sss$sss$sss" | git stripspace >actual && + test_cmp expect actual && - echo "$ttt$ttt" >expect && - echo "$ttt$ttt$sss" | git stripspace >actual && - test_cmp expect actual && + echo "$ttt$ttt" >expect && + echo "$ttt$ttt$sss" | git stripspace >actual && + test_cmp expect actual && - echo "$ttt$ttt" >expect && - echo "$ttt$ttt$sss$sss" | git stripspace >actual && - test_cmp expect actual && + echo "$ttt$ttt" >expect && + echo "$ttt$ttt$sss$sss" | git stripspace >actual && + test_cmp expect actual && - echo "$ttt$ttt$ttt" >expect && - echo "$ttt$ttt$ttt$sss" | git stripspace >actual && - test_cmp expect actual + echo "$ttt$ttt$ttt" >expect && + echo "$ttt$ttt$ttt$sss" | git stripspace >actual && + test_cmp expect actual ' # spaces only: -test_expect_success \ - 'spaces with newline at end should be replaced with empty string' ' - echo | git stripspace >actual && - test_must_be_empty actual && +test_expect_success 'spaces with newline at end should be replaced with empty string' ' + echo | git stripspace >actual && + test_must_be_empty actual && - echo "$sss" | git stripspace >actual && - test_must_be_empty actual && + echo "$sss" | git stripspace >actual && + test_must_be_empty actual && - echo "$sss$sss" | git stripspace >actual && - test_must_be_empty actual && + echo "$sss$sss" | git stripspace >actual && + test_must_be_empty actual && - echo "$sss$sss$sss" | git stripspace >actual && - test_must_be_empty actual && + echo "$sss$sss$sss" | git stripspace >actual && + test_must_be_empty actual && - echo "$sss$sss$sss$sss" | git stripspace >actual && - test_must_be_empty actual + echo "$sss$sss$sss$sss" | git stripspace >actual && + test_must_be_empty actual ' -test_expect_success \ - 'spaces without newline at end should not show spaces' ' - printf "" | git stripspace >tmp && - ! grep " " tmp >/dev/null && - printf "$sss" | git stripspace >tmp && - ! grep " " tmp >/dev/null && - printf "$sss$sss" | git stripspace >tmp && - ! grep " " tmp >/dev/null && - printf "$sss$sss$sss" | git stripspace >tmp && - ! grep " " tmp >/dev/null && - printf "$sss$sss$sss$sss" | git stripspace >tmp && - ! grep " " tmp >/dev/null +test_expect_success 'spaces without newline at end should not show spaces' ' + printf "" | git stripspace >tmp && + ! grep " " tmp >/dev/null && + printf "$sss" | git stripspace >tmp && + ! grep " " tmp >/dev/null && + printf "$sss$sss" | git stripspace >tmp && + ! grep " " tmp >/dev/null && + printf "$sss$sss$sss" | git stripspace >tmp && + ! grep " " tmp >/dev/null && + printf "$sss$sss$sss$sss" | git stripspace >tmp && + ! grep " " tmp >/dev/null ' -test_expect_success \ - 'spaces without newline at end should be replaced with empty string' ' - printf "" | git stripspace >actual && - test_must_be_empty actual && +test_expect_success 'spaces without newline at end should be replaced with empty string' ' + printf "" | git stripspace >actual && + test_must_be_empty actual && - printf "$sss$sss" | git stripspace >actual && - test_must_be_empty actual && + printf "$sss$sss" | git stripspace >actual && + test_must_be_empty actual && - printf "$sss$sss$sss" | git stripspace >actual && - test_must_be_empty actual && + printf "$sss$sss$sss" | git stripspace >actual && + test_must_be_empty actual && - printf "$sss$sss$sss$sss" | git stripspace >actual && - test_must_be_empty actual + printf "$sss$sss$sss$sss" | git stripspace >actual && + test_must_be_empty actual ' -test_expect_success \ - 'consecutive text lines should be unchanged' ' - printf "$ttt$ttt\n$ttt\n" >expect && - printf "$ttt$ttt\n$ttt\n" | git stripspace >actual && - test_cmp expect actual && +test_expect_success 'consecutive text lines should be unchanged' ' + printf "$ttt$ttt\n$ttt\n" >expect && + printf "$ttt$ttt\n$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt\n$ttt$ttt\n$ttt\n" >expect && - printf "$ttt\n$ttt$ttt\n$ttt\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt\n$ttt$ttt\n$ttt\n" >expect && + printf "$ttt\n$ttt$ttt\n$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt\n$ttt\n$ttt\n$ttt$ttt\n" >expect && - printf "$ttt\n$ttt\n$ttt\n$ttt$ttt\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt\n$ttt\n$ttt\n$ttt$ttt\n" >expect && + printf "$ttt\n$ttt\n$ttt\n$ttt$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt\n$ttt\n\n$ttt$ttt\n$ttt\n" >expect && - printf "$ttt\n$ttt\n\n$ttt$ttt\n$ttt\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt\n$ttt\n\n$ttt$ttt\n$ttt\n" >expect && + printf "$ttt\n$ttt\n\n$ttt$ttt\n$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt$ttt\n\n$ttt\n$ttt$ttt\n" >expect && - printf "$ttt$ttt\n\n$ttt\n$ttt$ttt\n" | git stripspace >actual && - test_cmp expect actual && + printf "$ttt$ttt\n\n$ttt\n$ttt$ttt\n" >expect && + printf "$ttt$ttt\n\n$ttt\n$ttt$ttt\n" | git stripspace >actual && + test_cmp expect actual && - printf "$ttt\n$ttt$ttt\n\n$ttt\n" >expect && - printf "$ttt\n$ttt$ttt\n\n$ttt\n" | git stripspace >actual && - test_cmp expect actual + printf "$ttt\n$ttt$ttt\n\n$ttt\n" >expect && + printf "$ttt\n$ttt$ttt\n\n$ttt\n" | git stripspace >actual && + test_cmp expect actual ' test_expect_success 'strip comments, too' ' diff --git a/t/t0033-safe-directory.sh b/t/t0033-safe-directory.sh index aecb308cf6..dc3496897a 100755 --- a/t/t0033-safe-directory.sh +++ b/t/t0033-safe-directory.sh @@ -71,4 +71,13 @@ test_expect_success 'safe.directory=*, but is reset' ' expect_rejected_dir ' +test_expect_success 'safe.directory in included file' ' + cat >gitconfig-include <<-EOF && + [safe] + directory = "$(pwd)" + EOF + git config --global --add include.path "$(pwd)/gitconfig-include" && + git status +' + test_done diff --git a/t/t0035-safe-bare-repository.sh b/t/t0035-safe-bare-repository.sh index ecbdc8238d..038b8b788d 100755 --- a/t/t0035-safe-bare-repository.sh +++ b/t/t0035-safe-bare-repository.sh @@ -7,13 +7,26 @@ TEST_PASSES_SANITIZE_LEAK=true pwd="$(pwd)" -expect_accepted () { - git "$@" rev-parse --git-dir +expect_accepted_implicit () { + test_when_finished 'rm "$pwd/trace.perf"' && + GIT_TRACE2_PERF="$pwd/trace.perf" git "$@" rev-parse --git-dir && + # Note: we're intentionally only checking that the bare repo has a + # directory *prefix* of $pwd + grep -F "implicit-bare-repository:$pwd" "$pwd/trace.perf" +} + +expect_accepted_explicit () { + test_when_finished 'rm "$pwd/trace.perf"' && + GIT_DIR="$1" GIT_TRACE2_PERF="$pwd/trace.perf" git rev-parse --git-dir && + ! grep -F "implicit-bare-repository:$pwd" "$pwd/trace.perf" } expect_rejected () { - test_must_fail git "$@" rev-parse --git-dir 2>err && - grep -F "cannot use bare repository" err + test_when_finished 'rm "$pwd/trace.perf"' && + test_env GIT_TRACE2_PERF="$pwd/trace.perf" \ + test_must_fail git "$@" rev-parse --git-dir 2>err && + grep -F "cannot use bare repository" err && + grep -F "implicit-bare-repository:$pwd" "$pwd/trace.perf" } test_expect_success 'setup bare repo in worktree' ' @@ -22,12 +35,13 @@ test_expect_success 'setup bare repo in worktree' ' ' test_expect_success 'safe.bareRepository unset' ' - expect_accepted -C outer-repo/bare-repo + test_unconfig --global safe.bareRepository && + expect_accepted_implicit -C outer-repo/bare-repo ' test_expect_success 'safe.bareRepository=all' ' test_config_global safe.bareRepository all && - expect_accepted -C outer-repo/bare-repo + expect_accepted_implicit -C outer-repo/bare-repo ' test_expect_success 'safe.bareRepository=explicit' ' @@ -47,8 +61,21 @@ test_expect_success 'safe.bareRepository in the repository' ' test_expect_success 'safe.bareRepository on the command line' ' test_config_global safe.bareRepository explicit && - expect_accepted -C outer-repo/bare-repo \ + expect_accepted_implicit -C outer-repo/bare-repo \ -c safe.bareRepository=all ' +test_expect_success 'safe.bareRepository in included file' ' + cat >gitconfig-include <<-\EOF && + [safe] + bareRepository = explicit + EOF + git config --global --add include.path "$(pwd)/gitconfig-include" && + expect_rejected -C outer-repo/bare-repo +' + +test_expect_success 'no trace when GIT_DIR is explicitly provided' ' + expect_accepted_explicit "$pwd/outer-repo/bare-repo" +' + test_done diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index 5cc62306e3..a0ad6192d6 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -13,29 +13,35 @@ usage: test-tool parse-options <options> A helper function for the parse-options API. - --yes get a boolean + --[no-]yes get a boolean -D, --no-doubt begins with 'no-' + --doubt opposite of --no-doubt -B, --no-fear be brave - -b, --boolean increment by one - -4, --or4 bitwise-or boolean with ...0100 - --neg-or4 same as --no-or4 + -b, --[no-]boolean increment by one + -4, --[no-]or4 bitwise-or boolean with ...0100 + --[no-]neg-or4 same as --no-or4 - -i, --integer <n> get a integer + -i, --[no-]integer <n> + get a integer -j <n> get a integer, too -m, --magnitude <n> get a magnitude - --set23 set integer to 23 + --[no-]set23 set integer to 23 --mode1 set integer to 1 (cmdmode option) --mode2 set integer to 2 (cmdmode option) - -L, --length <str> get length of <str> - -F, --file <file> set file to <file> + -L, --[no-]length <str> + get length of <str> + -F, --[no-]file <file> + set file to <file> String options - -s, --string <string> + -s, --[no-]string <string> get a string - --string2 <str> get another string - --st <st> get another string (pervert ordering) + --[no-]string2 <str> get another string + --[no-]st <st> get another string (pervert ordering) -o <str> get another string - --list <str> add str to list + --longhelp help text of this entry + spans multiple lines + --[no-]list <str> add str to list Magic arguments -NUM set integer to NUM @@ -44,16 +50,17 @@ Magic arguments --no-ambiguous negative ambiguity Standard options - --abbrev[=<n>] use <n> digits to display object names - -v, --verbose be verbose - -n, --dry-run dry run - -q, --quiet be quiet - --expect <string> expected output in the variable dump + --[no-]abbrev[=<n>] use <n> digits to display object names + -v, --[no-]verbose be verbose + -n, --[no-]dry-run dry run + -q, --[no-]quiet be quiet + --[no-]expect <string> + expected output in the variable dump Alias - -A, --alias-source <string> + -A, --[no-]alias-source <string> get a string - -Z, --alias-target <string> + -Z, --[no-]alias-target <string> alias of --alias-source EOF @@ -709,4 +716,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/t0041-usage.sh b/t/t0041-usage.sh index c4fc34eb18..9ea974b0c6 100755 --- a/t/t0041-usage.sh +++ b/t/t0041-usage.sh @@ -5,6 +5,7 @@ test_description='Test commands behavior when given invalid argument value' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup ' ' diff --git a/t/t0055-beyond-symlinks.sh b/t/t0055-beyond-symlinks.sh index 6bada37022..c3eb1158ef 100755 --- a/t/t0055-beyond-symlinks.sh +++ b/t/t0055-beyond-symlinks.sh @@ -15,12 +15,22 @@ test_expect_success SYMLINKS setup ' test_expect_success SYMLINKS 'update-index --add beyond symlinks' ' test_must_fail git update-index --add c/d && - ! ( git ls-files | grep c/d ) + cat >expect <<-\EOF && + a + b/d + EOF + git ls-files >actual && + test_cmp expect actual ' test_expect_success SYMLINKS 'add beyond symlinks' ' test_must_fail git add c/d && - ! ( git ls-files | grep c/d ) + cat >expect <<-\EOF && + a + b/d + EOF + git ls-files >actual && + test_cmp expect actual ' test_done diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh index 68e29c904a..0afa3d0d31 100755 --- a/t/t0060-path-utils.sh +++ b/t/t0060-path-utils.sh @@ -10,20 +10,27 @@ TEST_PASSES_SANITIZE_LEAK=true norm_path() { expected=$(test-tool path-utils print_path "$2") - test_expect_success $3 "normalize path: $1 => $2" \ - "test \"\$(test-tool path-utils normalize_path_copy '$1')\" = '$expected'" + test_expect_success $3 "normalize path: $1 => $2" " + echo '$expected' >expect && + test-tool path-utils normalize_path_copy '$1' >actual && + test_cmp expect actual + " } relative_path() { expected=$(test-tool path-utils print_path "$3") - test_expect_success $4 "relative path: $1 $2 => $3" \ - "test \"\$(test-tool path-utils relative_path '$1' '$2')\" = '$expected'" + test_expect_success $4 "relative path: $1 $2 => $3" " + echo '$expected' >expect && + test-tool path-utils relative_path '$1' '$2' >actual && + test_cmp expect actual + " } test_submodule_relative_url() { test_expect_success "test_submodule_relative_url: $1 $2 $3 => $4" " - actual=\$(test-tool submodule resolve-relative-url '$1' '$2' '$3') && - test \"\$actual\" = '$4' + echo '$4' >expect && + test-tool submodule resolve-relative-url '$1' '$2' '$3' >actual && + test_cmp expect actual " } @@ -64,9 +71,11 @@ ancestor() { expected=$(($expected-$rootslash+$rootoff)) ;; esac - test_expect_success $4 "longest ancestor: $1 $2 => $expected" \ - "actual=\$(test-tool path-utils longest_ancestor_length '$1' '$2') && - test \"\$actual\" = '$expected'" + test_expect_success $4 "longest ancestor: $1 $2 => $expected" " + echo '$expected' >expect && + test-tool path-utils longest_ancestor_length '$1' '$2' >actual && + test_cmp expect actual + " } # Some absolute path tests should be skipped on Windows due to path mangling @@ -166,8 +175,10 @@ ancestor D:/Users/me C:/ -1 MINGW ancestor //server/share/my-directory //server/share/ 14 MINGW test_expect_success 'strip_path_suffix' ' - test c:/msysgit = $(test-tool path-utils strip_path_suffix \ - c:/msysgit/libexec//git-core libexec/git-core) + echo c:/msysgit >expect && + test-tool path-utils strip_path_suffix \ + c:/msysgit/libexec//git-core libexec/git-core >actual && + test_cmp expect actual ' test_expect_success 'absolute path rejects the empty string' ' @@ -188,35 +199,61 @@ test_expect_success 'real path rejects the empty string' ' ' test_expect_success POSIX 'real path works on absolute paths 1' ' + echo / >expect && + test-tool path-utils real_path "/" >actual && + test_cmp expect actual && + nopath="hopefully-absent-path" && - test "/" = "$(test-tool path-utils real_path "/")" && - test "/$nopath" = "$(test-tool path-utils real_path "/$nopath")" + echo "/$nopath" >expect && + test-tool path-utils real_path "/$nopath" >actual && + test_cmp expect actual ' test_expect_success 'real path works on absolute paths 2' ' - nopath="hopefully-absent-path" && # Find an existing top-level directory for the remaining tests: d=$(pwd -P | sed -e "s|^\([^/]*/[^/]*\)/.*|\1|") && - test "$d" = "$(test-tool path-utils real_path "$d")" && - test "$d/$nopath" = "$(test-tool path-utils real_path "$d/$nopath")" + echo "$d" >expect && + test-tool path-utils real_path "$d" >actual && + test_cmp expect actual && + + nopath="hopefully-absent-path" && + echo "$d/$nopath" >expect && + test-tool path-utils real_path "$d/$nopath" >actual && + test_cmp expect actual ' test_expect_success POSIX 'real path removes extra leading slashes' ' + echo "/" >expect && + test-tool path-utils real_path "///" >actual && + test_cmp expect actual && + nopath="hopefully-absent-path" && - test "/" = "$(test-tool path-utils real_path "///")" && - test "/$nopath" = "$(test-tool path-utils real_path "///$nopath")" && + echo "/$nopath" >expect && + test-tool path-utils real_path "///$nopath" >actual && + test_cmp expect actual && + # Find an existing top-level directory for the remaining tests: d=$(pwd -P | sed -e "s|^\([^/]*/[^/]*\)/.*|\1|") && - test "$d" = "$(test-tool path-utils real_path "//$d")" && - test "$d/$nopath" = "$(test-tool path-utils real_path "//$d/$nopath")" + echo "$d" >expect && + test-tool path-utils real_path "//$d" >actual && + test_cmp expect actual && + + echo "$d/$nopath" >expect && + test-tool path-utils real_path "//$d/$nopath" >actual && + test_cmp expect actual ' test_expect_success 'real path removes other extra slashes' ' - nopath="hopefully-absent-path" && # Find an existing top-level directory for the remaining tests: d=$(pwd -P | sed -e "s|^\([^/]*/[^/]*\)/.*|\1|") && - test "$d" = "$(test-tool path-utils real_path "$d///")" && - test "$d/$nopath" = "$(test-tool path-utils real_path "$d///$nopath")" + echo "$d" >expect && + test-tool path-utils real_path "$d///" >actual && + test_cmp expect actual && + + nopath="hopefully-absent-path" && + echo "$d/$nopath" >expect && + test-tool path-utils real_path "$d///$nopath" >actual && + test_cmp expect actual ' test_expect_success SYMLINKS 'real path works on symlinks' ' @@ -227,19 +264,29 @@ test_expect_success SYMLINKS 'real path works on symlinks' ' mkdir third && dir="$(cd .git && pwd -P)" && dir2=third/../second/other/.git && - test "$dir" = "$(test-tool path-utils real_path $dir2)" && + echo "$dir" >expect && + test-tool path-utils real_path $dir2 >actual && + test_cmp expect actual && file="$dir"/index && - test "$file" = "$(test-tool path-utils real_path $dir2/index)" && + echo "$file" >expect && + test-tool path-utils real_path $dir2/index >actual && + test_cmp expect actual && basename=blub && - test "$dir/$basename" = "$(cd .git && test-tool path-utils real_path "$basename")" && + echo "$dir/$basename" >expect && + test-tool -C .git path-utils real_path "$basename" >actual && + test_cmp expect actual && ln -s ../first/file .git/syml && sym="$(cd first && pwd -P)"/file && - test "$sym" = "$(test-tool path-utils real_path "$dir2/syml")" + echo "$sym" >expect && + test-tool path-utils real_path "$dir2/syml" >actual && + test_cmp expect actual ' test_expect_success SYMLINKS 'prefix_path works with absolute paths to work tree symlinks' ' ln -s target symlink && - test "$(test-tool path-utils prefix_path prefix "$(pwd)/symlink")" = "symlink" + echo "symlink" >expect && + test-tool path-utils prefix_path prefix "$(pwd)/symlink" >actual && + test_cmp expect actual ' test_expect_success 'prefix_path works with only absolute path to work tree' ' @@ -255,7 +302,10 @@ test_expect_success 'prefix_path rejects absolute path to dir with same beginnin test_expect_success SYMLINKS 'prefix_path works with absolute path to a symlink to work tree having same beginning as work tree' ' git init repo && ln -s repo repolink && - test "a" = "$(cd repo && test-tool path-utils prefix_path prefix "$(pwd)/../repolink/a")" + echo "a" >expect && + repo_path="$(cd repo && pwd)" && + test-tool -C repo path-utils prefix_path prefix "$repo_path/../repolink/a" >actual && + test_cmp expect actual ' relative_path /foo/a/b/c/ /foo/a/b/ c/ 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/t0063-string-list.sh b/t/t0063-string-list.sh index 46d4839194..1fee6d9010 100755 --- a/t/t0063-string-list.sh +++ b/t/t0063-string-list.sh @@ -18,6 +18,14 @@ test_split () { " } +test_split_in_place() { + cat >expected && + test_expect_success "split (in place) $1 at $2, max $3" " + test-tool string-list split_in_place '$1' '$2' '$3' >actual && + test_cmp expected actual + " +} + test_split "foo:bar:baz" ":" "-1" <<EOF 3 [0]: "foo" @@ -61,6 +69,49 @@ test_split ":" ":" "-1" <<EOF [1]: "" EOF +test_split_in_place "foo:;:bar:;:baz:;:" ":;" "-1" <<EOF +10 +[0]: "foo" +[1]: "" +[2]: "" +[3]: "bar" +[4]: "" +[5]: "" +[6]: "baz" +[7]: "" +[8]: "" +[9]: "" +EOF + +test_split_in_place "foo:;:bar:;:baz" ":;" "0" <<EOF +1 +[0]: "foo:;:bar:;:baz" +EOF + +test_split_in_place "foo:;:bar:;:baz" ":;" "1" <<EOF +2 +[0]: "foo" +[1]: ";:bar:;:baz" +EOF + +test_split_in_place "foo:;:bar:;:baz" ":;" "2" <<EOF +3 +[0]: "foo" +[1]: "" +[2]: ":bar:;:baz" +EOF + +test_split_in_place "foo:;:bar:;:" ":;" "-1" <<EOF +7 +[0]: "foo" +[1]: "" +[2]: "" +[3]: "bar" +[4]: "" +[5]: "" +[6]: "" +EOF + test_expect_success "test filter_string_list" ' test "x-" = "x$(test-tool string-list filter - y)" && test "x-" = "x$(test-tool string-list filter no y)" && diff --git a/t/t0066-dir-iterator.sh b/t/t0066-dir-iterator.sh index 04b811622b..7d0a0da8c0 100755 --- a/t/t0066-dir-iterator.sh +++ b/t/t0066-dir-iterator.sh @@ -106,13 +106,7 @@ test_expect_success SYMLINKS 'setup dirs with symlinks' ' ln -s d dir4/a/e && ln -s ../b dir4/a/f && - mkdir -p dir5/a/b && - mkdir -p dir5/a/c && - ln -s ../c dir5/a/b/d && - ln -s ../ dir5/a/b/e && - ln -s ../../ dir5/a/b/f && - - ln -s dir4 dir6 + ln -s dir4 dir5 ' test_expect_success SYMLINKS 'dir-iterator should not follow symlinks by default' ' @@ -131,44 +125,10 @@ test_expect_success SYMLINKS 'dir-iterator should not follow symlinks by default test_cmp expected-no-follow-sorted-output actual-no-follow-sorted-output ' -test_expect_success SYMLINKS 'dir-iterator should follow symlinks w/ follow flag' ' - cat >expected-follow-sorted-output <<-EOF && - [d] (a) [a] ./dir4/a - [d] (a/f) [f] ./dir4/a/f - [d] (a/f/c) [c] ./dir4/a/f/c - [d] (b) [b] ./dir4/b - [d] (b/c) [c] ./dir4/b/c - [f] (a/d) [d] ./dir4/a/d - [f] (a/e) [e] ./dir4/a/e - EOF - - test-tool dir-iterator --follow-symlinks ./dir4 >out && - sort out >actual-follow-sorted-output && - - test_cmp expected-follow-sorted-output actual-follow-sorted-output -' - test_expect_success SYMLINKS 'dir-iterator does not resolve top-level symlinks' ' - test_must_fail test-tool dir-iterator ./dir6 >out && + test_must_fail test-tool dir-iterator ./dir5 >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..4b90b74d5d 100755 --- a/t/t0068-for-each-repo.sh +++ b/t/t0068-for-each-repo.sh @@ -2,15 +2,18 @@ test_description='git for-each-repo builtin' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh 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 +21,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 ' @@ -33,4 +40,23 @@ test_expect_success 'do nothing on empty config' ' git for-each-repo --config=bogus.config -- help --no-such-option ' +test_expect_success 'error on bad config keys' ' + test_expect_code 129 git for-each-repo --config=a && + test_expect_code 129 git for-each-repo --config=a.b. && + test_expect_code 129 git for-each-repo --config="'\''.b" +' + +test_expect_success 'error on NULL value for config keys' ' + cat >>.git/config <<-\EOF && + [empty] + key + EOF + cat >expect <<-\EOF && + error: missing value for '\''empty.key'\'' + EOF + test_expect_code 129 git for-each-repo --config=empty.key 2>actual.raw && + grep ^error actual.raw >actual && + test_cmp expect actual +' + test_done diff --git a/t/t0070-fundamental.sh b/t/t0070-fundamental.sh index 8d59905ef0..574de34198 100755 --- a/t/t0070-fundamental.sh +++ b/t/t0070-fundamental.sh @@ -6,6 +6,7 @@ test_description='check that the most basic functions work Verify wrappers and compatibility functions. ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'character classes (isspace, isalpha etc.)' ' diff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh index b6d2f591ac..f6998269be 100755 --- a/t/t0091-bugreport.sh +++ b/t/t0091-bugreport.sh @@ -5,29 +5,50 @@ test_description='git bugreport' TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh -# Headers "[System Info]" will be followed by a non-empty line if we put some -# information there; we can make sure all our headers were followed by some -# information to check if the command was successful. -HEADER_PATTERN="^\[.*\]$" - -check_all_headers_populated () { - while read -r line - do - if test "$(grep "$HEADER_PATTERN" "$line")" - then - echo "$line" - read -r nextline - if test -z "$nextline"; then - return 1; - fi - fi - done -} - -test_expect_success 'creates a report with content in the right places' ' - test_when_finished rm git-bugreport-check-headers.txt && - git bugreport -s check-headers && - check_all_headers_populated <git-bugreport-check-headers.txt +test_expect_success 'create a report' ' + git bugreport -s format && + test_file_not_empty git-bugreport-format.txt +' + +test_expect_success 'report contains wanted template (before first section)' ' + sed -ne "/^\[/q;p" git-bugreport-format.txt >actual && + cat >expect <<-\EOF && + Thank you for filling out a Git bug report! + Please answer the following questions to help us understand your issue. + + What did you do before the bug happened? (Steps to reproduce your issue) + + What did you expect to happen? (Expected behavior) + + What happened instead? (Actual behavior) + + What'\''s different between what you expected and what actually happened? + + Anything else you want to add: + + Please review the rest of the bug report below. + You can delete any lines you don'\''t wish to share. + + + EOF + test_cmp expect actual +' + +test_expect_success 'sanity check "System Info" section' ' + test_when_finished rm -f git-bugreport-format.txt && + + sed -ne "/^\[System Info\]$/,/^$/p" <git-bugreport-format.txt >system && + + # The beginning should match "git version --build-info" verbatim, + # but rather than checking bit-for-bit equality, just test some basics. + grep "git version [0-9]." system && + grep "shell-path: ." system && + + # After the version, there should be some more info. + # This is bound to differ from environment to environment, + # so we just do some rather high-level checks. + grep "uname: ." system && + grep "compiler info: ." system ' test_expect_success 'dies if file with same name as report already exists' ' diff --git a/t/t0100-previous.sh b/t/t0100-previous.sh index a16cc3d298..70a3223f21 100755 --- a/t/t0100-previous.sh +++ b/t/t0100-previous.sh @@ -12,7 +12,9 @@ test_expect_success 'branch -d @{-1}' ' test_commit A && git checkout -b junk && git checkout - && - test "$(git symbolic-ref HEAD)" = refs/heads/main && + echo refs/heads/main >expect && + git symbolic-ref HEAD >actual && + test_cmp expect actual && git branch -d @{-1} && test_must_fail git rev-parse --verify refs/heads/junk ' @@ -21,7 +23,9 @@ test_expect_success 'branch -d @{-12} when there is not enough switches yet' ' git reflog expire --expire=now && git checkout -b junk2 && git checkout - && - test "$(git symbolic-ref HEAD)" = refs/heads/main && + echo refs/heads/main >expect && + git symbolic-ref HEAD >actual && + test_cmp expect actual && test_must_fail git branch -d @{-12} && git rev-parse --verify refs/heads/main ' diff --git a/t/t0211-trace2-perf.sh b/t/t0211-trace2-perf.sh index 22d0845544..cfba686132 100755 --- a/t/t0211-trace2-perf.sh +++ b/t/t0211-trace2-perf.sh @@ -173,4 +173,99 @@ test_expect_success 'using global config, perf stream, return code 0' ' test_cmp expect actual ' +# Exercise the stopwatch timers in a loop and confirm that we have +# as many start/stop intervals as expected. We cannot really test the +# actual (total, min, max) timer values, so we have to assume that they +# are good, but we can verify the interval count. +# +# The timer "test/test1" should only emit a global summary "timer" event. +# The timer "test/test2" should emit per-thread "th_timer" events and a +# global summary "timer" event. + +have_timer_event () { + thread=$1 event=$2 category=$3 name=$4 intervals=$5 file=$6 && + + pattern="d0|${thread}|${event}||||${category}|name:${name} intervals:${intervals}" && + + grep "${pattern}" ${file} +} + +test_expect_success 'stopwatch timer test/test1' ' + test_when_finished "rm trace.perf actual" && + test_config_global trace2.perfBrief 1 && + test_config_global trace2.perfTarget "$(pwd)/trace.perf" && + + # Use the timer "test1" 5 times from "main". + test-tool trace2 100timer 5 10 && + + perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <trace.perf >actual && + + have_timer_event "main" "timer" "test" "test1" 5 actual +' + +test_expect_success PTHREADS '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" && + + # Use the timer "test2" 5 times each in 3 threads. + test-tool trace2 101timer 5 10 3 && + + perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <trace.perf >actual && + + # So we should have 3 per-thread events of 5 each. + have_timer_event "th01:ut_101" "th_timer" "test" "test2" 5 actual && + have_timer_event "th02:ut_101" "th_timer" "test" "test2" 5 actual && + have_timer_event "th03:ut_101" "th_timer" "test" "test2" 5 actual && + + # And we should have 15 total uses. + have_timer_event "main" "timer" "test" "test2" 15 actual +' + +# Exercise the global counters and confirm that we get the expected values. +# +# The counter "test/test1" should only emit a global summary "counter" event. +# The counter "test/test2" could emit per-thread "th_counter" events and a +# global summary "counter" event. + +have_counter_event () { + thread=$1 event=$2 category=$3 name=$4 value=$5 file=$6 && + + pattern="d0|${thread}|${event}||||${category}|name:${name} value:${value}" && + + grep "${patern}" ${file} +} + +test_expect_success 'global counter test/test1' ' + test_when_finished "rm trace.perf actual" && + test_config_global trace2.perfBrief 1 && + test_config_global trace2.perfTarget "$(pwd)/trace.perf" && + + # Use the counter "test1" and add n integers. + test-tool trace2 200counter 1 2 3 4 5 && + + perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <trace.perf >actual && + + have_counter_event "main" "counter" "test" "test1" 15 actual +' + +test_expect_success PTHREADS '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" && + + # Add 2 integers to the counter "test2" in each of 3 threads. + test-tool trace2 201counter 7 13 3 && + + perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <trace.perf >actual && + + # So we should have 3 per-thread events of 5 each. + have_counter_event "th01:ut_201" "th_counter" "test" "test2" 20 actual && + have_counter_event "th02:ut_201" "th_counter" "test" "test2" 20 actual && + have_counter_event "th03:ut_201" "th_counter" "test" "test2" 20 actual && + + # And we should have a single event with the total across all threads. + have_counter_event "main" "counter" "test" "test2" 60 actual +' + test_done diff --git a/t/t0211/scrub_perf.perl b/t/t0211/scrub_perf.perl index 299999f0f8..7a50bae646 100644 --- a/t/t0211/scrub_perf.perl +++ b/t/t0211/scrub_perf.perl @@ -64,6 +64,12 @@ while (<>) { goto SKIP_LINE; } } + elsif ($tokens[$col_event] =~ m/timer/) { + # This also captures "th_timer" events + $tokens[$col_rest] =~ s/ total:\d+\.\d*/ total:_T_TOTAL_/; + $tokens[$col_rest] =~ s/ min:\d+\.\d*/ min:_T_MIN_/; + $tokens[$col_rest] =~ s/ max:\d+\.\d*/ max:_T_MAX_/; + } # t_abs and t_rel are either blank or a float. Replace the float # with a constant for matching the HEREDOC in the test script. diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh index 3485c0534e..a4f5bba507 100755 --- a/t/t0300-credentials.sh +++ b/t/t0300-credentials.sh @@ -35,6 +35,16 @@ test_expect_success 'setup helper scripts' ' test -z "$pass" || echo password=$pass EOF + write_script git-credential-verbatim-with-expiry <<-\EOF && + user=$1; shift + pass=$1; shift + pexpiry=$1; shift + . ./dump + test -z "$user" || echo username=$user + test -z "$pass" || echo password=$pass + test -z "$pexpiry" || echo password_expiry_utc=$pexpiry + EOF + PATH="$PWD:$PATH" ' @@ -109,6 +119,43 @@ test_expect_success 'credential_fill continues through partial response' ' EOF ' +test_expect_success 'credential_fill populates password_expiry_utc' ' + check fill "verbatim-with-expiry one two 9999999999" <<-\EOF + protocol=http + host=example.com + -- + protocol=http + host=example.com + username=one + password=two + password_expiry_utc=9999999999 + -- + verbatim-with-expiry: get + verbatim-with-expiry: protocol=http + verbatim-with-expiry: host=example.com + EOF +' + +test_expect_success 'credential_fill ignores expired password' ' + check fill "verbatim-with-expiry one two 5" "verbatim three four" <<-\EOF + protocol=http + host=example.com + -- + protocol=http + host=example.com + username=three + password=four + -- + verbatim-with-expiry: get + verbatim-with-expiry: protocol=http + verbatim-with-expiry: host=example.com + verbatim: get + verbatim: protocol=http + verbatim: host=example.com + verbatim: username=one + EOF +' + test_expect_success 'credential_fill passes along metadata' ' check fill "verbatim one two" <<-\EOF protocol=ftp @@ -149,6 +196,42 @@ test_expect_success 'credential_approve calls all helpers' ' EOF ' +test_expect_success 'credential_approve stores password expiry' ' + check approve useless <<-\EOF + protocol=http + host=example.com + username=foo + password=bar + password_expiry_utc=9999999999 + -- + -- + useless: store + useless: protocol=http + useless: host=example.com + useless: username=foo + useless: password=bar + useless: password_expiry_utc=9999999999 + EOF +' + +test_expect_success 'credential_approve stores oauth refresh token' ' + check approve useless <<-\EOF + protocol=http + host=example.com + username=foo + password=bar + oauth_refresh_token=xyzzy + -- + -- + useless: store + useless: protocol=http + useless: host=example.com + useless: username=foo + useless: password=bar + useless: oauth_refresh_token=xyzzy + EOF +' + test_expect_success 'do not bother storing password-less credential' ' check approve useless <<-\EOF protocol=http @@ -159,6 +242,17 @@ test_expect_success 'do not bother storing password-less credential' ' EOF ' +test_expect_success 'credential_approve does not store expired password' ' + check approve useless <<-\EOF + protocol=http + host=example.com + username=foo + password=bar + password_expiry_utc=5 + -- + -- + EOF +' test_expect_success 'credential_reject calls all helpers' ' check reject useless "verbatim one two" <<-\EOF @@ -181,6 +275,24 @@ test_expect_success 'credential_reject calls all helpers' ' EOF ' +test_expect_success 'credential_reject erases credential regardless of expiry' ' + check reject useless <<-\EOF + protocol=http + host=example.com + username=foo + password=bar + password_expiry_utc=5 + -- + -- + useless: erase + useless: protocol=http + useless: host=example.com + useless: username=foo + useless: password=bar + useless: password_expiry_utc=5 + EOF +' + test_expect_success 'usernames can be preserved' ' check fill "verbatim \"\" three" <<-\EOF protocol=http @@ -714,7 +826,7 @@ test_expect_success 'credential config with partial URLs' ' git -c credential.$partial.helper=yep \ -c credential.with%0anewline.username=uh-oh \ - credential fill <stdin >stdout 2>stderr && + credential fill <stdin 2>stderr && test_i18ngrep "skipping credential lookup for key" stderr ' diff --git a/t/t0301-credential-cache.sh b/t/t0301-credential-cache.sh index 698b7159f0..8300faadea 100755 --- a/t/t0301-credential-cache.sh +++ b/t/t0301-credential-cache.sh @@ -29,6 +29,8 @@ test_atexit 'git credential-cache exit' # test that the daemon works with no special setup helper_test cache +helper_test_password_expiry_utc cache +helper_test_oauth_refresh_token cache test_expect_success 'socket defaults to ~/.cache/git/credential/socket' ' test_when_finished " diff --git a/t/t0303-credential-external.sh b/t/t0303-credential-external.sh index f028fd1418..095574bfc6 100755 --- a/t/t0303-credential-external.sh +++ b/t/t0303-credential-external.sh @@ -45,6 +45,8 @@ test -z "$GIT_TEST_CREDENTIAL_HELPER_SETUP" || helper_test_clean "$GIT_TEST_CREDENTIAL_HELPER" helper_test "$GIT_TEST_CREDENTIAL_HELPER" +helper_test_password_expiry_utc "$GIT_TEST_CREDENTIAL_HELPER" +helper_test_oauth_refresh_token "$GIT_TEST_CREDENTIAL_HELPER" if test -z "$GIT_TEST_CREDENTIAL_HELPER_TIMEOUT"; then say "# skipping timeout tests (GIT_TEST_CREDENTIAL_HELPER_TIMEOUT not set)" diff --git a/t/t0410-partial-clone.sh b/t/t0410-partial-clone.sh index 1e864cf317..5b7bee888d 100755 --- a/t/t0410-partial-clone.sh +++ b/t/t0410-partial-clone.sh @@ -215,6 +215,20 @@ test_expect_success 'fetching of missing objects' ' grep "$HASH" out ' +test_expect_success 'fetching of a promised object that promisor remote no longer has' ' + rm -f err && + test_create_repo unreliable-server && + git -C unreliable-server config uploadpack.allowanysha1inwant 1 && + git -C unreliable-server config uploadpack.allowfilter 1 && + test_commit -C unreliable-server foo && + + git clone --filter=blob:none --no-checkout "file://$(pwd)/unreliable-server" unreliable-client && + + rm -rf unreliable-server/.git/objects/* && + test_must_fail git -C unreliable-client checkout HEAD 2>err && + grep "could not fetch.*from promisor remote" err +' + test_expect_success 'fetching of missing objects works with ref-in-want enabled' ' # ref-in-want requires protocol version 2 git -C server config protocol.version 2 && diff --git a/t/t0450-txt-doc-vs-help.sh b/t/t0450-txt-doc-vs-help.sh new file mode 100755 index 0000000000..cd3969e852 --- /dev/null +++ b/t/t0450-txt-doc-vs-help.sh @@ -0,0 +1,172 @@ +#!/bin/sh + +test_description='assert (unbuilt) Documentation/*.txt and -h output + +Run this with --debug to see a summary of where we still fail to make +the two versions consistent with one another.' + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +test_expect_success 'setup: list of builtins' ' + git --list-cmds=builtins >builtins +' + +test_expect_success 'list of txt and help mismatches is sorted' ' + sort -u "$TEST_DIRECTORY"/t0450/txt-help-mismatches >expect && + if ! test_cmp expect "$TEST_DIRECTORY"/t0450/txt-help-mismatches + then + BUG "please keep the list of txt and help mismatches sorted" + fi +' + +help_to_synopsis () { + builtin="$1" && + out_dir="out/$builtin" && + out="$out_dir/help.synopsis" && + if test -f "$out" + then + echo "$out" && + return 0 + fi && + mkdir -p "$out_dir" && + test_expect_code 129 git $builtin -h >"$out.raw" 2>&1 && + sed -n \ + -e '1,/^$/ { + /^$/d; + s/^usage: //; + s/^ *or: //; + p; + }' <"$out.raw" >"$out" && + echo "$out" +} + +builtin_to_txt () { + echo "$GIT_BUILD_DIR/Documentation/git-$1.txt" +} + +txt_to_synopsis () { + builtin="$1" && + out_dir="out/$builtin" && + out="$out_dir/txt.synopsis" && + if test -f "$out" + then + echo "$out" && + return 0 + fi && + b2t="$(builtin_to_txt "$builtin")" && + sed -n \ + -e '/^\[verse\]$/,/^$/ { + /^$/d; + /^\[verse\]$/d; + + s/{litdd}/--/g; + s/'\''\(git[ a-z-]*\)'\''/\1/g; + + p; + }' \ + <"$b2t" >"$out" && + echo "$out" +} + +check_dashed_labels () { + ! grep -E "<[^>_-]+_" "$1" +} + +HT=" " + +align_after_nl () { + builtin="$1" && + len=$(printf "git %s " "$builtin" | wc -c) && + pad=$(printf "%${len}s" "") && + + sed "s/^[ $HT][ $HT]*/$pad/" +} + +test_debug '>failing' +while read builtin +do + # -h output assertions + test_expect_success "$builtin -h output has no \t" ' + h2s="$(help_to_synopsis "$builtin")" && + ! grep "$HT" "$h2s" + ' + + test_expect_success "$builtin -h output has dashed labels" ' + check_dashed_labels "$(help_to_synopsis "$builtin")" + ' + + test_expect_success "$builtin -h output has consistent spacing" ' + h2s="$(help_to_synopsis "$builtin")" && + sed -n \ + -e "/^ / { + s/[^ ].*//; + p; + }" \ + <"$h2s" >help && + sort -u help >help.ws && + if test -s help.ws + then + test_line_count = 1 help.ws + fi + ' + + txt="$(builtin_to_txt "$builtin")" && + preq="$(echo BUILTIN_TXT_$builtin | tr '[:lower:]-' '[:upper:]_')" && + + if test -f "$txt" + then + test_set_prereq "$preq" + fi && + + # *.txt output assertions + test_expect_success "$preq" "$builtin *.txt SYNOPSIS has dashed labels" ' + check_dashed_labels "$(txt_to_synopsis "$builtin")" + ' + + # *.txt output consistency assertions + result= + if grep -q "^$builtin$" "$TEST_DIRECTORY"/t0450/txt-help-mismatches + then + result=failure + else + result=success + fi && + test_expect_$result "$preq" "$builtin -h output and SYNOPSIS agree" ' + t2s="$(txt_to_synopsis "$builtin")" && + if test "$builtin" = "merge-tree" + then + test_when_finished "rm -f t2s.new" && + sed -e '\''s/ (deprecated)$//g'\'' <"$t2s" >t2s.new + t2s=t2s.new + fi && + h2s="$(help_to_synopsis "$builtin")" && + + # The *.txt and -h use different spacing for the + # alignment of continued usage output, normalize it. + align_after_nl "$builtin" <"$t2s" >txt && + align_after_nl "$builtin" <"$h2s" >help && + test_cmp txt help + ' + + if test_have_prereq "$preq" && test -e txt && test -e help + then + test_debug ' + if test_cmp txt help >cmp 2>/dev/null + then + echo "=== DONE: $builtin ===" + else + echo "=== TODO: $builtin ===" && + cat cmp + fi >>failing + ' + + # Not in test_expect_success in case --run is being + # used with --debug + rm -f txt help tmp 2>/dev/null + fi +done <builtins + +test_debug 'say "$(cat failing)"' + +test_done diff --git a/t/t0450/txt-help-mismatches b/t/t0450/txt-help-mismatches new file mode 100644 index 0000000000..a0777acd66 --- /dev/null +++ b/t/t0450/txt-help-mismatches @@ -0,0 +1,58 @@ +add +am +apply +archive +bisect +blame +branch +check-ref-format +checkout +checkout-index +clone +column +config +credential +credential-cache +credential-store +fast-export +fast-import +fetch-pack +fmt-merge-msg +for-each-ref +format-patch +fsck-objects +fsmonitor--daemon +gc +grep +index-pack +init-db +log +ls-files +ls-tree +mailinfo +mailsplit +maintenance +merge +merge-file +merge-index +merge-one-file +multi-pack-index +name-rev +notes +pack-objects +push +range-diff +rebase +remote +remote-ext +remote-fd +repack +reset +restore +rev-parse +show +stage +switch +update-index +update-ref +whatchanged diff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh index 516a6112fd..88c524f655 100755 --- a/t/t1001-read-tree-m-2way.sh +++ b/t/t1001-read-tree-m-2way.sh @@ -26,7 +26,7 @@ TEST_PASSES_SANITIZE_LEAK=true . "$TEST_DIRECTORY"/lib-read-tree.sh read_tree_twoway () { - git read-tree -m "$1" "$2" && git ls-files --stage + git read-tree -m "$1" "$2" && git ls-files --stage } compare_change () { @@ -370,7 +370,7 @@ test_expect_success 'read-tree supports the super-prefix' ' cat <<-EOF >expect && error: Updating '\''fictional/a'\'' would lose untracked files in it EOF - test_must_fail git --super-prefix fictional/ read-tree -u -m "$treeH" "$treeM" 2>actual && + test_must_fail git read-tree --super-prefix fictional/ -u -m "$treeH" "$treeM" 2>actual && test_cmp expect actual ' diff --git a/t/t1002-read-tree-m-u-2way.sh b/t/t1002-read-tree-m-u-2way.sh index bd5313caec..a7c2ed0d7c 100755 --- a/t/t1002-read-tree-m-u-2way.sh +++ b/t/t1002-read-tree-m-u-2way.sh @@ -37,315 +37,312 @@ check_cache_at () { esac } -test_expect_success \ - setup \ - 'echo frotz >frotz && - echo nitfol >nitfol && - echo bozbar >bozbar && - echo rezrov >rezrov && - git update-index --add nitfol bozbar rezrov && - treeH=$(git write-tree) && - echo treeH $treeH && - git ls-tree $treeH && - - echo gnusto >bozbar && - git update-index --add frotz bozbar --force-remove rezrov && - git ls-files --stage >M.out && - treeM=$(git write-tree) && - echo treeM $treeM && - git ls-tree $treeM && - cp bozbar bozbar.M && - cp frotz frotz.M && - cp nitfol nitfol.M && - git diff-tree $treeH $treeM' - -test_expect_success \ - '1, 2, 3 - no carry forward' \ - 'rm -f .git/index nitfol bozbar rezrov frotz && - read_tree_u_must_succeed --reset -u $treeH && - read_tree_u_must_succeed -m -u $treeH $treeM && - git ls-files --stage >1-3.out && - cmp M.out 1-3.out && - test_cmp bozbar.M bozbar && - test_cmp frotz.M frotz && - test_cmp nitfol.M nitfol && - check_cache_at bozbar clean && - check_cache_at frotz clean && - check_cache_at nitfol clean' - -test_expect_success \ - '4 - carry forward local addition.' \ - 'rm -f .git/index nitfol bozbar rezrov frotz && - read_tree_u_must_succeed --reset -u $treeH && - echo "+100644 X 0 yomin" >expected && - echo yomin >yomin && - git update-index --add yomin && - read_tree_u_must_succeed -m -u $treeH $treeM && - git ls-files --stage >4.out && - test_might_fail git diff -U0 --no-index M.out 4.out >4diff.out && - compare_change 4diff.out expected && - check_cache_at yomin clean && - test_cmp bozbar.M bozbar && - test_cmp frotz.M frotz && - test_cmp nitfol.M nitfol && - echo yomin >yomin1 && - diff yomin yomin1 && - rm -f yomin1' - -test_expect_success \ - '5 - carry forward local addition.' \ - 'rm -f .git/index nitfol bozbar rezrov frotz && - read_tree_u_must_succeed --reset -u $treeH && - read_tree_u_must_succeed -m -u $treeH && - echo yomin >yomin && - git update-index --add yomin && - echo yomin yomin >yomin && - read_tree_u_must_succeed -m -u $treeH $treeM && - git ls-files --stage >5.out && - test_might_fail git diff -U0 --no-index M.out 5.out >5diff.out && - compare_change 5diff.out expected && - check_cache_at yomin dirty && - test_cmp bozbar.M bozbar && - test_cmp frotz.M frotz && - test_cmp nitfol.M nitfol && - : dirty index should have prevented -u from checking it out. && - echo yomin yomin >yomin1 && - diff yomin yomin1 && - rm -f yomin1' - -test_expect_success \ - '6 - local addition already has the same.' \ - 'rm -f .git/index nitfol bozbar rezrov frotz && - read_tree_u_must_succeed --reset -u $treeH && - echo frotz >frotz && - git update-index --add frotz && - read_tree_u_must_succeed -m -u $treeH $treeM && - git ls-files --stage >6.out && - test_cmp M.out 6.out && - check_cache_at frotz clean && - test_cmp bozbar.M bozbar && - test_cmp frotz.M frotz && - test_cmp nitfol.M nitfol && - echo frotz >frotz1 && - diff frotz frotz1 && - rm -f frotz1' - -test_expect_success \ - '7 - local addition already has the same.' \ - 'rm -f .git/index nitfol bozbar rezrov frotz && - read_tree_u_must_succeed --reset -u $treeH && - echo frotz >frotz && - git update-index --add frotz && - echo frotz frotz >frotz && - read_tree_u_must_succeed -m -u $treeH $treeM && - git ls-files --stage >7.out && - test_cmp M.out 7.out && - check_cache_at frotz dirty && - test_cmp bozbar.M bozbar && - test_cmp nitfol.M nitfol && - : dirty index should have prevented -u from checking it out. && - echo frotz frotz >frotz1 && - diff frotz frotz1 && - rm -f frotz1' - -test_expect_success \ - '8 - conflicting addition.' \ - 'rm -f .git/index nitfol bozbar rezrov frotz && - read_tree_u_must_succeed --reset -u $treeH && - echo frotz frotz >frotz && - git update-index --add frotz && - if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi' - -test_expect_success \ - '9 - conflicting addition.' \ - 'rm -f .git/index nitfol bozbar rezrov frotz && - read_tree_u_must_succeed --reset -u $treeH && - echo frotz frotz >frotz && - git update-index --add frotz && - echo frotz >frotz && - if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi' - -test_expect_success \ - '10 - path removed.' \ - 'rm -f .git/index nitfol bozbar rezrov frotz && - read_tree_u_must_succeed --reset -u $treeH && - echo rezrov >rezrov && - git update-index --add rezrov && - read_tree_u_must_succeed -m -u $treeH $treeM && - git ls-files --stage >10.out && - cmp M.out 10.out && - test_cmp bozbar.M bozbar && - test_cmp frotz.M frotz && - test_cmp nitfol.M nitfol +test_expect_success setup ' + echo frotz >frotz && + echo nitfol >nitfol && + echo bozbar >bozbar && + echo rezrov >rezrov && + git update-index --add nitfol bozbar rezrov && + treeH=$(git write-tree) && + echo treeH $treeH && + git ls-tree $treeH && + + echo gnusto >bozbar && + git update-index --add frotz bozbar --force-remove rezrov && + git ls-files --stage >M.out && + treeM=$(git write-tree) && + echo treeM $treeM && + git ls-tree $treeM && + cp bozbar bozbar.M && + cp frotz frotz.M && + cp nitfol nitfol.M && + git diff-tree $treeH $treeM ' -test_expect_success \ - '11 - dirty path removed.' \ - 'rm -f .git/index nitfol bozbar rezrov frotz && - read_tree_u_must_succeed --reset -u $treeH && - echo rezrov >rezrov && - git update-index --add rezrov && - echo rezrov rezrov >rezrov && - if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi' - -test_expect_success \ - '12 - unmatching local changes being removed.' \ - 'rm -f .git/index nitfol bozbar rezrov frotz && - read_tree_u_must_succeed --reset -u $treeH && - echo rezrov rezrov >rezrov && - git update-index --add rezrov && - if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi' - -test_expect_success \ - '13 - unmatching local changes being removed.' \ - 'rm -f .git/index nitfol bozbar rezrov frotz && - read_tree_u_must_succeed --reset -u $treeH && - echo rezrov rezrov >rezrov && - git update-index --add rezrov && - echo rezrov >rezrov && - if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi' +test_expect_success '1, 2, 3 - no carry forward' ' + rm -f .git/index nitfol bozbar rezrov frotz && + read_tree_u_must_succeed --reset -u $treeH && + read_tree_u_must_succeed -m -u $treeH $treeM && + git ls-files --stage >1-3.out && + cmp M.out 1-3.out && + test_cmp bozbar.M bozbar && + test_cmp frotz.M frotz && + test_cmp nitfol.M nitfol && + check_cache_at bozbar clean && + check_cache_at frotz clean && + check_cache_at nitfol clean +' + +test_expect_success '4 - carry forward local addition.' ' + rm -f .git/index nitfol bozbar rezrov frotz && + read_tree_u_must_succeed --reset -u $treeH && + echo "+100644 X 0 yomin" >expected && + echo yomin >yomin && + git update-index --add yomin && + read_tree_u_must_succeed -m -u $treeH $treeM && + git ls-files --stage >4.out && + test_might_fail git diff -U0 --no-index M.out 4.out >4diff.out && + compare_change 4diff.out expected && + check_cache_at yomin clean && + test_cmp bozbar.M bozbar && + test_cmp frotz.M frotz && + test_cmp nitfol.M nitfol && + echo yomin >yomin1 && + diff yomin yomin1 && + rm -f yomin1 +' + +test_expect_success '5 - carry forward local addition.' ' + rm -f .git/index nitfol bozbar rezrov frotz && + read_tree_u_must_succeed --reset -u $treeH && + read_tree_u_must_succeed -m -u $treeH && + echo yomin >yomin && + git update-index --add yomin && + echo yomin yomin >yomin && + read_tree_u_must_succeed -m -u $treeH $treeM && + git ls-files --stage >5.out && + test_might_fail git diff -U0 --no-index M.out 5.out >5diff.out && + compare_change 5diff.out expected && + check_cache_at yomin dirty && + test_cmp bozbar.M bozbar && + test_cmp frotz.M frotz && + test_cmp nitfol.M nitfol && + : dirty index should have prevented -u from checking it out. && + echo yomin yomin >yomin1 && + diff yomin yomin1 && + rm -f yomin1 +' + +test_expect_success '6 - local addition already has the same.' ' + rm -f .git/index nitfol bozbar rezrov frotz && + read_tree_u_must_succeed --reset -u $treeH && + echo frotz >frotz && + git update-index --add frotz && + read_tree_u_must_succeed -m -u $treeH $treeM && + git ls-files --stage >6.out && + test_cmp M.out 6.out && + check_cache_at frotz clean && + test_cmp bozbar.M bozbar && + test_cmp frotz.M frotz && + test_cmp nitfol.M nitfol && + echo frotz >frotz1 && + diff frotz frotz1 && + rm -f frotz1 +' + +test_expect_success '7 - local addition already has the same.' ' + rm -f .git/index nitfol bozbar rezrov frotz && + read_tree_u_must_succeed --reset -u $treeH && + echo frotz >frotz && + git update-index --add frotz && + echo frotz frotz >frotz && + read_tree_u_must_succeed -m -u $treeH $treeM && + git ls-files --stage >7.out && + test_cmp M.out 7.out && + check_cache_at frotz dirty && + test_cmp bozbar.M bozbar && + test_cmp nitfol.M nitfol && + : dirty index should have prevented -u from checking it out. && + echo frotz frotz >frotz1 && + diff frotz frotz1 && + rm -f frotz1 +' + +test_expect_success '8 - conflicting addition.' ' + rm -f .git/index nitfol bozbar rezrov frotz && + read_tree_u_must_succeed --reset -u $treeH && + echo frotz frotz >frotz && + git update-index --add frotz && + ! read_tree_u_must_succeed -m -u $treeH $treeM +' + +test_expect_success '9 - conflicting addition.' ' + rm -f .git/index nitfol bozbar rezrov frotz && + read_tree_u_must_succeed --reset -u $treeH && + echo frotz frotz >frotz && + git update-index --add frotz && + echo frotz >frotz && + ! read_tree_u_must_succeed -m -u $treeH $treeM +' + +test_expect_success '10 - path removed.' ' + rm -f .git/index nitfol bozbar rezrov frotz && + read_tree_u_must_succeed --reset -u $treeH && + echo rezrov >rezrov && + git update-index --add rezrov && + read_tree_u_must_succeed -m -u $treeH $treeM && + git ls-files --stage >10.out && + cmp M.out 10.out && + test_cmp bozbar.M bozbar && + test_cmp frotz.M frotz && + test_cmp nitfol.M nitfol +' + +test_expect_success '11 - dirty path removed.' ' + rm -f .git/index nitfol bozbar rezrov frotz && + read_tree_u_must_succeed --reset -u $treeH && + echo rezrov >rezrov && + git update-index --add rezrov && + echo rezrov rezrov >rezrov && + ! read_tree_u_must_succeed -m -u $treeH $treeM +' + +test_expect_success '12 - unmatching local changes being removed.' ' + rm -f .git/index nitfol bozbar rezrov frotz && + read_tree_u_must_succeed --reset -u $treeH && + echo rezrov rezrov >rezrov && + git update-index --add rezrov && + ! read_tree_u_must_succeed -m -u $treeH $treeM +' + +test_expect_success '13 - unmatching local changes being removed.' ' + rm -f .git/index nitfol bozbar rezrov frotz && + read_tree_u_must_succeed --reset -u $treeH && + echo rezrov rezrov >rezrov && + git update-index --add rezrov && + echo rezrov >rezrov && + ! read_tree_u_must_succeed -m -u $treeH $treeM +' cat >expected <<EOF -100644 X 0 nitfol +100644 X 0 nitfol EOF -test_expect_success \ - '14 - unchanged in two heads.' \ - 'rm -f .git/index nitfol bozbar rezrov frotz && - read_tree_u_must_succeed --reset -u $treeH && - echo nitfol nitfol >nitfol && - git update-index --add nitfol && - read_tree_u_must_succeed -m -u $treeH $treeM && - git ls-files --stage >14.out && - test_must_fail git diff -U0 --no-index M.out 14.out >14diff.out && - compare_change 14diff.out expected && - test_cmp bozbar.M bozbar && - test_cmp frotz.M frotz && - check_cache_at nitfol clean && - echo nitfol nitfol >nitfol1 && - diff nitfol nitfol1 && - rm -f nitfol1' - -test_expect_success \ - '15 - unchanged in two heads.' \ - 'rm -f .git/index nitfol bozbar rezrov frotz && - read_tree_u_must_succeed --reset -u $treeH && - echo nitfol nitfol >nitfol && - git update-index --add nitfol && - echo nitfol nitfol nitfol >nitfol && - read_tree_u_must_succeed -m -u $treeH $treeM && - git ls-files --stage >15.out && - test_must_fail git diff -U0 --no-index M.out 15.out >15diff.out && - compare_change 15diff.out expected && - check_cache_at nitfol dirty && - test_cmp bozbar.M bozbar && - test_cmp frotz.M frotz && - echo nitfol nitfol nitfol >nitfol1 && - diff nitfol nitfol1 && - rm -f nitfol1' - -test_expect_success \ - '16 - conflicting local change.' \ - 'rm -f .git/index nitfol bozbar rezrov frotz && - read_tree_u_must_succeed --reset -u $treeH && - echo bozbar bozbar >bozbar && - git update-index --add bozbar && - if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi' - -test_expect_success \ - '17 - conflicting local change.' \ - 'rm -f .git/index nitfol bozbar rezrov frotz && - read_tree_u_must_succeed --reset -u $treeH && - echo bozbar bozbar >bozbar && - git update-index --add bozbar && - echo bozbar bozbar bozbar >bozbar && - if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi' - -test_expect_success \ - '18 - local change already having a good result.' \ - 'rm -f .git/index nitfol bozbar rezrov frotz && - read_tree_u_must_succeed --reset -u $treeH && - echo gnusto >bozbar && - git update-index --add bozbar && - read_tree_u_must_succeed -m -u $treeH $treeM && - git ls-files --stage >18.out && - test_cmp M.out 18.out && - check_cache_at bozbar clean && - test_cmp bozbar.M bozbar && - test_cmp frotz.M frotz && - test_cmp nitfol.M nitfol +test_expect_success '14 - unchanged in two heads.' ' + rm -f .git/index nitfol bozbar rezrov frotz && + read_tree_u_must_succeed --reset -u $treeH && + echo nitfol nitfol >nitfol && + git update-index --add nitfol && + read_tree_u_must_succeed -m -u $treeH $treeM && + git ls-files --stage >14.out && + test_must_fail git diff -U0 --no-index M.out 14.out >14diff.out && + compare_change 14diff.out expected && + test_cmp bozbar.M bozbar && + test_cmp frotz.M frotz && + check_cache_at nitfol clean && + echo nitfol nitfol >nitfol1 && + diff nitfol nitfol1 && + rm -f nitfol1 ' -test_expect_success \ - '19 - local change already having a good result, further modified.' \ - 'rm -f .git/index nitfol bozbar rezrov frotz && - read_tree_u_must_succeed --reset -u $treeH && - echo gnusto >bozbar && - git update-index --add bozbar && - echo gnusto gnusto >bozbar && - read_tree_u_must_succeed -m -u $treeH $treeM && - git ls-files --stage >19.out && - test_cmp M.out 19.out && - check_cache_at bozbar dirty && - test_cmp frotz.M frotz && - test_cmp nitfol.M nitfol && - echo gnusto gnusto >bozbar1 && - diff bozbar bozbar1 && - rm -f bozbar1' - -test_expect_success \ - '20 - no local change, use new tree.' \ - 'rm -f .git/index nitfol bozbar rezrov frotz && - read_tree_u_must_succeed --reset -u $treeH && - echo bozbar >bozbar && - git update-index --add bozbar && - read_tree_u_must_succeed -m -u $treeH $treeM && - git ls-files --stage >20.out && - test_cmp M.out 20.out && - check_cache_at bozbar clean && - test_cmp bozbar.M bozbar && - test_cmp frotz.M frotz && - test_cmp nitfol.M nitfol +test_expect_success '15 - unchanged in two heads.' ' + rm -f .git/index nitfol bozbar rezrov frotz && + read_tree_u_must_succeed --reset -u $treeH && + echo nitfol nitfol >nitfol && + git update-index --add nitfol && + echo nitfol nitfol nitfol >nitfol && + read_tree_u_must_succeed -m -u $treeH $treeM && + git ls-files --stage >15.out && + test_must_fail git diff -U0 --no-index M.out 15.out >15diff.out && + compare_change 15diff.out expected && + check_cache_at nitfol dirty && + test_cmp bozbar.M bozbar && + test_cmp frotz.M frotz && + echo nitfol nitfol nitfol >nitfol1 && + diff nitfol nitfol1 && + rm -f nitfol1 ' -test_expect_success \ - '21 - no local change, dirty cache.' \ - 'rm -f .git/index nitfol bozbar rezrov frotz && - read_tree_u_must_succeed --reset -u $treeH && - echo bozbar >bozbar && - git update-index --add bozbar && - echo gnusto gnusto >bozbar && - if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi' +test_expect_success '16 - conflicting local change.' ' + rm -f .git/index nitfol bozbar rezrov frotz && + read_tree_u_must_succeed --reset -u $treeH && + echo bozbar bozbar >bozbar && + git update-index --add bozbar && + ! read_tree_u_must_succeed -m -u $treeH $treeM +' + +test_expect_success '17 - conflicting local change.' ' + rm -f .git/index nitfol bozbar rezrov frotz && + read_tree_u_must_succeed --reset -u $treeH && + echo bozbar bozbar >bozbar && + git update-index --add bozbar && + echo bozbar bozbar bozbar >bozbar && + ! read_tree_u_must_succeed -m -u $treeH $treeM +' + +test_expect_success '18 - local change already having a good result.' ' + rm -f .git/index nitfol bozbar rezrov frotz && + read_tree_u_must_succeed --reset -u $treeH && + echo gnusto >bozbar && + git update-index --add bozbar && + read_tree_u_must_succeed -m -u $treeH $treeM && + git ls-files --stage >18.out && + test_cmp M.out 18.out && + check_cache_at bozbar clean && + test_cmp bozbar.M bozbar && + test_cmp frotz.M frotz && + test_cmp nitfol.M nitfol +' + +test_expect_success '19 - local change already having a good result, further modified.' ' + rm -f .git/index nitfol bozbar rezrov frotz && + read_tree_u_must_succeed --reset -u $treeH && + echo gnusto >bozbar && + git update-index --add bozbar && + echo gnusto gnusto >bozbar && + read_tree_u_must_succeed -m -u $treeH $treeM && + git ls-files --stage >19.out && + test_cmp M.out 19.out && + check_cache_at bozbar dirty && + test_cmp frotz.M frotz && + test_cmp nitfol.M nitfol && + echo gnusto gnusto >bozbar1 && + diff bozbar bozbar1 && + rm -f bozbar1 +' + +test_expect_success '20 - no local change, use new tree.' ' + rm -f .git/index nitfol bozbar rezrov frotz && + read_tree_u_must_succeed --reset -u $treeH && + echo bozbar >bozbar && + git update-index --add bozbar && + read_tree_u_must_succeed -m -u $treeH $treeM && + git ls-files --stage >20.out && + test_cmp M.out 20.out && + check_cache_at bozbar clean && + test_cmp bozbar.M bozbar && + test_cmp frotz.M frotz && + test_cmp nitfol.M nitfol +' + +test_expect_success '21 - no local change, dirty cache.' ' + rm -f .git/index nitfol bozbar rezrov frotz && + read_tree_u_must_succeed --reset -u $treeH && + echo bozbar >bozbar && + git update-index --add bozbar && + echo gnusto gnusto >bozbar && + ! read_tree_u_must_succeed -m -u $treeH $treeM +' # Also make sure we did not break DF vs DF/DF case. -test_expect_success \ - 'DF vs DF/DF case setup.' \ - 'rm -f .git/index && - echo DF >DF && - git update-index --add DF && - treeDF=$(git write-tree) && - echo treeDF $treeDF && - git ls-tree $treeDF && - - rm -f DF && - mkdir DF && - echo DF/DF >DF/DF && - git update-index --add --remove DF DF/DF && - treeDFDF=$(git write-tree) && - echo treeDFDF $treeDFDF && - git ls-tree $treeDFDF && - git ls-files --stage >DFDF.out' - -test_expect_success \ - 'DF vs DF/DF case test.' \ - 'rm -f .git/index && - rm -fr DF && - echo DF >DF && - git update-index --add DF && - read_tree_u_must_succeed -m -u $treeDF $treeDFDF && - git ls-files --stage >DFDFcheck.out && - test_cmp DFDF.out DFDFcheck.out && - check_cache_at DF/DF clean' +test_expect_success 'DF vs DF/DF case setup.' ' + rm -f .git/index && + echo DF >DF && + git update-index --add DF && + treeDF=$(git write-tree) && + echo treeDF $treeDF && + git ls-tree $treeDF && + + rm -f DF && + mkdir DF && + echo DF/DF >DF/DF && + git update-index --add --remove DF DF/DF && + treeDFDF=$(git write-tree) && + echo treeDFDF $treeDFDF && + git ls-tree $treeDFDF && + git ls-files --stage >DFDF.out +' + +test_expect_success 'DF vs DF/DF case test.' ' + rm -f .git/index && + rm -fr DF && + echo DF >DF && + git update-index --add DF && + read_tree_u_must_succeed -m -u $treeDF $treeDFDF && + git ls-files --stage >DFDFcheck.out && + test_cmp DFDF.out DFDFcheck.out && + check_cache_at DF/DF clean +' test_done diff --git a/t/t1005-read-tree-reset.sh b/t/t1005-read-tree-reset.sh index 12e30d77d0..26be4a2b5a 100755 --- a/t/t1005-read-tree-reset.sh +++ b/t/t1005-read-tree-reset.sh @@ -41,7 +41,8 @@ test_expect_success 'reset should remove remnants from a failed merge' ' git ls-files -s && read_tree_u_must_succeed --reset -u HEAD && git ls-files -s >actual && - ! test -f old + ! test -f old && + test_cmp expect actual ' test_expect_success 'two-way reset should remove remnants too' ' @@ -56,7 +57,8 @@ test_expect_success 'two-way reset should remove remnants too' ' git ls-files -s && read_tree_u_must_succeed --reset -u HEAD HEAD && git ls-files -s >actual && - ! test -f old + ! test -f old && + test_cmp expect actual ' test_expect_success 'Porcelain reset should remove remnants too' ' @@ -71,7 +73,8 @@ test_expect_success 'Porcelain reset should remove remnants too' ' git ls-files -s && git reset --hard && git ls-files -s >actual && - ! test -f old + ! test -f old && + test_cmp expect actual ' test_expect_success 'Porcelain checkout -f should remove remnants too' ' @@ -86,7 +89,8 @@ test_expect_success 'Porcelain checkout -f should remove remnants too' ' git ls-files -s && git checkout -f && git ls-files -s >actual && - ! test -f old + ! test -f old && + test_cmp expect actual ' test_expect_success 'Porcelain checkout -f HEAD should remove remnants too' ' @@ -101,7 +105,8 @@ test_expect_success 'Porcelain checkout -f HEAD should remove remnants too' ' git ls-files -s && git checkout -f HEAD && git ls-files -s >actual && - ! test -f old + ! test -f old && + test_cmp expect actual ' test_done diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh index 23b8942edb..d73a0be1b9 100755 --- a/t/t1006-cat-file.sh +++ b/t/t1006-cat-file.sh @@ -89,7 +89,8 @@ done for opt in --buffer \ --follow-symlinks \ --batch-all-objects \ - -z + -z \ + -Z do test_expect_success "usage: bad option combination: $opt without batch mode" ' test_incompatible_usage git cat-file $opt && @@ -109,26 +110,12 @@ strlen () { echo_without_newline "$1" | wc -c | sed -e 's/^ *//' } -maybe_remove_timestamp () { - if test -z "$2"; then - echo_without_newline "$1" - else - echo_without_newline "$(printf '%s\n' "$1" | remove_timestamp)" - fi -} - -remove_timestamp () { - sed -e 's/ [0-9][0-9]* [-+][0-9][0-9][0-9][0-9]$//' -} - - run_tests () { type=$1 sha1=$2 size=$3 content=$4 pretty_content=$5 - no_ts=$6 batch_output="$sha1 $type $size $content" @@ -163,21 +150,21 @@ $content" test -z "$content" || test_expect_success "Content of $type is correct" ' - maybe_remove_timestamp "$content" $no_ts >expect && - maybe_remove_timestamp "$(git cat-file $type $sha1)" $no_ts >actual && + echo_without_newline "$content" >expect && + git cat-file $type $sha1 >actual && test_cmp expect actual ' test_expect_success "Pretty content of $type is correct" ' - maybe_remove_timestamp "$pretty_content" $no_ts >expect && - maybe_remove_timestamp "$(git cat-file -p $sha1)" $no_ts >actual && + echo_without_newline "$pretty_content" >expect && + git cat-file -p $sha1 >actual && test_cmp expect actual ' test -z "$content" || test_expect_success "--batch output of $type is correct" ' - maybe_remove_timestamp "$batch_output" $no_ts >expect && - maybe_remove_timestamp "$(echo $sha1 | git cat-file --batch)" $no_ts >actual && + echo "$batch_output" >expect && + echo $sha1 | git cat-file --batch >actual && test_cmp expect actual ' @@ -191,9 +178,8 @@ $content" do test -z "$content" || test_expect_success "--batch-command $opt output of $type content is correct" ' - maybe_remove_timestamp "$batch_output" $no_ts >expect && - maybe_remove_timestamp "$(test_write_lines "contents $sha1" | - git cat-file --batch-command $opt)" $no_ts >actual && + echo "$batch_output" >expect && + test_write_lines "contents $sha1" | git cat-file --batch-command $opt >actual && test_cmp expect actual ' @@ -228,10 +214,9 @@ $content" test_expect_success "--batch without type ($type)" ' { echo "$size" && - maybe_remove_timestamp "$content" $no_ts + echo "$content" } >expect && - echo $sha1 | git cat-file --batch="%(objectsize)" >actual.full && - maybe_remove_timestamp "$(cat actual.full)" $no_ts >actual && + echo $sha1 | git cat-file --batch="%(objectsize)" >actual && test_cmp expect actual ' @@ -239,10 +224,9 @@ $content" test_expect_success "--batch without size ($type)" ' { echo "$type" && - maybe_remove_timestamp "$content" $no_ts + echo "$content" } >expect && - echo $sha1 | git cat-file --batch="%(objecttype)" >actual.full && - maybe_remove_timestamp "$(cat actual.full)" $no_ts >actual && + echo $sha1 | git cat-file --batch="%(objecttype)" >actual && test_cmp expect actual ' } @@ -284,7 +268,7 @@ test_expect_success '--batch-check without %(rest) considers whole line' ' tree_sha1=$(git write-tree) tree_size=$(($(test_oid rawsz) + 13)) -tree_pretty_content="100644 blob $hello_sha1 hello" +tree_pretty_content="100644 blob $hello_sha1 hello${LF}" run_tests 'tree' $tree_sha1 $tree_size "" "$tree_pretty_content" @@ -292,30 +276,32 @@ commit_message="Initial commit" commit_sha1=$(echo_without_newline "$commit_message" | git commit-tree $tree_sha1) commit_size=$(($(test_oid hexsz) + 137)) commit_content="tree $tree_sha1 -author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> 0000000000 +0000 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 0000000000 +0000 +author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE $commit_message" -run_tests 'commit' $commit_sha1 $commit_size "$commit_content" "$commit_content" 1 +run_tests 'commit' $commit_sha1 $commit_size "$commit_content" "$commit_content" tag_header_without_timestamp="object $hello_sha1 type blob tag hellotag tagger $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" tag_description="This is a tag" -tag_content="$tag_header_without_timestamp 0000000000 +0000 +tag_content="$tag_header_without_timestamp 0 +0000 $tag_description" tag_sha1=$(echo_without_newline "$tag_content" | git hash-object -t tag --stdin -w) tag_size=$(strlen "$tag_content") -run_tests 'tag' $tag_sha1 $tag_size "$tag_content" "$tag_content" 1 +run_tests 'tag' $tag_sha1 $tag_size "$tag_content" "$tag_content" -test_expect_success \ - "Reach a blob from a tag pointing to it" \ - "test '$hello_content' = \"\$(git cat-file blob $tag_sha1)\"" +test_expect_success "Reach a blob from a tag pointing to it" ' + echo_without_newline "$hello_content" >expect && + git cat-file blob $tag_sha1 >actual && + test_cmp expect actual +' for batch in batch batch-check batch-command do @@ -351,30 +337,47 @@ do done test_expect_success "--batch-check for a non-existent named object" ' - test "foobar42 missing -foobar84 missing" = \ - "$( ( echo foobar42 && echo_without_newline foobar84 ) | git cat-file --batch-check)" + cat >expect <<-EOF && + foobar42 missing + foobar84 missing + EOF + + printf "foobar42\nfoobar84" >in && + git cat-file --batch-check <in >actual && + test_cmp expect actual ' test_expect_success "--batch-check for a non-existent hash" ' - test "0000000000000000000000000000000000000042 missing -0000000000000000000000000000000000000084 missing" = \ - "$( ( echo 0000000000000000000000000000000000000042 && - echo_without_newline 0000000000000000000000000000000000000084 ) | - git cat-file --batch-check)" + cat >expect <<-EOF && + 0000000000000000000000000000000000000042 missing + 0000000000000000000000000000000000000084 missing + EOF + + printf "0000000000000000000000000000000000000042\n0000000000000000000000000000000000000084" >in && + git cat-file --batch-check <in >actual && + test_cmp expect actual ' test_expect_success "--batch for an existent and a non-existent hash" ' - test "$tag_sha1 tag $tag_size -$tag_content -0000000000000000000000000000000000000000 missing" = \ - "$( ( echo $tag_sha1 && - echo_without_newline 0000000000000000000000000000000000000000 ) | - git cat-file --batch)" + cat >expect <<-EOF && + $tag_sha1 tag $tag_size + $tag_content + 0000000000000000000000000000000000000000 missing + EOF + + printf "$tag_sha1\n0000000000000000000000000000000000000000" >in && + git cat-file --batch <in >actual && + test_cmp expect actual ' test_expect_success "--batch-check for an empty line" ' - test " missing" = "$(echo | git cat-file --batch-check)" + cat >expect <<-EOF && + missing + EOF + + echo >in && + git cat-file --batch-check <in >actual && + test_cmp expect actual ' test_expect_success 'empty --batch-check notices missing object' ' @@ -390,23 +393,34 @@ deadbeef " -batch_output="$hello_sha1 blob $hello_size -$hello_content -$commit_sha1 commit $commit_size -$commit_content -$tag_sha1 tag $tag_size -$tag_content -deadbeef missing - missing" +printf "%s\0" \ + "$hello_sha1 blob $hello_size" \ + "$hello_content" \ + "$commit_sha1 commit $commit_size" \ + "$commit_content" \ + "$tag_sha1 tag $tag_size" \ + "$tag_content" \ + "deadbeef missing" \ + " missing" >batch_output test_expect_success '--batch with multiple sha1s gives correct format' ' - test "$(maybe_remove_timestamp "$batch_output" 1)" = "$(maybe_remove_timestamp "$(echo_without_newline "$batch_input" | git cat-file --batch)" 1)" + tr "\0" "\n" <batch_output >expect && + echo_without_newline "$batch_input" >in && + git cat-file --batch <in >actual && + test_cmp expect actual ' test_expect_success '--batch, -z with multiple sha1s gives correct format' ' echo_without_newline_nul "$batch_input" >in && - test "$(maybe_remove_timestamp "$batch_output" 1)" = \ - "$(maybe_remove_timestamp "$(git cat-file --batch -z <in)" 1)" + tr "\0" "\n" <batch_output >expect && + git cat-file --batch -z <in >actual && + test_cmp expect actual +' + +test_expect_success '--batch, -Z with multiple sha1s gives correct format' ' + echo_without_newline_nul "$batch_input" >in && + git cat-file --batch -Z <in >actual && + test_cmp batch_output actual ' batch_check_input="$hello_sha1 @@ -417,36 +431,55 @@ deadbeef " -batch_check_output="$hello_sha1 blob $hello_size -$tree_sha1 tree $tree_size -$commit_sha1 commit $commit_size -$tag_sha1 tag $tag_size -deadbeef missing - missing" +printf "%s\0" \ + "$hello_sha1 blob $hello_size" \ + "$tree_sha1 tree $tree_size" \ + "$commit_sha1 commit $commit_size" \ + "$tag_sha1 tag $tag_size" \ + "deadbeef missing" \ + " missing" >batch_check_output test_expect_success "--batch-check with multiple sha1s gives correct format" ' - test "$batch_check_output" = \ - "$(echo_without_newline "$batch_check_input" | git cat-file --batch-check)" + tr "\0" "\n" <batch_check_output >expect && + echo_without_newline "$batch_check_input" >in && + git cat-file --batch-check <in >actual && + test_cmp expect actual ' test_expect_success "--batch-check, -z with multiple sha1s gives correct format" ' - echo_without_newline_nul "$batch_check_input" >in && - test "$batch_check_output" = "$(git cat-file --batch-check -z <in)" + tr "\0" "\n" <batch_check_output >expect && + echo_without_newline_nul "$batch_check_input" >in && + git cat-file --batch-check -z <in >actual && + test_cmp expect actual ' -test_expect_success FUNNYNAMES '--batch-check, -z with newline in input' ' +test_expect_success "--batch-check, -Z with multiple sha1s gives correct format" ' + echo_without_newline_nul "$batch_check_input" >in && + git cat-file --batch-check -Z <in >actual && + test_cmp batch_check_output actual +' + +test_expect_success FUNNYNAMES 'setup with newline in input' ' touch -- "newline${LF}embedded" && git add -- "newline${LF}embedded" && git commit -m "file with newline embedded" && test_tick && - printf "HEAD:newline${LF}embedded" >in && - git cat-file --batch-check -z <in >actual && + printf "HEAD:newline${LF}embedded" >in +' +test_expect_success FUNNYNAMES '--batch-check, -z with newline in input' ' + git cat-file --batch-check -z <in >actual && echo "$(git rev-parse "HEAD:newline${LF}embedded") blob 0" >expect && test_cmp expect actual ' +test_expect_success FUNNYNAMES '--batch-check, -Z with newline in input' ' + git cat-file --batch-check -Z <in >actual && + printf "%s\0" "$(git rev-parse "HEAD:newline${LF}embedded") blob 0" >expect && + test_cmp expect actual +' + batch_command_multiple_info="info $hello_sha1 info $tree_sha1 info $commit_sha1 @@ -470,7 +503,13 @@ test_expect_success '--batch-command with multiple info calls gives correct form echo "$batch_command_multiple_info" | tr "\n" "\0" >in && git cat-file --batch-command --buffer -z <in >actual && - test_cmp expect actual + test_cmp expect actual && + + echo "$batch_command_multiple_info" | tr "\n" "\0" >in && + tr "\n" "\0" <expect >expect_nul && + git cat-file --batch-command --buffer -Z <in >actual && + + test_cmp expect_nul actual ' batch_command_multiple_contents="contents $hello_sha1 @@ -480,27 +519,30 @@ contents deadbeef flush" test_expect_success '--batch-command with multiple command calls gives correct format' ' - remove_timestamp >expect <<-EOF && - $hello_sha1 blob $hello_size - $hello_content - $commit_sha1 commit $commit_size - $commit_content - $tag_sha1 tag $tag_size - $tag_content - deadbeef missing - EOF + printf "%s\0" \ + "$hello_sha1 blob $hello_size" \ + "$hello_content" \ + "$commit_sha1 commit $commit_size" \ + "$commit_content" \ + "$tag_sha1 tag $tag_size" \ + "$tag_content" \ + "deadbeef missing" >expect_nul && + tr "\0" "\n" <expect_nul >expect && echo "$batch_command_multiple_contents" >in && - git cat-file --batch-command --buffer <in >actual_raw && + git cat-file --batch-command --buffer <in >actual && - remove_timestamp <actual_raw >actual && test_cmp expect actual && echo "$batch_command_multiple_contents" | tr "\n" "\0" >in && - git cat-file --batch-command --buffer -z <in >actual_raw && + git cat-file --batch-command --buffer -z <in >actual && - remove_timestamp <actual_raw >actual && - test_cmp expect actual + test_cmp expect actual && + + echo "$batch_command_multiple_contents" | tr "\n" "\0" >in && + git cat-file --batch-command --buffer -Z <in >actual && + + test_cmp expect_nul actual ' test_expect_success 'setup blobs which are likely to delta' ' @@ -603,7 +645,8 @@ do fatal: Not a valid object name $(test_oid deadbeef_short) EOF test_must_fail git cat-file $arg1 $arg2 $(test_oid deadbeef_short) >out 2>err.actual && - test_must_be_empty out + test_must_be_empty out && + test_cmp expect.err err.actual ' test_expect_success "cat-file $arg1 $arg2 error on missing full OID" ' @@ -839,6 +882,13 @@ test_expect_success 'git cat-file --batch-check --follow-symlinks works for brok test_cmp expect actual ' +test_expect_success 'git cat-file --batch-check --follow-symlinks -Z works for broken in-repo, same-dir links' ' + printf "HEAD:broken-same-dir-link\0" >in && + printf "dangling 25\0HEAD:broken-same-dir-link\0" >expect && + git cat-file --batch-check --follow-symlinks -Z <in >actual && + test_cmp expect actual +' + test_expect_success 'git cat-file --batch-check --follow-symlinks works for same-dir links-to-links' ' echo HEAD:link-to-link | git cat-file --batch-check --follow-symlinks >actual && test_cmp found actual @@ -853,6 +903,15 @@ test_expect_success 'git cat-file --batch-check --follow-symlinks works for pare test_cmp expect actual ' +test_expect_success 'git cat-file --batch-check --follow-symlinks -Z works for parent-dir links' ' + echo HEAD:dir/parent-dir-link | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual && + printf "notdir 29\0HEAD:dir/parent-dir-link/nope\0" >expect && + printf "HEAD:dir/parent-dir-link/nope\0" >in && + git cat-file --batch-check --follow-symlinks -Z <in >actual && + test_cmp expect actual +' + test_expect_success 'git cat-file --batch-check --follow-symlinks works for .. links' ' echo dangling 22 >expect && echo HEAD:dir/link-dir/nope >>expect && @@ -967,6 +1026,13 @@ test_expect_success 'git cat-file --batch-check --follow-symlink breaks loops' ' test_cmp expect actual ' +test_expect_success 'git cat-file --batch-check --follow-symlink -Z breaks loops' ' + printf "loop 10\0HEAD:loop1\0" >expect && + printf "HEAD:loop1\0" >in && + git cat-file --batch-check --follow-symlinks -Z <in >actual && + test_cmp expect actual +' + test_expect_success 'git cat-file --batch --follow-symlink returns correct sha and mode' ' echo HEAD:morx | git cat-file --batch >expect && echo HEAD:morx | git cat-file --batch --follow-symlinks >actual && diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh index ac5ad8c740..ac3d173767 100755 --- a/t/t1007-hash-object.sh +++ b/t/t1007-hash-object.sh @@ -203,23 +203,34 @@ done test_expect_success 'too-short tree' ' echo abc >malformed-tree && test_must_fail git hash-object -t tree malformed-tree 2>err && - test_i18ngrep "too-short tree object" err + grep "too-short tree object" err ' test_expect_success 'malformed mode in tree' ' - hex_sha1=$(echo foo | git hash-object --stdin -w) && - bin_sha1=$(echo $hex_sha1 | hex2oct) && - printf "9100644 \0$bin_sha1" >tree-with-malformed-mode && + hex_oid=$(echo foo | git hash-object --stdin -w) && + bin_oid=$(echo $hex_oid | hex2oct) && + printf "9100644 \0$bin_oid" >tree-with-malformed-mode && test_must_fail git hash-object -t tree tree-with-malformed-mode 2>err && - test_i18ngrep "malformed mode in tree entry" err + grep "malformed mode in tree entry" err ' test_expect_success 'empty filename in tree' ' - hex_sha1=$(echo foo | git hash-object --stdin -w) && - bin_sha1=$(echo $hex_sha1 | hex2oct) && - printf "100644 \0$bin_sha1" >tree-with-empty-filename && + hex_oid=$(echo foo | git hash-object --stdin -w) && + bin_oid=$(echo $hex_oid | hex2oct) && + printf "100644 \0$bin_oid" >tree-with-empty-filename && test_must_fail git hash-object -t tree tree-with-empty-filename 2>err && - test_i18ngrep "empty filename in tree entry" err + grep "empty filename in tree entry" err +' + +test_expect_success 'duplicate filename in tree' ' + hex_oid=$(echo foo | git hash-object --stdin -w) && + bin_oid=$(echo $hex_oid | hex2oct) && + { + printf "100644 file\0$bin_oid" && + printf "100644 file\0$bin_oid" + } >tree-with-duplicate-filename && + test_must_fail git hash-object -t tree tree-with-duplicate-filename 2>err && + grep "duplicateEntries" err ' test_expect_success 'corrupt commit' ' diff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh index 3c08194526..22875ba598 100755 --- a/t/t1010-mktree.sh +++ b/t/t1010-mktree.sh @@ -60,11 +60,11 @@ test_expect_success 'allow missing object with --missing' ' ' test_expect_success 'mktree refuses to read ls-tree -r output (1)' ' - test_must_fail git mktree <all >actual + test_must_fail git mktree <all ' test_expect_success 'mktree refuses to read ls-tree -r output (2)' ' - test_must_fail git mktree <all.withsub >actual + test_must_fail git mktree <all.withsub ' test_done diff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh index 742f0fa909..595b24c0ad 100755 --- a/t/t1011-read-tree-sparse-checkout.sh +++ b/t/t1011-read-tree-sparse-checkout.sh @@ -12,6 +12,7 @@ test_description='sparse checkout tests ' TEST_CREATE_REPO_NO_TEMPLATE=1 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-read-tree.sh diff --git a/t/t1022-read-tree-partial-clone.sh b/t/t1022-read-tree-partial-clone.sh index a9953b6a71..cca4380e43 100755 --- a/t/t1022-read-tree-partial-clone.sh +++ b/t/t1022-read-tree-partial-clone.sh @@ -3,7 +3,7 @@ test_description='git read-tree in partial clones' TEST_NO_CREATE_REPO=1 - +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'read-tree in partial clone prefetches in one batch' ' @@ -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..9ceb17f911 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 ' @@ -555,7 +555,7 @@ test_expect_success 'cone mode: set with core.ignoreCase=true' ' check_files repo a folder1 ' -test_expect_success 'interaction with submodules' ' +test_expect_success 'setup submodules' ' git clone repo super && ( cd super && @@ -566,11 +566,22 @@ test_expect_success 'interaction with submodules' ' git commit -m "add submodule" && git sparse-checkout init --cone && git sparse-checkout set folder1 - ) && + ) +' + +test_expect_success 'interaction with submodules' ' check_files super a folder1 modules && check_files super/modules/child a deep folder1 folder2 ' +test_expect_success 'check-rules interaction with submodules' ' + git -C super ls-tree --name-only -r HEAD >all-files && + git -C super sparse-checkout check-rules >check-rules-matches <all-files && + + test_i18ngrep ! "modules/" check-rules-matches && + test_i18ngrep "folder1/" check-rules-matches +' + test_expect_success 'different sparse-checkouts with worktrees' ' git -C repo sparse-checkout set --cone deep folder1 && git -C repo worktree add --detach ../worktree && @@ -667,6 +678,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 @@ -873,4 +893,156 @@ test_expect_success 'by default, non-cone mode will warn on individual files' ' grep "pass a leading slash before paths.*if you want a single file" warning ' +test_expect_success 'setup bare repo' ' + git clone --bare "file://$(pwd)/repo" bare +' +test_expect_success 'list fails outside work tree' ' + test_must_fail git -C bare sparse-checkout list 2>err && + test_i18ngrep "this operation must be run in a work tree" err +' + +test_expect_success 'add fails outside work tree' ' + test_must_fail git -C bare sparse-checkout add deeper 2>err && + test_i18ngrep "this operation must be run in a work tree" err +' + +test_expect_success 'set fails outside work tree' ' + test_must_fail git -C bare sparse-checkout set deeper 2>err && + test_i18ngrep "this operation must be run in a work tree" err +' + +test_expect_success 'init fails outside work tree' ' + test_must_fail git -C bare sparse-checkout init 2>err && + test_i18ngrep "this operation must be run in a work tree" err +' + +test_expect_success 'reapply fails outside work tree' ' + test_must_fail git -C bare sparse-checkout reapply 2>err && + test_i18ngrep "this operation must be run in a work tree" err +' + +test_expect_success 'disable fails outside work tree' ' + test_must_fail git -C bare sparse-checkout disable 2>err && + test_i18ngrep "this operation must be run in a work tree" err +' + +test_expect_success 'setup clean' ' + git -C repo clean -fdx +' + +test_expect_success 'check-rules cone mode' ' + cat >rules <<-\EOF && + folder1 + deep/deeper1/deepest + EOF + + git -C bare ls-tree -r --name-only HEAD >all-files && + git -C bare sparse-checkout check-rules --cone \ + --rules-file ../rules >check-rules-file <all-files && + + git -C repo sparse-checkout set --cone --stdin <rules&& + git -C repo ls-files -t >out && + sed -n "/^S /!s/^. //p" out >ls-files && + + git -C repo sparse-checkout check-rules >check-rules-default <all-files && + + test_i18ngrep "deep/deeper1/deepest/a" check-rules-file && + test_i18ngrep ! "deep/deeper2" check-rules-file && + + test_cmp check-rules-file ls-files && + test_cmp check-rules-file check-rules-default +' + +test_expect_success 'check-rules non-cone mode' ' + cat >rules <<-\EOF && + deep/deeper1/deepest/a + EOF + + git -C bare ls-tree -r --name-only HEAD >all-files && + git -C bare sparse-checkout check-rules --no-cone --rules-file ../rules\ + >check-rules-file <all-files && + + cat rules | git -C repo sparse-checkout set --no-cone --stdin && + git -C repo ls-files -t >out && + sed -n "/^S /!s/^. //p" out >ls-files && + + git -C repo sparse-checkout check-rules >check-rules-default <all-files && + + cat >expect <<-\EOF && + deep/deeper1/deepest/a + EOF + + test_cmp expect check-rules-file && + test_cmp check-rules-file ls-files && + test_cmp check-rules-file check-rules-default +' + +test_expect_success 'check-rules cone mode is default' ' + cat >rules <<-\EOF && + folder1 + EOF + + cat >all-files <<-\EOF && + toplevel + folder2/file + folder1/file + EOF + + cat >expect <<-\EOF && + toplevel + folder1/file + EOF + + git -C repo sparse-checkout set --no-cone && + git -C repo sparse-checkout check-rules \ + --rules-file ../rules >actual <all-files && + + git -C bare sparse-checkout check-rules \ + --rules-file ../rules >actual-bare <all-files && + + test_cmp expect actual && + test_cmp expect actual-bare +' + +test_expect_success 'check-rules quoting' ' + cat >rules <<-EOF && + "folder\" a" + EOF + cat >files <<-EOF && + "folder\" a/file" + "folder\" b/file" + EOF + cat >expect <<-EOF && + "folder\" a/file" + EOF + git sparse-checkout check-rules --cone \ + --rules-file rules >actual <files && + + test_cmp expect actual +' + +test_expect_success 'check-rules null termination' ' + cat >rules <<-EOF && + "folder\" a" + EOF + + lf_to_nul >files <<-EOF && + folder" a/a + folder" a/b + folder" b/fileQ + EOF + + cat >expect <<-EOF && + folder" a/aQfolder" a/bQ + EOF + + git sparse-checkout check-rules --cone -z \ + --rules-file rules >actual.nul <files && + nul_to_q <actual.nul >actual && + echo >>actual && + + test_cmp expect actual +' + + test_done diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh index 4844922e57..2a4f35e984 100755 --- a/t/t1092-sparse-checkout-compatibility.sh +++ b/t/t1092-sparse-checkout-compatibility.sh @@ -162,6 +162,19 @@ init_repos () { git -C sparse-index sparse-checkout set deep } +init_repos_as_submodules () { + git reset --hard && + init_repos && + git submodule add ./full-checkout && + git submodule add ./sparse-checkout && + git submodule add ./sparse-index && + + git submodule status >actual && + grep full-checkout actual && + grep sparse-checkout actual && + grep sparse-index actual +} + run_on_sparse () { ( cd sparse-checkout && @@ -1364,7 +1377,7 @@ test_expect_success 'index.sparse disabled inline uses full index' ' ! test_region index ensure_full_index trace2.txt ' -ensure_not_expanded () { +run_sparse_index_trace2 () { rm -f trace2.txt && if test -z "$WITHOUT_UNTRACKED_TXT" then @@ -1384,7 +1397,16 @@ ensure_not_expanded () { git -C sparse-index "$@" \ >sparse-index-out \ 2>sparse-index-error || return 1 - fi && + fi +} + +ensure_expanded () { + run_sparse_index_trace2 "$@" && + test_region index ensure_full_index trace2.txt +} + +ensure_not_expanded () { + run_sparse_index_trace2 "$@" && test_region ! index ensure_full_index trace2.txt } @@ -1501,6 +1523,31 @@ test_expect_success 'sparse-index is not expanded: stash' ' ensure_not_expanded stash pop ' +test_expect_success 'describe tested on all' ' + init_repos && + + # Add tag to be read by describe + + run_on_all git tag -a v1.0 -m "Version 1" && + test_all_match git describe --dirty && + run_on_all rm g && + test_all_match git describe --dirty +' + + +test_expect_success 'sparse-index is not expanded: describe' ' + init_repos && + + # Add tag to be read by describe + + git -C sparse-index tag -a v1.0 -m "Version 1" && + + ensure_not_expanded describe --dirty && + echo "test" >>sparse-index/g && + ensure_not_expanded describe --dirty && + ensure_not_expanded describe +' + test_expect_success 'sparse index is not expanded: diff' ' init_repos && @@ -1983,4 +2030,305 @@ test_expect_success 'sparse index is not expanded: rm' ' ensure_not_expanded rm -r deep ' +test_expect_success 'grep with and --cached' ' + init_repos && + + test_all_match git grep --cached a && + test_all_match git grep --cached a -- "folder1/*" +' + +test_expect_success 'grep is not expanded' ' + init_repos && + + ensure_not_expanded grep a && + ensure_not_expanded grep a -- deep/* && + + # All files within the folder1/* pathspec are sparse, + # so this command does not find any matches + ensure_not_expanded ! grep a -- folder1/* && + + # test out-of-cone pathspec with or without wildcard + ensure_not_expanded grep --cached a -- "folder1/a" && + ensure_not_expanded grep --cached a -- "folder1/*" && + + # test in-cone pathspec with or without wildcard + ensure_not_expanded grep --cached a -- "deep/a" && + ensure_not_expanded grep --cached a -- "deep/*" +' + +# NEEDSWORK: when running `grep` in the superproject with --recurse-submodules, +# Git expands the index of the submodules unexpectedly. Even though `grep` +# builtin is marked as "command_requires_full_index = 0", this config is only +# useful for the superproject. Namely, the submodules have their own configs, +# which are _not_ populated by the one-time sparse-index feature switch. +test_expect_failure 'grep within submodules is not expanded' ' + init_repos_as_submodules && + + # do not use ensure_not_expanded() here, becasue `grep` should be + # run in the superproject, not in "./sparse-index" + GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ + git grep --cached --recurse-submodules a -- "*/folder1/*" && + test_region ! index ensure_full_index trace2.txt +' + +# NEEDSWORK: this test is not actually testing the code. The design purpose +# of this test is to verify the grep result when the submodules are using a +# sparse-index. Namely, we want "folder1/" as a tree (a sparse directory); but +# because of the index expansion, we are now grepping the "folder1/a" blob. +# Because of the problem stated above 'grep within submodules is not expanded', +# we don't have the ideal test environment yet. +test_expect_success 'grep sparse directory within submodules' ' + init_repos_as_submodules && + + cat >expect <<-\EOF && + full-checkout/folder1/a:a + sparse-checkout/folder1/a:a + sparse-index/folder1/a:a + EOF + git grep --cached --recurse-submodules a -- "*/folder1/*" >actual && + test_cmp actual expect +' + +test_expect_success 'write-tree' ' + init_repos && + + test_all_match git write-tree && + + write_script edit-contents <<-\EOF && + echo text >>"$1" + EOF + + # make a change inside the sparse cone + run_on_all ../edit-contents deep/a && + test_all_match git update-index deep/a && + test_all_match git write-tree && + test_all_match git status --porcelain=v2 && + + # make a change outside the sparse cone + run_on_all mkdir -p folder1 && + run_on_all cp a folder1/a && + run_on_all ../edit-contents folder1/a && + test_all_match git update-index folder1/a && + test_all_match git write-tree && + test_all_match git status --porcelain=v2 && + + # check that SKIP_WORKTREE files are not materialized + test_path_is_missing sparse-checkout/folder2/a && + test_path_is_missing sparse-index/folder2/a +' + +test_expect_success 'sparse-index is not expanded: write-tree' ' + init_repos && + + ensure_not_expanded write-tree && + + echo "test1" >>sparse-index/a && + git -C sparse-index update-index a && + ensure_not_expanded write-tree +' + +test_expect_success 'diff-files with pathspec inside sparse definition' ' + init_repos && + + write_script edit-contents <<-\EOF && + echo text >>"$1" + EOF + + run_on_all ../edit-contents deep/a && + + test_all_match git diff-files && + + test_all_match git diff-files -- deep/a && + + # test wildcard + test_all_match git diff-files -- "deep/*" +' + +test_expect_success 'diff-files with pathspec outside sparse definition' ' + init_repos && + + test_sparse_match git diff-files -- folder2/a && + + write_script edit-contents <<-\EOF && + echo text >>"$1" + EOF + + # The directory "folder1" is outside the cone of interest + # and will not exist in the sparse checkout repositories. + # Create it as needed, add file "folder1/a" there with + # contents that is different from the staged version. + run_on_all mkdir -p folder1 && + run_on_all cp a folder1/a && + + run_on_all ../edit-contents folder1/a && + test_all_match git diff-files && + test_all_match git diff-files -- folder1/a && + test_all_match git diff-files -- "folder*/a" +' + +test_expect_success 'sparse index is not expanded: diff-files' ' + init_repos && + + write_script edit-contents <<-\EOF && + echo text >>"$1" + EOF + + run_on_all ../edit-contents deep/a && + + ensure_not_expanded diff-files && + ensure_not_expanded diff-files -- deep/a && + ensure_not_expanded diff-files -- "deep/*" +' + +test_expect_success 'diff-tree' ' + init_repos && + + # Test change inside sparse cone + tree1=$(git -C sparse-index rev-parse HEAD^{tree}) && + tree2=$(git -C sparse-index rev-parse update-deep^{tree}) && + test_all_match git diff-tree $tree1 $tree2 && + test_all_match git diff-tree $tree1 $tree2 -- deep/a && + test_all_match git diff-tree HEAD update-deep && + test_all_match git diff-tree HEAD update-deep -- deep/a && + + # Test change outside sparse cone + tree3=$(git -C sparse-index rev-parse update-folder1^{tree}) && + test_all_match git diff-tree $tree1 $tree3 && + test_all_match git diff-tree $tree1 $tree3 -- folder1/a && + test_all_match git diff-tree HEAD update-folder1 && + test_all_match git diff-tree HEAD update-folder1 -- folder1/a && + + # Check that SKIP_WORKTREE files are not materialized + test_path_is_missing sparse-checkout/folder1/a && + test_path_is_missing sparse-index/folder1/a && + test_path_is_missing sparse-checkout/folder2/a && + test_path_is_missing sparse-index/folder2/a +' + +test_expect_success 'sparse-index is not expanded: diff-tree' ' + init_repos && + + tree1=$(git -C sparse-index rev-parse HEAD^{tree}) && + tree2=$(git -C sparse-index rev-parse update-deep^{tree}) && + tree3=$(git -C sparse-index rev-parse update-folder1^{tree}) && + + ensure_not_expanded diff-tree $tree1 $tree2 && + ensure_not_expanded diff-tree $tree1 $tree2 -- deep/a && + ensure_not_expanded diff-tree HEAD update-deep && + ensure_not_expanded diff-tree HEAD update-deep -- deep/a && + ensure_not_expanded diff-tree $tree1 $tree3 && + ensure_not_expanded diff-tree $tree1 $tree3 -- folder1/a && + ensure_not_expanded diff-tree HEAD update-folder1 && + ensure_not_expanded diff-tree HEAD update-folder1 -- folder1/a +' + +test_expect_success 'worktree' ' + init_repos && + + write_script edit-contents <<-\EOF && + echo text >>"$1" + EOF + + for repo in full-checkout sparse-checkout sparse-index + do + worktree=${repo}-wt && + git -C $repo worktree add ../$worktree && + + # Compare worktree content with "ls" + (cd $repo && ls) >worktree_contents && + (cd $worktree && ls) >new_worktree_contents && + test_cmp worktree_contents new_worktree_contents && + + # Compare index content with "ls-files --sparse" + git -C $repo ls-files --sparse >index_contents && + git -C $worktree ls-files --sparse >new_index_contents && + test_cmp index_contents new_index_contents && + + git -C $repo worktree remove ../$worktree || return 1 + done && + + test_all_match git worktree add .worktrees/hotfix && + run_on_all ../edit-contents .worktrees/hotfix/deep/a && + test_all_match test_must_fail git worktree remove .worktrees/hotfix +' + +test_expect_success 'worktree is not expanded' ' + init_repos && + + ensure_not_expanded worktree add .worktrees/hotfix && + ensure_not_expanded worktree remove .worktrees/hotfix +' + +test_expect_success 'check-attr with pathspec inside sparse definition' ' + init_repos && + + echo "a -crlf myAttr" >>.gitattributes && + run_on_all cp ../.gitattributes ./deep && + + test_all_match git check-attr -a -- deep/a && + + test_all_match git add deep/.gitattributes && + test_all_match git check-attr -a --cached -- deep/a +' + +test_expect_success 'check-attr with pathspec outside sparse definition' ' + init_repos && + + echo "a -crlf myAttr" >>.gitattributes && + run_on_sparse mkdir folder1 && + run_on_all cp ../.gitattributes ./folder1 && + run_on_all cp a folder1/a && + + test_all_match git check-attr -a -- folder1/a && + + git -C full-checkout add folder1/.gitattributes && + test_sparse_match git add --sparse folder1/.gitattributes && + test_all_match git commit -m "add .gitattributes" && + test_sparse_match git sparse-checkout reapply && + test_all_match git check-attr -a --cached -- folder1/a +' + +# NEEDSWORK: The 'diff --check' test is left as 'test_expect_failure' due +# to an underlying issue in oneway_diff() within diff-lib.c. +# 'do_oneway_diff()' is not called as expected for paths that could match +# inside of a sparse directory. Specifically, the 'ce_path_match()' function +# fails to recognize files inside a sparse directory (e.g., when 'folder1/' +# is a sparse directory, 'folder1/a' cannot be recognized). The goal is to +# proceed with 'do_oneway_diff()' if the pathspec could match inside of a +# sparse directory. +test_expect_failure 'diff --check with pathspec outside sparse definition' ' + init_repos && + + write_script edit-contents <<-\EOF && + echo "a " >"$1" + EOF + + test_all_match git config core.whitespace -trailing-space,-space-before-tab && + + echo "a whitespace=trailing-space,space-before-tab" >>.gitattributes && + run_on_all mkdir -p folder1 && + run_on_all cp ../.gitattributes ./folder1 && + test_all_match git add --sparse folder1/.gitattributes && + run_on_all ../edit-contents folder1/a && + test_all_match git add --sparse folder1/a && + + test_sparse_match git sparse-checkout reapply && + test_all_match test_must_fail git diff --check --cached -- folder1/a +' + +test_expect_success 'sparse-index is not expanded: check-attr' ' + init_repos && + + echo "a -crlf myAttr" >>.gitattributes && + mkdir ./sparse-index/folder1 && + cp ./sparse-index/a ./sparse-index/folder1/a && + cp .gitattributes ./sparse-index/deep && + cp .gitattributes ./sparse-index/folder1 && + + git -C sparse-index add deep/.gitattributes && + git -C sparse-index add --sparse folder1/.gitattributes && + ensure_not_expanded check-attr -a --cached -- deep/a && + ensure_not_expanded check-attr -a --cached -- folder1/a +' + test_done diff --git a/t/t1300-config.sh b/t/t1300-config.sh index e8505bd39c..387d336c91 100755 --- a/t/t1300-config.sh +++ b/t/t1300-config.sh @@ -98,6 +98,23 @@ test_expect_success 'subsections are not canonicalized by git-config' ' test_cmp_config two section.SubSection.key ' +test_missing_key () { + local key="$1" && + local title="$2" && + test_expect_success "value for $title is not printed" ' + test_must_fail git config "$key" >out 2>err && + test_must_be_empty out && + test_must_be_empty err + ' +} + +test_missing_key 'missingsection.missingkey' 'missing section and missing key' +test_missing_key 'missingsection.penguin' 'missing section and existing key' +test_missing_key 'section.missingkey' 'existing section and missing key' +test_missing_key 'section.MissingSubSection.missingkey' 'missing subsection and missing key' +test_missing_key 'section.SubSection.missingkey' 'existing subsection and missing key' +test_missing_key 'section.MissingSubSection.key' 'missing subsection and existing key' + cat > .git/config <<\EOF [alpha] bar = foo @@ -1488,35 +1505,29 @@ test_expect_success 'git config ignores pairs without count' ' test_must_be_empty error ' -test_expect_success 'git config ignores pairs with zero count' ' - test_must_fail env \ - GIT_CONFIG_COUNT=0 \ - GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \ - git config pair.one -' - test_expect_success 'git config ignores pairs exceeding count' ' GIT_CONFIG_COUNT=1 \ GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \ GIT_CONFIG_KEY_1="pair.two" GIT_CONFIG_VALUE_1="value" \ - git config --get-regexp "pair.*" >actual && + git config --get-regexp "pair.*" >actual 2>error && cat >expect <<-EOF && pair.one value EOF - test_cmp expect actual + test_cmp expect actual && + test_must_be_empty error ' test_expect_success 'git config ignores pairs with zero count' ' test_must_fail env \ GIT_CONFIG_COUNT=0 GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \ - git config pair.one >error && + git config pair.one 2>error && test_must_be_empty error ' test_expect_success 'git config ignores pairs with empty count' ' test_must_fail env \ GIT_CONFIG_COUNT= GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \ - git config pair.one >error && + git config pair.one 2>error && test_must_be_empty error ' @@ -1601,11 +1612,11 @@ test_expect_success 'git config --edit respects core.editor' ' # malformed configuration files test_expect_success 'barf on syntax error' ' cat >.git/config <<-\EOF && - # broken section line + # broken key=value [section] key garbage EOF - test_must_fail git config --get section.key >actual 2>error && + test_must_fail git config --get section.key 2>error && test_i18ngrep " line 3 " error ' @@ -1615,17 +1626,17 @@ test_expect_success 'barf on incomplete section header' ' [section key = value EOF - test_must_fail git config --get section.key >actual 2>error && + test_must_fail git config --get section.key 2>error && test_i18ngrep " line 2 " error ' test_expect_success 'barf on incomplete string' ' cat >.git/config <<-\EOF && - # broken section line + # broken value string [section] key = "value string EOF - test_must_fail git config --get section.key >actual 2>error && + test_must_fail git config --get section.key 2>error && test_i18ngrep " line 3 " error ' @@ -1657,6 +1668,21 @@ test_expect_success 'urlmatch' ' test_cmp expect actual ' +test_expect_success 'urlmatch with --show-scope' ' + cat >.git/config <<-\EOF && + [http "https://weak.example.com"] + sslVerify = false + cookieFile = /tmp/cookie.txt + EOF + + cat >expect <<-EOF && + local http.cookiefile /tmp/cookie.txt + local http.sslverify false + EOF + git config --get-urlmatch --show-scope HTTP https://weak.example.com >actual && + test_cmp expect actual +' + test_expect_success 'urlmatch favors more specific URLs' ' cat >.git/config <<-\EOF && [http "https://example.com/"] @@ -2044,6 +2070,12 @@ test_expect_success '--show-origin blob ref' ' test_cmp expect output ' +test_expect_success '--show-origin with --default' ' + git config --show-origin --default foo some.key >actual && + echo "command line: foo" >expect && + test_cmp expect actual +' + test_expect_success '--show-scope with --list' ' cat >expect <<-EOF && global user.global=true @@ -2112,6 +2144,12 @@ test_expect_success '--show-scope with --show-origin' ' test_cmp expect output ' +test_expect_success '--show-scope with --default' ' + git config --show-scope --default foo some.key >actual && + echo "command foo" >expect && + test_cmp expect actual +' + test_expect_success 'override global and system config' ' test_when_finished rm -f \"\$HOME\"/.gitconfig && cat >"$HOME"/.gitconfig <<-EOF && @@ -2258,6 +2296,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/t1301-shared-repo.sh b/t/t1301-shared-repo.sh index 93a2f91f8a..e5a0d65caa 100755 --- a/t/t1301-shared-repo.sh +++ b/t/t1301-shared-repo.sh @@ -8,6 +8,8 @@ test_description='Test shared repository initialization' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_CREATE_REPO_NO_TEMPLATE=1 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Remove a default ACL from the test dir if possible. @@ -25,6 +27,7 @@ test_expect_success 'shared = 0400 (faulty permission u-w)' ' for u in 002 022 do test_expect_success POSIXPERM "shared=1 does not clear bits preset by umask $u" ' + test_when_finished "rm -rf sub" && mkdir sub && ( cd sub && umask $u && @@ -42,16 +45,35 @@ do ;; esac ' - rm -rf sub done test_expect_success 'shared=all' ' - mkdir sub && - cd sub && git init --template= --shared=all && test 2 = $(git config core.sharedrepository) ' +test_expect_failure 'template can set core.bare' ' + test_when_finished "rm -rf subdir" && + test_when_finished "rm -rf templates" && + test_config core.bare true && + umask 0022 && + mkdir -p templates/ && + cp .git/config templates/config && + git init --template=templates subdir && + test_path_exists subdir/HEAD +' + +test_expect_success 'template can set core.bare but overridden by command line' ' + test_when_finished "rm -rf subdir" && + test_when_finished "rm -rf templates" && + test_config core.bare true && + umask 0022 && + mkdir -p templates/ && + cp .git/config templates/config && + git init --no-bare --template=templates subdir && + test_path_exists subdir/.git/HEAD +' + test_expect_success POSIXPERM 'update-server-info honors core.sharedRepository' ' : > a1 && git add a1 && @@ -89,7 +111,7 @@ do rm -f .git/info/refs && git update-server-info && actual="$(test_modebits .git/info/refs)" && - verbose test "x$actual" = "x-$y" + test "x$actual" = "x-$y" ' @@ -99,7 +121,7 @@ do rm -f .git/info/refs && git update-server-info && actual="$(test_modebits .git/info/refs)" && - verbose test "x$actual" = "x-$x" + test "x$actual" = "x-$x" ' @@ -132,6 +154,7 @@ test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' ' ' test_expect_success POSIXPERM 'forced modes' ' + test_when_finished "rm -rf new" && mkdir -p templates/hooks && echo update-server-info >templates/hooks/post-update && chmod +x templates/hooks/post-update && @@ -140,7 +163,8 @@ test_expect_success POSIXPERM 'forced modes' ' ( cd new && umask 002 && - git init --shared=0660 --template=templates && + git init --shared=0660 --template=../templates && + test_path_is_file .git/hooks/post-update && >frotz && git add frotz && git commit -a -m initial && @@ -173,6 +197,7 @@ test_expect_success POSIXPERM 'forced modes' ' ' test_expect_success POSIXPERM 'remote init does not use config from cwd' ' + test_when_finished "rm -rf child.git" && git config core.sharedrepository 0666 && umask 0022 && git init --bare child.git && @@ -192,7 +217,7 @@ test_expect_success POSIXPERM 're-init respects core.sharedrepository (local)' ' ' test_expect_success POSIXPERM 're-init respects core.sharedrepository (remote)' ' - rm -rf child.git && + test_when_finished "rm -rf child.git" && umask 0022 && git init --bare --shared=0666 child.git && test_path_is_missing child.git/foo && @@ -203,7 +228,7 @@ test_expect_success POSIXPERM 're-init respects core.sharedrepository (remote)' ' test_expect_success POSIXPERM 'template can set core.sharedrepository' ' - rm -rf child.git && + test_when_finished "rm -rf child.git" && umask 0022 && git config core.sharedrepository 0666 && cp .git/config templates/config && diff --git a/t/t1302-repo-version.sh b/t/t1302-repo-version.sh index 0acabb6d11..179474fa65 100755 --- a/t/t1302-repo-version.sh +++ b/t/t1302-repo-version.sh @@ -5,6 +5,7 @@ test_description='Test repository version check' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' @@ -27,7 +28,7 @@ test_expect_success 'setup' ' ' test_expect_success 'gitdir selection on normal repos' ' - echo $(test_oid version) >expect && + test_oid version >expect && git config core.repositoryformatversion >actual && git -C test config core.repositoryformatversion >actual2 && test_cmp expect actual && @@ -36,7 +37,7 @@ test_expect_success 'gitdir selection on normal repos' ' test_expect_success 'gitdir selection on unsupported repo' ' # Make sure it would stop at test2, not trash - test_expect_code 1 git -C test2 config core.repositoryformatversion >actual + test_expect_code 1 git -C test2 config core.repositoryformatversion ' test_expect_success 'gitdir not required mode' ' diff --git a/t/t1304-default-acl.sh b/t/t1304-default-acl.sh index 335d3f3211..31b89dd969 100755 --- a/t/t1304-default-acl.sh +++ b/t/t1304-default-acl.sh @@ -9,6 +9,7 @@ test_description='Test repository with default ACL' # => this must come before . ./test-lib.sh umask 077 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # We need an arbitrary other user give permission to using ACLs. root @@ -18,7 +19,7 @@ test_expect_success 'checking for a working acl setup' ' if setfacl -m d:m:rwx -m u:root:rwx . && getfacl . | grep user:root:rwx && touch should-have-readable-acl && - getfacl should-have-readable-acl | egrep "mask::?rw-" + getfacl should-have-readable-acl | grep -E "mask::?rw-" then test_set_prereq SETFACL fi @@ -34,7 +35,7 @@ check_perms_and_acl () { getfacl "$1" > actual && grep -q "user:root:rwx" actual && grep -q "user:${LOGNAME}:rwx" actual && - egrep "mask::?r--" actual > /dev/null 2>&1 && + grep -E "mask::?r--" actual > /dev/null 2>&1 && grep -q "group::---" actual || false } diff --git a/t/t1308-config-set.sh b/t/t1308-config-set.sh index b38e158d3b..777648722c 100755 --- a/t/t1308-config-set.sh +++ b/t/t1308-config-set.sh @@ -58,6 +58,8 @@ test_expect_success 'setup default config' ' skin = false nose = 1 horns + [value] + less EOF ' @@ -116,10 +118,53 @@ test_expect_success 'find value with the highest priority' ' check_config get_value case.baz "hask" ' +test_expect_success 'return value for an existing key' ' + test-tool config get lamb.chop >out 2>err && + test_must_be_empty out && + test_must_be_empty err +' + +test_expect_success 'return value for value-less key' ' + test-tool config get value.less >out 2>err && + test_must_be_empty out && + test_must_be_empty err +' + +test_expect_success 'return value for a missing key' ' + cat >expect <<-\EOF && + Value not found for "missing.key" + EOF + test_expect_code 1 test-tool config get missing.key >actual 2>err && + test_cmp actual expect && + test_must_be_empty err +' + +test_expect_success 'return value for a bad key: CONFIG_INVALID_KEY' ' + cat >expect <<-\EOF && + Key "fails.iskeychar.-" is invalid + EOF + test_expect_code 1 test-tool config get fails.iskeychar.- >actual 2>err && + test_cmp actual expect && + test_must_be_empty out +' + +test_expect_success 'return value for a bad key: CONFIG_NO_SECTION_OR_NAME' ' + cat >expect <<-\EOF && + Key "keynosection" has no section + EOF + test_expect_code 1 test-tool config get keynosection >actual 2>err && + test_cmp actual expect && + test_must_be_empty out +' + test_expect_success 'find integer value for a key' ' check_config get_int lamb.chop 65 ' +test_expect_success 'parse integer value during iteration' ' + check_config git_config_int lamb.chop 65 +' + test_expect_success 'find string value for a key' ' check_config get_string case.baz hask && check_config expect_code 1 get_string case.ba "Value not found for \"case.ba\"" @@ -134,6 +179,11 @@ test_expect_success 'find integer if value is non parse-able' ' check_config expect_code 128 get_int lamb.head ' +test_expect_success 'non parse-able integer value during iteration' ' + check_config expect_code 128 git_config_int lamb.head 2>result && + grep "fatal: bad numeric config value .* in file \.git/config" result +' + test_expect_success 'find bool value for the entered key' ' check_config get_bool goat.head 1 && check_config get_bool goat.skin 0 && @@ -146,6 +196,71 @@ test_expect_success 'find multiple values' ' check_config get_value_multi case.baz sam bat hask ' +test_NULL_in_multi () { + local op="$1" && + local file="$2" && + + test_expect_success "$op: NULL value in config${file:+ in $file}" ' + config="$file" && + if test -z "$config" + then + config=.git/config && + test_when_finished "mv $config.old $config" && + mv "$config" "$config".old + fi && + + # Value-less in the middle of a list + cat >"$config" <<-\EOF && + [a]key=x + [a]key + [a]key=y + EOF + case "$op" in + *_multi) + cat >expect <<-\EOF + x + (NULL) + y + EOF + ;; + *) + cat >expect <<-\EOF + y + EOF + ;; + esac && + test-tool config "$op" a.key $file >actual && + test_cmp expect actual && + + # Value-less at the end of a least + cat >"$config" <<-\EOF && + [a]key=x + [a]key=y + [a]key + EOF + case "$op" in + *_multi) + cat >expect <<-\EOF + x + y + (NULL) + EOF + ;; + *) + cat >expect <<-\EOF + (NULL) + EOF + ;; + esac && + test-tool config "$op" a.key $file >actual && + test_cmp expect actual + ' +} + +test_NULL_in_multi "get_value_multi" +test_NULL_in_multi "configset_get_value" "my.config" +test_NULL_in_multi "configset_get_value_multi" "my.config" + test_expect_success 'find value from a configset' ' cat >config2 <<-\EOF && [case] @@ -207,7 +322,7 @@ test_expect_success 'proper error on error in default config files' ' cp .git/config .git/config.old && test_when_finished "mv .git/config.old .git/config" && echo "[" >>.git/config && - echo "fatal: bad config line 34 in file .git/config" >expect && + echo "fatal: bad config line 36 in file .git/config" >expect && test_expect_code 128 test-tool config get_value foo.bar 2>actual && test_cmp expect actual ' diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh index cf58cf025c..4d66cd7f4a 100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -1568,6 +1568,7 @@ test_expect_success 'transaction can create and delete' ' EOF git update-ref --stdin <stdin >actual && printf "%s: ok\n" start commit start commit >expect && + test_cmp expect actual && test_must_fail git show-ref --verify refs/heads/create-and-delete ' @@ -1595,6 +1596,8 @@ test_expect_success 'transaction cannot restart ongoing transaction' ' commit EOF test_must_fail git update-ref --stdin <stdin >actual && + printf "%s: ok\n" start >expect && + test_cmp expect actual && test_must_fail git show-ref --verify refs/heads/restart ' diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh index 0c204089b8..c7745e1bf6 100755 --- a/t/t1401-symbolic-ref.sh +++ b/t/t1401-symbolic-ref.sh @@ -33,7 +33,8 @@ test_expect_success 'symbolic-ref refuses non-ref for HEAD' ' reset_to_sane test_expect_success 'symbolic-ref refuses bare sha1' ' - test_must_fail git symbolic-ref HEAD $(git rev-parse HEAD) + rev=$(git rev-parse HEAD) && + test_must_fail git symbolic-ref HEAD "$rev" ' reset_to_sane @@ -175,4 +176,52 @@ test_expect_success 'symbolic-ref allows top-level target for non-HEAD' ' test_cmp_rev top-level HEAD ' +test_expect_success 'symbolic-ref pointing at another' ' + git update-ref refs/heads/maint-2.37 HEAD && + git symbolic-ref refs/heads/maint refs/heads/maint-2.37 && + git checkout maint && + + git symbolic-ref HEAD >actual && + echo refs/heads/maint-2.37 >expect && + test_cmp expect actual && + + git symbolic-ref --no-recurse HEAD >actual && + echo refs/heads/maint >expect && + test_cmp expect actual +' + +test_expect_success 'symbolic-ref --short handles complex utf8 case' ' + name="测试-加-增加-加-增加" && + git symbolic-ref TEST_SYMREF "refs/heads/$name" && + # In the real world, we saw problems with this case only + # when the locale includes UTF-8. Set it here to try to make things as + # hard as possible for us to pass, but in practice we should do the + # right thing regardless (and of course some platforms may not even + # have this locale). + LC_ALL=en_US.UTF-8 git symbolic-ref --short TEST_SYMREF >actual && + echo "$name" >expect && + test_cmp expect actual +' + +test_expect_success 'symbolic-ref --short handles name with suffix' ' + git symbolic-ref TEST_SYMREF "refs/remotes/origin/HEAD" && + git symbolic-ref --short TEST_SYMREF >actual && + echo "origin" >expect && + test_cmp expect actual +' + +test_expect_success 'symbolic-ref --short handles almost-matching name' ' + git symbolic-ref TEST_SYMREF "refs/headsXfoo" && + git symbolic-ref --short TEST_SYMREF >actual && + echo "headsXfoo" >expect && + test_cmp expect actual +' + +test_expect_success 'symbolic-ref --short handles name with percent' ' + git symbolic-ref TEST_SYMREF "refs/heads/%foo" && + git symbolic-ref --short TEST_SYMREF >actual && + echo "%foo" >expect && + test_cmp expect actual +' + test_done diff --git a/t/t1404-update-ref-errors.sh b/t/t1404-update-ref-errors.sh index 13c2b43bba..937ae0d733 100755 --- a/t/t1404-update-ref-errors.sh +++ b/t/t1404-update-ref-errors.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='Test git update-ref error handling' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Create some references, perhaps run pack-refs --all, then try to @@ -549,7 +551,6 @@ test_expect_success REFFILES 'no bogus intermediate values during delete' ' git update-ref $prefix/foo $C && git pack-refs --all && git update-ref $prefix/foo $D && - git for-each-ref $prefix >unchanged && # Now try to update the reference, but hold the `packed-refs` lock # for a while to see what happens while the process is blocked: : >.git/packed-refs.lock && diff --git a/t/t1408-packed-refs.sh b/t/t1408-packed-refs.sh index 41ba1f1d7f..9469c79a58 100755 --- a/t/t1408-packed-refs.sh +++ b/t/t1408-packed-refs.sh @@ -5,6 +5,7 @@ test_description='packed-refs entries are covered by loose refs' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t1409-avoid-packing-refs.sh b/t/t1409-avoid-packing-refs.sh index be12fb6350..f23c0152a8 100755 --- a/t/t1409-avoid-packing-refs.sh +++ b/t/t1409-avoid-packing-refs.sh @@ -2,6 +2,7 @@ test_description='avoid rewriting packed-refs unnecessarily' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Add an identifying mark to the packed-refs file header line. This diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh index aa59954f6c..6c45965b1e 100755 --- a/t/t1410-reflog.sh +++ b/t/t1410-reflog.sh @@ -7,6 +7,7 @@ test_description='Test prune and reflog expiration' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh check_have () { diff --git a/t/t1413-reflog-detach.sh b/t/t1413-reflog-detach.sh index 934688a1ee..d2a4822d46 100755 --- a/t/t1413-reflog-detach.sh +++ b/t/t1413-reflog-detach.sh @@ -4,6 +4,7 @@ test_description='Test reflog interaction with detached HEAD' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh reset_state () { diff --git a/t/t1416-ref-transaction-hooks.sh b/t/t1416-ref-transaction-hooks.sh index 27731722a5..b32ca798f9 100755 --- a/t/t1416-ref-transaction-hooks.sh +++ b/t/t1416-ref-transaction-hooks.sh @@ -5,6 +5,7 @@ test_description='reference transaction hooks' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t1419-exclude-refs.sh b/t/t1419-exclude-refs.sh new file mode 100755 index 0000000000..5d8c86b657 --- /dev/null +++ b/t/t1419-exclude-refs.sh @@ -0,0 +1,122 @@ +#!/bin/sh + +test_description='test exclude_patterns functionality in main ref store' + +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +for_each_ref__exclude () { + GIT_TRACE2_PERF=1 test-tool ref-store main \ + for-each-ref--exclude "$@" >actual.raw + cut -d ' ' -f 2 actual.raw +} + +for_each_ref () { + git for-each-ref --format='%(refname)' "$@" +} + +assert_jumps () { + local nr="$1" + local trace="$2" + + grep -q "name:jumps_made value:$nr$" $trace +} + +assert_no_jumps () { + ! assert_jumps ".*" "$1" +} + +test_expect_success 'setup' ' + test_commit --no-tag base && + base="$(git rev-parse HEAD)" && + + for name in foo bar baz quux + do + for i in 1 2 3 + do + echo "create refs/heads/$name/$i $base" || return 1 + done || return 1 + done >in && + echo "delete refs/heads/main" >>in && + + git update-ref --stdin <in && + git pack-refs --all +' + +test_expect_success 'excluded region in middle' ' + for_each_ref__exclude refs/heads refs/heads/foo >actual 2>perf && + for_each_ref refs/heads/bar refs/heads/baz refs/heads/quux >expect && + + test_cmp expect actual && + assert_jumps 1 perf +' + +test_expect_success 'excluded region at beginning' ' + for_each_ref__exclude refs/heads refs/heads/bar >actual 2>perf && + for_each_ref refs/heads/baz refs/heads/foo refs/heads/quux >expect && + + test_cmp expect actual && + assert_jumps 1 perf +' + +test_expect_success 'excluded region at end' ' + for_each_ref__exclude refs/heads refs/heads/quux >actual 2>perf && + for_each_ref refs/heads/foo refs/heads/bar refs/heads/baz >expect && + + test_cmp expect actual && + assert_jumps 1 perf +' + +test_expect_success 'disjoint excluded regions' ' + for_each_ref__exclude refs/heads refs/heads/bar refs/heads/quux >actual 2>perf && + for_each_ref refs/heads/baz refs/heads/foo >expect && + + test_cmp expect actual && + assert_jumps 2 perf +' + +test_expect_success 'adjacent, non-overlapping excluded regions' ' + for_each_ref__exclude refs/heads refs/heads/bar refs/heads/baz >actual 2>perf && + for_each_ref refs/heads/foo refs/heads/quux >expect && + + test_cmp expect actual && + assert_jumps 1 perf +' + +test_expect_success 'overlapping excluded regions' ' + for_each_ref__exclude refs/heads refs/heads/ba refs/heads/baz >actual 2>perf && + for_each_ref refs/heads/foo refs/heads/quux >expect && + + test_cmp expect actual && + assert_jumps 1 perf +' + +test_expect_success 'several overlapping excluded regions' ' + for_each_ref__exclude refs/heads \ + refs/heads/bar refs/heads/baz refs/heads/foo >actual 2>perf && + for_each_ref refs/heads/quux >expect && + + test_cmp expect actual && + assert_jumps 1 perf +' + +test_expect_success 'non-matching excluded section' ' + for_each_ref__exclude refs/heads refs/heads/does/not/exist >actual 2>perf && + for_each_ref >expect && + + test_cmp expect actual && + assert_no_jumps perf +' + +test_expect_success 'meta-characters are discarded' ' + for_each_ref__exclude refs/heads "refs/heads/ba*" >actual 2>perf && + for_each_ref >expect && + + test_cmp expect actual && + assert_no_jumps perf +' + +test_done diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh index de0f6d5e7f..10a539158c 100755 --- a/t/t1450-fsck.sh +++ b/t/t1450-fsck.sh @@ -212,7 +212,7 @@ test_expect_success 'email without @ is okay' ' test_expect_success 'email with embedded > is not okay' ' git cat-file commit HEAD >basis && sed "s/@[a-z]/&>/" basis >bad-email && - new=$(git hash-object -t commit -w --stdin <bad-email) && + new=$(git hash-object --literally -t commit -w --stdin <bad-email) && test_when_finished "remove_object $new" && git update-ref refs/heads/bogus "$new" && test_when_finished "git update-ref -d refs/heads/bogus" && @@ -223,7 +223,7 @@ test_expect_success 'email with embedded > is not okay' ' test_expect_success 'missing < email delimiter is reported nicely' ' git cat-file commit HEAD >basis && sed "s/<//" basis >bad-email-2 && - new=$(git hash-object -t commit -w --stdin <bad-email-2) && + new=$(git hash-object --literally -t commit -w --stdin <bad-email-2) && test_when_finished "remove_object $new" && git update-ref refs/heads/bogus "$new" && test_when_finished "git update-ref -d refs/heads/bogus" && @@ -234,7 +234,7 @@ test_expect_success 'missing < email delimiter is reported nicely' ' test_expect_success 'missing email is reported nicely' ' git cat-file commit HEAD >basis && sed "s/[a-z]* <[^>]*>//" basis >bad-email-3 && - new=$(git hash-object -t commit -w --stdin <bad-email-3) && + new=$(git hash-object --literally -t commit -w --stdin <bad-email-3) && test_when_finished "remove_object $new" && git update-ref refs/heads/bogus "$new" && test_when_finished "git update-ref -d refs/heads/bogus" && @@ -245,7 +245,7 @@ test_expect_success 'missing email is reported nicely' ' test_expect_success '> in name is reported' ' git cat-file commit HEAD >basis && sed "s/ </> </" basis >bad-email-4 && - new=$(git hash-object -t commit -w --stdin <bad-email-4) && + new=$(git hash-object --literally -t commit -w --stdin <bad-email-4) && test_when_finished "remove_object $new" && git update-ref refs/heads/bogus "$new" && test_when_finished "git update-ref -d refs/heads/bogus" && @@ -258,7 +258,7 @@ test_expect_success 'integer overflow in timestamps is reported' ' git cat-file commit HEAD >basis && sed "s/^\\(author .*>\\) [0-9]*/\\1 18446744073709551617/" \ <basis >bad-timestamp && - new=$(git hash-object -t commit -w --stdin <bad-timestamp) && + new=$(git hash-object --literally -t commit -w --stdin <bad-timestamp) && test_when_finished "remove_object $new" && git update-ref refs/heads/bogus "$new" && test_when_finished "git update-ref -d refs/heads/bogus" && @@ -269,7 +269,7 @@ test_expect_success 'integer overflow in timestamps is reported' ' test_expect_success 'commit with NUL in header' ' git cat-file commit HEAD >basis && sed "s/author ./author Q/" <basis | q_to_nul >commit-NUL-header && - new=$(git hash-object -t commit -w --stdin <commit-NUL-header) && + new=$(git hash-object --literally -t commit -w --stdin <commit-NUL-header) && test_when_finished "remove_object $new" && git update-ref refs/heads/bogus "$new" && test_when_finished "git update-ref -d refs/heads/bogus" && @@ -292,7 +292,7 @@ test_expect_success 'tree object with duplicate entries' ' git cat-file tree $T && git cat-file tree $T ) | - git hash-object -w -t tree --stdin + git hash-object --literally -w -t tree --stdin ) && test_must_fail git fsck 2>out && test_i18ngrep "error in tree .*contains duplicate file entries" out @@ -426,7 +426,7 @@ test_expect_success 'tag with incorrect tag name & missing tagger' ' This is an invalid tag. EOF - tag=$(git hash-object -t tag -w --stdin <wrong-tag) && + tag=$(git hash-object --literally -t tag -w --stdin <wrong-tag) && test_when_finished "remove_object $tag" && echo $tag >.git/refs/tags/wrong && test_when_finished "git update-ref -d refs/tags/wrong" && @@ -558,7 +558,7 @@ test_expect_success 'rev-list --verify-objects with commit graph (parent)' ' test_expect_success 'force fsck to ignore double author' ' git cat-file commit HEAD >basis && sed "s/^author .*/&,&/" <basis | tr , \\n >multiple-authors && - new=$(git hash-object -t commit -w --stdin <multiple-authors) && + new=$(git hash-object --literally -t commit -w --stdin <multiple-authors) && test_when_finished "remove_object $new" && git update-ref refs/heads/bogus "$new" && test_when_finished "git update-ref -d refs/heads/bogus" && @@ -573,7 +573,7 @@ test_expect_success 'fsck notices blob entry pointing to null sha1' ' (git init null-blob && cd null-blob && sha=$(printf "100644 file$_bz$_bzoid" | - git hash-object -w --stdin -t tree) && + git hash-object --literally -w --stdin -t tree) && git fsck 2>out && test_i18ngrep "warning.*null sha1" out ) @@ -583,12 +583,22 @@ test_expect_success 'fsck notices submodule entry pointing to null sha1' ' (git init null-commit && cd null-commit && sha=$(printf "160000 submodule$_bz$_bzoid" | - git hash-object -w --stdin -t tree) && + git hash-object --literally -w --stdin -t tree) && git fsck 2>out && test_i18ngrep "warning.*null sha1" out ) ' +test_expect_success 'fsck notices excessively large tree entry name' ' + git init large-name && + ( + cd large-name && + test_commit a-long-name && + git -c fsck.largePathname=warn:10 fsck 2>out && + grep "warning.*large pathname" out + ) +' + while read name path pretty; do while read mode type; do : ${pretty:=$path} @@ -648,7 +658,7 @@ test_expect_success 'NUL in commit' ' git commit --allow-empty -m "initial commitQNUL after message" && git cat-file commit HEAD >original && q_to_nul <original >munged && - git hash-object -w -t commit --stdin <munged >name && + git hash-object --literally -w -t commit --stdin <munged >name && git branch bad $(cat name) && test_must_fail git -c fsck.nulInCommit=error fsck 2>warn.1 && @@ -794,8 +804,8 @@ test_expect_success 'fsck errors in packed objects' ' git cat-file commit HEAD >basis && sed "s/</one/" basis >one && sed "s/</foo/" basis >two && - one=$(git hash-object -t commit -w one) && - two=$(git hash-object -t commit -w two) && + one=$(git hash-object --literally -t commit -w one) && + two=$(git hash-object --literally -t commit -w two) && pack=$( { echo $one && @@ -989,10 +999,7 @@ test_expect_success 'fsck error and recovery on invalid object type' ' garbage_blob=$(git hash-object --stdin -w -t garbage --literally </dev/null) && - cat >err.expect <<-\EOF && - fatal: invalid object type - EOF - test_must_fail git fsck >out 2>err && + test_must_fail git fsck 2>err && grep -e "^error" -e "^fatal" err >errors && test_line_count = 1 errors && grep "$garbage_blob: object is of unknown type '"'"'garbage'"'"':" err @@ -1023,4 +1030,34 @@ test_expect_success 'fsck error on gitattributes with excessive size' ' test_cmp expected actual ' +test_expect_success 'fsck detects problems in worktree index' ' + test_when_finished "git worktree remove -f wt" && + git worktree add wt && + + echo "this will be removed to break the worktree index" >wt/file && + git -C wt add file && + blob=$(git -C wt rev-parse :file) && + remove_object $blob && + + test_must_fail git fsck --name-objects >actual 2>&1 && + cat >expect <<-EOF && + missing blob $blob (.git/worktrees/wt/index:file) + EOF + test_cmp expect actual +' + +test_expect_success 'fsck reports problems in current worktree index without filename' ' + test_when_finished "rm -f .git/index && git read-tree HEAD" && + echo "this object will be removed to break current worktree index" >file && + git add file && + blob=$(git rev-parse :file) && + remove_object $blob && + + test_must_fail git fsck --name-objects >actual 2>&1 && + cat >expect <<-EOF && + missing blob $blob (:file) + EOF + test_cmp expect actual +' + test_done diff --git a/t/t1451-fsck-buffer.sh b/t/t1451-fsck-buffer.sh new file mode 100755 index 0000000000..3413da40e4 --- /dev/null +++ b/t/t1451-fsck-buffer.sh @@ -0,0 +1,142 @@ +#!/bin/sh + +test_description='fsck on buffers without NUL termination + +The goal here is to make sure that the various fsck parsers never look +past the end of the buffer they are given, even when encountering broken +or truncated objects. + +We have to use "hash-object" for this because most code paths that read objects +append an extra NUL for safety after the buffer. But hash-object, since it is +reading straight from a file (and possibly even mmap-ing it) cannot always do +so. + +These tests _might_ catch such overruns in normal use, but should be run with +ASan or valgrind for more confidence. +' + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +# the general idea for tags and commits is to build up the "base" file +# progressively, and then test new truncations on top of it. +reset () { + test_expect_success 'reset input to empty' ' + >base + ' +} + +add () { + content="$1" + type=${content%% *} + test_expect_success "add $type line" ' + echo "$content" >>base + ' +} + +check () { + type=$1 + fsck=$2 + content=$3 + test_expect_success "truncated $type ($fsck, \"$content\")" ' + # do not pipe into hash-object here; we want to increase + # the chance that it uses a fixed-size buffer or mmap, + # and a pipe would be read into a strbuf. + { + cat base && + echo "$content" + } >input && + test_must_fail git hash-object -t "$type" input 2>err && + grep "$fsck" err + ' +} + +test_expect_success 'create valid objects' ' + git commit --allow-empty -m foo && + commit=$(git rev-parse --verify HEAD) && + tree=$(git rev-parse --verify HEAD^{tree}) +' + +reset +check commit missingTree "" +check commit missingTree "tr" +check commit missingTree "tree" +check commit badTreeSha1 "tree " +check commit badTreeSha1 "tree 1234" +add "tree $tree" + +# these expect missingAuthor because "parent" is optional +check commit missingAuthor "" +check commit missingAuthor "par" +check commit missingAuthor "parent" +check commit badParentSha1 "parent " +check commit badParentSha1 "parent 1234" +add "parent $commit" + +check commit missingAuthor "" +check commit missingAuthor "au" +check commit missingAuthor "author" +ident_checks () { + check $1 missingEmail "$2 " + check $1 missingEmail "$2 name" + check $1 badEmail "$2 name <" + check $1 badEmail "$2 name <email" + check $1 missingSpaceBeforeDate "$2 name <email>" + check $1 badDate "$2 name <email> " + check $1 badDate "$2 name <email> 1234" + check $1 badTimezone "$2 name <email> 1234 " + check $1 badTimezone "$2 name <email> 1234 +" +} +ident_checks commit author +add "author name <email> 1234 +0000" + +check commit missingCommitter "" +check commit missingCommitter "co" +check commit missingCommitter "committer" +ident_checks commit committer +add "committer name <email> 1234 +0000" + +reset +check tag missingObject "" +check tag missingObject "obj" +check tag missingObject "object" +check tag badObjectSha1 "object " +check tag badObjectSha1 "object 1234" +add "object $commit" + +check tag missingType "" +check tag missingType "ty" +check tag missingType "type" +check tag badType "type " +check tag badType "type com" +add "type commit" + +check tag missingTagEntry "" +check tag missingTagEntry "ta" +check tag missingTagEntry "tag" +check tag badTagName "tag " +add "tag foo" + +check tag missingTagger "" +check tag missingTagger "ta" +check tag missingTagger "tagger" +ident_checks tag tagger + +# trees are a binary format and can't use our earlier helpers +test_expect_success 'truncated tree (short hash)' ' + printf "100644 foo\0\1\1\1\1" >input && + test_must_fail git hash-object -t tree input 2>err && + grep badTree err +' + +test_expect_success 'truncated tree (missing nul)' ' + # these two things are indistinguishable to the parser. The important + # thing about this is example is that there are enough bytes to + # make up a hash, and that there is no NUL (and we confirm that the + # parser does not walk past the end of the buffer). + printf "100644 a long filename, or a hash with missing nul?" >input && + test_must_fail git hash-object -t tree input 2>err && + grep badTree err +' + +test_done diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh index 81de584ea2..37ee5091b5 100755 --- a/t/t1500-rev-parse.sh +++ b/t/t1500-rev-parse.sh @@ -195,7 +195,7 @@ test_expect_success 'rev-parse --is-shallow-repository in non-shallow repo' ' ' test_expect_success 'rev-parse --show-object-format in repo' ' - echo "$(test_oid algo)" >expect && + test_oid algo >expect && git rev-parse --show-object-format >actual && test_cmp expect actual && git rev-parse --show-object-format=storage >actual && diff --git a/t/t1501-work-tree.sh b/t/t1501-work-tree.sh index b75558040f..ae6528aece 100755 --- a/t/t1501-work-tree.sh +++ b/t/t1501-work-tree.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test separate work tree' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh index de1d48f3ba..f0737593c3 100755 --- a/t/t1502-rev-parse-parseopt.sh +++ b/t/t1502-rev-parse-parseopt.sh @@ -3,13 +3,29 @@ test_description='test git rev-parse --parseopt' . ./test-lib.sh +check_invalid_long_option () { + spec="$1" + opt="$2" + test_expect_success "test --parseopt invalid switch $opt help output for $spec" ' + { + cat <<-\EOF && + error: unknown option `'${opt#--}\'' + EOF + sed -e 1d -e \$d <"$TEST_DIRECTORY/t1502/$spec.help" + } >expect && + test_expect_code 129 git rev-parse --parseopt -- $opt \ + 2>output <"$TEST_DIRECTORY/t1502/$spec" && + test_cmp expect output + ' +} + test_expect_success 'setup optionspec' ' sed -e "s/^|//" >optionspec <<\EOF |some-command [options] <args>... | |some-command does foo and bar! |-- -|h,help show the help +|h,help! show the help | |foo some nifty option --foo |bar= some cool option --bar with an argument @@ -58,44 +74,8 @@ EOF ' test_expect_success 'test --parseopt help output' ' - sed -e "s/^|//" >expect <<\END_EXPECT && -|cat <<\EOF -|usage: some-command [options] <args>... -| -| some-command does foo and bar! -| -| -h, --help show the help -| --foo some nifty option --foo -| --bar ... some cool option --bar with an argument -| -b, --baz a short and long option -| -|An option group Header -| -C[...] option C with an optional argument -| -d, --data[=...] short and long option with an optional argument -| -|Argument hints -| -B <arg> short option required argument -| --bar2 <arg> long option required argument -| -e, --fuz <with-space> -| short and long option required argument -| -s[<some>] short option optional argument -| --long[=<data>] long option optional argument -| -g, --fluf[=<path>] short and long option optional argument -| --longest <very-long-argument-hint> -| a very long argument hint -| --pair <key=value> with an equals sign in the hint -| --aswitch help te=t contains? fl*g characters!` -| --bswitch <hint> hint has trailing tab character -| --cswitch switch has trailing tab character -| --short-hint <a> with a one symbol hint -| -|Extras -| --extra1 line above used to cause a segfault but no longer does -| -|EOF -END_EXPECT test_expect_code 129 git rev-parse --parseopt -- -h > output < optionspec && - test_cmp expect output + test_cmp "$TEST_DIRECTORY/t1502/optionspec.help" output ' test_expect_success 'test --parseopt help output no switches' ' @@ -131,7 +111,7 @@ test_expect_success 'test --parseopt help-all output hidden switches' ' | | some-command does foo and bar! | -| --hidden1 A hidden switch +| --[no-]hidden1 A hidden switch | |EOF END_EXPECT @@ -140,41 +120,12 @@ END_EXPECT ' test_expect_success 'test --parseopt invalid switch help output' ' - sed -e "s/^|//" >expect <<\END_EXPECT && -|error: unknown option `does-not-exist'\'' -|usage: some-command [options] <args>... -| -| some-command does foo and bar! -| -| -h, --help show the help -| --foo some nifty option --foo -| --bar ... some cool option --bar with an argument -| -b, --baz a short and long option -| -|An option group Header -| -C[...] option C with an optional argument -| -d, --data[=...] short and long option with an optional argument -| -|Argument hints -| -B <arg> short option required argument -| --bar2 <arg> long option required argument -| -e, --fuz <with-space> -| short and long option required argument -| -s[<some>] short option optional argument -| --long[=<data>] long option optional argument -| -g, --fluf[=<path>] short and long option optional argument -| --longest <very-long-argument-hint> -| a very long argument hint -| --pair <key=value> with an equals sign in the hint -| --aswitch help te=t contains? fl*g characters!` -| --bswitch <hint> hint has trailing tab character -| --cswitch switch has trailing tab character -| --short-hint <a> with a one symbol hint -| -|Extras -| --extra1 line above used to cause a segfault but no longer does -| -END_EXPECT + { + cat <<-\EOF && + error: unknown option `does-not-exist'\'' + EOF + sed -e 1d -e \$d <"$TEST_DIRECTORY/t1502/optionspec.help" + } >expect && test_expect_code 129 git rev-parse --parseopt -- --does-not-exist 1>/dev/null 2>output < optionspec && test_cmp expect output ' @@ -288,7 +239,7 @@ test_expect_success 'test --parseopt help output: "wrapped" options normal "or:" | [--another-option] |cmd [--yet-another-option] |-- - |h,help show the help + |h,help! show the help EOF sed -e "s/^|//" >expect <<-\END_EXPECT && @@ -302,14 +253,14 @@ test_expect_success 'test --parseopt help output: "wrapped" options normal "or:" |EOF END_EXPECT - test_must_fail git rev-parse --parseopt -- -h >out <spec >actual && + test_must_fail git rev-parse --parseopt -- -h <spec >actual && test_cmp expect actual ' test_expect_success 'test --parseopt invalid opt-spec' ' test_write_lines x -- "=, x" >spec && echo "fatal: missing opt-spec before option flags" >expect && - test_must_fail git rev-parse --parseopt -- >out <spec 2>err && + test_must_fail git rev-parse --parseopt -- <spec 2>err && test_cmp expect err ' @@ -322,7 +273,7 @@ test_expect_success 'test --parseopt help output: multi-line blurb after empty l |line |blurb |-- - |h,help show the help + |h,help! show the help EOF sed -e "s/^|//" >expect <<-\END_EXPECT && @@ -339,8 +290,36 @@ test_expect_success 'test --parseopt help output: multi-line blurb after empty l |EOF END_EXPECT - test_must_fail git rev-parse --parseopt -- -h >out <spec >actual && + test_must_fail git rev-parse --parseopt -- -h <spec >actual && test_cmp expect actual ' +test_expect_success 'test --parseopt help output for optionspec-neg' ' + test_expect_code 129 git rev-parse --parseopt -- \ + -h >output <"$TEST_DIRECTORY/t1502/optionspec-neg" && + test_cmp "$TEST_DIRECTORY/t1502/optionspec-neg.help" output +' + +test_expect_success 'test --parseopt valid options for optionspec-neg' ' + cat >expect <<-\EOF && + set -- --foo --no-foo --no-bar --positive-only --no-negative -- + EOF + git rev-parse --parseopt -- <"$TEST_DIRECTORY/t1502/optionspec-neg" >output \ + --foo --no-foo --no-bar --positive-only --no-negative && + test_cmp expect output +' + +test_expect_success 'test --parseopt positivated option for optionspec-neg' ' + cat >expect <<-\EOF && + set -- --no-no-bar --no-no-bar -- + EOF + git rev-parse --parseopt -- <"$TEST_DIRECTORY/t1502/optionspec-neg" >output \ + --no-no-bar --bar && + test_cmp expect output +' + +check_invalid_long_option optionspec-neg --no-positive-only +check_invalid_long_option optionspec-neg --negative +check_invalid_long_option optionspec-neg --no-no-negative + test_done diff --git a/t/t1502/.gitattributes b/t/t1502/.gitattributes new file mode 100644 index 0000000000..562b12e16e --- /dev/null +++ b/t/t1502/.gitattributes @@ -0,0 +1 @@ +* -whitespace diff --git a/t/t1502/optionspec-neg b/t/t1502/optionspec-neg new file mode 100644 index 0000000000..392f43eb0b --- /dev/null +++ b/t/t1502/optionspec-neg @@ -0,0 +1,8 @@ +some-command [options] <args>... + +some-command does foo and bar! +-- +foo can be negated +no-bar can be positivated +positive-only! cannot be negated +no-negative! cannot be positivated diff --git a/t/t1502/optionspec-neg.help b/t/t1502/optionspec-neg.help new file mode 100644 index 0000000000..7a29f8cb03 --- /dev/null +++ b/t/t1502/optionspec-neg.help @@ -0,0 +1,12 @@ +cat <<\EOF +usage: some-command [options] <args>... + + some-command does foo and bar! + + --[no-]foo can be negated + --no-bar can be positivated + --bar opposite of --no-bar + --positive-only cannot be negated + --no-negative cannot be positivated + +EOF diff --git a/t/t1502/optionspec.help b/t/t1502/optionspec.help new file mode 100755 index 0000000000..cbdd54d41b --- /dev/null +++ b/t/t1502/optionspec.help @@ -0,0 +1,36 @@ +cat <<\EOF +usage: some-command [options] <args>... + + some-command does foo and bar! + + -h, --help show the help + --[no-]foo some nifty option --foo + --[no-]bar ... some cool option --bar with an argument + -b, --[no-]baz a short and long option + +An option group Header + -C[...] option C with an optional argument + -d, --[no-]data[=...] short and long option with an optional argument + +Argument hints + -B <arg> short option required argument + --[no-]bar2 <arg> long option required argument + -e, --[no-]fuz <with-space> + short and long option required argument + -s[<some>] short option optional argument + --[no-]long[=<data>] long option optional argument + -g, --[no-]fluf[=<path>] + short and long option optional argument + --[no-]longest <very-long-argument-hint> + a very long argument hint + --[no-]pair <key=value> + with an equals sign in the hint + --[no-]aswitch help te=t contains? fl*g characters!` + --[no-]bswitch <hint> hint has trailing tab character + --[no-]cswitch switch has trailing tab character + --[no-]short-hint <a> with a one symbol hint + +Extras + --[no-]extra1 line above used to cause a segfault but no longer does + +EOF diff --git a/t/t1504-ceiling-dirs.sh b/t/t1504-ceiling-dirs.sh index 0fafcf9dde..c1679e31d8 100755 --- a/t/t1504-ceiling-dirs.sh +++ b/t/t1504-ceiling-dirs.sh @@ -6,8 +6,12 @@ TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_prefix() { - test_expect_success "$1" \ - "test '$2' = \"\$(git rev-parse --show-prefix)\"" + local expect="$2" && + test_expect_success "$1: git rev-parse --show-prefix is '$2'" ' + echo "$expect" >expect && + git rev-parse --show-prefix >actual && + test_cmp expect actual + ' } test_fail() { diff --git a/t/t1507-rev-parse-upstream.sh b/t/t1507-rev-parse-upstream.sh index c34714ffe3..b9af6b3ac0 100755 --- a/t/t1507-rev-parse-upstream.sh +++ b/t/t1507-rev-parse-upstream.sh @@ -5,6 +5,7 @@ test_description='test <branch>@{upstream} syntax' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh @@ -97,7 +98,8 @@ test_expect_success 'my-side@{u} resolves to correct commit' ' commit_subject my-side >actual && test_cmp expect actual && echo 5 >expect && - commit_subject my-side@{u} >actual + commit_subject my-side@{u} >actual && + test_cmp expect actual ' test_expect_success 'not-tracking@{u} fails' ' @@ -183,6 +185,11 @@ test_expect_success '@{u} error message when no upstream' ' test_cmp expect actual ' +test_expect_success '@{u} silent error when no upstream' ' + test_must_fail git rev-parse --verify --quiet @{u} 2>actual && + test_must_be_empty actual +' + test_expect_success 'branch@{u} error message with misspelt branch' ' cat >expect <<-EOF && fatal: no such branch: ${SQ}no-such-branch${SQ} @@ -258,7 +265,8 @@ test_expect_success '@{reflog}-parsing does not look beyond colon' ' git add @{yesterday} && git commit -m "funny reflog file" && git hash-object @{yesterday} >expect && - git rev-parse HEAD:@{yesterday} >actual + git rev-parse HEAD:@{yesterday} >actual && + test_cmp expect actual ' test_expect_success '@{upstream}-parsing does not look beyond colon' ' @@ -266,7 +274,8 @@ test_expect_success '@{upstream}-parsing does not look beyond colon' ' git add @{upstream} && git commit -m "funny upstream file" && git hash-object @{upstream} >expect && - git rev-parse HEAD:@{upstream} >actual + git rev-parse HEAD:@{upstream} >actual && + test_cmp expect actual ' test_done diff --git a/t/t1508-at-combinations.sh b/t/t1508-at-combinations.sh index 87a4286414..e841309d0e 100755 --- a/t/t1508-at-combinations.sh +++ b/t/t1508-at-combinations.sh @@ -4,6 +4,7 @@ test_description='test various @{X} syntax combinations together' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh check() { diff --git a/t/t1509-root-work-tree.sh b/t/t1509-root-work-tree.sh index 553a3f601b..c799f5b6ac 100755 --- a/t/t1509-root-work-tree.sh +++ b/t/t1509-root-work-tree.sh @@ -221,7 +221,8 @@ test_expect_success 'setup' ' rm -rf /.git && echo "Initialized empty Git repository in /.git/" > expected && git init > result && - test_cmp expected result + test_cmp expected result && + git config --global --add safe.directory / ' test_vars 'auto gitdir, root' ".git" "/" "" @@ -242,7 +243,7 @@ say "auto bare gitdir" # DESTROYYYYY!!!!! test_expect_success 'setup' ' rm -rf /refs /objects /info /hooks && - rm -f /expected /ls.expected /me /result && + rm -f /HEAD /expected /ls.expected /me /result && cd / && echo "Initialized empty Git repository in /" > expected && git init --bare > result && @@ -255,4 +256,9 @@ test_expect_success 'go to /foo' 'cd /foo' test_vars 'auto gitdir, root' "/" "" "" +test_expect_success 'cleanup root' ' + rm -rf /.git /refs /objects /info /hooks /branches /foo && + rm -f /HEAD /config /description /expected /ls.expected /me /result +' + test_done diff --git a/t/t1514-rev-parse-push.sh b/t/t1514-rev-parse-push.sh index d868a08110..a835a196aa 100755 --- a/t/t1514-rev-parse-push.sh +++ b/t/t1514-rev-parse-push.sh @@ -4,6 +4,7 @@ test_description='test <branch>@{push} syntax' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh resolve () { diff --git a/t/t1600-index.sh b/t/t1600-index.sh index 010989f90e..62e7fd1596 100755 --- a/t/t1600-index.sh +++ b/t/t1600-index.sh @@ -65,6 +65,37 @@ test_expect_success 'out of bounds index.version issues warning' ' ) ' +test_expect_success 'index.skipHash config option' ' + rm -f .git/index && + git -c index.skipHash=true add a && + test_trailing_hash .git/index >hash && + echo $(test_oid zero) >expect && + test_cmp expect hash && + git fsck && + + rm -f .git/index && + git -c feature.manyFiles=true add a && + test_trailing_hash .git/index >hash && + cmp expect hash && + + rm -f .git/index && + git -c feature.manyFiles=true \ + -c index.skipHash=false add a && + test_trailing_hash .git/index >hash && + ! cmp expect hash && + + test_commit start && + git -c protocol.file.allow=always submodule add ./ sub && + git config index.skipHash false && + git -C sub config index.skipHash true && + rm -f .git/modules/sub/index && + >sub/file && + git -C sub add a && + test_trailing_hash .git/modules/sub/index >hash && + test_cmp expect hash && + git -C sub fsck +' + test_index_version () { INDEX_VERSION_CONFIG=$1 && FEATURE_MANY_FILES=$2 && @@ -87,7 +118,7 @@ test_index_version () { fi && git add a && echo $EXPECTED_OUTPUT_VERSION >expect && - test-tool index-version <.git/index >actual && + git update-index --show-index-version >actual && test_cmp expect actual ) } diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh index b4ab166369..a7b7263b35 100755 --- a/t/t1700-split-index.sh +++ b/t/t1700-split-index.sh @@ -43,7 +43,7 @@ test_expect_success 'enable split index' ' git config splitIndex.maxPercentChange 100 && git update-index --split-index && test-tool dump-split-index .git/index >actual && - indexversion=$(test-tool index-version <.git/index) && + indexversion=$(git update-index --show-index-version) && # NEEDSWORK: Stop hard-coding checksums. if test "$indexversion" = "4" diff --git a/t/t1800-hook.sh b/t/t1800-hook.sh index 43fcb7c0bf..8b0234cf2d 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 && @@ -156,24 +156,32 @@ test_expect_success 'git hook run a hook with a bad shebang' ' mkdir bad-hooks && write_script bad-hooks/test-hook "/bad/path/no/spaces" </dev/null && - # TODO: We should emit the same (or at least a more similar) - # error on MINGW (essentially Git for Windows) and all other - # platforms.. See the OS-specific code in start_command() - if test_have_prereq !MINGW - then - cat >expect <<-\EOF - fatal: cannot run bad-hooks/test-hook: ... - EOF - else - cat >expect <<-\EOF - error: cannot spawn bad-hooks/test-hook: ... - EOF - fi && test_expect_code 1 git \ -c core.hooksPath=bad-hooks \ hook run test-hook >out 2>err && test_must_be_empty out && - sed -e "s/test-hook: .*/test-hook: .../" <err >actual && + + # TODO: We should emit the same (or at least a more similar) + # error on MINGW (essentially Git for Windows) and all other + # platforms.. See the OS-specific code in start_command() + grep -E "^(error|fatal): cannot (exec|spawn) .*bad-hooks/test-hook" err +' + +test_expect_success 'stdin to hooks' ' + write_script .git/hooks/test-hook <<-\EOF && + echo BEGIN stdin + cat + echo END stdin + EOF + + cat >expect <<-EOF && + BEGIN stdin + hello + END stdin + EOF + + echo hello >input && + git hook run --to-stdin=input test-hook 2>actual && test_cmp expect actual ' diff --git a/t/t2004-checkout-cache-temp.sh b/t/t2004-checkout-cache-temp.sh index b16d69ca4a..45dd1bc858 100755 --- a/t/t2004-checkout-cache-temp.sh +++ b/t/t2004-checkout-cache-temp.sh @@ -117,6 +117,26 @@ test_expect_success 'checkout all stages/one file to temporary files' ' test $(cat $s3) = tree3path1) ' +test_expect_success '--stage=all implies --temp' ' + rm -f path* .merge_* actual && + git checkout-index --stage=all -- path1 && + test_path_is_missing path1 +' + +test_expect_success 'overriding --stage=all resets implied --temp' ' + rm -f path* .merge_* actual && + git checkout-index --stage=all --stage=2 -- path1 && + echo tree2path1 >expect && + test_cmp expect path1 +' + +test_expect_success '--stage=all --no-temp is rejected' ' + rm -f path* .merge_* actual && + test_must_fail git checkout-index --stage=all --no-temp -- path1 2>err && + grep -v "already exists" err && + grep "options .--stage=all. and .--no-temp. cannot be used together" err +' + test_expect_success 'checkout some stages/one file to temporary files' ' rm -f path* .merge_* actual && git checkout-index --stage=all --temp -- path2 >actual && diff --git a/t/t2005-checkout-index-symlinks.sh b/t/t2005-checkout-index-symlinks.sh index 112682a45a..67d18cfa10 100755 --- a/t/t2005-checkout-index-symlinks.sh +++ b/t/t2005-checkout-index-symlinks.sh @@ -22,8 +22,10 @@ test_expect_success \ git checkout-index symlink && test -f symlink' -test_expect_success \ -'the file must be the blob we added during the setup' ' -test "$(git hash-object -t blob symlink)" = $l' +test_expect_success 'the file must be the blob we added during the setup' ' + echo "$l" >expect && + git hash-object -t blob symlink >actual && + test_cmp expect actual +' test_done diff --git a/t/t2012-checkout-last.sh b/t/t2012-checkout-last.sh index 1f6c4ed042..4b6372f4c3 100755 --- a/t/t2012-checkout-last.sh +++ b/t/t2012-checkout-last.sh @@ -5,6 +5,7 @@ test_description='checkout can switch to last branch and merge base' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t2015-checkout-unborn.sh b/t/t2015-checkout-unborn.sh index 9425aae639..fb0e13881c 100755 --- a/t/t2015-checkout-unborn.sh +++ b/t/t2015-checkout-unborn.sh @@ -9,11 +9,12 @@ TEST_PASSES_SANITIZE_LEAK=true test_expect_success 'setup' ' mkdir parent && - (cd parent && - git init && - echo content >file && - git add file && - git commit -m base + ( + cd parent && + git init && + echo content >file && + git add file && + git commit -m base ) && git fetch parent main:origin ' diff --git a/t/t2016-checkout-patch.sh b/t/t2016-checkout-patch.sh index a5822e41af..747eb5563e 100755 --- a/t/t2016-checkout-patch.sh +++ b/t/t2016-checkout-patch.sh @@ -4,12 +4,6 @@ test_description='git checkout --patch' . ./lib-patch-mode.sh -if ! test_have_prereq ADD_I_USE_BUILTIN && ! test_have_prereq PERL -then - skip_all='skipping interactive add tests, PERL not set' - test_done -fi - test_expect_success 'setup' ' mkdir dir && echo parent > dir/foo && diff --git a/t/t2018-checkout-branch.sh b/t/t2018-checkout-branch.sh index 771c3c3c50..8581ad3437 100755 --- a/t/t2018-checkout-branch.sh +++ b/t/t2018-checkout-branch.sh @@ -3,6 +3,7 @@ test_description='checkout' TEST_CREATE_REPO_NO_TEMPLATE=1 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Arguments: [!] <branch> <oid> [<checkout options>] diff --git a/t/t2019-checkout-ambiguous-ref.sh b/t/t2019-checkout-ambiguous-ref.sh index 2c8c926b4d..9540588664 100755 --- a/t/t2019-checkout-ambiguous-ref.sh +++ b/t/t2019-checkout-ambiguous-ref.sh @@ -16,7 +16,7 @@ test_expect_success 'setup ambiguous refs' ' ' test_expect_success 'checkout ambiguous ref succeeds' ' - git checkout ambiguity >stdout 2>stderr + git checkout ambiguity 2>stderr ' test_expect_success 'checkout produces ambiguity warning' ' @@ -37,7 +37,7 @@ test_expect_success 'checkout reports switch to branch' ' ' test_expect_success 'checkout vague ref succeeds' ' - git checkout vagueness >stdout 2>stderr && + git checkout vagueness 2>stderr && test_set_prereq VAGUENESS_SUCCESS ' diff --git a/t/t2021-checkout-overwrite.sh b/t/t2021-checkout-overwrite.sh index 713c3fa603..ecfacf0f7f 100755 --- a/t/t2021-checkout-overwrite.sh +++ b/t/t2021-checkout-overwrite.sh @@ -50,10 +50,13 @@ test_expect_success 'checkout commit with dir must not remove untracked a/b' ' test_expect_success SYMLINKS 'the symlink remained' ' - test_when_finished "rm a/b" && test -h a/b ' +test_expect_success 'cleanup after previous symlink tests' ' + rm a/b +' + test_expect_success SYMLINKS 'checkout -f must not follow symlinks when removing entries' ' git checkout -f start && mkdir dir && @@ -66,4 +69,15 @@ test_expect_success SYMLINKS 'checkout -f must not follow symlinks when removing test_path_is_file untracked/f ' +test_expect_success 'checkout --overwrite-ignore should succeed if only ignored files in the way' ' + git checkout -b df_conflict && + test_commit contents some_dir && + git checkout start && + mkdir some_dir && + echo autogenerated information >some_dir/ignore && + echo ignore >.git/info/exclude && + git checkout --overwrite-ignore df_conflict && + test_path_is_file some_dir +' + test_done diff --git a/t/t2024-checkout-dwim.sh b/t/t2024-checkout-dwim.sh index 4a1c901456..74049a9812 100755 --- a/t/t2024-checkout-dwim.sh +++ b/t/t2024-checkout-dwim.sh @@ -305,10 +305,13 @@ test_expect_success 'loosely defined local base branch is reported correctly' ' test_config branch.strict.merge refs/heads/main && test_config branch.loose.merge main && - git checkout strict | sed -e "s/strict/BRANCHNAME/g" >expect && + git checkout strict >expect.raw 2>&1 && + sed -e "s/strict/BRANCHNAME/g" <expect.raw >expect && status_uno_is_clean && - git checkout loose | sed -e "s/loose/BRANCHNAME/g" >actual && + git checkout loose >actual.raw 2>&1 && + sed -e "s/loose/BRANCHNAME/g" <actual.raw >actual && status_uno_is_clean && + grep BRANCHNAME actual && test_cmp expect actual ' diff --git a/t/t2025-checkout-no-overlay.sh b/t/t2025-checkout-no-overlay.sh index 8f13341cf8..3832c3de81 100755 --- a/t/t2025-checkout-no-overlay.sh +++ b/t/t2025-checkout-no-overlay.sh @@ -2,6 +2,7 @@ test_description='checkout --no-overlay <tree-ish> -- <pathspec>' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t2027-checkout-track.sh b/t/t2027-checkout-track.sh index dca35aa3e3..a8bbc60954 100755 --- a/t/t2027-checkout-track.sh +++ b/t/t2027-checkout-track.sh @@ -5,6 +5,7 @@ test_description='tests for git branch --track' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t2060-switch.sh b/t/t2060-switch.sh index 5a7caf958c..e247a4735b 100755 --- a/t/t2060-switch.sh +++ b/t/t2060-switch.sh @@ -146,4 +146,33 @@ test_expect_success 'tracking info copied with autoSetupMerge=inherit' ' test_cmp_config "" --default "" branch.main2.merge ' +test_expect_success 'switch back when temporarily detached and checked out elsewhere ' ' + test_when_finished " + git worktree remove wt1 ||: + git worktree remove wt2 ||: + git checkout - ||: + git branch -D shared ||: + " && + git checkout -b shared && + test_commit shared-first && + HASH1=$(git rev-parse --verify HEAD) && + test_commit shared-second && + test_commit shared-third && + HASH2=$(git rev-parse --verify HEAD) && + git worktree add wt1 -f shared && + git -C wt1 bisect start && + git -C wt1 bisect good $HASH1 && + git -C wt1 bisect bad $HASH2 && + git worktree add wt2 -f shared && + git -C wt2 bisect start && + git -C wt2 bisect good $HASH1 && + git -C wt2 bisect bad $HASH2 && + # we test in both worktrees to ensure that works + # as expected with "first" and "next" worktrees + test_must_fail git -C wt1 switch shared && + git -C wt1 switch --ignore-other-worktrees shared && + test_must_fail git -C wt2 switch shared && + git -C wt2 switch --ignore-other-worktrees shared +' + test_done diff --git a/t/t2070-restore.sh b/t/t2070-restore.sh index 7c43ddf1d9..c5d19dd973 100755 --- a/t/t2070-restore.sh +++ b/t/t2070-restore.sh @@ -137,4 +137,20 @@ test_expect_success 'restore --staged invalidates cache tree for deletions' ' test_must_fail git rev-parse HEAD:new1 ' +test_expect_success 'restore with merge options rejects --staged' ' + for opts in \ + "--staged --ours" \ + "--staged --theirs" \ + "--staged --merge" \ + "--staged --conflict=diff3" \ + "--staged --worktree --ours" \ + "--staged --worktree --theirs" \ + "--staged --worktree --merge" \ + "--staged --worktree --conflict=zdiff3" + do + test_must_fail git restore $opts . 2>err && + grep "cannot be used with --staged" err || return + done +' + test_done diff --git a/t/t2104-update-index-skip-worktree.sh b/t/t2104-update-index-skip-worktree.sh index b8686aabd3..0bab134d71 100755 --- a/t/t2104-update-index-skip-worktree.sh +++ b/t/t2104-update-index-skip-worktree.sh @@ -39,7 +39,7 @@ test_expect_success 'setup' ' ' test_expect_success 'index is at version 2' ' - test "$(test-tool index-version < .git/index)" = 2 + test "$(git update-index --show-index-version)" = 2 ' test_expect_success 'update-index --skip-worktree' ' @@ -48,7 +48,7 @@ test_expect_success 'update-index --skip-worktree' ' ' test_expect_success 'index is at version 3 after having some skip-worktree entries' ' - test "$(test-tool index-version < .git/index)" = 3 + test "$(git update-index --show-index-version)" = 3 ' test_expect_success 'ls-files -t' ' @@ -61,7 +61,7 @@ test_expect_success 'update-index --no-skip-worktree' ' ' test_expect_success 'index version is back to 2 when there is no skip-worktree entry' ' - test "$(test-tool index-version < .git/index)" = 2 + test "$(git update-index --show-index-version)" = 2 ' test_done diff --git a/t/t2107-update-index-basic.sh b/t/t2107-update-index-basic.sh index 07e6de84e6..22f4c92399 100755 --- a/t/t2107-update-index-basic.sh +++ b/t/t2107-update-index-basic.sh @@ -83,7 +83,7 @@ test_expect_success '.lock files cleaned up' ' cd repo && git config core.worktree ../../worktree && # --refresh triggers late setup_work_tree, - # active_cache_changed is zero, rollback_lock_file fails + # the_index.cache_changed is zero, rollback_lock_file fails git update-index --refresh --verbose >out && test_must_be_empty out && ! test -f .git/index.lock @@ -111,4 +111,35 @@ test_expect_success '--chmod=+x and chmod=-x in the same argument list' ' test_cmp expect actual ' +test_expect_success '--index-version' ' + git commit --allow-empty -m snap && + git reset --hard && + git rm -f -r --cached . && + + # The default index version is 2 --- update this test + # when you change it in the code + git update-index --show-index-version >actual && + echo 2 >expect && + test_cmp expect actual && + + # The next test wants us to be using version 2 + git update-index --index-version 2 && + + git update-index --index-version 4 --verbose >actual && + echo "index-version: was 2, set to 4" >expect && + test_cmp expect actual && + + git update-index --index-version 4 --verbose >actual && + echo "index-version: was 4, set to 4" >expect && + test_cmp expect actual && + + git update-index --index-version 2 --verbose >actual && + echo "index-version: was 4, set to 2" >expect && + test_cmp expect actual && + + # non-verbose should be silent + git update-index --index-version 4 >actual && + test_must_be_empty actual +' + test_done diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh index be394f1131..c01492f33f 100755 --- a/t/t2200-add-update.sh +++ b/t/t2200-add-update.sh @@ -197,4 +197,15 @@ test_expect_success '"add -u non-existent" should fail' ' ! grep "non-existent" actual ' +test_expect_success '"commit -a" implies "add -u" if index becomes empty' ' + git rm -rf \* && + git commit -m clean-slate && + test_commit file1 && + rm file1.t && + test_tick && + git commit -a -m remove && + git ls-tree HEAD: >out && + test_must_be_empty out +' + test_done diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh index d587e0b20d..df4aff7825 100755 --- a/t/t2400-worktree-add.sh +++ b/t/t2400-worktree-add.sh @@ -121,7 +121,8 @@ test_expect_success '"add" worktree creating new branch' ' test_expect_success 'die the same branch is already checked out' ' ( cd here && - test_must_fail git checkout newmain + test_must_fail git checkout newmain 2>actual && + grep "already used by worktree at" actual ) ' @@ -298,17 +299,24 @@ test_expect_success '"add" no auto-vivify with --detach and <branch> omitted' ' test_must_fail git -C mish/mash symbolic-ref HEAD ' -test_expect_success '"add" -b/-B mutually exclusive' ' - test_must_fail git worktree add -b poodle -B poodle bamboo main -' - -test_expect_success '"add" -b/--detach mutually exclusive' ' - test_must_fail git worktree add -b poodle --detach bamboo main -' +# Helper function to test mutually exclusive options. +# +# Note: Quoted arguments containing spaces are not supported. +test_wt_add_excl () { + local opts="$*" && + test_expect_success "'worktree add' with '$opts' has mutually exclusive options" ' + test_must_fail git worktree add $opts 2>actual && + grep -E "fatal:( options)? .* cannot be used together" actual + ' +} -test_expect_success '"add" -B/--detach mutually exclusive' ' - test_must_fail git worktree add -B poodle --detach bamboo main -' +test_wt_add_excl -b poodle -B poodle bamboo main +test_wt_add_excl -b poodle --detach bamboo main +test_wt_add_excl -B poodle --detach bamboo main +test_wt_add_excl --orphan --detach bamboo +test_wt_add_excl --orphan --no-checkout bamboo +test_wt_add_excl --orphan bamboo main +test_wt_add_excl --orphan -b bamboo wtdir/ main test_expect_success '"add -B" fails if the branch is checked out' ' git rev-parse newmain >before && @@ -326,10 +334,111 @@ test_expect_success 'add -B' ' ' test_expect_success 'add --quiet' ' + test_when_finished "git worktree remove -f -f another-worktree" && git worktree add --quiet another-worktree main 2>actual && test_must_be_empty actual ' +test_expect_success 'add --quiet -b' ' + test_when_finished "git branch -D quietnewbranch" && + test_when_finished "git worktree remove -f -f another-worktree" && + git worktree add --quiet -b quietnewbranch another-worktree 2>actual && + test_must_be_empty actual +' + +test_expect_success '"add --orphan"' ' + test_when_finished "git worktree remove -f -f orphandir" && + git worktree add --orphan -b neworphan orphandir && + echo refs/heads/neworphan >expected && + git -C orphandir symbolic-ref HEAD >actual && + test_cmp expected actual +' + +test_expect_success '"add --orphan (no -b)"' ' + test_when_finished "git worktree remove -f -f neworphan" && + git worktree add --orphan neworphan && + echo refs/heads/neworphan >expected && + git -C neworphan symbolic-ref HEAD >actual && + test_cmp expected actual +' + +test_expect_success '"add --orphan --quiet"' ' + test_when_finished "git worktree remove -f -f orphandir" && + git worktree add --quiet --orphan -b neworphan orphandir 2>log.actual && + test_must_be_empty log.actual && + echo refs/heads/neworphan >expected && + git -C orphandir symbolic-ref HEAD >actual && + test_cmp expected actual +' + +test_expect_success '"add --orphan" fails if the branch already exists' ' + test_when_finished "git branch -D existingbranch" && + git worktree add -b existingbranch orphandir main && + git worktree remove orphandir && + test_must_fail git worktree add --orphan -b existingbranch orphandir +' + +test_expect_success '"add --orphan" with empty repository' ' + test_when_finished "rm -rf empty_repo" && + echo refs/heads/newbranch >expected && + GIT_DIR="empty_repo" git init --bare && + git -C empty_repo worktree add --orphan -b newbranch worktreedir && + git -C empty_repo/worktreedir symbolic-ref HEAD >actual && + test_cmp expected actual +' + +test_expect_success '"add" worktree with orphan branch and lock' ' + git worktree add --lock --orphan -b orphanbr orphan-with-lock && + test_when_finished "git worktree unlock orphan-with-lock || :" && + test -f .git/worktrees/orphan-with-lock/locked +' + +test_expect_success '"add" worktree with orphan branch, lock, and reason' ' + lock_reason="why not" && + git worktree add --detach --lock --reason "$lock_reason" orphan-with-lock-reason main && + test_when_finished "git worktree unlock orphan-with-lock-reason || :" && + test -f .git/worktrees/orphan-with-lock-reason/locked && + echo "$lock_reason" >expect && + test_cmp expect .git/worktrees/orphan-with-lock-reason/locked +' + +# Note: Quoted arguments containing spaces are not supported. +test_wt_add_orphan_hint () { + local context="$1" && + local use_branch=$2 && + shift 2 && + local opts="$*" && + test_expect_success "'worktree add' show orphan hint in bad/orphan HEAD w/ $context" ' + test_when_finished "rm -rf repo" && + git init repo && + (cd repo && test_commit commit) && + git -C repo switch --orphan noref && + test_must_fail git -C repo worktree add $opts foobar/ 2>actual && + ! grep "error: unknown switch" actual && + grep "hint: If you meant to create a worktree containing a new orphan branch" actual && + if [ $use_branch -eq 1 ] + then + grep -E "^hint: +git worktree add --orphan -b [^ ]+ [^ ]+$" actual + else + grep -E "^hint: +git worktree add --orphan [^ ]+$" actual + fi + + ' +} + +test_wt_add_orphan_hint 'no opts' 0 +test_wt_add_orphan_hint '-b' 1 -b foobar_branch +test_wt_add_orphan_hint '-B' 1 -B foobar_branch + +test_expect_success "'worktree add' doesn't show orphan hint in bad/orphan HEAD w/ --quiet" ' + test_when_finished "rm -rf repo" && + git init repo && + (cd repo && test_commit commit) && + test_must_fail git -C repo worktree add --quiet foobar_branch foobar/ 2>actual && + ! grep "error: unknown switch" actual && + ! grep "hint: If you meant to create a worktree containing a new orphan branch" actual +' + test_expect_success 'local clone from linked checkout' ' git clone --local here here-clone && ( cd here-clone && git fsck ) @@ -446,6 +555,14 @@ setup_remote_repo () { ) } +test_expect_success '"add" <path> <remote/branch> w/ no HEAD' ' + test_when_finished rm -rf repo_upstream repo_local foo && + setup_remote_repo repo_upstream repo_local && + git -C repo_local config --bool core.bare true && + git -C repo_local branch -D main && + git -C repo_local worktree add ./foo repo_upstream/foo +' + test_expect_success '--no-track avoids setting up tracking' ' test_when_finished rm -rf repo_upstream repo_local foo && setup_remote_repo repo_upstream repo_local && @@ -528,6 +645,35 @@ test_expect_success 'git worktree add --guess-remote sets up tracking' ' test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo ) ' +test_expect_success 'git worktree add --guess-remote sets up tracking (quiet)' ' + test_when_finished rm -rf repo_a repo_b foo && + setup_remote_repo repo_a repo_b && + ( + cd repo_b && + git worktree add --quiet --guess-remote ../foo 2>actual && + test_must_be_empty actual + ) && + ( + cd foo && + test_branch_upstream foo repo_a foo && + test_cmp_rev refs/remotes/repo_a/foo refs/heads/foo + ) +' + +test_expect_success 'git worktree --no-guess-remote (quiet)' ' + test_when_finished rm -rf repo_a repo_b foo && + setup_remote_repo repo_a repo_b && + ( + cd repo_b && + git worktree add --quiet --no-guess-remote ../foo + ) && + ( + cd foo && + test_must_fail git config "branch.foo.remote" && + test_must_fail git config "branch.foo.merge" && + test_cmp_rev ! refs/remotes/repo_a/foo refs/heads/foo + ) +' test_expect_success 'git worktree add with worktree.guessRemote sets up tracking' ' test_when_finished rm -rf repo_a repo_b foo && @@ -560,6 +706,348 @@ test_expect_success 'git worktree --no-guess-remote option overrides config' ' ) ' +test_dwim_orphan () { + local info_text="No possible source branch, inferring '--orphan'" && + local fetch_error_text="fatal: No local or remote refs exist despite at least one remote" && + local orphan_hint="hint: If you meant to create a worktree containing a new orphan branch" && + local invalid_ref_regex="^fatal: invalid reference: " && + local bad_combo_regex="^fatal: '[-a-z]*' and '[-a-z]*' cannot be used together" && + + local git_ns="repo" && + local dashc_args="-C $git_ns" && + local use_cd=0 && + + local bad_head=0 && + local empty_repo=1 && + local local_ref=0 && + local use_quiet=0 && + local remote=0 && + local remote_ref=0 && + local use_detach=0 && + local use_new_branch=0 && + + local outcome="$1" && + local outcome_text && + local success && + shift && + local args="" && + local context="" && + case "$outcome" in + "infer") + success=1 && + outcome_text='"add" DWIM infer --orphan' + ;; + "no_infer") + success=1 && + outcome_text='"add" DWIM doesnt infer --orphan' + ;; + "fetch_error") + success=0 && + outcome_text='"add" error need fetch' + ;; + "fatal_orphan_bad_combo") + success=0 && + outcome_text='"add" error inferred "--orphan" gives illegal opts combo' + ;; + "warn_bad_head") + success=0 && + outcome_text='"add" error, warn on bad HEAD, hint use orphan' + ;; + *) + echo "test_dwim_orphan(): invalid outcome: '$outcome'" >&2 && + return 1 + ;; + esac && + while [ $# -gt 0 ] + do + case "$1" in + # How and from where to create the worktree + "-C_repo") + use_cd=0 && + git_ns="repo" && + dashc_args="-C $git_ns" && + context="$context, 'git -C repo'" + ;; + "-C_wt") + use_cd=0 && + git_ns="wt" && + dashc_args="-C $git_ns" && + context="$context, 'git -C wt'" + ;; + "cd_repo") + use_cd=1 && + git_ns="repo" && + dashc_args="" && + context="$context, 'cd repo && git'" + ;; + "cd_wt") + use_cd=1 && + git_ns="wt" && + dashc_args="" && + context="$context, 'cd wt && git'" + ;; + + # Bypass the "pull first" warning + "force") + args="$args --force" && + context="$context, --force" + ;; + + # Try to use remote refs when DWIM + "guess_remote") + args="$args --guess-remote" && + context="$context, --guess-remote" + ;; + "no_guess_remote") + args="$args --no-guess-remote" && + context="$context, --no-guess-remote" + ;; + + # Whether there is at least one local branch present + "local_ref") + empty_repo=0 && + local_ref=1 && + context="$context, >=1 local branches" + ;; + "no_local_ref") + empty_repo=0 && + context="$context, 0 local branches" + ;; + + # Whether the HEAD points at a valid ref (skip this opt when no refs) + "good_head") + # requires: local_ref + context="$context, valid HEAD" + ;; + "bad_head") + bad_head=1 && + context="$context, invalid (or orphan) HEAD" + ;; + + # Whether the code path is tested with the base add command, -b, or --detach + "no_-b") + use_new_branch=0 && + context="$context, no --branch" + ;; + "-b") + use_new_branch=1 && + context="$context, --branch" + ;; + "detach") + use_detach=1 && + context="$context, --detach" + ;; + + # Whether to check that all output is suppressed (except errors) + # or that the output is as expected + "quiet") + use_quiet=1 && + args="$args --quiet" && + context="$context, --quiet" + ;; + "no_quiet") + use_quiet=0 && + context="$context, no --quiet (expect output)" + ;; + + # Whether there is at least one remote attached to the repo + "remote") + empty_repo=0 && + remote=1 && + context="$context, >=1 remotes" + ;; + "no_remote") + empty_repo=0 && + remote=0 && + context="$context, 0 remotes" + ;; + + # Whether there is at least one valid remote ref + "remote_ref") + # requires: remote + empty_repo=0 && + remote_ref=1 && + context="$context, >=1 fetched remote branches" + ;; + "no_remote_ref") + empty_repo=0 && + remote_ref=0 && + context="$context, 0 fetched remote branches" + ;; + + # Options or flags that become illegal when --orphan is inferred + "no_checkout") + args="$args --no-checkout" && + context="$context, --no-checkout" + ;; + "track") + args="$args --track" && + context="$context, --track" + ;; + + # All other options are illegal + *) + echo "test_dwim_orphan(): invalid arg: '$1'" >&2 && + return 1 + ;; + esac && + shift + done && + context="${context#', '}" && + if [ $use_new_branch -eq 1 ] + then + args="$args -b foo" + elif [ $use_detach -eq 1 ] + then + args="$args --detach" + else + context="DWIM (no --branch), $context" + fi && + if [ $empty_repo -eq 1 ] + then + context="empty repo, $context" + fi && + args="$args ../foo" && + context="${context%', '}" && + test_expect_success "$outcome_text w/ $context" ' + test_when_finished "rm -rf repo" && + git init repo && + if [ $local_ref -eq 1 ] && [ "$git_ns" = "repo" ] + then + (cd repo && test_commit commit) && + if [ $bad_head -eq 1 ] + then + git -C repo symbolic-ref HEAD refs/heads/badbranch + fi + elif [ $local_ref -eq 1 ] && [ "$git_ns" = "wt" ] + then + test_when_finished "git -C repo worktree remove -f ../wt" && + git -C repo worktree add --orphan -b main ../wt && + (cd wt && test_commit commit) && + if [ $bad_head -eq 1 ] + then + git -C wt symbolic-ref HEAD refs/heads/badbranch + fi + elif [ $local_ref -eq 0 ] && [ "$git_ns" = "wt" ] + then + test_when_finished "git -C repo worktree remove -f ../wt" && + git -C repo worktree add --orphan -b orphanbranch ../wt + fi && + + if [ $remote -eq 1 ] + then + test_when_finished "rm -rf upstream" && + git init upstream && + (cd upstream && test_commit commit) && + git -C upstream switch -c foo && + git -C repo remote add upstream ../upstream + fi && + + if [ $remote_ref -eq 1 ] + then + git -C repo fetch + fi && + if [ $success -eq 1 ] + then + test_when_finished git -C repo worktree remove ../foo + fi && + ( + if [ $use_cd -eq 1 ] + then + cd $git_ns + fi && + if [ "$outcome" = "infer" ] + then + git $dashc_args worktree add $args 2>actual && + if [ $use_quiet -eq 1 ] + then + test_must_be_empty actual + else + grep "$info_text" actual + fi + elif [ "$outcome" = "no_infer" ] + then + git $dashc_args worktree add $args 2>actual && + if [ $use_quiet -eq 1 ] + then + test_must_be_empty actual + else + ! grep "$info_text" actual + fi + elif [ "$outcome" = "fetch_error" ] + then + test_must_fail git $dashc_args worktree add $args 2>actual && + grep "$fetch_error_text" actual + elif [ "$outcome" = "fatal_orphan_bad_combo" ] + then + test_must_fail git $dashc_args worktree add $args 2>actual && + if [ $use_quiet -eq 1 ] + then + ! grep "$info_text" actual + else + grep "$info_text" actual + fi && + grep "$bad_combo_regex" actual + elif [ "$outcome" = "warn_bad_head" ] + then + test_must_fail git $dashc_args worktree add $args 2>actual && + if [ $use_quiet -eq 1 ] + then + grep "$invalid_ref_regex" actual && + ! grep "$orphan_hint" actual + else + headpath=$(git $dashc_args rev-parse --path-format=absolute --git-path HEAD) && + headcontents=$(cat "$headpath") && + grep "HEAD points to an invalid (or orphaned) reference" actual && + grep "HEAD path: .$headpath." actual && + grep "HEAD contents: .$headcontents." actual && + grep "$orphan_hint" actual && + ! grep "$info_text" actual + fi && + grep "$invalid_ref_regex" actual + else + # Unreachable + false + fi + ) && + if [ $success -ne 1 ] + then + test_path_is_missing foo + fi + ' +} + +for quiet_mode in "no_quiet" "quiet" +do + for changedir_type in "cd_repo" "cd_wt" "-C_repo" "-C_wt" + do + dwim_test_args="$quiet_mode $changedir_type" + test_dwim_orphan 'infer' $dwim_test_args no_-b + test_dwim_orphan 'no_infer' $dwim_test_args no_-b local_ref good_head + test_dwim_orphan 'infer' $dwim_test_args no_-b no_local_ref no_remote no_remote_ref no_guess_remote + test_dwim_orphan 'infer' $dwim_test_args no_-b no_local_ref remote no_remote_ref no_guess_remote + test_dwim_orphan 'fetch_error' $dwim_test_args no_-b no_local_ref remote no_remote_ref guess_remote + test_dwim_orphan 'infer' $dwim_test_args no_-b no_local_ref remote no_remote_ref guess_remote force + test_dwim_orphan 'no_infer' $dwim_test_args no_-b no_local_ref remote remote_ref guess_remote + + test_dwim_orphan 'infer' $dwim_test_args -b + test_dwim_orphan 'no_infer' $dwim_test_args -b local_ref good_head + test_dwim_orphan 'infer' $dwim_test_args -b no_local_ref no_remote no_remote_ref no_guess_remote + test_dwim_orphan 'infer' $dwim_test_args -b no_local_ref remote no_remote_ref no_guess_remote + test_dwim_orphan 'infer' $dwim_test_args -b no_local_ref remote no_remote_ref guess_remote + test_dwim_orphan 'infer' $dwim_test_args -b no_local_ref remote remote_ref guess_remote + + test_dwim_orphan 'warn_bad_head' $dwim_test_args no_-b local_ref bad_head + test_dwim_orphan 'warn_bad_head' $dwim_test_args -b local_ref bad_head + test_dwim_orphan 'warn_bad_head' $dwim_test_args detach local_ref bad_head + done + + test_dwim_orphan 'fatal_orphan_bad_combo' $quiet_mode no_-b no_checkout + test_dwim_orphan 'fatal_orphan_bad_combo' $quiet_mode no_-b track + test_dwim_orphan 'fatal_orphan_bad_combo' $quiet_mode -b no_checkout + test_dwim_orphan 'fatal_orphan_bad_combo' $quiet_mode -b track +done + post_checkout_hook () { test_when_finished "rm -rf .git/hooks" && mkdir .git/hooks && diff --git a/t/t2401-worktree-prune.sh b/t/t2401-worktree-prune.sh index 3d28c7f06b..568a47ec42 100755 --- a/t/t2401-worktree-prune.sh +++ b/t/t2401-worktree-prune.sh @@ -5,6 +5,7 @@ test_description='prune $GIT_DIR/worktrees' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success initialize ' diff --git a/t/t2402-worktree-list.sh b/t/t2402-worktree-list.sh index 79e0fce2d9..9ad9be0c20 100755 --- a/t/t2402-worktree-list.sh +++ b/t/t2402-worktree-list.sh @@ -5,6 +5,7 @@ test_description='test git worktree list' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t2406-worktree-repair.sh b/t/t2406-worktree-repair.sh index 5c44453e1c..8970780efc 100755 --- a/t/t2406-worktree-repair.sh +++ b/t/t2406-worktree-repair.sh @@ -2,6 +2,7 @@ test_description='test git worktree repair' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t2407-worktree-heads.sh b/t/t2407-worktree-heads.sh index 019a40df2c..469443d8ae 100755 --- a/t/t2407-worktree-heads.sh +++ b/t/t2407-worktree-heads.sh @@ -58,7 +58,7 @@ test_expect_success !SANITIZE_LEAK 'refuse to overwrite: worktree in bisect' ' git -C wt-4 bisect good wt-1 && test_must_fail git branch -f wt-4 HEAD 2>err && - grep "cannot force update the branch '\''wt-4'\'' checked out at.*wt-4" err + grep "cannot force update the branch '\''wt-4'\'' used by worktree at.*wt-4" err ' test_expect_success !SANITIZE_LEAK 'refuse to overwrite: worktree in rebase (apply)' ' @@ -68,7 +68,7 @@ test_expect_success !SANITIZE_LEAK 'refuse to overwrite: worktree in rebase (app test_must_fail git -C wt-2 rebase --apply conflict-2 && test_must_fail git branch -f wt-2 HEAD 2>err && - grep "cannot force update the branch '\''wt-2'\'' checked out at.*wt-2" err + grep "cannot force update the branch '\''wt-2'\'' used by worktree at.*wt-2" err ' test_expect_success !SANITIZE_LEAK 'refuse to overwrite: worktree in rebase (merge)' ' @@ -78,7 +78,7 @@ test_expect_success !SANITIZE_LEAK 'refuse to overwrite: worktree in rebase (mer test_must_fail git -C wt-2 rebase conflict-2 && test_must_fail git branch -f wt-2 HEAD 2>err && - grep "cannot force update the branch '\''wt-2'\'' checked out at.*wt-2" err + grep "cannot force update the branch '\''wt-2'\'' used by worktree at.*wt-2" err ' test_expect_success !SANITIZE_LEAK 'refuse to overwrite: worktree in rebase with --update-refs' ' @@ -90,7 +90,7 @@ test_expect_success !SANITIZE_LEAK 'refuse to overwrite: worktree in rebase with for i in 3 4 do test_must_fail git branch -f can-be-updated HEAD 2>err && - grep "cannot force update the branch '\''can-be-updated'\'' checked out at.*wt-3" err || + grep "cannot force update the branch '\''can-be-updated'\'' used by worktree at.*wt-3" err || return 1 done ' @@ -150,7 +150,7 @@ test_expect_success 'refuse to overwrite when in error states' ' for i in 1 2 do test_must_fail git branch -f fake-$i HEAD 2>err && - grep "cannot force update the branch '\''fake-$i'\'' checked out at" err || + grep "cannot force update the branch '\''fake-$i'\'' used by worktree at" err || return 1 done ' diff --git a/t/t3007-ls-files-recurse-submodules.sh b/t/t3007-ls-files-recurse-submodules.sh index dd7770e85d..7308a3d4e2 100755 --- a/t/t3007-ls-files-recurse-submodules.sh +++ b/t/t3007-ls-files-recurse-submodules.sh @@ -299,6 +299,39 @@ test_expect_success '--recurse-submodules does not support --error-unmatch' ' test_i18ngrep "does not support --error-unmatch" actual ' +test_expect_success '--recurse-submodules parses submodule repo config' ' + test_config -C submodule index.sparse "invalid non-boolean value" && + test_must_fail git ls-files --recurse-submodules 2>err && + grep "bad boolean config value" err +' + +test_expect_success '--recurse-submodules parses submodule worktree config' ' + test_config -C submodule extensions.worktreeConfig true && + test_config -C submodule --worktree index.sparse "invalid non-boolean value" && + + test_must_fail git ls-files --recurse-submodules 2>err && + grep "bad boolean config value" err +' + +test_expect_success '--recurse-submodules submodules ignore super project worktreeConfig extension' ' + # Enable worktree config in both super project & submodule, set an + # invalid config in the submodule worktree config + test_config extensions.worktreeConfig true && + test_config -C submodule extensions.worktreeConfig true && + test_config -C submodule --worktree index.sparse "invalid non-boolean value" && + + # Now, disable the worktree config in the submodule. Note that we need + # to manually re-enable extensions.worktreeConfig when the test is + # finished, otherwise the test_unconfig of index.sparse will not work. + test_unconfig -C submodule extensions.worktreeConfig && + test_when_finished "git -C submodule config extensions.worktreeConfig true" && + + # With extensions.worktreeConfig disabled in the submodule, the invalid + # worktree config is not picked up. + git ls-files --recurse-submodules 2>err && + ! grep "bad boolean config value" err +' + test_incompatible_with_recurse_submodules () { test_expect_success "--recurse-submodules and $1 are incompatible" " test_must_fail git ls-files --recurse-submodules $1 2>actual && diff --git a/t/t3009-ls-files-others-nonsubmodule.sh b/t/t3009-ls-files-others-nonsubmodule.sh index 963f3462b7..14218b3424 100755 --- a/t/t3009-ls-files-others-nonsubmodule.sh +++ b/t/t3009-ls-files-others-nonsubmodule.sh @@ -18,6 +18,7 @@ This test runs git ls-files --others with the following working tree: git repository with a commit and an untracked file ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup: directories' ' diff --git a/t/t3010-ls-files-killed-modified.sh b/t/t3010-ls-files-killed-modified.sh index 580e158f99..054178703d 100755 --- a/t/t3010-ls-files-killed-modified.sh +++ b/t/t3010-ls-files-killed-modified.sh @@ -41,6 +41,8 @@ Also for modification test, the cache and working tree have: We should report path0, path1, path2/file2, path3/file3, path7 and path8 modified without reporting path9 and path10. submod1 is also modified. ' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'git update-index --add to add various paths.' ' diff --git a/t/t3013-ls-files-format.sh b/t/t3013-ls-files-format.sh index efb7450bf1..6e6ea0b6f3 100755 --- a/t/t3013-ls-files-format.sh +++ b/t/t3013-ls-files-format.sh @@ -38,6 +38,41 @@ test_expect_success 'git ls-files --format objectname v.s. -s' ' test_cmp expect actual ' +test_expect_success 'git ls-files --format objecttype' ' + git ls-files --format="%(objectname)" o1.txt o4.txt o6.txt >objectname && + git cat-file --batch-check="%(objecttype)" >expect <objectname && + git ls-files --format="%(objecttype)" o1.txt o4.txt o6.txt >actual && + test_cmp expect actual +' + +test_expect_success 'git ls-files --format objectsize' ' + cat>expect <<-\EOF && +26 +29 +27 +26 +- +26 + EOF + git ls-files --format="%(objectsize)" >actual && + + test_cmp expect actual +' + +test_expect_success 'git ls-files --format objectsize:padded' ' + cat>expect <<-\EOF && + 26 + 29 + 27 + 26 + - + 26 + EOF + git ls-files --format="%(objectsize:padded)" >actual && + + test_cmp expect actual +' + test_expect_success 'git ls-files --format v.s. --eol' ' git ls-files --eol >tmp && sed -e "s/ / /g" -e "s/ */ /g" tmp >expect 2>err && @@ -54,6 +89,22 @@ test_expect_success 'git ls-files --format path v.s. -s' ' test_cmp expect actual ' +test_expect_success 'git ls-files --format with relative path' ' + cat >expect <<-\EOF && + ../o1.txt + ../o2.txt + ../o3.txt + ../o4.txt + ../o5.txt + ../o6.txt + EOF + mkdir sub && + cd sub && + git ls-files --format="%(path)" ":/" >../actual && + cd .. && + test_cmp expect actual +' + test_expect_success 'git ls-files --format with -m' ' echo change >o1.txt && cat >expect <<-\EOF && diff --git a/t/t3050-subprojects-fetch.sh b/t/t3050-subprojects-fetch.sh index f1f09abdd9..3884694165 100755 --- a/t/t3050-subprojects-fetch.sh +++ b/t/t3050-subprojects-fetch.sh @@ -2,6 +2,7 @@ test_description='fetching and pushing project with subproject' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t3060-ls-files-with-tree.sh b/t/t3060-ls-files-with-tree.sh index 52f76f7b57..5a06732ca7 100755 --- a/t/t3060-ls-files-with-tree.sh +++ b/t/t3060-ls-files-with-tree.sh @@ -8,6 +8,8 @@ test_description='git ls-files test (--with-tree). This test runs git ls-files --with-tree and in particular in a scenario known to trigger a crash with some versions of git. ' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' @@ -38,7 +40,7 @@ test_expect_success 'setup' ' git commit -a -m "remove them all" && # The bug also requires some entry before our directory so that - # prune_path will modify the_index.cache + # prune_index will modify the_repository->index.cache mkdir a_directory_that_sorts_before_sub && >a_directory_that_sorts_before_sub/file && @@ -54,7 +56,7 @@ test_expect_success 'usage' ' ' test_expect_success 'git ls-files --with-tree should succeed from subdir' ' - # We have to run from a sub-directory to trigger prune_path + # We have to run from a sub-directory to trigger prune_index # Then we finally get to run our --with-tree test ( cd sub && diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh index 5d871fde96..4dd42df38c 100755 --- a/t/t3070-wildmatch.sh +++ b/t/t3070-wildmatch.sh @@ -431,4 +431,15 @@ match 1 1 1 1 'a' '[B-a]' match 0 1 0 1 'z' '[Z-y]' match 1 1 1 1 'Z' '[Z-y]' +test_expect_success 'matching does not exhibit exponential behavior' ' + { + test-tool wildmatch wildmatch \ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab \ + "*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a" & + pid=$! + } && + sleep 2 && + ! kill $! +' + test_done diff --git a/t/t3101-ls-tree-dirname.sh b/t/t3101-ls-tree-dirname.sh index 217006d1bf..5af2dac0e4 100755 --- a/t/t3101-ls-tree-dirname.sh +++ b/t/t3101-ls-tree-dirname.sh @@ -154,6 +154,14 @@ EOF test_output ' +test_expect_success 'ls-tree --no-full-name' ' + git -C path0 ls-tree --no-full-name $tree a >current && + cat >expected <<-EOF && + 040000 tree X a + EOF + test_output +' + test_expect_success 'ls-tree --full-tree' ' ( cd path1/b/c && diff --git a/t/t3104-ls-tree-format.sh b/t/t3104-ls-tree-format.sh index 383896667b..3adb206a93 100755 --- a/t/t3104-ls-tree-format.sh +++ b/t/t3104-ls-tree-format.sh @@ -20,7 +20,6 @@ test_ls_tree_format () { format=$1 && opts=$2 && fmtopts=$3 && - shift 2 && test_expect_success "ls-tree '--format=<$format>' is like options '$opts $fmtopts'" ' git ls-tree $opts -r HEAD >expect && @@ -36,6 +35,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 c7ec1c7520..080e4f24a6 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -8,6 +8,7 @@ test_description='git branch assorted tests' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh @@ -201,8 +202,8 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou test_expect_success 'git branch -M baz bam should add entries to .git/logs/HEAD' ' msg="Branch: renamed refs/heads/baz to refs/heads/bam" && - grep " 0\{40\}.*$msg$" .git/logs/HEAD && - grep "^0\{40\}.*$msg$" .git/logs/HEAD + grep " $ZERO_OID.*$msg$" .git/logs/HEAD && + grep "^$ZERO_OID.*$msg$" .git/logs/HEAD ' test_expect_success 'git branch -M should leave orphaned HEAD alone' ' @@ -239,15 +240,34 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou git worktree prune ' +test_expect_success 'git branch -M fails if updating any linked working tree fails' ' + git worktree add -b baz bazdir1 && + git worktree add -f bazdir2 baz && + touch .git/worktrees/bazdir1/HEAD.lock && + test_must_fail git branch -M baz bam && + test $(git -C bazdir2 rev-parse --abbrev-ref HEAD) = bam && + git branch -M bam baz && + rm .git/worktrees/bazdir1/HEAD.lock && + touch .git/worktrees/bazdir2/HEAD.lock && + test_must_fail git branch -M baz bam && + test $(git -C bazdir1 rev-parse --abbrev-ref HEAD) = bam && + rm -rf bazdir1 bazdir2 && + git worktree prune +' + test_expect_success 'git branch -M baz bam should succeed within a worktree in which baz is checked out' ' git checkout -b baz && git worktree add -f bazdir baz && ( cd bazdir && git branch -M baz bam && - test $(git rev-parse --abbrev-ref HEAD) = bam + echo bam >expect && + git rev-parse --abbrev-ref HEAD >actual && + test_cmp expect actual ) && - test $(git rev-parse --abbrev-ref HEAD) = bam && + echo bam >expect && + git rev-parse --abbrev-ref HEAD >actual && + test_cmp expect actual && rm -r bazdir && git worktree prune ' @@ -268,6 +288,67 @@ test_expect_success 'git branch -M topic topic should work when main is checked git branch -M topic topic ' +test_expect_success 'git branch -M and -C fail on detached HEAD' ' + git checkout HEAD^{} && + test_when_finished git checkout - && + echo "fatal: cannot rename the current branch while not on any." >expect && + test_must_fail git branch -M must-fail 2>err && + test_cmp expect err && + echo "fatal: cannot copy the current branch while not on any." >expect && + test_must_fail git branch -C must-fail 2>err && + test_cmp expect err +' + +test_expect_success 'git branch -m should work with orphan branches' ' + test_when_finished git checkout - && + test_when_finished git worktree remove -f wt && + git worktree add wt --detach && + # rename orphan in another worktreee + git -C wt checkout --orphan orphan-foo-wt && + git branch -m orphan-foo-wt orphan-bar-wt && + test orphan-bar-wt=$(git -C orphan-worktree branch --show-current) && + # rename orphan in the current worktree + git checkout --orphan orphan-foo && + git branch -m orphan-foo orphan-bar && + test orphan-bar=$(git branch --show-current) +' + +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 && @@ -861,7 +942,19 @@ test_expect_success 'test deleting branch without config' ' test_expect_success 'deleting currently checked out branch fails' ' git worktree add -b my7 my7 && test_must_fail git -C my7 branch -d my7 && - test_must_fail git branch -d my7 && + test_must_fail git branch -d my7 2>actual && + grep "^error: Cannot delete branch .my7. used by worktree at " actual && + rm -r my7 && + git worktree prune +' + +test_expect_success 'deleting in-use branch fails' ' + git worktree add my7 && + test_commit -C my7 bt7 && + git -C my7 bisect start HEAD HEAD~2 && + test_must_fail git -C my7 branch -d my7 && + test_must_fail git branch -d my7 2>actual && + grep "^error: Cannot delete branch .my7. used by worktree at " actual && rm -r my7 && git worktree prune ' @@ -1383,7 +1476,7 @@ test_expect_success 'branch --delete --force removes dangling branch' ' test_expect_success 'use --edit-description' ' EDITOR=: git branch --edit-description && - test_must_fail git config branch.main.description && + test_expect_code 1 git config branch.main.description && write_script editor <<-\EOF && echo "New contents" >"$1" diff --git a/t/t3202-show-branch.sh b/t/t3202-show-branch.sh index ea7cfd1951..b17f388f56 100755 --- a/t/t3202-show-branch.sh +++ b/t/t3202-show-branch.sh @@ -119,6 +119,22 @@ test_expect_success 'show branch --remotes' ' test_must_be_empty actual.out ' +test_expect_success 'show-branch --sparse' ' + test_when_finished "git checkout branch10 && git branch -D branchA" && + git checkout -b branchA branch10 && + git merge -s ours -m "merge 1 and 10 to make A" branch1 && + git commit --allow-empty -m "another" && + + git show-branch --sparse >out && + grep "merge 1 and 10 to make A" out && + + git show-branch >out && + ! grep "merge 1 and 10 to make A" out && + + git show-branch --no-sparse >out && + ! grep "merge 1 and 10 to make A" out +' + test_expect_success 'setup show branch --list' ' sed "s/^> //" >expect <<-\EOF > [branch1] branch1 @@ -197,6 +213,15 @@ done <<\EOF --reflog --current EOF +# unnegatable options +for opt in topo-order date-order reflog +do + test_expect_success "show-branch --no-$opt (should fail)" ' + test_must_fail git show-branch --no-$opt 2>err && + grep "unknown option .no-$opt." err + ' +done + test_expect_success 'error descriptions on non-existent branch' ' cat >expect <<-EOF && error: No branch named '\''non-existent'\'.' @@ -221,4 +246,22 @@ test_expect_success 'fatal descriptions on non-existent branch' ' test_cmp expect actual ' +test_expect_success 'error descriptions on orphan branch' ' + test_when_finished git worktree remove -f wt && + git worktree add wt --detach && + git -C wt checkout --orphan orphan-branch && + test_branch_op_in_wt() { + test_orphan_error() { + test_must_fail git $* 2>actual && + test_i18ngrep "No commit on branch .orphan-branch. yet.$" actual + } && + test_orphan_error -C wt branch $1 $2 && # implicit branch + test_orphan_error -C wt branch $1 orphan-branch $2 && # explicit branch + test_orphan_error branch $1 orphan-branch $2 # different worktree + } && + test_branch_op_in_wt --edit-description && + test_branch_op_in_wt --set-upstream-to=ne && + test_branch_op_in_wt -c new-branch +' + test_done diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh index d34d77f893..758963b189 100755 --- a/t/t3203-branch-output.sh +++ b/t/t3203-branch-output.sh @@ -55,9 +55,17 @@ cat >expect <<'EOF' EOF test_expect_success 'git branch -r shows remote branches' ' git branch -r >actual && + test_cmp expect actual && + + git branch --remotes >actual && test_cmp expect actual ' +test_expect_success 'git branch --no-remotes is rejected' ' + test_must_fail git branch --no-remotes 2>err && + grep "unknown option .no-remotes." err +' + cat >expect <<'EOF' branch-one branch-two @@ -68,9 +76,17 @@ cat >expect <<'EOF' EOF test_expect_success 'git branch -a shows local and remote branches' ' git branch -a >actual && + test_cmp expect actual && + + git branch --all >actual && test_cmp expect actual ' +test_expect_success 'git branch --no-all is rejected' ' + test_must_fail git branch --no-all 2>err && + grep "unknown option .no-all." err +' + cat >expect <<'EOF' two one @@ -337,10 +353,48 @@ test_expect_success 'git branch --format option' ' test_cmp expect actual ' +test_expect_success 'git branch --format with ahead-behind' ' + cat >expect <<-\EOF && + (HEAD detached from fromtag) 0 0 + refs/heads/ambiguous 0 0 + refs/heads/branch-one 1 0 + refs/heads/branch-two 0 0 + refs/heads/main 1 0 + refs/heads/ref-to-branch 1 0 + refs/heads/ref-to-remote 1 0 + EOF + git branch --format="%(refname) %(ahead-behind:HEAD)" >actual && + test_cmp expect actual +' + test_expect_success 'git branch with --format=%(rest) must fail' ' test_must_fail git branch --format="%(rest)" >actual ' +test_expect_success 'git branch --format --omit-empty' ' + cat >expect <<-\EOF && + Refname is (HEAD detached from fromtag) + Refname is refs/heads/ambiguous + Refname is refs/heads/branch-one + Refname is refs/heads/branch-two + + Refname is refs/heads/ref-to-branch + Refname is refs/heads/ref-to-remote + EOF + git branch --format="%(if:notequals=refs/heads/main)%(refname)%(then)Refname is %(refname)%(end)" >actual && + test_cmp expect actual && + cat >expect <<-\EOF && + Refname is (HEAD detached from fromtag) + Refname is refs/heads/ambiguous + Refname is refs/heads/branch-one + Refname is refs/heads/branch-two + Refname is refs/heads/ref-to-branch + Refname is refs/heads/ref-to-remote + EOF + git branch --omit-empty --format="%(if:notequals=refs/heads/main)%(refname)%(then)Refname is %(refname)%(end)" >actual && + test_cmp expect actual +' + test_expect_success 'worktree colors correct' ' cat >expect <<-EOF && * <GREEN>(HEAD detached from fromtag)<RESET> diff --git a/t/t3204-branch-name-interpretation.sh b/t/t3204-branch-name-interpretation.sh index 993a6b5eff..594e3e43e1 100755 --- a/t/t3204-branch-name-interpretation.sh +++ b/t/t3204-branch-name-interpretation.sh @@ -9,6 +9,7 @@ This script aims to check the behavior of those corner cases. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh expect_branch() { @@ -57,6 +58,16 @@ test_expect_success 'create branch with pseudo-qualified name' ' expect_branch refs/heads/refs/heads/qualified two ' +test_expect_success 'force-copy a branch to itself via @{-1} is no-op' ' + git branch -t copiable main && + git checkout copiable && + git checkout - && + git branch -C @{-1} copiable && + git config --get-all branch.copiable.merge >actual && + echo refs/heads/main >expect && + test_cmp expect actual +' + test_expect_success 'delete branch via @{-1}' ' git branch previous-del && @@ -133,4 +144,28 @@ test_expect_success 'checkout does not treat remote @{upstream} as a branch' ' expect_branch HEAD one ' +test_expect_success 'edit-description via @{-1}' ' + git checkout -b desc-branch && + git checkout -b non-desc-branch && + write_script editor <<-\EOF && + echo "Branch description" >"$1" + EOF + EDITOR=./editor git branch --edit-description @{-1} && + test_must_fail git config branch.non-desc-branch.description && + git config branch.desc-branch.description >actual && + printf "Branch description\n\n" >expect && + test_cmp expect actual +' + +test_expect_success 'modify branch upstream via "@{-1}" and "@{-1}@{upstream}"' ' + git checkout -b upstream-branch && + git checkout -b upstream-other -t upstream-branch && + git branch --set-upstream-to upstream-other @{-1} && + git config branch.upstream-branch.merge >actual && + echo "refs/heads/upstream-other" >expect && + test_cmp expect actual && + git branch --unset-upstream @{-1}@{upstream} && + test_must_fail git config branch.upstream-other.merge +' + test_done diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh index 84dd0cd26d..b5f4d6a653 100755 --- a/t/t3206-range-diff.sh +++ b/t/t3206-range-diff.sh @@ -33,6 +33,26 @@ test_expect_success 'setup' ' u3 sha256:736c4bc u4 sha256:673e77d + # topic (abbrev=10) + t1_abbrev sha1:4de457d2c0 + t2_abbrev sha1:fccce22f8c + t3_abbrev sha1:147e64ef53 + t4_abbrev sha1:a63e992599 + t1_abbrev sha256:b89f8b9092 + t2_abbrev sha256:5f12aadf34 + t3_abbrev sha256:ea8b273a6c + t4_abbrev sha256:14b73361fc + + # unmodified (abbrev=10) + u1_abbrev sha1:35b9b25f76 + u2_abbrev sha1:de345ab3de + u3_abbrev sha1:9af6654000 + u4_abbrev sha1:2901f773f3 + u1_abbrev sha256:e3731be242 + u2_abbrev sha256:14fadf8cee + u3_abbrev sha256:736c4bcb44 + u4_abbrev sha256:673e77d589 + # reordered r1 sha1:aca177a r2 sha1:14ad629 @@ -153,6 +173,18 @@ test_expect_success 'simple A B C (unmodified)' ' test_cmp expect actual ' +test_expect_success 'simple A..B A..C (unmodified) with --abbrev' ' + git range-diff --no-color --abbrev=10 main..topic main..unmodified \ + >actual && + cat >expect <<-EOF && + 1: $(test_oid t1_abbrev) = 1: $(test_oid u1_abbrev) s/5/A/ + 2: $(test_oid t2_abbrev) = 2: $(test_oid u2_abbrev) s/4/A/ + 3: $(test_oid t3_abbrev) = 3: $(test_oid u3_abbrev) s/11/B/ + 4: $(test_oid t4_abbrev) = 4: $(test_oid u4_abbrev) s/12/B/ + EOF + test_cmp expect actual +' + test_expect_success 'A^! and A^-<n> (unmodified)' ' git range-diff --no-color topic^! unmodified^-1 >actual && cat >expect <<-EOF && diff --git a/t/t3210-pack-refs.sh b/t/t3210-pack-refs.sh index 577f32dc71..7326adb70f 100755 --- a/t/t3210-pack-refs.sh +++ b/t/t3210-pack-refs.sh @@ -12,107 +12,145 @@ semantic is still the same. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'enable reflogs' ' git config core.logallrefupdates true ' -test_expect_success \ - 'prepare a trivial repository' \ - 'echo Hello > A && - git update-index --add A && - git commit -m "Initial commit." && - HEAD=$(git rev-parse --verify HEAD)' +test_expect_success 'prepare a trivial repository' ' + echo Hello > A && + git update-index --add A && + git commit -m "Initial commit." && + HEAD=$(git rev-parse --verify HEAD) +' SHA1= -test_expect_success \ - 'see if git show-ref works as expected' \ - 'git branch a && - SHA1=$(cat .git/refs/heads/a) && - echo "$SHA1 refs/heads/a" >expect && - git show-ref a >result && - test_cmp expect result' - -test_expect_success \ - 'see if a branch still exists when packed' \ - 'git branch b && - git pack-refs --all && - rm -f .git/refs/heads/b && - echo "$SHA1 refs/heads/b" >expect && - git show-ref b >result && - test_cmp expect result' +test_expect_success 'see if git show-ref works as expected' ' + git branch a && + SHA1=$(cat .git/refs/heads/a) && + echo "$SHA1 refs/heads/a" >expect && + git show-ref a >result && + test_cmp expect result +' + +test_expect_success 'see if a branch still exists when packed' ' + git branch b && + git pack-refs --all && + rm -f .git/refs/heads/b && + echo "$SHA1 refs/heads/b" >expect && + git show-ref b >result && + test_cmp expect result +' test_expect_success 'git branch c/d should barf if branch c exists' ' - git branch c && - git pack-refs --all && - rm -f .git/refs/heads/c && - test_must_fail git branch c/d + git branch c && + git pack-refs --all && + rm -f .git/refs/heads/c && + test_must_fail git branch c/d ' -test_expect_success \ - 'see if a branch still exists after git pack-refs --prune' \ - 'git branch e && - git pack-refs --all --prune && - echo "$SHA1 refs/heads/e" >expect && - git show-ref e >result && - test_cmp expect result' +test_expect_success 'see if a branch still exists after git pack-refs --prune' ' + git branch e && + git pack-refs --all --prune && + echo "$SHA1 refs/heads/e" >expect && + git show-ref e >result && + test_cmp expect result +' test_expect_success 'see if git pack-refs --prune remove ref files' ' - git branch f && - git pack-refs --all --prune && - ! test -f .git/refs/heads/f + git branch f && + git pack-refs --all --prune && + ! test -f .git/refs/heads/f ' test_expect_success 'see if git pack-refs --prune removes empty dirs' ' - git branch r/s/t && - git pack-refs --all --prune && - ! test -e .git/refs/heads/r + git branch r/s/t && + git pack-refs --all --prune && + ! test -e .git/refs/heads/r ' -test_expect_success \ - 'git branch g should work when git branch g/h has been deleted' \ - 'git branch g/h && - git pack-refs --all --prune && - git branch -d g/h && - git branch g && - git pack-refs --all && - git branch -d g' +test_expect_success 'git branch g should work when git branch g/h has been deleted' ' + git branch g/h && + git pack-refs --all --prune && + git branch -d g/h && + git branch g && + git pack-refs --all && + git branch -d g +' test_expect_success 'git branch i/j/k should barf if branch i exists' ' - git branch i && - git pack-refs --all --prune && - test_must_fail git branch i/j/k + git branch i && + git pack-refs --all --prune && + test_must_fail git branch i/j/k +' + +test_expect_success 'test git branch k after branch k/l/m and k/lm have been deleted' ' + git branch k/l && + git branch k/lm && + git branch -d k/l && + git branch k/l/m && + git branch -d k/l/m && + git branch -d k/lm && + git branch k ' -test_expect_success \ - 'test git branch k after branch k/l/m and k/lm have been deleted' \ - 'git branch k/l && - git branch k/lm && - git branch -d k/l && - git branch k/l/m && - git branch -d k/l/m && - git branch -d k/lm && - git branch k' - -test_expect_success \ - 'test git branch n after some branch deletion and pruning' \ - 'git branch n/o && - git branch n/op && - git branch -d n/o && - git branch n/o/p && - git branch -d n/op && - git pack-refs --all --prune && - git branch -d n/o/p && - git branch n' - -test_expect_success \ - 'see if up-to-date packed refs are preserved' \ - 'git branch q && - git pack-refs --all --prune && - git update-ref refs/heads/q refs/heads/q && - ! test -f .git/refs/heads/q' +test_expect_success 'test git branch n after some branch deletion and pruning' ' + git branch n/o && + git branch n/op && + git branch -d n/o && + git branch n/o/p && + git branch -d n/op && + git pack-refs --all --prune && + git branch -d n/o/p && + git branch n +' + +test_expect_success 'test excluded refs are not packed' ' + git branch dont_pack1 && + git branch dont_pack2 && + git branch pack_this && + git pack-refs --all --exclude "refs/heads/dont_pack*" && + test -f .git/refs/heads/dont_pack1 && + test -f .git/refs/heads/dont_pack2 && + ! test -f .git/refs/heads/pack_this' + +test_expect_success 'test --no-exclude refs clears excluded refs' ' + git branch dont_pack3 && + git branch dont_pack4 && + git pack-refs --all --exclude "refs/heads/dont_pack*" --no-exclude && + ! test -f .git/refs/heads/dont_pack3 && + ! test -f .git/refs/heads/dont_pack4' + +test_expect_success 'test only included refs are packed' ' + git branch pack_this1 && + git branch pack_this2 && + git tag dont_pack5 && + git pack-refs --include "refs/heads/pack_this*" && + test -f .git/refs/tags/dont_pack5 && + ! test -f .git/refs/heads/pack_this1 && + ! test -f .git/refs/heads/pack_this2' + +test_expect_success 'test --no-include refs clears included refs' ' + git branch pack1 && + git branch pack2 && + git pack-refs --include "refs/heads/pack*" --no-include && + test -f .git/refs/heads/pack1 && + test -f .git/refs/heads/pack2' + +test_expect_success 'test --exclude takes precedence over --include' ' + git branch dont_pack5 && + git pack-refs --include "refs/heads/pack*" --exclude "refs/heads/pack*" && + test -f .git/refs/heads/dont_pack5' + +test_expect_success 'see if up-to-date packed refs are preserved' ' + git branch q && + git pack-refs --all --prune && + git update-ref refs/heads/q refs/heads/q && + ! test -f .git/refs/heads/q +' test_expect_success 'pack, prune and repack' ' git tag foo && diff --git a/t/t3301-notes.sh b/t/t3301-notes.sh index 3288aaec7d..d734000d2f 100755 --- a/t/t3301-notes.sh +++ b/t/t3301-notes.sh @@ -362,6 +362,7 @@ test_expect_success 'do not create empty note with -m ""' ' ' test_expect_success 'create note with combination of -m and -F' ' + test_when_finished git notes remove HEAD && cat >expect-combine_m_and_F <<-EOF && foo @@ -380,6 +381,41 @@ test_expect_success 'create note with combination of -m and -F' ' test_cmp expect-combine_m_and_F actual ' +test_expect_success 'create note with combination of -m and -F and --separator' ' + test_when_finished git notes remove HEAD && + cat >expect-combine_m_and_F <<-\EOF && + foo + ------- + xyzzy + ------- + bar + ------- + zyxxy + ------- + baz + EOF + echo "xyzzy" >note_a && + echo "zyxxy" >note_b && + git notes add -m "foo" -F note_a -m "bar" -F note_b -m "baz" --separator="-------" && + git notes show >actual && + test_cmp expect-combine_m_and_F actual +' + +test_expect_success 'create note with combination of -m and -F and --no-separator' ' + cat >expect-combine_m_and_F <<-\EOF && + foo + xyzzy + bar + zyxxy + baz + EOF + echo "xyzzy" >note_a && + echo "zyxxy" >note_b && + git notes add -m "foo" -F note_a -m "bar" -F note_b -m "baz" --no-separator && + git notes show >actual && + test_cmp expect-combine_m_and_F actual +' + test_expect_success 'remove note with "git notes remove"' ' git notes remove HEAD^ && git notes remove && @@ -521,6 +557,112 @@ test_expect_success 'listing non-existing notes fails' ' test_must_be_empty actual ' +test_expect_success 'append: specify a separator with an empty arg' ' + test_when_finished git notes remove HEAD && + cat >expect <<-\EOF && + notes-1 + + notes-2 + EOF + + git notes add -m "notes-1" && + git notes append --separator="" -m "notes-2" && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'append: specify a separator without arg' ' + test_when_finished git notes remove HEAD && + cat >expect <<-\EOF && + notes-1 + + notes-2 + EOF + + git notes add -m "notes-1" && + git notes append --separator -m "notes-2" && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'append: specify as --no-separator' ' + test_when_finished git notes remove HEAD && + cat >expect <<-\EOF && + notes-1 + notes-2 + EOF + + git notes add -m "notes-1" && + git notes append --no-separator -m "notes-2" && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'append: specify separator with line break' ' + test_when_finished git notes remove HEAD && + cat >expect <<-\EOF && + notes-1 + ------- + notes-2 + EOF + + git notes add -m "notes-1" && + git notes append --separator="-------$LF" -m "notes-2" && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'append: specify separator without line break' ' + test_when_finished git notes remove HEAD && + cat >expect <<-\EOF && + notes-1 + ------- + notes-2 + EOF + + git notes add -m "notes-1" && + git notes append --separator="-------" -m "notes-2" && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'append: specify separator with multiple messages' ' + test_when_finished git notes remove HEAD && + cat >expect <<-\EOF && + notes-1 + ------- + notes-2 + ------- + notes-3 + EOF + + git notes add -m "notes-1" && + git notes append --separator="-------" -m "notes-2" -m "notes-3" && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'append note with combination of -m and -F and --separator' ' + test_when_finished git notes remove HEAD && + cat >expect-combine_m_and_F <<-\EOF && + m-notes-1 + ------- + f-notes-1 + ------- + m-notes-2 + ------- + f-notes-2 + ------- + m-notes-3 + EOF + + echo "f-notes-1" >note_a && + echo "f-notes-2" >note_b && + git notes append -m "m-notes-1" -F note_a -m "m-notes-2" -F note_b -m "m-notes-3" --separator="-------" && + git notes show >actual && + test_cmp expect-combine_m_and_F actual +' + test_expect_success 'append to existing note with "git notes append"' ' cat >expect <<-EOF && Initial set of notes @@ -818,6 +960,33 @@ test_expect_success 'create note from blob with "git notes add -C" reuses blob i test_cmp blob actual ' +test_expect_success 'create note from blob with "-C", also specify "-m", "-F" and "--separator"' ' + # 8th will be reuseed in following tests, so rollback when the test is done + test_when_finished "git notes remove && git notes add -C $(cat blob)" && + commit=$(git rev-parse HEAD) && + cat >expect <<-EOF && + commit $commit + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:20:13 2005 -0700 + + ${indent}8th + + Notes: + ${indent}This is a blob object + ${indent}------- + ${indent}This is created by -m + ${indent}------- + ${indent}This is created by -F + EOF + + git notes remove && + echo "This is a blob object" | git hash-object -w --stdin >blob && + echo "This is created by -F" >note_a && + git notes add -C $(cat blob) -m "This is created by -m" -F note_a --separator="-------" && + git log -1 >actual && + test_cmp expect actual +' + test_expect_success 'create note from other note with "git notes add -c"' ' test_commit 9th && commit=$(git rev-parse HEAD) && diff --git a/t/t3305-notes-fanout.sh b/t/t3305-notes-fanout.sh index 22ffe5bcb9..1ec1fb6715 100755 --- a/t/t3305-notes-fanout.sh +++ b/t/t3305-notes-fanout.sh @@ -9,7 +9,7 @@ path_has_fanout() { path=$1 && fanout=$2 && after_last_slash=$(($(test_oid hexsz) - $fanout * 2)) && - echo $path | grep -q "^\([0-9a-f]\{2\}/\)\{$fanout\}[0-9a-f]\{$after_last_slash\}$" + echo $path | grep -q -E "^([0-9a-f]{2}/){$fanout}[0-9a-f]{$after_last_slash}$" } touched_one_note_with_fanout() { diff --git a/t/t3309-notes-merge-auto-resolve.sh b/t/t3309-notes-merge-auto-resolve.sh index 141d3e4ca4..9bd5dbf341 100755 --- a/t/t3309-notes-merge-auto-resolve.sh +++ b/t/t3309-notes-merge-auto-resolve.sh @@ -360,7 +360,12 @@ test_expect_success 'merge z into y with invalid strategy => Fail/No changes' ' test_expect_success 'merge z into y with invalid configuration option => Fail/No changes' ' git config core.notesRef refs/notes/y && - test_must_fail git -c notes.mergeStrategy="foo" notes merge z && + cat >expect <<-\EOF && + error: unknown notes merge strategy foo + fatal: unable to parse '\''notes.mergeStrategy'\'' from command-line config + EOF + test_must_fail git -c notes.mergeStrategy="foo" notes merge z 2>actual && + test_cmp expect actual && # Verify no changes (y) verify_notes y y ' diff --git a/t/t3321-notes-stripspace.sh b/t/t3321-notes-stripspace.sh new file mode 100755 index 0000000000..36abdca5ee --- /dev/null +++ b/t/t3321-notes-stripspace.sh @@ -0,0 +1,578 @@ +#!/bin/sh +# +# Copyright (c) 2023 Teng Long +# + +test_description='Test commit notes with stripspace behavior' + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +MULTI_LF="$LF$LF$LF" +write_script fake_editor <<\EOF +echo "$MSG" >"$1" +echo "$MSG" >&2 +EOF +GIT_EDITOR=./fake_editor +export GIT_EDITOR + +test_expect_success 'setup the commit' ' + test_commit 1st +' + +test_expect_success 'add note by editor' ' + test_when_finished "git notes remove" && + cat >expect <<-EOF && + first-line + + second-line + EOF + + MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes add && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'add note by specifying single "-m", "--stripspace" is the default behavior' ' + test_when_finished "git notes remove" && + cat >expect <<-EOF && + first-line + + second-line + EOF + + git notes add -m "${LF}first-line${MULTI_LF}second-line${LF}" && + git notes show >actual && + test_cmp expect actual && + git notes remove && + git notes add --stripspace -m "${LF}first-line${MULTI_LF}second-line${LF}" && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'add note by specifying single "-m" and "--no-stripspace" ' ' + test_when_finished "git notes remove" && + cat >expect <<-EOF && + ${LF}first-line${MULTI_LF}second-line + EOF + + git notes add --no-stripspace \ + -m "${LF}first-line${MULTI_LF}second-line${LF}" && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'add note by specifying multiple "-m", "--stripspace" is the default behavior' ' + test_when_finished "git notes remove" && + cat >expect <<-EOF && + first-line + + second-line + EOF + + git notes add -m "${LF}" \ + -m "first-line" \ + -m "${MULTI_LF}" \ + -m "second-line" \ + -m "${LF}" && + git notes show >actual && + test_cmp expect actual && + git notes remove && + git notes add --stripspace -m "${LF}" \ + -m "first-line" \ + -m "${MULTI_LF}" \ + -m "second-line" \ + -m "${LF}" && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'add notes by specifying multiple "-m" and "--no-stripspace"' ' + test_when_finished "git notes remove" && + cat >expect <<-EOF && + ${LF} + first-line + ${MULTI_LF} + second-line${LF} + EOF + + git notes add --no-stripspace \ + -m "${LF}" \ + -m "first-line" \ + -m "${MULTI_LF}" \ + -m "second-line" \ + -m "${LF}" && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'add note by specifying single "-F", "--stripspace" is the default behavior' ' + test_when_finished "git notes remove" && + cat >expect <<-EOF && + first-line + + second-line + EOF + + cat >note-file <<-EOF && + ${LF} + first-line + ${MULTI_LF} + second-line + ${LF} + EOF + + git notes add -F note-file && + git notes show >actual && + test_cmp expect actual && + git notes remove && + git notes add --stripspace -F note-file && + git notes show >actual +' + +test_expect_success 'add note by specifying single "-F" and "--no-stripspace"' ' + test_when_finished "git notes remove" && + cat >expect <<-EOF && + ${LF} + first-line + ${MULTI_LF} + second-line + ${LF} + EOF + + cat >note-file <<-EOF && + ${LF} + first-line + ${MULTI_LF} + second-line + ${LF} + EOF + + git notes add --no-stripspace -F note-file && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'add note by specifying multiple "-F", "--stripspace" is the default behavior' ' + test_when_finished "git notes remove" && + cat >expect <<-EOF && + file-1-first-line + + file-1-second-line + + file-2-first-line + + file-2-second-line + EOF + + cat >note-file-1 <<-EOF && + ${LF} + file-1-first-line + ${MULTI_LF} + file-1-second-line + ${LF} + EOF + + cat >note-file-2 <<-EOF && + ${LF} + file-2-first-line + ${MULTI_LF} + file-2-second-line + ${LF} + EOF + + git notes add -F note-file-1 -F note-file-2 && + git notes show >actual && + test_cmp expect actual && + git notes remove && + git notes add --stripspace -F note-file-1 -F note-file-2 && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'add note by specifying multiple "-F" with "--no-stripspace"' ' + test_when_finished "git notes remove" && + cat >expect <<-EOF && + ${LF} + file-1-first-line + ${MULTI_LF} + file-1-second-line + ${LF} + + ${LF} + file-2-first-line + ${MULTI_LF} + file-2-second-line + ${LF} + EOF + + cat >note-file-1 <<-EOF && + ${LF} + file-1-first-line + ${MULTI_LF} + file-1-second-line + ${LF} + EOF + + cat >note-file-2 <<-EOF && + ${LF} + file-2-first-line + ${MULTI_LF} + file-2-second-line + ${LF} + EOF + + git notes add --no-stripspace -F note-file-1 -F note-file-2 && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'append note by editor' ' + test_when_finished "git notes remove" && + cat >expect <<-EOF && + first-line + + second-line + EOF + + git notes add -m "first-line" && + MSG="${MULTI_LF}second-line${LF}" git notes append && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'append note by specifying single "-m"' ' + test_when_finished "git notes remove" && + cat >expect <<-EOF && + first-line + + second-line + EOF + + git notes add -m "${LF}first-line" && + git notes append -m "${MULTI_LF}second-line${LF}" && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'append note by specifying multiple "-m"' ' + test_when_finished "git notes remove" && + cat >expect <<-EOF && + first-line + + second-line + EOF + + git notes add -m "${LF}first-line" && + git notes append -m "${MULTI_LF}" \ + -m "second-line" \ + -m "${LF}" && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'add note by specifying single "-F"' ' + test_when_finished "git notes remove" && + cat >expect <<-EOF && + first-line + + second-line + EOF + + cat >note-file <<-EOF && + ${LF} + first-line + ${MULTI_LF} + second-line + ${LF} + EOF + + git notes add -F note-file && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'add notes by specifying multiple "-F"' ' + test_when_finished "git notes remove" && + cat >expect <<-EOF && + file-1-first-line + + file-1-second-line + + file-2-first-line + + file-2-second-line + EOF + + cat >note-file-1 <<-EOF && + ${LF} + file-1-first-line + ${MULTI_LF} + file-1-second-line + ${LF} + EOF + + cat >note-file-2 <<-EOF && + ${LF} + file-2-first-line + ${MULTI_LF} + file-2-second-line + ${LF} + EOF + + git notes add -F note-file-1 -F note-file-2 && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'append note by specifying single "-F"' ' + test_when_finished "git notes remove" && + cat >expect <<-EOF && + initial-line + + first-line + + second-line + EOF + + cat >note-file <<-EOF && + ${LF} + first-line + ${MULTI_LF} + second-line + ${LF} + EOF + + git notes add -m "initial-line" && + git notes append -F note-file && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'append notes by specifying multiple "-F"' ' + test_when_finished "git notes remove" && + cat >expect <<-EOF && + initial-line + + file-1-first-line + + file-1-second-line + + file-2-first-line + + file-2-second-line + EOF + + cat >note-file-1 <<-EOF && + ${LF} + file-1-first-line + ${MULTI_LF} + file-1-second-line + ${LF} + EOF + + cat >note-file-2 <<-EOF && + ${LF} + file-2-first-line + ${MULTI_LF} + file-2-second-line + ${LF} + EOF + + git notes add -m "initial-line" && + git notes append -F note-file-1 -F note-file-2 && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'append note by specifying multiple "-F" with "--no-stripspace"' ' + test_when_finished "git notes remove" && + cat >expect <<-EOF && + initial-line + ${LF}${LF} + file-1-first-line + ${MULTI_LF} + file-1-second-line + ${LF} + + ${LF} + file-2-first-line + ${MULTI_LF} + file-2-second-line + ${LF} + EOF + + cat >note-file-1 <<-EOF && + ${LF} + file-1-first-line + ${MULTI_LF} + file-1-second-line + ${LF} + EOF + + cat >note-file-2 <<-EOF && + ${LF} + file-2-first-line + ${MULTI_LF} + file-2-second-line + ${LF} + EOF + + git notes add -m "initial-line" && + git notes append --no-stripspace -F note-file-1 -F note-file-2 && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'add notes with empty messages' ' + rev=$(git rev-parse HEAD) && + git notes add -m "${LF}" \ + -m "${MULTI_LF}" \ + -m "${LF}" >actual 2>&1 && + test_i18ngrep "Removing note for object" actual +' + +test_expect_success 'add note by specifying "-C", "--no-stripspace" is the default behavior' ' + test_when_finished "git notes remove" && + cat >expect <<-EOF && + ${LF} + first-line + ${MULTI_LF} + second-line + ${LF} + EOF + + cat expect | git hash-object -w --stdin >blob && + git notes add -C $(cat blob) && + git notes show >actual && + test_cmp expect actual && + git notes remove && + git notes add --no-stripspace -C $(cat blob) && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'reuse note by specifying "-C" and "--stripspace"' ' + test_when_finished "git notes remove" && + cat >data <<-EOF && + ${LF} + first-line + ${MULTI_LF} + second-line + ${LF} + EOF + + cat >expect <<-EOF && + first-line + + second-line + EOF + + cat data | git hash-object -w --stdin >blob && + git notes add --stripspace -C $(cat blob) && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'reuse with "-C" and add note with "-m", "-m" will stripspace all together' ' + test_when_finished "git notes remove" && + cat >data <<-EOF && + ${LF} + first-line + ${MULTI_LF} + second-line + ${LF} + EOF + + cat >expect <<-EOF && + first-line + + second-line + + third-line + EOF + + cat data | git hash-object -w --stdin >blob && + git notes add -C $(cat blob) -m "third-line" && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'add note with "-m" and reuse note with "-C", "-C" will not stripspace all together' ' + test_when_finished "git notes remove" && + cat >data <<-EOF && + + second-line + EOF + + cat >expect <<-EOF && + first-line + ${LF} + second-line + EOF + + cat data | git hash-object -w --stdin >blob && + git notes add -m "first-line" -C $(cat blob) && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'add note by specifying "-c", "--stripspace" is the default behavior' ' + test_when_finished "git notes remove" && + cat >expect <<-EOF && + first-line + + second-line + EOF + + echo "initial-line" | git hash-object -w --stdin >blob && + MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes add -c $(cat blob) && + git notes show >actual && + test_cmp expect actual && + git notes remove && + MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes add --stripspace -c $(cat blob) && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'add note by specifying "-c" with "--no-stripspace"' ' + test_when_finished "git notes remove" && + cat >expect <<-EOF && + ${LF}first-line${MULTI_LF}second-line${LF} + EOF + + echo "initial-line" | git hash-object -w --stdin >blob && + MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes add --no-stripspace -c $(cat blob) && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'edit note by specifying "-c", "--stripspace" is the default behavior' ' + test_when_finished "git notes remove" && + cat >expect <<-EOF && + first-line + + second-line + EOF + + MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes edit && + git notes show >actual && + test_cmp expect actual && + git notes remove && + MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes edit --stripspace && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'edit note by specifying "-c" with "--no-stripspace"' ' + test_when_finished "git notes remove" && + cat >expect <<-EOF && + ${LF}first-line${MULTI_LF}second-line${LF} + EOF + + MSG="${LF}first-line${MULTI_LF}second-line${LF}" git notes add --no-stripspace && + git notes show >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index d5a8ee39fc..d3df19a51f 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -388,6 +388,20 @@ test_expect_success 'switch to branch checked out here' ' git rebase main main ' +test_expect_success 'switch to branch checked out elsewhere fails' ' + test_when_finished " + git worktree remove wt1 && + git worktree remove wt2 && + git branch -d shared + " && + git worktree add wt1 -b shared && + git worktree add wt2 -f shared && + # we test in both worktrees to ensure that works + # as expected with "first" and "next" worktrees + test_must_fail git -C wt1 rebase shared shared && + test_must_fail git -C wt2 rebase shared shared +' + test_expect_success 'switch to branch not checked out' ' git checkout main && git branch other && @@ -407,7 +421,7 @@ test_expect_success 'refuse to switch to branch checked out elsewhere' ' git checkout main && git worktree add wt && test_must_fail git -C wt rebase main main 2>err && - test_i18ngrep "already checked out" err + test_i18ngrep "already used by worktree at" err ' test_expect_success MINGW,SYMLINKS_WINDOWS 'rebase when .git/logs is a symlink' ' diff --git a/t/t3402-rebase-merge.sh b/t/t3402-rebase-merge.sh index 7e46f4ca85..e9e03ca4b5 100755 --- a/t/t3402-rebase-merge.sh +++ b/t/t3402-rebase-merge.sh @@ -8,6 +8,7 @@ test_description='git rebase --merge test' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh T="A quick brown fox @@ -131,27 +132,6 @@ test_expect_success 'picking rebase' ' esac ' -test_expect_success 'rebase -s funny -Xopt' ' - test_when_finished "rm -fr test-bin funny.was.run" && - mkdir test-bin && - cat >test-bin/git-merge-funny <<-EOF && - #!$SHELL_PATH - case "\$1" in --opt) ;; *) exit 2 ;; esac - shift && - >funny.was.run && - exec git merge-recursive "\$@" - EOF - chmod +x test-bin/git-merge-funny && - git reset --hard && - git checkout -b test-funny main^ && - test_commit funny && - ( - PATH=./test-bin:$PATH && - git rebase -s funny -Xopt main - ) && - test -f funny.was.run -' - test_expect_success 'rebase --skip works with two conflicts in a row' ' git checkout second-side && tr "[A-Z]" "[a-z]" <newfile >tmp && diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index f0a0a54fba..8ea2bf1302 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -604,7 +604,8 @@ test_expect_success 'clean error after failed "exec"' ' echo "edited again" > file7 && git add file7 && test_must_fail git rebase --continue 2>error && - test_i18ngrep "you have staged changes in your working tree" error + test_i18ngrep "you have staged changes in your working tree" error && + test_i18ngrep ! "could not open.*for reading" error ' test_expect_success 'rebase a detached HEAD' ' @@ -758,7 +759,7 @@ test_expect_success 'reword' ' git show HEAD~2 | grep "C changed" ' -test_expect_success 'no uncommited changes when rewording the todo list is reloaded' ' +test_expect_success 'no uncommitted changes when rewording and the todo list is reloaded' ' git checkout E && test_when_finished "git checkout @{-1}" && ( @@ -1244,9 +1245,9 @@ test_expect_success 'short commit ID collide' ' test $colliding_id = "$(git rev-parse HEAD | cut -c 1-4)" && grep "^pick $colliding_id " \ .git/rebase-merge/git-rebase-todo.tmp && - grep "^pick [0-9a-f]\{$hexsz\}" \ + grep -E "^pick [0-9a-f]{$hexsz}" \ .git/rebase-merge/git-rebase-todo && - grep "^pick [0-9a-f]\{$hexsz\}" \ + grep -E "^pick [0-9a-f]{$hexsz}" \ .git/rebase-merge/git-rebase-todo.backup && git rebase --continue ) && @@ -1261,7 +1262,7 @@ test_expect_success 'respect core.abbrev' ' set_cat_todo_editor && test_must_fail git rebase -i HEAD~4 >todo-list ) && - test 4 = $(grep -c "pick [0-9a-f]\{12,\}" todo-list) + test 4 = $(grep -c -E "pick [0-9a-f]{12,}" todo-list) ' test_expect_success 'todo count' ' @@ -1276,20 +1277,34 @@ test_expect_success 'todo count' ' ' test_expect_success 'rebase -i commits that overwrite untracked files (pick)' ' - git checkout --force branch2 && + git checkout --force A && git clean -f && + cat >todo <<-EOF && + exec >file2 + pick $(git rev-parse B) B + pick $(git rev-parse C) C + pick $(git rev-parse D) D + exec cat .git/rebase-merge/done >actual + EOF ( - set_fake_editor && - FAKE_LINES="edit 1 2" git rebase -i A - ) && - test_cmp_rev HEAD F && - test_path_is_missing file6 && - >file6 && - test_must_fail git rebase --continue && - test_cmp_rev HEAD F && - rm file6 && + set_replace_editor todo && + test_must_fail git rebase -i A + ) && + test_cmp_rev HEAD B && + test_cmp_rev REBASE_HEAD C && + head -n3 todo >expect && + test_cmp expect .git/rebase-merge/done && + rm file2 && + test_path_is_missing .git/rebase-merge/patch && + echo changed >file1 && + git add file1 && + test_must_fail git rebase --continue 2>err && + grep "error: you have staged changes in your working tree" err && + git reset --hard HEAD && git rebase --continue && - test_cmp_rev HEAD I + test_cmp_rev HEAD D && + tail -n3 todo >>expect && + test_cmp expect actual ' test_expect_success 'rebase -i commits that overwrite untracked files (squash)' ' @@ -1305,7 +1320,14 @@ test_expect_success 'rebase -i commits that overwrite untracked files (squash)' >file6 && test_must_fail git rebase --continue && test_cmp_rev HEAD F && + test_cmp_rev REBASE_HEAD I && rm file6 && + test_path_is_missing .git/rebase-merge/patch && + echo changed >file1 && + git add file1 && + test_must_fail git rebase --continue 2>err && + grep "error: you have staged changes in your working tree" err && + git reset --hard HEAD && git rebase --continue && test $(git cat-file commit HEAD | sed -ne \$p) = I && git reset --hard original-branch2 @@ -1323,7 +1345,14 @@ test_expect_success 'rebase -i commits that overwrite untracked files (no ff)' ' >file6 && test_must_fail git rebase --continue && test $(git cat-file commit HEAD | sed -ne \$p) = F && + test_cmp_rev REBASE_HEAD I && rm file6 && + test_path_is_missing .git/rebase-merge/patch && + echo changed >file1 && + git add file1 && + test_must_fail git rebase --continue 2>err && + grep "error: you have staged changes in your working tree" err && + git reset --hard HEAD && git rebase --continue && test $(git cat-file commit HEAD | sed -ne \$p) = I ' @@ -1449,14 +1478,15 @@ test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = ig test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = warn' ' cat >expect <<-EOF && - error: invalid line 1: badcmd $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4) + error: invalid command '\''pickled'\'' + error: invalid line 1: pickled $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4) Warning: some commits may have been dropped accidentally. Dropped commits (newer to older): - $(git rev-list --pretty=oneline --abbrev-commit -1 primary) - $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4) To avoid this message, use "drop" to explicitly remove a commit. EOF - head -n4 expect >expect.2 && + head -n5 expect >expect.2 && tail -n1 expect >>expect.2 && tail -n4 expect.2 >expect.3 && test_config rebase.missingCommitsCheck warn && @@ -1467,7 +1497,7 @@ test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = wa git rebase -i --root && cp .git/rebase-merge/git-rebase-todo.backup orig && FAKE_LINES="2 3 4" git rebase --edit-todo 2>actual.2 && - head -n6 actual.2 >actual && + head -n7 actual.2 >actual && test_cmp expect actual && cp orig .git/rebase-merge/git-rebase-todo && FAKE_LINES="1 2 3 4" git rebase --edit-todo 2>actual.2 && @@ -1483,7 +1513,8 @@ test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = wa test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = error' ' cat >expect <<-EOF && - error: invalid line 1: badcmd $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4) + error: invalid command '\''pickled'\'' + error: invalid line 1: pickled $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4) Warning: some commits may have been dropped accidentally. Dropped commits (newer to older): - $(git rev-list --pretty=oneline --abbrev-commit -1 primary) @@ -1583,7 +1614,7 @@ test_expect_success 'static check of bad command' ' set_fake_editor && test_must_fail env FAKE_LINES="1 2 3 bad 4 5" \ git rebase -i --root 2>actual && - test_i18ngrep "badcmd $(git rev-list --oneline -1 primary~1)" \ + test_i18ngrep "pickled $(git rev-list --oneline -1 primary~1)" \ actual && test_i18ngrep "You can fix this with .git rebase --edit-todo.." \ actual && @@ -1594,6 +1625,32 @@ test_expect_success 'static check of bad command' ' test C = $(git cat-file commit HEAD^ | sed -ne \$p) ' +test_expect_success 'the first command cannot be a fixup' ' + rebase_setup_and_clean fixup-first && + + cat >orig <<-EOF && + fixup $(git log -1 --format="%h %s" B) + pick $(git log -1 --format="%h %s" C) + EOF + + ( + set_replace_editor orig && + test_must_fail git rebase -i A 2>actual + ) && + grep "cannot .fixup. without a previous commit" actual && + grep "You can fix this with .git rebase --edit-todo.." actual && + # verify that the todo list has not been truncated + grep -v "^#" .git/rebase-merge/git-rebase-todo >actual && + test_cmp orig actual && + + test_must_fail git rebase --edit-todo 2>actual && + grep "cannot .fixup. without a previous commit" actual && + grep "You can fix this with .git rebase --edit-todo.." actual && + # verify that the todo list has not been truncated + grep -v "^#" .git/rebase-merge/git-rebase-todo >actual && + test_cmp orig actual +' + test_expect_success 'tabs and spaces are accepted in the todolist' ' rebase_setup_and_clean indented-comment && write_script add-indent.sh <<-\EOF && @@ -2072,6 +2129,7 @@ test_expect_success '--update-refs: --edit-todo with no update-ref lines' ' ' test_expect_success '--update-refs: check failed ref update' ' + test_when_finished "test_might_fail git rebase --abort" && git checkout -B update-refs-error no-conflict-branch && git branch -f base HEAD~4 && git branch -f first HEAD~3 && @@ -2123,6 +2181,28 @@ test_expect_success '--update-refs: check failed ref update' ' test_cmp expect err.trimmed ' +test_expect_success 'bad labels and refs rejected when parsing todo list' ' + test_when_finished "test_might_fail git rebase --abort" && + cat >todo <<-\EOF && + exec >execed + label # + label :invalid + update-ref :bad + update-ref topic + EOF + rm -f execed && + ( + set_replace_editor todo && + test_must_fail git rebase -i HEAD 2>err + ) && + grep "'\''#'\'' is not a valid label" err && + grep "'\'':invalid'\'' is not a valid label" err && + grep "'\'':bad'\'' is not a valid refname" err && + grep "update-ref requires a fully qualified refname e.g. refs/heads/topic" \ + err && + test_path_is_missing execed +' + # This must be the last test in this file test_expect_success '$EDITOR and friends are unchanged' ' test_editor_unchanged diff --git a/t/t3405-rebase-malformed.sh b/t/t3405-rebase-malformed.sh index 2524331861..8979bc3407 100755 --- a/t/t3405-rebase-malformed.sh +++ b/t/t3405-rebase-malformed.sh @@ -5,6 +5,7 @@ test_description='rebase should handle arbitrary git message' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh index d17b450e81..ceca160005 100755 --- a/t/t3406-rebase-message.sh +++ b/t/t3406-rebase-message.sh @@ -10,10 +10,16 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME test_expect_success 'setup' ' test_commit O fileO && test_commit X fileX && + git branch fast-forward && test_commit A fileA && test_commit B fileB && test_commit Y fileY && + git checkout -b conflicts O && + test_commit P && + test_commit conflict-X fileX && + test_commit Q && + git checkout -b topic O && git cherry-pick A B && test_commit Z fileZ && @@ -79,54 +85,165 @@ test_expect_success 'error out early upon -C<n> or --whitespace=<bad>' ' test_i18ngrep "Invalid whitespace option" err ' -test_expect_success 'GIT_REFLOG_ACTION' ' - git checkout start && - test_commit reflog-onto && - git checkout -b reflog-topic start && - test_commit reflog-to-rebase && +write_reflog_expect () { + if test $mode = --apply + then + sed 's/(continue)/(pick)/' + else + cat + fi >expect +} - git rebase reflog-onto && - git log -g --format=%gs -3 >actual && - cat >expect <<-\EOF && - rebase (finish): returning to refs/heads/reflog-topic - rebase (pick): reflog-to-rebase - rebase (start): checkout reflog-onto +test_reflog () { + mode=$1 + reflog_action="$2" + + test_expect_success "rebase $mode reflog${reflog_action:+ GIT_REFLOG_ACTION=$reflog_action}" ' + git checkout conflicts && + test_when_finished "git reset --hard Q" && + + ( + if test -n "$reflog_action" + then + GIT_REFLOG_ACTION="$reflog_action" && + export GIT_REFLOG_ACTION + fi && + test_must_fail git rebase $mode main && + echo resolved >fileX && + git add fileX && + git rebase --continue + ) && + + git log -g --format=%gs -5 >actual && + write_reflog_expect <<-EOF && + ${reflog_action:-rebase} (finish): returning to refs/heads/conflicts + ${reflog_action:-rebase} (pick): Q + ${reflog_action:-rebase} (continue): conflict-X + ${reflog_action:-rebase} (pick): P + ${reflog_action:-rebase} (start): checkout main EOF test_cmp expect actual && - git checkout -b reflog-prefix reflog-to-rebase && - GIT_REFLOG_ACTION=change-the-reflog git rebase reflog-onto && - git log -g --format=%gs -3 >actual && - cat >expect <<-\EOF && - change-the-reflog (finish): returning to refs/heads/reflog-prefix - change-the-reflog (pick): reflog-to-rebase - change-the-reflog (start): checkout reflog-onto + git log -g --format=%gs -1 conflicts >actual && + write_reflog_expect <<-EOF && + ${reflog_action:-rebase} (finish): refs/heads/conflicts onto $(git rev-parse main) + EOF + test_cmp expect actual && + + # check there is only one new entry in the branch reflog + test_cmp_rev conflicts@{1} Q + ' + + test_expect_success "rebase $mode fast-forward reflog${reflog_action:+ GIT_REFLOG_ACTION=$reflog_action}" ' + git checkout fast-forward && + test_when_finished "git reset --hard X" && + + ( + if test -n "$reflog_action" + then + GIT_REFLOG_ACTION="$reflog_action" && + export GIT_REFLOG_ACTION + fi && + git rebase $mode main + ) && + + git log -g --format=%gs -2 >actual && + write_reflog_expect <<-EOF && + ${reflog_action:-rebase} (finish): returning to refs/heads/fast-forward + ${reflog_action:-rebase} (start): checkout main + EOF + test_cmp expect actual && + + git log -g --format=%gs -1 fast-forward >actual && + write_reflog_expect <<-EOF && + ${reflog_action:-rebase} (finish): refs/heads/fast-forward onto $(git rev-parse main) + EOF + test_cmp expect actual && + + # check there is only one new entry in the branch reflog + test_cmp_rev fast-forward@{1} X + ' + + test_expect_success "rebase $mode --skip reflog${reflog_action:+ GIT_REFLOG_ACTION=$reflog_action}" ' + git checkout conflicts && + test_when_finished "git reset --hard Q" && + + ( + if test -n "$reflog_action" + then + GIT_REFLOG_ACTION="$reflog_action" && + export GIT_REFLOG_ACTION + fi && + test_must_fail git rebase $mode main && + git rebase --skip + ) && + + git log -g --format=%gs -4 >actual && + write_reflog_expect <<-EOF && + ${reflog_action:-rebase} (finish): returning to refs/heads/conflicts + ${reflog_action:-rebase} (pick): Q + ${reflog_action:-rebase} (pick): P + ${reflog_action:-rebase} (start): checkout main EOF test_cmp expect actual -' + ' -test_expect_success 'rebase --apply reflog' ' - git checkout -b reflog-apply start && - old_head_reflog="$(git log -g --format=%gs -1 HEAD)" && + test_expect_success "rebase $mode --abort reflog${reflog_action:+ GIT_REFLOG_ACTION=$reflog_action}" ' + git checkout conflicts && + test_when_finished "git reset --hard Q" && - git rebase --apply Y && + git log -g -1 conflicts >branch-expect && + ( + if test -n "$reflog_action" + then + GIT_REFLOG_ACTION="$reflog_action" && + export GIT_REFLOG_ACTION + fi && + test_must_fail git rebase $mode main && + git rebase --abort + ) && - git log -g --format=%gs -4 HEAD >actual && - cat >expect <<-EOF && - rebase finished: returning to refs/heads/reflog-apply - rebase: Z - rebase: checkout Y - $old_head_reflog + git log -g --format=%gs -3 >actual && + write_reflog_expect <<-EOF && + ${reflog_action:-rebase} (abort): returning to refs/heads/conflicts + ${reflog_action:-rebase} (pick): P + ${reflog_action:-rebase} (start): checkout main EOF test_cmp expect actual && - git log -g --format=%gs -2 reflog-apply >actual && - cat >expect <<-EOF && - rebase finished: refs/heads/reflog-apply onto $(git rev-parse Y) - branch: Created from start + # check branch reflog is unchanged + git log -g -1 conflicts >branch-actual && + test_cmp branch-expect branch-actual + ' + + test_expect_success "rebase $mode --abort detached HEAD reflog${reflog_action:+ GIT_REFLOG_ACTION=$reflog_action}" ' + git checkout Q && + test_when_finished "git reset --hard Q" && + + ( + if test -n "$reflog_action" + then + GIT_REFLOG_ACTION="$reflog_action" && + export GIT_REFLOG_ACTION + fi && + test_must_fail git rebase $mode main && + git rebase --abort + ) && + + git log -g --format=%gs -3 >actual && + write_reflog_expect <<-EOF && + ${reflog_action:-rebase} (abort): returning to $(git rev-parse Q) + ${reflog_action:-rebase} (pick): P + ${reflog_action:-rebase} (start): checkout main EOF test_cmp expect actual -' + ' +} + +test_reflog --merge +test_reflog --merge my-reflog-action +test_reflog --apply +test_reflog --apply my-reflog-action test_expect_success 'rebase -i onto unrelated history' ' git init unrelated && diff --git a/t/t3409-rebase-environ.sh b/t/t3409-rebase-environ.sh index 83ffb39d9f..acaf5558db 100755 --- a/t/t3409-rebase-environ.sh +++ b/t/t3409-rebase-environ.sh @@ -2,6 +2,7 @@ test_description='git rebase interactive environment' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh index 58371d8a54..e75b3d0e07 100755 --- a/t/t3412-rebase-root.sh +++ b/t/t3412-rebase-root.sh @@ -7,6 +7,7 @@ Tests if git rebase --root --onto <newparent> can rebase the root commit. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh log_with_names () { diff --git a/t/t3413-rebase-hook.sh b/t/t3413-rebase-hook.sh index 9fab0d779b..e8456831e8 100755 --- a/t/t3413-rebase-hook.sh +++ b/t/t3413-rebase-hook.sh @@ -5,6 +5,7 @@ test_description='git rebase with its hook(s)' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t3416-rebase-onto-threedots.sh b/t/t3416-rebase-onto-threedots.sh index 3e04802cb0..f8c4ed78c9 100755 --- a/t/t3416-rebase-onto-threedots.sh +++ b/t/t3416-rebase-onto-threedots.sh @@ -5,6 +5,7 @@ test_description='git rebase --onto A...B' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY/lib-rebase.sh" @@ -79,8 +80,10 @@ test_expect_success 'rebase -i --onto main...topic' ' git reset --hard && git checkout topic && git reset --hard G && - set_fake_editor && - EXPECT_COUNT=1 git rebase -i --onto main...topic F && + ( + set_fake_editor && + EXPECT_COUNT=1 git rebase -i --onto main...topic F + ) && git rev-parse HEAD^1 >actual && git rev-parse C^0 >expect && test_cmp expect actual @@ -90,20 +93,22 @@ test_expect_success 'rebase -i --onto main...' ' git reset --hard && git checkout topic && git reset --hard G && - set_fake_editor && - EXPECT_COUNT=1 git rebase -i --onto main... F && + ( + set_fake_editor && + EXPECT_COUNT=1 git rebase -i --onto main... F + ) && git rev-parse HEAD^1 >actual && git rev-parse C^0 >expect && test_cmp expect actual ' -test_expect_success 'rebase -i --onto main...side' ' +test_expect_success 'rebase --onto main...side requires a single merge-base' ' git reset --hard && git checkout side && git reset --hard K && - set_fake_editor && - test_must_fail git rebase -i --onto main...side J + test_must_fail git rebase -i --onto main...side J 2>err && + grep "need exactly one merge base" err ' test_expect_success 'rebase --keep-base --onto incompatible' ' @@ -156,8 +161,10 @@ test_expect_success 'rebase -i --keep-base main from topic' ' git checkout topic && git reset --hard G && - set_fake_editor && - EXPECT_COUNT=2 git rebase -i --keep-base main && + ( + set_fake_editor && + EXPECT_COUNT=2 git rebase -i --keep-base main + ) && git rev-parse C >base.expect && git merge-base main HEAD >base.actual && test_cmp base.expect base.actual && @@ -171,8 +178,10 @@ test_expect_success 'rebase -i --keep-base main topic from main' ' git checkout main && git branch -f topic G && - set_fake_editor && - EXPECT_COUNT=2 git rebase -i --keep-base main topic && + ( + set_fake_editor && + EXPECT_COUNT=2 git rebase -i --keep-base main topic + ) && git rev-parse C >base.expect && git merge-base main HEAD >base.actual && test_cmp base.expect base.actual && @@ -182,13 +191,39 @@ test_expect_success 'rebase -i --keep-base main topic from main' ' test_cmp expect actual ' -test_expect_success 'rebase -i --keep-base main from side' ' +test_expect_success 'rebase --keep-base requires a single merge base' ' git reset --hard && git checkout side && git reset --hard K && - set_fake_editor && - test_must_fail git rebase -i --keep-base main + test_must_fail git rebase -i --keep-base main 2>err && + grep "need exactly one merge base with branch" err +' + +test_expect_success 'rebase --keep-base keeps cherry picks' ' + git checkout -f -B main E && + git cherry-pick F && + ( + set_fake_editor && + EXPECT_COUNT=2 git rebase -i --keep-base HEAD G + ) && + test_cmp_rev HEAD G +' + +test_expect_success 'rebase --keep-base --no-reapply-cherry-picks' ' + git checkout -f -B main E && + git cherry-pick F && + ( + set_fake_editor && + EXPECT_COUNT=1 git rebase -i --keep-base \ + --no-reapply-cherry-picks HEAD G + ) && + test_cmp_rev HEAD^ C +' + +# This must be the last test in this file +test_expect_success '$EDITOR and friends are unchanged' ' + test_editor_unchanged ' test_done diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh index 130e2f9b55..c4e2fcac67 100755 --- a/t/t3418-rebase-continue.sh +++ b/t/t3418-rebase-continue.sh @@ -62,61 +62,39 @@ test_expect_success 'rebase --continue remembers merge strategy and options' ' rm -fr .git/rebase-* && git reset --hard commit-new-file-F2-on-topic-branch && test_commit "commit-new-file-F3-on-topic-branch" F3 32 && - test_when_finished "rm -fr test-bin funny.was.run" && + test_when_finished "rm -fr test-bin" && mkdir test-bin && - cat >test-bin/git-merge-funny <<-EOF && - #!$SHELL_PATH - case "\$1" in --opt) ;; *) exit 2 ;; esac - shift && - >funny.was.run && - exec git merge-recursive "\$@" + + write_script test-bin/git-merge-funny <<-\EOF && + printf "[%s]\n" $# "$1" "$2" "$3" "$5" >actual + shift 3 && + exec git merge-recursive "$@" EOF - chmod +x test-bin/git-merge-funny && - ( - PATH=./test-bin:$PATH && - test_must_fail git rebase -s funny -Xopt main topic - ) && - test -f funny.was.run && - rm funny.was.run && - echo "Resolved" >F2 && - git add F2 && - ( - PATH=./test-bin:$PATH && - git rebase --continue - ) && - test -f funny.was.run -' -test_expect_success 'rebase -i --continue handles merge strategy and options' ' - rm -fr .git/rebase-* && - git reset --hard commit-new-file-F2-on-topic-branch && - test_commit "commit-new-file-F3-on-topic-branch-for-dash-i" F3 32 && - test_when_finished "rm -fr test-bin funny.was.run funny.args" && - mkdir test-bin && - cat >test-bin/git-merge-funny <<-EOF && - #!$SHELL_PATH - echo "\$@" >>funny.args - case "\$1" in --opt) ;; *) exit 2 ;; esac - case "\$2" in --foo) ;; *) exit 2 ;; esac - case "\$4" in --) ;; *) exit 2 ;; esac - shift 2 && - >funny.was.run && - exec git merge-recursive "\$@" + cat >expect <<-\EOF && + [7] + [--option=arg with space] + [--op"tion\] + [--new + line ] + [--] EOF - chmod +x test-bin/git-merge-funny && + + rm -f actual && ( PATH=./test-bin:$PATH && - test_must_fail git rebase -i -s funny -Xopt -Xfoo main topic + test_must_fail git rebase -s funny -X"option=arg with space" \ + -Xop\"tion\\ -X"new${LF}line " main topic ) && - test -f funny.was.run && - rm funny.was.run && + test_cmp expect actual && + rm actual && echo "Resolved" >F2 && git add F2 && ( PATH=./test-bin:$PATH && git rebase --continue ) && - test -f funny.was.run + test_cmp expect actual ' test_expect_success 'rebase -r passes merge strategy options correctly' ' @@ -137,15 +115,23 @@ test_expect_success '--skip after failed fixup cleans commit message' ' test_when_finished "test_might_fail git rebase --abort" && git checkout -b with-conflicting-fixup && test_commit wants-fixup && - test_commit "fixup! wants-fixup" wants-fixup.t 1 wants-fixup-1 && - test_commit "fixup! wants-fixup" wants-fixup.t 2 wants-fixup-2 && - test_commit "fixup! wants-fixup" wants-fixup.t 3 wants-fixup-3 && + test_commit "fixup 1" wants-fixup.t 1 wants-fixup-1 && + test_commit "fixup 2" wants-fixup.t 2 wants-fixup-2 && + test_commit "fixup 3" wants-fixup.t 3 wants-fixup-3 && test_must_fail env FAKE_LINES="1 fixup 2 squash 4" \ git rebase -i HEAD~4 && : now there is a conflict, and comments in the commit message && - git show HEAD >out && - grep "fixup! wants-fixup" out && + test_commit_message HEAD <<-\EOF && + # This is a combination of 2 commits. + # This is the 1st commit message: + + wants-fixup + + # The commit message #2 will be skipped: + + # fixup 1 + EOF : skip and continue && echo "cp \"\$1\" .git/copy.txt" | write_script copy-editor.sh && @@ -155,33 +141,49 @@ test_expect_success '--skip after failed fixup cleans commit message' ' test_path_is_missing .git/copy.txt && : now the comments in the commit message should have been cleaned up && - git show HEAD >out && - ! grep "fixup! wants-fixup" out && + test_commit_message HEAD -m wants-fixup && : now, let us ensure that "squash" is handled correctly && git reset --hard wants-fixup-3 && - test_must_fail env FAKE_LINES="1 squash 4 squash 2 squash 4" \ + test_must_fail env FAKE_LINES="1 squash 2 squash 1 squash 3 squash 1" \ git rebase -i HEAD~4 && - : the first squash failed, but there are two more in the chain && + : the second squash failed, but there are two more in the chain && (test_set_editor "$PWD/copy-editor.sh" && test_must_fail git rebase --skip) && : not the final squash, no need to edit the commit message && test_path_is_missing .git/copy.txt && - : The first squash was skipped, therefore: && - git show HEAD >out && - test_i18ngrep "# This is a combination of 2 commits" out && - test_i18ngrep "# This is the commit message #2:" out && + : The first and third squashes succeeded, therefore: && + test_commit_message HEAD <<-\EOF && + # This is a combination of 3 commits. + # This is the 1st commit message: + + wants-fixup + + # This is the commit message #2: + + fixup 1 + + # This is the commit message #3: + + fixup 2 + EOF (test_set_editor "$PWD/copy-editor.sh" && git rebase --skip) && - git show HEAD >out && - test_i18ngrep ! "# This is a combination" out && + test_commit_message HEAD <<-\EOF && + wants-fixup + + fixup 1 + + fixup 2 + EOF : Final squash failed, but there was still a squash && - test_i18ngrep "# This is a combination of 2 commits" .git/copy.txt && - test_i18ngrep "# This is the commit message #2:" .git/copy.txt + head -n1 .git/copy.txt >first-line && + test_i18ngrep "# This is a combination of 3 commits" first-line && + test_i18ngrep "# This is the commit message #3:" .git/copy.txt ' test_expect_success 'setup rerere database' ' @@ -266,6 +268,24 @@ test_expect_success 'the todo command "break" works' ' test_path_is_file execed ' +test_expect_success 'patch file is removed before break command' ' + test_when_finished "git rebase --abort" && + cat >todo <<-\EOF && + pick commit-new-file-F2-on-topic-branch + break + EOF + + ( + set_replace_editor todo && + test_must_fail git rebase -i --onto commit-new-file-F2 HEAD + ) && + test_path_is_file .git/rebase-merge/patch && + echo 22>F2 && + git add F2 && + git rebase --continue && + test_path_is_missing .git/rebase-merge/patch +' + test_expect_success '--reschedule-failed-exec' ' test_when_finished "git rebase --abort" && test_must_fail git rebase -x false --reschedule-failed-exec HEAD^ && diff --git a/t/t3419-rebase-patch-id.sh b/t/t3419-rebase-patch-id.sh index 295040f2fe..6c61f240cf 100755 --- a/t/t3419-rebase-patch-id.sh +++ b/t/t3419-rebase-patch-id.sh @@ -5,6 +5,7 @@ test_description='git rebase - test patch id computation' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh scramble () { @@ -43,15 +44,26 @@ test_expect_success 'setup: 500 lines' ' git add newfile && git commit -q -m "add small file" && - git cherry-pick main >/dev/null 2>&1 -' + git cherry-pick main >/dev/null 2>&1 && + + git branch -f squashed main && + git checkout -q -f squashed && + git reset -q --soft HEAD~2 && + git commit -q -m squashed && + + git branch -f mode main && + git checkout -q -f mode && + test_chmod +x file && + git commit -q -a --amend && -test_expect_success 'setup attributes' ' - echo "file binary" >.gitattributes + git branch -f modeother other && + git checkout -q -f modeother && + test_chmod +x file && + git commit -q -a --amend ' test_expect_success 'detect upstream patch' ' - git checkout -q main && + git checkout -q main^{} && scramble file && git add file && git commit -q -m "change big file again" && @@ -61,14 +73,46 @@ test_expect_success 'detect upstream patch' ' test_must_be_empty revs ' +test_expect_success 'detect upstream patch binary' ' + echo "file binary" >.gitattributes && + git checkout -q other^{} && + git rebase main && + git rev-list main...HEAD~ >revs && + test_must_be_empty revs && + test_when_finished "rm .gitattributes" +' + +test_expect_success 'detect upstream patch modechange' ' + git checkout -q modeother^{} && + git rebase mode && + git rev-list mode...HEAD~ >revs && + test_must_be_empty revs +' + test_expect_success 'do not drop patch' ' - git branch -f squashed main && - git checkout -q -f squashed && - git reset -q --soft HEAD~2 && - git commit -q -m squashed && git checkout -q other^{} && test_must_fail git rebase squashed && - git rebase --quit + test_when_finished "git rebase --abort" +' + +test_expect_success 'do not drop patch binary' ' + echo "file binary" >.gitattributes && + git checkout -q other^{} && + test_must_fail git rebase squashed && + test_when_finished "git rebase --abort" && + test_when_finished "rm .gitattributes" +' + +test_expect_success 'do not drop patch modechange' ' + git checkout -q modeother^{} && + git rebase other && + cat >expected <<-\EOF && + diff --git a/file b/file + old mode 100644 + new mode 100755 + EOF + git diff HEAD~ >modediff && + test_cmp expected modediff ' test_done diff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh index 6dabb05a2a..2eba00bdf5 100755 --- a/t/t3422-rebase-incompatible-options.sh +++ b/t/t3422-rebase-incompatible-options.sh @@ -25,11 +25,11 @@ test_expect_success 'setup' ' ' # -# Rebase has lots of useful options like --whitepsace=fix, which are -# actually all built in terms of flags to git-am. Since neither -# --merge nor --interactive (nor any options that imply those two) use -# git-am, using them together will result in flags like --whitespace=fix -# being ignored. Make sure rebase warns the user and aborts instead. +# Rebase has a couple options which are specific to the apply backend, +# and several options which are specific to the merge backend. Flags +# from the different sets cannot work together, and we do not want to +# just ignore one of the sets of flags. Make sure rebase warns the +# user and aborts instead. # test_rebase_am_only () { @@ -50,6 +50,11 @@ test_rebase_am_only () { test_must_fail git rebase $opt --strategy-option=ours A " + test_expect_success "$opt incompatible with --autosquash" " + git checkout B^0 && + test_must_fail git rebase $opt --autosquash A + " + test_expect_success "$opt incompatible with --interactive" " git checkout B^0 && test_must_fail git rebase $opt --interactive A @@ -60,9 +65,82 @@ test_rebase_am_only () { test_must_fail git rebase $opt --exec 'true' A " + test_expect_success "$opt incompatible with --keep-empty" " + git checkout B^0 && + test_must_fail git rebase $opt --keep-empty A + " + + test_expect_success "$opt incompatible with --empty=..." " + git checkout B^0 && + test_must_fail git rebase $opt --empty=ask A + " + + test_expect_success "$opt incompatible with --no-reapply-cherry-picks" " + git checkout B^0 && + test_must_fail git rebase $opt --no-reapply-cherry-picks A + " + + test_expect_success "$opt incompatible with --reapply-cherry-picks" " + git checkout B^0 && + test_must_fail git rebase $opt --reapply-cherry-picks A + " + + test_expect_success "$opt incompatible with --rebase-merges" " + git checkout B^0 && + test_must_fail git rebase $opt --rebase-merges A + " + + test_expect_success "$opt incompatible with --update-refs" " + git checkout B^0 && + test_must_fail git rebase $opt --update-refs A + " + + test_expect_success "$opt incompatible with --root without --onto" " + git checkout B^0 && + test_must_fail git rebase $opt --root A + " + + test_expect_success "$opt incompatible with rebase.autosquash" " + git checkout B^0 && + test_must_fail git -c rebase.autosquash=true rebase $opt A 2>err && + grep -e --no-autosquash err + " + + test_expect_success "$opt incompatible with rebase.rebaseMerges" " + git checkout B^0 && + test_must_fail git -c rebase.rebaseMerges=true rebase $opt A 2>err && + grep -e --no-rebase-merges err + " + + test_expect_success "$opt incompatible with rebase.updateRefs" " + git checkout B^0 && + test_must_fail git -c rebase.updateRefs=true rebase $opt A 2>err && + grep -e --no-update-refs err + " + + test_expect_success "$opt okay with overridden rebase.autosquash" " + test_when_finished \"git reset --hard B^0\" && + git checkout B^0 && + git -c rebase.autosquash=true rebase --no-autosquash $opt A + " + + test_expect_success "$opt okay with overridden rebase.rebaseMerges" " + test_when_finished \"git reset --hard B^0\" && + git checkout B^0 && + git -c rebase.rebaseMerges=true rebase --no-rebase-merges $opt A + " + + test_expect_success "$opt okay with overridden rebase.updateRefs" " + test_when_finished \"git reset --hard B^0\" && + git checkout B^0 && + git -c rebase.updateRefs=true rebase --no-update-refs $opt A + " } +# Check options which imply --apply test_rebase_am_only --whitespace=fix test_rebase_am_only -C4 +# Also check an explicit --apply +test_rebase_am_only --apply test_done diff --git a/t/t3423-rebase-reword.sh b/t/t3423-rebase-reword.sh index 4859bb8f72..2fab703d61 100755 --- a/t/t3423-rebase-reword.sh +++ b/t/t3423-rebase-reword.sh @@ -2,6 +2,7 @@ test_description='git rebase interactive with rewording' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh diff --git a/t/t3425-rebase-topology-merges.sh b/t/t3425-rebase-topology-merges.sh index 63acc1ea4d..a16428bdf5 100755 --- a/t/t3425-rebase-topology-merges.sh +++ b/t/t3425-rebase-topology-merges.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='rebase topology tests with merges' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh diff --git a/t/t3427-rebase-subtree.sh b/t/t3427-rebase-subtree.sh index 48b76f8232..1b3e97c875 100755 --- a/t/t3427-rebase-subtree.sh +++ b/t/t3427-rebase-subtree.sh @@ -74,9 +74,9 @@ test_expect_success 'Rebase -Xsubtree --empty=ask --onto commit' ' test_must_fail git rebase -Xsubtree=files_subtree --empty=ask --onto files-main main && : first pick results in no changes && git rebase --skip && - verbose test "$(commit_message HEAD~2)" = "topic_4" && - verbose test "$(commit_message HEAD~)" = "files_subtree/topic_5" && - verbose test "$(commit_message HEAD)" = "Empty commit" + test "$(commit_message HEAD~2)" = "topic_4" && + test "$(commit_message HEAD~)" = "files_subtree/topic_5" && + test "$(commit_message HEAD)" = "Empty commit" ' test_expect_success 'Rebase -Xsubtree --empty=ask --rebase-merges --onto commit' ' @@ -85,9 +85,9 @@ test_expect_success 'Rebase -Xsubtree --empty=ask --rebase-merges --onto commit' test_must_fail git rebase -Xsubtree=files_subtree --empty=ask --rebase-merges --onto files-main --root && : first pick results in no changes && git rebase --skip && - verbose test "$(commit_message HEAD~2)" = "topic_4" && - verbose test "$(commit_message HEAD~)" = "files_subtree/topic_5" && - verbose test "$(commit_message HEAD)" = "Empty commit" + test "$(commit_message HEAD~2)" = "topic_4" && + test "$(commit_message HEAD~)" = "files_subtree/topic_5" && + test "$(commit_message HEAD)" = "Empty commit" ' test_done diff --git a/t/t3428-rebase-signoff.sh b/t/t3428-rebase-signoff.sh index f6993b7e14..e1b1e94764 100755 --- a/t/t3428-rebase-signoff.sh +++ b/t/t3428-rebase-signoff.sh @@ -5,6 +5,7 @@ test_description='git rebase --signoff This test runs git rebase --signoff and make sure that it works. ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # A simple file to commit diff --git a/t/t3429-rebase-edit-todo.sh b/t/t3429-rebase-edit-todo.sh index abd66f3602..8e0d03969a 100755 --- a/t/t3429-rebase-edit-todo.sh +++ b/t/t3429-rebase-edit-todo.sh @@ -2,6 +2,7 @@ test_description='rebase should reread the todo file if an exec modifies it' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh diff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh index f351701fec..59b5d6b6f2 100755 --- a/t/t3430-rebase-merges.sh +++ b/t/t3430-rebase-merges.sh @@ -128,14 +128,41 @@ test_expect_success 'generate correct todo list' ' ' test_expect_success '`reset` refuses to overwrite untracked files' ' - git checkout -b refuse-to-reset && + git checkout B && test_commit dont-overwrite-untracked && - git checkout @{-1} && - : >dont-overwrite-untracked.t && - echo "reset refs/tags/dont-overwrite-untracked" >script-from-scratch && + cat >script-from-scratch <<-EOF && + exec >dont-overwrite-untracked.t + pick $(git rev-parse B) B + reset refs/tags/dont-overwrite-untracked + pick $(git rev-parse C) C + exec cat .git/rebase-merge/done >actual + EOF test_config sequence.editor \""$PWD"/replace-editor.sh\" && - test_must_fail git rebase -ir HEAD && - git rebase --abort + test_must_fail git rebase -ir A && + test_cmp_rev HEAD B && + head -n3 script-from-scratch >expect && + test_cmp expect .git/rebase-merge/done && + rm dont-overwrite-untracked.t && + git rebase --continue && + tail -n3 script-from-scratch >>expect && + test_cmp expect actual +' + +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)' ' @@ -148,12 +175,16 @@ test_expect_success 'failed `merge -C` writes patch (may be rescheduled, too)' ' test_config sequence.editor \""$PWD"/replace-editor.sh\" && test_tick && test_must_fail git rebase -ir HEAD && + test_cmp_rev REBASE_HEAD H^0 && grep "^merge -C .* G$" .git/rebase-merge/done && grep "^merge -C .* G$" .git/rebase-merge/git-rebase-todo && - test_path_is_file .git/rebase-merge/patch && + test_path_is_missing .git/rebase-merge/patch && + echo changed >file1 && + git add file1 && + test_must_fail git rebase --continue 2>err && + grep "error: you have staged changes in your working tree" err && : fail because of merge conflict && - rm G.t .git/rebase-merge/patch && git reset --hard conflicting-G && test_must_fail git rebase --continue && ! grep "^merge -C .* G$" .git/rebase-merge/git-rebase-todo && @@ -233,6 +264,16 @@ test_expect_success 'with a branch tip that was cherry-picked already' ' EOF ' +test_expect_success '--no-rebase-merges countermands --rebase-merges' ' + git checkout -b no-rebase-merges E && + git rebase --rebase-merges --no-rebase-merges C && + test_cmp_graph C.. <<-\EOF + * B + * D + o C + EOF +' + test_expect_success 'do not rebase cousins unless asked for' ' git checkout -b cousins main && before="$(git rev-parse --verify HEAD)" && @@ -251,6 +292,40 @@ test_expect_success 'do not rebase cousins unless asked for' ' EOF ' +test_expect_success 'rebase.rebaseMerges=rebase-cousins is equivalent to --rebase-merges=rebase-cousins' ' + test_config rebase.rebaseMerges rebase-cousins && + git checkout -b config-rebase-cousins main && + git rebase HEAD^ && + test_cmp_graph HEAD^.. <<-\EOF + * Merge the topic branch '\''onebranch'\'' + |\ + | * D + | * G + |/ + o H + EOF +' + +test_expect_success '--no-rebase-merges overrides rebase.rebaseMerges=no-rebase-cousins' ' + test_config rebase.rebaseMerges no-rebase-cousins && + git checkout -b override-config-no-rebase-cousins E && + git rebase --no-rebase-merges C && + test_cmp_graph C.. <<-\EOF + * B + * D + o C + EOF +' + +test_expect_success '--rebase-merges overrides rebase.rebaseMerges=rebase-cousins' ' + test_config rebase.rebaseMerges rebase-cousins && + git checkout -b override-config-rebase-cousins E && + before="$(git rev-parse --verify HEAD)" && + test_tick && + git rebase --rebase-merges C && + test_cmp_rev HEAD $before +' + test_expect_success 'refs/rewritten/* is worktree-local' ' git worktree add wt && cat >wt/script-from-scratch <<-\EOF && @@ -517,4 +592,23 @@ test_expect_success '--rebase-merges with message matched with onto label' ' EOF ' +test_expect_success 'progress shows the correct total' ' + git checkout -b progress H && + git rebase --rebase-merges --force-rebase --verbose A 2> err && + # Expecting "Rebasing (N/14)" here, no bogus total number + grep "^Rebasing.*/14.$" err >progress && + test_line_count = 14 progress +' + +test_expect_success 'truncate label names' ' + commit=$(git commit-tree -p HEAD^ -p HEAD -m "0123456789 我 123" HEAD^{tree}) && + git merge --ff-only $commit && + + done="$(git rev-parse --git-path rebase-merge/done)" && + git -c rebase.maxLabelLength=14 rebase --rebase-merges -x "cp \"$done\" out" --root && + grep "label 0123456789-我$" out && + git -c rebase.maxLabelLength=13 rebase --rebase-merges -x "cp \"$done\" out" --root && + grep "label 0123456789-$" out +' + test_done diff --git a/t/t3431-rebase-fork-point.sh b/t/t3431-rebase-fork-point.sh index 1d0b15380e..4bfc779bb8 100755 --- a/t/t3431-rebase-fork-point.sh +++ b/t/t3431-rebase-fork-point.sh @@ -8,6 +8,7 @@ test_description='git rebase --fork-point test' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # A---B---D---E (main) @@ -50,7 +51,7 @@ test_rebase () { test_rebase 'G F E D B A' test_rebase 'G F D B A' --onto D -test_rebase 'G F B A' --keep-base +test_rebase 'G F C B A' --keep-base test_rebase 'G F C E D B A' --no-fork-point test_rebase 'G F C D B A' --no-fork-point --onto D test_rebase 'G F C B A' --no-fork-point --keep-base diff --git a/t/t3432-rebase-fast-forward.sh b/t/t3432-rebase-fast-forward.sh index 5086e14c02..7f1a5dd3de 100755 --- a/t/t3432-rebase-fast-forward.sh +++ b/t/t3432-rebase-fast-forward.sh @@ -8,6 +8,7 @@ test_description='ensure rebase fast-forwards commits when possible' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t3433-rebase-across-mode-change.sh b/t/t3433-rebase-across-mode-change.sh index 05df964670..c8172b0852 100755 --- a/t/t3433-rebase-across-mode-change.sh +++ b/t/t3433-rebase-across-mode-change.sh @@ -2,6 +2,7 @@ test_description='git rebase across mode change' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t3437-rebase-fixup-options.sh b/t/t3437-rebase-fixup-options.sh index c023fefd68..7929e2e2e3 100755 --- a/t/t3437-rebase-fixup-options.sh +++ b/t/t3437-rebase-fixup-options.sh @@ -14,27 +14,13 @@ to the "fixup" command that works with "fixup!", "fixup -C" works with "amend!" upon --autosquash. ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh EMPTY="" -# test_commit_message <rev> -m <msg> -# test_commit_message <rev> <path> -# Verify that the commit message of <rev> matches -# <msg> or the content of <path>. -test_commit_message () { - git show --no-patch --pretty=format:%B "$1" >actual && - case "$2" in - -m) - echo "$3" >expect && - test_cmp expect actual ;; - *) - test_cmp "$2" actual ;; - esac -} - get_author () { rev="$1" && git log -1 --pretty=format:"%an %ae %at" "$rev" @@ -50,6 +36,7 @@ test_expect_success 'setup' ' body EOF + test_commit initial && test_commit A A && test_commit B B && get_author HEAD >expected-author && @@ -208,4 +195,29 @@ test_expect_success 'fixup -C works upon --autosquash with amend!' ' actual-squash-message ' +test_expect_success 'fixup -[Cc]<commit> works' ' + test_when_finished "test_might_fail git rebase --abort" && + cat >todo <<-\EOF && + pick A + fixup -CA1 + pick B + fixup -cA2 + EOF + ( + set_replace_editor todo && + FAKE_COMMIT_MESSAGE="edited and fixed up" \ + git rebase -i initial initial + ) && + git log --pretty=format:%B initial.. >actual && + cat >expect <<-EOF && + edited and fixed up + $EMPTY + new subject + $EMPTY + new + body + EOF + test_cmp expect actual +' + test_done diff --git a/t/t3438-rebase-broken-files.sh b/t/t3438-rebase-broken-files.sh index b92a3ce46b..c614c4f2e4 100755 --- a/t/t3438-rebase-broken-files.sh +++ b/t/t3438-rebase-broken-files.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='rebase behavior when on-disk files are broken' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'set up conflicting branches' ' diff --git a/t/t3500-cherry.sh b/t/t3500-cherry.sh index 0458a58b4b..78c3eac54b 100755 --- a/t/t3500-cherry.sh +++ b/t/t3500-cherry.sh @@ -16,46 +16,43 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME GIT_AUTHOR_EMAIL=bogus_email_address export GIT_AUTHOR_EMAIL -test_expect_success \ - 'prepare repository with topic branch, and check cherry finds the 2 patches from there' \ - 'echo First > A && - git update-index --add A && - test_tick && - git commit -m "Add A." && - - git checkout -b my-topic-branch && - - echo Second > B && - git update-index --add B && - test_tick && - git commit -m "Add B." && - - echo AnotherSecond > C && - git update-index --add C && - test_tick && - git commit -m "Add C." && - - git checkout -f main && - rm -f B C && - - echo Third >> A && - git update-index A && - test_tick && - git commit -m "Modify A." && - - expr "$(echo $(git cherry main my-topic-branch) )" : "+ [^ ]* + .*" +test_expect_success 'prepare repository with topic branch, and check cherry finds the 2 patches from there' ' + echo First > A && + git update-index --add A && + test_tick && + git commit -m "Add A." && + + git checkout -b my-topic-branch && + + echo Second > B && + git update-index --add B && + test_tick && + git commit -m "Add B." && + + echo AnotherSecond > C && + git update-index --add C && + test_tick && + git commit -m "Add C." && + + git checkout -f main && + rm -f B C && + + echo Third >> A && + git update-index A && + test_tick && + git commit -m "Modify A." && + + expr "$(echo $(git cherry main my-topic-branch) )" : "+ [^ ]* + .*" ' -test_expect_success \ - 'check that cherry with limit returns only the top patch'\ - 'expr "$(echo $(git cherry main my-topic-branch my-topic-branch^1) )" : "+ [^ ]*" +test_expect_success 'check that cherry with limit returns only the top patch' ' + expr "$(echo $(git cherry main my-topic-branch my-topic-branch^1) )" : "+ [^ ]*" ' -test_expect_success \ - 'cherry-pick one of the 2 patches, and check cherry recognized one and only one as new' \ - 'git cherry-pick my-topic-branch^0 && - echo $(git cherry main my-topic-branch) && - expr "$(echo $(git cherry main my-topic-branch) )" : "+ [^ ]* - .*" +test_expect_success 'cherry-pick one of the 2 patches, and check cherry recognized one and only one as new' ' + git cherry-pick my-topic-branch^0 && + echo $(git cherry main my-topic-branch) && + expr "$(echo $(git cherry main my-topic-branch) )" : "+ [^ ]* - .*" ' test_expect_success 'cherry ignores whitespace' ' diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh index 1f4cfc3744..4158590322 100755 --- a/t/t3501-revert-cherry-pick.sh +++ b/t/t3501-revert-cherry-pick.sh @@ -1,18 +1,11 @@ #!/bin/sh -test_description='test cherry-pick and revert with renames - - -- - + rename2: renames oops to opos - + rename1: renames oops to spoo - + added: adds extra line to oops - ++ initial: has lines in oops - -' +test_description='miscellaneous basic tests for cherry-pick and revert' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' @@ -62,6 +55,14 @@ test_expect_success 'revert --nonsense' ' test_i18ngrep "[Uu]sage:" msg ' +# the following two test cherry-pick and revert with renames +# +# -- +# + rename2: renames oops to opos +# + rename1: renames oops to spoo +# + added: adds extra line to oops +# ++ initial: has lines in oops + test_expect_success 'cherry-pick after renaming branch' ' git checkout rename2 && @@ -175,6 +176,29 @@ test_expect_success 'advice from failed revert' ' test_cmp expected actual ' +test_expect_subject () { + echo "$1" >expect && + git log -1 --pretty=%s >actual && + test_cmp expect actual +} + +test_expect_success 'titles of fresh reverts' ' + test_commit --no-tag A file1 && + test_commit --no-tag B file1 && + git revert --no-edit HEAD && + test_expect_subject "Revert \"B\"" && + git revert --no-edit HEAD && + test_expect_subject "Reapply \"B\"" && + git revert --no-edit HEAD && + test_expect_subject "Revert \"Reapply \"B\"\"" +' + +test_expect_success 'title of legacy double revert' ' + test_commit --no-tag "Revert \"Revert \"B\"\"" file1 && + git revert --no-edit HEAD && + test_expect_subject "Revert \"Revert \"Revert \"B\"\"\"" +' + test_expect_success 'identification of reverted commit (default)' ' test_commit to-ident && test_when_finished "git reset --hard to-ident" && diff --git a/t/t3502-cherry-pick-merge.sh b/t/t3502-cherry-pick-merge.sh index 5495eacfec..1b2c0d6aca 100755 --- a/t/t3502-cherry-pick-merge.sh +++ b/t/t3502-cherry-pick-merge.sh @@ -11,6 +11,7 @@ test_description='cherry picking and reverting a merge GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t3503-cherry-pick-root.sh b/t/t3503-cherry-pick-root.sh index 95fe4feaee..76d393dc8a 100755 --- a/t/t3503-cherry-pick-root.sh +++ b/t/t3503-cherry-pick-root.sh @@ -5,6 +5,7 @@ test_description='test cherry-picking (and reverting) a root commit' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t3506-cherry-pick-ff.sh b/t/t3506-cherry-pick-ff.sh index 7e11bd4a4c..b71bad17b8 100755 --- a/t/t3506-cherry-pick-ff.sh +++ b/t/t3506-cherry-pick-ff.sh @@ -5,6 +5,7 @@ test_description='test cherry-picking with --ff option' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t3511-cherry-pick-x.sh b/t/t3511-cherry-pick-x.sh index 84a587daf3..dd5d92ef30 100755 --- a/t/t3511-cherry-pick-x.sh +++ b/t/t3511-cherry-pick-x.sh @@ -2,6 +2,7 @@ test_description='Test cherry-pick -x and -s' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh pristine_detach () { diff --git a/t/t3700-add.sh b/t/t3700-add.sh index 8689b48589..7623689da2 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -24,17 +24,17 @@ test_mode_in_index () { esac } -test_expect_success \ - 'Test of git add' \ - 'touch foo && git add foo' +test_expect_success 'Test of git add' ' + touch foo && git add foo +' -test_expect_success \ - 'Post-check that foo is in the index' \ - 'git ls-files foo | grep foo' +test_expect_success 'Post-check that foo is in the index' ' + git ls-files foo | grep foo +' -test_expect_success \ - 'Test that "git add -- -q" works' \ - 'touch -- -q && git add -- -q' +test_expect_success 'Test that "git add -- -q" works' ' + touch -- -q && git add -- -q +' BATCH_CONFIGURATION='-c core.fsync=loose-object -c core.fsyncmethod=batch' @@ -106,24 +106,32 @@ test_expect_success '.gitignore test setup' ' test_expect_success '.gitignore is honored' ' git add . && - ! (git ls-files | grep "\\.ig") + git ls-files >files && + sed -n "/\\.ig/p" <files >actual && + test_must_be_empty actual ' test_expect_success 'error out when attempting to add ignored ones without -f' ' test_must_fail git add a.?? && - ! (git ls-files | grep "\\.ig") + git ls-files >files && + sed -n "/\\.ig/p" <files >actual && + test_must_be_empty actual ' test_expect_success 'error out when attempting to add ignored ones without -f' ' test_must_fail git add d.?? && - ! (git ls-files | grep "\\.ig") + git ls-files >files && + sed -n "/\\.ig/p" <files >actual && + test_must_be_empty actual ' test_expect_success 'error out when attempting to add ignored ones but add others' ' touch a.if && test_must_fail git add a.?? && - ! (git ls-files | grep "\\.ig") && - (git ls-files | grep a.if) + git ls-files >files && + sed -n "/\\.ig/p" <files >actual && + test_must_be_empty actual && + grep a.if files ' test_expect_success 'add ignored ones with -f' ' @@ -276,14 +284,14 @@ test_expect_success POSIXPERM,SANITY 'git add (add.ignore-errors = false)' ' rm -f foo2 test_expect_success POSIXPERM,SANITY '--no-ignore-errors overrides config' ' - git config add.ignore-errors 1 && - git reset --hard && - date >foo1 && - date >foo2 && - chmod 0 foo2 && - test_must_fail git add --verbose --no-ignore-errors . && - ! ( git ls-files foo1 | grep foo1 ) && - git config add.ignore-errors 0 + git config add.ignore-errors 1 && + git reset --hard && + date >foo1 && + date >foo2 && + chmod 0 foo2 && + test_must_fail git add --verbose --no-ignore-errors . && + ! ( git ls-files foo1 | grep foo1 ) && + git config add.ignore-errors 0 ' rm -f foo2 @@ -291,7 +299,7 @@ test_expect_success BSLASHPSPEC "git add 'fo\\[ou\\]bar' ignores foobar" ' git reset --hard && touch fo\[ou\]bar foobar && git add '\''fo\[ou\]bar'\'' && - git ls-files fo\[ou\]bar | fgrep fo\[ou\]bar && + git ls-files fo\[ou\]bar | grep -F fo\[ou\]bar && ! ( git ls-files foobar | grep foobar ) ' diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh index 5841f280fb..34aabb7f5f 100755 --- a/t/t3701-add-interactive.sh +++ b/t/t3701-add-interactive.sh @@ -7,12 +7,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . ./test-lib.sh . "$TEST_DIRECTORY"/lib-terminal.sh -if test_have_prereq !ADD_I_USE_BUILTIN,!PERL -then - skip_all='skipping add -i (scripted) tests, perl not available' - test_done -fi - diff_cmp () { for x do @@ -46,6 +40,21 @@ force_color () { ) } +test_expect_success 'warn about add.interactive.useBuiltin' ' + cat >expect <<-\EOF && + warning: the add.interactive.useBuiltin setting has been removed! + See its entry in '\''git help config'\'' for details. + No changes. + EOF + + for v in = =true =false + do + git -c "add.interactive.useBuiltin$v" add -p >out 2>actual && + test_must_be_empty out && + test_cmp expect actual || return 1 + done +' + test_expect_success 'setup (initial)' ' echo content >file && git add file && @@ -296,9 +305,11 @@ test_expect_success FILEMODE 'stage mode and hunk' ' echo content >>file && chmod +x file && printf "y\\ny\\n" | git add -p && - git diff --cached file | grep "new mode" && - git diff --cached file | grep "+content" && - test -z "$(git diff file)" + git diff --cached file >out && + grep "new mode" out && + grep "+content" out && + git diff file >out && + test_must_be_empty out ' # end of tests disabled when filemode is not usable @@ -547,15 +558,7 @@ test_expect_success 'split hunk "add -p (edit)"' ' ! grep "^+15" actual ' -test_expect_success 'setup ADD_I_USE_BUILTIN check' ' - result=success && - if ! test_have_prereq ADD_I_USE_BUILTIN - then - result=failure - fi -' - -test_expect_$result 'split hunk "add -p (no, yes, edit)"' ' +test_expect_success 'split hunk "add -p (no, yes, edit)"' ' test_write_lines 5 10 20 21 30 31 40 50 60 >test && git reset && # test sequence is s(plit), n(o), y(es), e(dit) @@ -579,7 +582,7 @@ test_expect_success 'split hunk with incomplete line at end' ' test_must_fail git grep --cached before ' -test_expect_$result 'edit, adding lines to the first hunk' ' +test_expect_success 'edit, adding lines to the first hunk' ' test_write_lines 10 11 20 30 40 50 51 60 >test && git reset && tr _ " " >patch <<-EOF && @@ -731,6 +734,44 @@ test_expect_success 'colors can be overridden' ' test_cmp expect actual ' +test_expect_success 'brackets appear without color' ' + git reset --hard && + test_when_finished "git rm -f bracket-test" && + test_write_lines context old more-context >bracket-test && + git add bracket-test && + test_write_lines context new more-context another-one >bracket-test && + + test_write_lines quit >input && + git add -i >actual <input && + + sed "s/^|//" >expect <<-\EOF && + | staged unstaged path + | 1: +3/-0 +2/-1 bracket-test + | + |*** Commands *** + | 1: [s]tatus 2: [u]pdate 3: [r]evert 4: [a]dd untracked + | 5: [p]atch 6: [d]iff 7: [q]uit 8: [h]elp + |What now> Bye. + EOF + + test_cmp expect actual +' + +test_expect_success 'colors can be skipped with color.ui=false' ' + git reset --hard && + test_when_finished "git rm -f color-test" && + test_write_lines context old more-context >color-test && + git add color-test && + test_write_lines context new more-context another-one >color-test && + + test_write_lines help quit >input && + force_color git \ + -c color.ui=false \ + add -i >actual.raw <input && + test_decode_color <actual.raw >actual && + test_cmp actual.raw actual +' + test_expect_success 'colorized diffs respect diff.wsErrorHighlight' ' git reset --hard && @@ -1068,4 +1109,25 @@ test_expect_success 'show help from add--helper' ' test_cmp expect actual ' +test_expect_success 'reset -p with unmerged files' ' + test_when_finished "git checkout --force main" && + test_commit one conflict && + git checkout -B side HEAD^ && + test_commit two conflict && + test_must_fail git merge one && + + # this is a noop with only an unmerged entry + git reset -p && + + # add files that sort before and after unmerged entry + echo a >a && + echo z >z && + git add a z && + + # confirm that we can reset those files + printf "%s\n" y y | git reset -p && + git diff-index --cached --diff-filter=u HEAD >staged && + test_must_be_empty staged +' + test_done diff --git a/t/t3702-add-edit.sh b/t/t3702-add-edit.sh index a1801a8cbd..82bfb2fd2a 100755 --- a/t/t3702-add-edit.sh +++ b/t/t3702-add-edit.sh @@ -100,7 +100,7 @@ EOF echo "#!$SHELL_PATH" >fake-editor.sh cat >> fake-editor.sh <<\EOF -egrep -v '^index' "$1" >orig-patch && +grep -E -v '^index' "$1" >orig-patch && mv -f patch "$1" EOF diff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh index e3cf0ffbe5..d3e428ff46 100755 --- a/t/t3800-mktag.sh +++ b/t/t3800-mktag.sh @@ -4,6 +4,7 @@ test_description='git mktag: tag object verify test' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh ########################################################### diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index 376cc8f4ab..0b3dfeaea2 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -1211,19 +1211,19 @@ test_expect_success 'stash with file including $IFS character' ' ' test_expect_success 'stash with pathspec matching multiple paths' ' - echo original >file && - echo original >other-file && - git commit -m "two" file other-file && - echo modified >file && - echo modified >other-file && - git stash push -- "*file" && - echo original >expect && - test_cmp expect file && - test_cmp expect other-file && - git stash pop && - echo modified >expect && - test_cmp expect file && - test_cmp expect other-file + echo original >file && + echo original >other-file && + git commit -m "two" file other-file && + echo modified >file && + echo modified >other-file && + git stash push -- "*file" && + echo original >expect && + test_cmp expect file && + test_cmp expect other-file && + git stash pop && + echo modified >expect && + test_cmp expect file && + test_cmp expect other-file ' test_expect_success 'stash push -p with pathspec shows no changes only once' ' 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/t4000-diff-format.sh b/t/t4000-diff-format.sh index bfcaae390f..8d50331b8c 100755 --- a/t/t4000-diff-format.sh +++ b/t/t4000-diff-format.sh @@ -5,6 +5,9 @@ test_description='Test built-in diff output engine. +We happen to know that all diff plumbing and diff Porcelain share the +same command line parser, so testing one should be sufficient; pick +diff-files as a representative. ' TEST_PASSES_SANITIZE_LEAK=true @@ -16,9 +19,11 @@ Line 2 line 3' cat path0 >path1 chmod +x path1 +mkdir path2 +>path2/path3 test_expect_success 'update-index --add two files with and without +x.' ' - git update-index --add path0 path1 + git update-index --add path0 path1 path2/path3 ' mv path0 path0- @@ -91,4 +96,31 @@ test_expect_success 'git diff-files --patch --no-patch does not show the patch' test_must_be_empty err ' + +# Smudge path2/path3 so that dirstat has something to show +date >path2/path3 + +for format in stat raw numstat shortstat summary \ + dirstat cumulative dirstat-by-file \ + patch-with-raw patch-with-stat compact-summary +do + test_expect_success "--no-patch in 'git diff-files --no-patch --$format' is a no-op" ' + git diff-files --no-patch "--$format" >actual && + git diff-files "--$format" >expect && + test_cmp expect actual + ' + + test_expect_success "--no-patch clears all previous ones" ' + git diff-files --$format -s -p >actual && + git diff-files -p >expect && + test_cmp expect actual + ' + + test_expect_success "--no-patch in 'git diff --no-patch --$format' is a no-op" ' + git diff --no-patch "--$format" >actual && + git diff "--$format" >expect && + test_cmp expect actual + ' +done + test_done diff --git a/t/t4002-diff-basic.sh b/t/t4002-diff-basic.sh index ea52e5b91b..7afc883ec3 100755 --- a/t/t4002-diff-basic.sh +++ b/t/t4002-diff-basic.sh @@ -284,132 +284,131 @@ cmp_diff_files_output () { test_cmp "$1" .test-tmp } -test_expect_success \ - 'diff-tree of known trees.' \ - 'git diff-tree $tree_O $tree_A >.test-a && - cmp -s .test-a .test-plain-OA' - -test_expect_success \ - 'diff-tree of known trees.' \ - 'git diff-tree -r $tree_O $tree_A >.test-a && - cmp -s .test-a .test-recursive-OA' - -test_expect_success \ - 'diff-tree of known trees.' \ - 'git diff-tree $tree_O $tree_B >.test-a && - cmp -s .test-a .test-plain-OB' - -test_expect_success \ - 'diff-tree of known trees.' \ - 'git diff-tree -r $tree_O $tree_B >.test-a && - cmp -s .test-a .test-recursive-OB' - -test_expect_success \ - 'diff-tree of known trees.' \ - 'git diff-tree $tree_A $tree_B >.test-a && - cmp -s .test-a .test-plain-AB' - -test_expect_success \ - 'diff-tree of known trees.' \ - 'git diff-tree -r $tree_A $tree_B >.test-a && - cmp -s .test-a .test-recursive-AB' - -test_expect_success \ - 'diff-tree --stdin of known trees.' \ - 'echo $tree_A $tree_B | git diff-tree --stdin > .test-a && - echo $tree_A $tree_B > .test-plain-ABx && - cat .test-plain-AB >> .test-plain-ABx && - cmp -s .test-a .test-plain-ABx' - -test_expect_success \ - 'diff-tree --stdin of known trees.' \ - 'echo $tree_A $tree_B | git diff-tree -r --stdin > .test-a && - echo $tree_A $tree_B > .test-recursive-ABx && - cat .test-recursive-AB >> .test-recursive-ABx && - cmp -s .test-a .test-recursive-ABx' - -test_expect_success \ - 'diff-cache O with A in cache' \ - 'git read-tree $tree_A && - git diff-index --cached $tree_O >.test-a && - cmp -s .test-a .test-recursive-OA' - -test_expect_success \ - 'diff-cache O with B in cache' \ - 'git read-tree $tree_B && - git diff-index --cached $tree_O >.test-a && - cmp -s .test-a .test-recursive-OB' - -test_expect_success \ - 'diff-cache A with B in cache' \ - 'git read-tree $tree_B && - git diff-index --cached $tree_A >.test-a && - cmp -s .test-a .test-recursive-AB' - -test_expect_success \ - 'diff-files with O in cache and A checked out' \ - 'rm -fr Z [A-Z][A-Z] && - git read-tree $tree_A && - git checkout-index -f -a && - git read-tree --reset $tree_O && - test_must_fail git update-index --refresh -q && - git diff-files >.test-a && - cmp_diff_files_output .test-a .test-recursive-OA' - -test_expect_success \ - 'diff-files with O in cache and B checked out' \ - 'rm -fr Z [A-Z][A-Z] && - git read-tree $tree_B && - git checkout-index -f -a && - git read-tree --reset $tree_O && - test_must_fail git update-index --refresh -q && - git diff-files >.test-a && - cmp_diff_files_output .test-a .test-recursive-OB' - -test_expect_success \ - 'diff-files with A in cache and B checked out' \ - 'rm -fr Z [A-Z][A-Z] && - git read-tree $tree_B && - git checkout-index -f -a && - git read-tree --reset $tree_A && - test_must_fail git update-index --refresh -q && - git diff-files >.test-a && - cmp_diff_files_output .test-a .test-recursive-AB' +test_expect_success 'diff-tree of known trees.' ' + git diff-tree $tree_O $tree_A >.test-a && + cmp -s .test-a .test-plain-OA +' + +test_expect_success 'diff-tree of known trees.' ' + git diff-tree -r $tree_O $tree_A >.test-a && + cmp -s .test-a .test-recursive-OA +' + +test_expect_success 'diff-tree of known trees.' ' + git diff-tree $tree_O $tree_B >.test-a && + cmp -s .test-a .test-plain-OB +' + +test_expect_success 'diff-tree of known trees.' ' + git diff-tree -r $tree_O $tree_B >.test-a && + cmp -s .test-a .test-recursive-OB +' + +test_expect_success 'diff-tree of known trees.' ' + git diff-tree $tree_A $tree_B >.test-a && + cmp -s .test-a .test-plain-AB +' + +test_expect_success 'diff-tree of known trees.' ' + git diff-tree -r $tree_A $tree_B >.test-a && + cmp -s .test-a .test-recursive-AB +' + +test_expect_success 'diff-tree --stdin of known trees.' ' + echo $tree_A $tree_B | git diff-tree --stdin > .test-a && + echo $tree_A $tree_B > .test-plain-ABx && + cat .test-plain-AB >> .test-plain-ABx && + cmp -s .test-a .test-plain-ABx +' + +test_expect_success 'diff-tree --stdin of known trees.' ' + echo $tree_A $tree_B | git diff-tree -r --stdin > .test-a && + echo $tree_A $tree_B > .test-recursive-ABx && + cat .test-recursive-AB >> .test-recursive-ABx && + cmp -s .test-a .test-recursive-ABx +' + +test_expect_success 'diff-cache O with A in cache' ' + git read-tree $tree_A && + git diff-index --cached $tree_O >.test-a && + cmp -s .test-a .test-recursive-OA +' + +test_expect_success 'diff-cache O with B in cache' ' + git read-tree $tree_B && + git diff-index --cached $tree_O >.test-a && + cmp -s .test-a .test-recursive-OB +' + +test_expect_success 'diff-cache A with B in cache' ' + git read-tree $tree_B && + git diff-index --cached $tree_A >.test-a && + cmp -s .test-a .test-recursive-AB +' + +test_expect_success 'diff-files with O in cache and A checked out' ' + rm -fr Z [A-Z][A-Z] && + git read-tree $tree_A && + git checkout-index -f -a && + git read-tree --reset $tree_O && + test_must_fail git update-index --refresh -q && + git diff-files >.test-a && + cmp_diff_files_output .test-a .test-recursive-OA +' + +test_expect_success 'diff-files with O in cache and B checked out' ' + rm -fr Z [A-Z][A-Z] && + git read-tree $tree_B && + git checkout-index -f -a && + git read-tree --reset $tree_O && + test_must_fail git update-index --refresh -q && + git diff-files >.test-a && + cmp_diff_files_output .test-a .test-recursive-OB +' + +test_expect_success 'diff-files with A in cache and B checked out' ' + rm -fr Z [A-Z][A-Z] && + git read-tree $tree_B && + git checkout-index -f -a && + git read-tree --reset $tree_A && + test_must_fail git update-index --refresh -q && + git diff-files >.test-a && + cmp_diff_files_output .test-a .test-recursive-AB +' ################################################################ # Now we have established the baseline, we do not have to # rely on individual object ID values that much. -test_expect_success \ - 'diff-tree O A == diff-tree -R A O' \ - 'git diff-tree $tree_O $tree_A >.test-a && - git diff-tree -R $tree_A $tree_O >.test-b && - cmp -s .test-a .test-b' - -test_expect_success \ - 'diff-tree -r O A == diff-tree -r -R A O' \ - 'git diff-tree -r $tree_O $tree_A >.test-a && - git diff-tree -r -R $tree_A $tree_O >.test-b && - cmp -s .test-a .test-b' - -test_expect_success \ - 'diff-tree B A == diff-tree -R A B' \ - 'git diff-tree $tree_B $tree_A >.test-a && - git diff-tree -R $tree_A $tree_B >.test-b && - cmp -s .test-a .test-b' - -test_expect_success \ - 'diff-tree -r B A == diff-tree -r -R A B' \ - 'git diff-tree -r $tree_B $tree_A >.test-a && - git diff-tree -r -R $tree_A $tree_B >.test-b && - cmp -s .test-a .test-b' - -test_expect_success \ - 'diff can read from stdin' \ - 'test_must_fail git diff --no-index -- MN - < NN | - grep -v "^index" | sed "s#/-#/NN#" >.test-a && - test_must_fail git diff --no-index -- MN NN | - grep -v "^index" >.test-b && - test_cmp .test-a .test-b' +test_expect_success 'diff-tree O A == diff-tree -R A O' ' + git diff-tree $tree_O $tree_A >.test-a && + git diff-tree -R $tree_A $tree_O >.test-b && + cmp -s .test-a .test-b +' + +test_expect_success 'diff-tree -r O A == diff-tree -r -R A O' ' + git diff-tree -r $tree_O $tree_A >.test-a && + git diff-tree -r -R $tree_A $tree_O >.test-b && + cmp -s .test-a .test-b +' + +test_expect_success 'diff-tree B A == diff-tree -R A B' ' + git diff-tree $tree_B $tree_A >.test-a && + git diff-tree -R $tree_A $tree_B >.test-b && + cmp -s .test-a .test-b +' + +test_expect_success 'diff-tree -r B A == diff-tree -r -R A B' ' + git diff-tree -r $tree_B $tree_A >.test-a && + git diff-tree -r -R $tree_A $tree_B >.test-b && + cmp -s .test-a .test-b' + +test_expect_success 'diff can read from stdin' ' + test_must_fail git diff --no-index -- MN - < NN | + grep -v "^index" | sed "s#/-#/NN#" >.test-a && + test_must_fail git diff --no-index -- MN NN | + grep -v "^index" >.test-b && + test_cmp .test-a .test-b +' test_done diff --git a/t/t4003-diff-rename-1.sh b/t/t4003-diff-rename-1.sh index 181e9683a7..ebe091828c 100755 --- a/t/t4003-diff-rename-1.sh +++ b/t/t4003-diff-rename-1.sh @@ -11,20 +11,20 @@ TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-diff.sh ;# test-lib chdir's into trash -test_expect_success \ - 'prepare reference tree' \ - 'COPYING_test_data >COPYING && - echo frotz >rezrov && - git update-index --add COPYING rezrov && - tree=$(git write-tree) && - echo $tree' - -test_expect_success \ - 'prepare work tree' \ - 'sed -e 's/HOWEVER/However/' <COPYING >COPYING.1 && - sed -e 's/GPL/G.P.L/g' <COPYING >COPYING.2 && - rm -f COPYING && - git update-index --add --remove COPYING COPYING.?' +test_expect_success 'prepare reference tree' ' + COPYING_test_data >COPYING && + echo frotz >rezrov && + git update-index --add COPYING rezrov && + tree=$(git write-tree) && + echo $tree +' + +test_expect_success 'prepare work tree' ' + sed -e 's/HOWEVER/However/' <COPYING >COPYING.1 && + sed -e 's/GPL/G.P.L/g' <COPYING >COPYING.2 && + rm -f COPYING && + git update-index --add --remove COPYING COPYING.? +' # tree has COPYING and rezrov. work tree has COPYING.1 and COPYING.2, # both are slightly edited, and unchanged rezrov. So we say you @@ -57,14 +57,14 @@ rename to COPYING.2 + This file is licensed under the G.P.L v2, or a later version EOF -test_expect_success \ - 'validate output from rename/copy detection (#1)' \ - 'compare_diff_patch current expected' +test_expect_success 'validate output from rename/copy detection (#1)' ' + compare_diff_patch current expected +' -test_expect_success \ - 'prepare work tree again' \ - 'mv COPYING.2 COPYING && - git update-index --add --remove COPYING COPYING.1 COPYING.2' +test_expect_success 'prepare work tree again' ' + mv COPYING.2 COPYING && + git update-index --add --remove COPYING COPYING.1 COPYING.2 +' # tree has COPYING and rezrov. work tree has COPYING and COPYING.1, # both are slightly edited, and unchanged rezrov. So we say you @@ -95,14 +95,14 @@ copy to COPYING.1 + However, in order to allow a migration to GPLv3 if that seems like EOF -test_expect_success \ - 'validate output from rename/copy detection (#2)' \ - 'compare_diff_patch current expected' +test_expect_success 'validate output from rename/copy detection (#2)' ' + compare_diff_patch current expected +' -test_expect_success \ - 'prepare work tree once again' \ - 'COPYING_test_data >COPYING && - git update-index --add --remove COPYING COPYING.1' +test_expect_success 'prepare work tree once again' ' + COPYING_test_data >COPYING && + git update-index --add --remove COPYING COPYING.1 +' # tree has COPYING and rezrov. work tree has COPYING and COPYING.1, # but COPYING is not edited. We say you copy-and-edit COPYING.1; this @@ -123,8 +123,8 @@ copy to COPYING.1 + However, in order to allow a migration to GPLv3 if that seems like EOF -test_expect_success \ - 'validate output from rename/copy detection (#3)' \ - 'compare_diff_patch current expected' +test_expect_success 'validate output from rename/copy detection (#3)' ' + compare_diff_patch current expected +' test_done diff --git a/t/t4004-diff-rename-symlink.sh b/t/t4004-diff-rename-symlink.sh index 8def4d4aee..1d70d4d221 100755 --- a/t/t4004-diff-rename-symlink.sh +++ b/t/t4004-diff-rename-symlink.sh @@ -14,21 +14,21 @@ TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-diff.sh -test_expect_success SYMLINKS \ - 'prepare reference tree' \ - 'echo xyzzy | tr -d '\\\\'012 >yomin && - ln -s xyzzy frotz && - git update-index --add frotz yomin && - tree=$(git write-tree) && - echo $tree' +test_expect_success SYMLINKS 'prepare reference tree' ' + echo xyzzy | tr -d '\\\\'012 >yomin && + ln -s xyzzy frotz && + git update-index --add frotz yomin && + tree=$(git write-tree) && + echo $tree +' -test_expect_success SYMLINKS \ - 'prepare work tree' \ - 'mv frotz rezrov && - rm -f yomin && - ln -s xyzzy nitfol && - ln -s xzzzy bozbar && - git update-index --add --remove frotz rezrov nitfol bozbar yomin' +test_expect_success SYMLINKS 'prepare work tree' ' + mv frotz rezrov && + rm -f yomin && + ln -s xyzzy nitfol && + ln -s xzzzy bozbar && + git update-index --add --remove frotz rezrov nitfol bozbar yomin +' # tree has frotz pointing at xyzzy, and yomin that contains xyzzy to # confuse things. work tree has rezrov (xyzzy) nitfol (xyzzy) and @@ -36,9 +36,9 @@ test_expect_success SYMLINKS \ # rezrov and nitfol are rename/copy of frotz and bozbar should be # a new creation. -test_expect_success SYMLINKS 'setup diff output' " - GIT_DIFF_OPTS=--unified=0 git diff-index -C -p $tree >current && - cat >expected <<\EOF +test_expect_success SYMLINKS 'setup diff output' ' + GIT_DIFF_OPTS=--unified=0 git diff-index -C -p $tree >current && + cat >expected <<\EOF diff --git a/bozbar b/bozbar new file mode 120000 --- /dev/null @@ -62,10 +62,10 @@ deleted file mode 100644 -xyzzy \ No newline at end of file EOF -" +' -test_expect_success SYMLINKS \ - 'validate diff output' \ - 'compare_diff_patch current expected' +test_expect_success SYMLINKS 'validate diff output' ' + compare_diff_patch current expected +' test_done diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh index c509143c81..c64d9d2f40 100755 --- a/t/t4012-diff-binary.sh +++ b/t/t4012-diff-binary.sh @@ -113,20 +113,20 @@ test_expect_success 'diff --no-index with binary creation' ' ' cat >expect <<EOF - binfile | Bin 0 -> 1026 bytes - textfile | 10000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + binfilë | Bin 0 -> 1026 bytes + tëxtfilë | 10000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ EOF test_expect_success 'diff --stat with binary files and big change count' ' - printf "\01\00%1024d" 1 >binfile && - git add binfile && + printf "\01\00%1024d" 1 >binfilë && + git add binfilë && i=0 && while test $i -lt 10000; do echo $i && i=$(($i + 1)) || return 1 - done >textfile && - git add textfile && - git diff --cached --stat binfile textfile >output && + done >tëxtfilë && + git add tëxtfilë && + git -c core.quotepath=false diff --cached --stat binfilë tëxtfilë >output && grep " | " output >actual && test_cmp expect actual ' diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index dfcf3a0aaa..5de1d19075 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -616,4 +616,46 @@ test_expect_success 'diff -I<regex>: detect malformed regex' ' test_i18ngrep "invalid regex given to -I: " error ' +# check_prefix <patch> <src> <dst> +# check only lines with paths to avoid dependency on exact oid/contents +check_prefix () { + grep -E '^(diff|---|\+\+\+) ' "$1" >actual.paths && + cat >expect <<-EOF && + diff --git $2 $3 + --- $2 + +++ $3 + EOF + test_cmp expect actual.paths +} + +test_expect_success 'diff-files does not respect diff.noprefix' ' + git -c diff.noprefix diff-files -p >actual && + check_prefix actual a/file0 b/file0 +' + +test_expect_success 'diff-files respects --no-prefix' ' + git diff-files -p --no-prefix >actual && + check_prefix actual file0 file0 +' + +test_expect_success 'diff respects diff.noprefix' ' + git -c diff.noprefix diff >actual && + check_prefix actual file0 file0 +' + +test_expect_success 'diff --default-prefix overrides diff.noprefix' ' + git -c diff.noprefix diff --default-prefix >actual && + check_prefix actual a/file0 b/file0 +' + +test_expect_success 'diff respects diff.mnemonicprefix' ' + git -c diff.mnemonicprefix diff >actual && + check_prefix actual i/file0 w/file0 +' + +test_expect_success 'diff --default-prefix overrides diff.mnemonicprefix' ' + git -c diff.mnemonicprefix diff --default-prefix >actual && + check_prefix actual a/file0 b/file0 +' + test_done diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index ad5c029279..0a4ab36c3a 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -59,6 +59,10 @@ test_expect_success setup ' test_tick && git commit -m "patchid 3" && + git checkout -b empty main && + test_tick && + git commit --allow-empty -m "empty commit" && + git checkout main ' @@ -128,6 +132,12 @@ test_expect_success 'replay did not screw up the log message' ' grep "^Side .* with .* backslash-n" actual ' +test_expect_success 'format-patch empty commit' ' + git format-patch --stdout main..empty >empty && + grep "^From " empty >from && + test_line_count = 1 from +' + test_expect_success 'extra headers' ' git config format.headers "To: R E Cipient <rcipient@example.com> " && @@ -445,13 +455,13 @@ test_expect_success 'no threading' ' cat >expect.thread <<EOF --- -Message-Id: <0> +Message-ID: <0> --- -Message-Id: <1> +Message-ID: <1> In-Reply-To: <0> References: <0> --- -Message-Id: <2> +Message-ID: <2> In-Reply-To: <0> References: <0> EOF @@ -460,17 +470,22 @@ test_expect_success 'thread' ' check_threading expect.thread --thread main ' +test_expect_success '--thread overrides format.thread=deep' ' + test_config format.thread deep && + check_threading expect.thread --thread main +' + cat >expect.in-reply-to <<EOF --- -Message-Id: <0> +Message-ID: <0> In-Reply-To: <1> References: <1> --- -Message-Id: <2> +Message-ID: <2> In-Reply-To: <1> References: <1> --- -Message-Id: <3> +Message-ID: <3> In-Reply-To: <1> References: <1> EOF @@ -482,17 +497,17 @@ test_expect_success 'thread in-reply-to' ' cat >expect.cover-letter <<EOF --- -Message-Id: <0> +Message-ID: <0> --- -Message-Id: <1> +Message-ID: <1> In-Reply-To: <0> References: <0> --- -Message-Id: <2> +Message-ID: <2> In-Reply-To: <0> References: <0> --- -Message-Id: <3> +Message-ID: <3> In-Reply-To: <0> References: <0> EOF @@ -503,21 +518,21 @@ test_expect_success 'thread cover-letter' ' cat >expect.cl-irt <<EOF --- -Message-Id: <0> +Message-ID: <0> In-Reply-To: <1> References: <1> --- -Message-Id: <2> +Message-ID: <2> In-Reply-To: <0> References: <1> <0> --- -Message-Id: <3> +Message-ID: <3> In-Reply-To: <0> References: <1> <0> --- -Message-Id: <4> +Message-ID: <4> In-Reply-To: <0> References: <1> <0> @@ -535,13 +550,13 @@ test_expect_success 'thread explicit shallow' ' cat >expect.deep <<EOF --- -Message-Id: <0> +Message-ID: <0> --- -Message-Id: <1> +Message-ID: <1> In-Reply-To: <0> References: <0> --- -Message-Id: <2> +Message-ID: <2> In-Reply-To: <1> References: <0> <1> @@ -553,16 +568,16 @@ test_expect_success 'thread deep' ' cat >expect.deep-irt <<EOF --- -Message-Id: <0> +Message-ID: <0> In-Reply-To: <1> References: <1> --- -Message-Id: <2> +Message-ID: <2> In-Reply-To: <0> References: <1> <0> --- -Message-Id: <3> +Message-ID: <3> In-Reply-To: <2> References: <1> <0> @@ -576,18 +591,18 @@ test_expect_success 'thread deep in-reply-to' ' cat >expect.deep-cl <<EOF --- -Message-Id: <0> +Message-ID: <0> --- -Message-Id: <1> +Message-ID: <1> In-Reply-To: <0> References: <0> --- -Message-Id: <2> +Message-ID: <2> In-Reply-To: <1> References: <0> <1> --- -Message-Id: <3> +Message-ID: <3> In-Reply-To: <2> References: <0> <1> @@ -600,22 +615,22 @@ test_expect_success 'thread deep cover-letter' ' cat >expect.deep-cl-irt <<EOF --- -Message-Id: <0> +Message-ID: <0> In-Reply-To: <1> References: <1> --- -Message-Id: <2> +Message-ID: <2> In-Reply-To: <0> References: <1> <0> --- -Message-Id: <3> +Message-ID: <3> In-Reply-To: <2> References: <1> <0> <2> --- -Message-Id: <4> +Message-ID: <4> In-Reply-To: <3> References: <1> <0> @@ -1358,7 +1373,27 @@ test_expect_success '--rfc' ' Subject: [RFC PATCH 1/1] header with . in it EOF git format-patch -n -1 --stdout --rfc >patch && - grep ^Subject: patch >actual && + grep "^Subject:" patch >actual && + test_cmp expect actual +' + +test_expect_success '--rfc does not overwrite prefix' ' + cat >expect <<-\EOF && + Subject: [RFC PATCH foobar 1/1] header with . in it + EOF + git -c format.subjectPrefix="PATCH foobar" \ + format-patch -n -1 --stdout --rfc >patch && + grep "^Subject:" patch >actual && + test_cmp expect actual +' + +test_expect_success '--rfc is argument order independent' ' + cat >expect <<-\EOF && + Subject: [RFC PATCH foobar 1/1] header with . in it + EOF + git format-patch -n -1 --stdout --rfc \ + --subject-prefix="PATCH foobar" >patch && + grep "^Subject:" patch >actual && test_cmp expect actual ' @@ -1457,7 +1492,7 @@ append_signoff() C=$(git commit-tree HEAD^^{tree} -p HEAD) && git format-patch --stdout --signoff $C^..$C >append_signoff.patch && sed -n -e "1,/^---$/p" append_signoff.patch | - egrep -n "^Subject|Sign|^$" + grep -E -n "^Subject|Sign|^$" } test_expect_success 'signoff: commit with no body' ' @@ -1976,6 +2011,20 @@ test_expect_success 'cover letter using branch description (6)' ' grep hello actual ' +test_expect_success 'cover letter with --description-file' ' + test_when_finished "rm -f description.txt" && + cat >description.txt <<-\EOF && + subject from file + + body from file + EOF + git checkout rebuild-1 && + git format-patch --stdout --cover-letter --cover-from-description auto \ + --description-file description.txt main >actual && + grep "^Subject: \[PATCH 0/2\] subject from file$" actual && + grep "^body from file$" actual +' + test_expect_success 'cover letter with nothing' ' git format-patch --stdout --cover-letter >actual && test_line_count = 0 actual @@ -2274,14 +2323,32 @@ test_expect_success 'format-patch --base with --attach' ' test_expect_success 'format-patch --attach cover-letter only is non-multipart' ' test_when_finished "rm -fr patches" && git format-patch -o patches --cover-letter --attach=mimemime --base=HEAD~ -1 && - ! egrep "^--+mimemime" patches/0000*.patch && - egrep "^--+mimemime$" patches/0001*.patch >output && + ! grep -E "^--+mimemime" patches/0000*.patch && + grep -E "^--+mimemime$" patches/0001*.patch >output && test_line_count = 2 output && - egrep "^--+mimemime--$" patches/0001*.patch >output && + grep -E "^--+mimemime--$" patches/0001*.patch >output && test_line_count = 1 output ' -test_expect_success 'format-patch --pretty=mboxrd' ' +test_expect_success 'format-patch with format.attach' ' + test_when_finished "rm -fr patches" && + separator=attachment-separator && + test_config format.attach "$separator" && + filename=$(git format-patch -o patches -1) && + grep "^Content-Type: multipart/.*$separator" "$filename" +' + +test_expect_success 'format-patch with format.attach=disabled' ' + test_when_finished "rm -fr patches" && + separator=attachment-separator && + test_config_global format.attach "$separator" && + test_config format.attach "" && + filename=$(git format-patch -o patches -1) && + # The output should not even declare content type for text/plain. + ! grep "^Content-Type: multipart/" "$filename" +' + +test_expect_success '-c format.mboxrd format-patch' ' sp=" " && cat >msg <<-INPUT_END && mboxrd should escape the body @@ -2316,7 +2383,9 @@ test_expect_success 'format-patch --pretty=mboxrd' ' INPUT_END C=$(git commit-tree HEAD^^{tree} -p HEAD <msg) && - git format-patch --pretty=mboxrd --stdout -1 $C~1..$C >patch && + git -c format.mboxrd format-patch --stdout -1 $C~1..$C >patch && + git format-patch --pretty=mboxrd --stdout -1 $C~1..$C >compat && + test_cmp patch compat && git grep -h --no-index -A11 \ "^>From could trip up a loose mbox parser" patch >actual && test_cmp expect actual @@ -2366,4 +2435,20 @@ test_expect_success 'interdiff: solo-patch' ' test_cmp expect actual ' +test_expect_success 'format-patch does not respect diff.noprefix' ' + git -c diff.noprefix format-patch -1 --stdout >actual && + grep "^--- a/blorp" actual +' + +test_expect_success 'format-patch respects format.noprefix' ' + git -c format.noprefix format-patch -1 --stdout >actual && + grep "^--- blorp" actual +' + +test_expect_success 'format-patch --default-prefix overrides format.noprefix' ' + git -c format.noprefix \ + format-patch -1 --default-prefix --stdout >actual && + grep "^--- a/blorp" actual +' + test_done diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index f3e20dd5bb..fcd2473e52 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -1,7 +1,7 @@ #!/bin/sh # # Copyright (c) 2006 Johannes E. Schindelin -# +# Copyright (c) 2023 Google LLC test_description='Test special whitespace in diff engine. @@ -11,6 +11,43 @@ TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-diff.sh +for opt_res in --patch --quiet -s --stat --shortstat --dirstat=lines \ + --raw! --name-only! --name-status! +do + opts=${opt_res%!} expect_failure= + test "$opts" = "$opt_res" || + expect_failure="test_expect_code 1" + + test_expect_success "status with $opts (different)" ' + echo foo >x && + git add x && + echo bar >x && + test_expect_code 1 git diff -w $opts --exit-code x + ' + + test_expect_success POSIXPERM "status with $opts (mode differs)" ' + test_when_finished "git update-index --chmod=-x x" && + echo foo >x && + git add x && + git update-index --chmod=+x x && + test_expect_code 1 git diff -w $opts --exit-code x + ' + + test_expect_success "status with $opts (removing an empty file)" ' + : >x && + git add x && + rm x && + test_expect_code 1 git diff -w $opts --exit-code -- x + ' + + test_expect_success "status with $opts (different but equivalent)" ' + echo foo >x && + git add x && + echo " foo" >x && + $expect_failure git diff -w $opts --exit-code x + ' +done + test_expect_success "Ray Lehtiniemi's example" ' cat <<-\EOF >x && do { @@ -1638,7 +1675,7 @@ test_expect_success 'no effect on diff from --color-moved with --word-diff' ' test_cmp expect actual ' -test_expect_success !SANITIZE_LEAK 'no effect on show from --color-moved with --word-diff' ' +test_expect_success 'no effect on show from --color-moved with --word-diff' ' git show --color-moved --word-diff >actual && git show --word-diff >expect && test_cmp expect actual @@ -2024,7 +2061,7 @@ test_expect_success '--color-moved rewinds for MIN_ALNUM_COUNT' ' test_cmp expected actual ' -test_expect_success !SANITIZE_LEAK 'move detection with submodules' ' +test_expect_success 'move detection with submodules' ' test_create_repo bananas && echo ripe >bananas/recipe && git -C bananas add recipe && diff --git a/t/t4017-diff-retval.sh b/t/t4017-diff-retval.sh index 5bc28ad9f0..f439f469bd 100755 --- a/t/t4017-diff-retval.sh +++ b/t/t4017-diff-retval.sh @@ -138,4 +138,9 @@ test_expect_success 'check honors conflict marker length' ' git reset --hard ' +test_expect_success 'option errors are not confused by --exit-code' ' + test_must_fail git diff --exit-code --nonsense 2>err && + grep '^usage:' err +' + test_done diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh index 42a2b9a13b..c8d555771d 100755 --- a/t/t4018-diff-funcname.sh +++ b/t/t4018-diff-funcname.sh @@ -63,6 +63,25 @@ do test_i18ngrep ! fatal msg && test_i18ngrep ! error msg ' + + test_expect_success "builtin $p pattern compiles on bare repo with --attr-source" ' + test_when_finished "rm -rf bare.git" && + git checkout -B master && + git add . && + echo "*.java diff=notexist" >.gitattributes && + git add .gitattributes && + git commit -am "changing gitattributes" && + git checkout -B branchA && + echo "*.java diff=$p" >.gitattributes && + git add .gitattributes && + git commit -am "changing gitattributes" && + git clone --bare --no-local . bare.git && + git -C bare.git symbolic-ref HEAD refs/heads/master && + test_expect_code 1 git -C bare.git --attr-source=branchA \ + diff --exit-code HEAD:A.java HEAD:B.java 2>msg && + test_i18ngrep ! fatal msg && + test_i18ngrep ! error msg + ' done test_expect_success 'last regexp must not be negated' ' diff --git a/t/t4018/java-class-brace-on-separate-line b/t/t4018/java-class-brace-on-separate-line new file mode 100644 index 0000000000..8795acd4cf --- /dev/null +++ b/t/t4018/java-class-brace-on-separate-line @@ -0,0 +1,6 @@ +class RIGHT +{ + static int ONE; + static int TWO; + static int ChangeMe; +} diff --git a/t/t4018/java-class-space-before-type-parameters b/t/t4018/java-class-space-before-type-parameters new file mode 100644 index 0000000000..0bdef1dfbe --- /dev/null +++ b/t/t4018/java-class-space-before-type-parameters @@ -0,0 +1,6 @@ +class RIGHT <TYPE, PARAMS, AFTER, SPACE> { + static int ONE; + static int TWO; + static int THREE; + private A ChangeMe; +} diff --git a/t/t4018/java-class-type-parameters b/t/t4018/java-class-type-parameters new file mode 100644 index 0000000000..579aa7af21 --- /dev/null +++ b/t/t4018/java-class-type-parameters @@ -0,0 +1,6 @@ +class RIGHT<A, B> { + static int ONE; + static int TWO; + static int THREE; + private A ChangeMe; +} diff --git a/t/t4018/java-class-type-parameters-implements b/t/t4018/java-class-type-parameters-implements new file mode 100644 index 0000000000..b8038b1866 --- /dev/null +++ b/t/t4018/java-class-type-parameters-implements @@ -0,0 +1,6 @@ +class RIGHT<A, B> implements List<A> { + static int ONE; + static int TWO; + static int THREE; + private A ChangeMe; +} diff --git a/t/t4018/java-interface-type-parameters b/t/t4018/java-interface-type-parameters new file mode 100644 index 0000000000..a4baa1ae68 --- /dev/null +++ b/t/t4018/java-interface-type-parameters @@ -0,0 +1,6 @@ +interface RIGHT<A, B> { + static int ONE; + static int TWO; + static int THREE; + public B foo(A ChangeMe); +} diff --git a/t/t4018/java-interface-type-parameters-extends b/t/t4018/java-interface-type-parameters-extends new file mode 100644 index 0000000000..31d7fb3244 --- /dev/null +++ b/t/t4018/java-interface-type-parameters-extends @@ -0,0 +1,6 @@ +interface RIGHT<A, B> extends Function<A, B> { + static int ONE; + static int TWO; + static int THREE; + public B foo(A ChangeMe); +} diff --git a/t/t4018/java-non-sealed b/t/t4018/java-non-sealed new file mode 100644 index 0000000000..069087c1c6 --- /dev/null +++ b/t/t4018/java-non-sealed @@ -0,0 +1,8 @@ +public abstract sealed class SealedClass { + public static non-sealed class RIGHT extends SealedClass { + static int ONE; + static int TWO; + static int THREE; + private int ChangeMe; + } +} diff --git a/t/t4018/java-record b/t/t4018/java-record new file mode 100644 index 0000000000..97aa819dd8 --- /dev/null +++ b/t/t4018/java-record @@ -0,0 +1,6 @@ +public record RIGHT(int comp1, double comp2, String comp3) { + static int ONE; + static int TWO; + static int THREE; + static int ChangeMe; +} diff --git a/t/t4018/java-record-space-before-components b/t/t4018/java-record-space-before-components new file mode 100644 index 0000000000..9827f22583 --- /dev/null +++ b/t/t4018/java-record-space-before-components @@ -0,0 +1,6 @@ +public record RIGHT (String components, String after, String space) { + static int ONE; + static int TWO; + static int THREE; + static int ChangeMe; +} diff --git a/t/t4018/java-record-type-parameters b/t/t4018/java-record-type-parameters new file mode 100644 index 0000000000..f62a035cc8 --- /dev/null +++ b/t/t4018/java-record-type-parameters @@ -0,0 +1,6 @@ +public record RIGHT<A, N extends Number>(A comp1, N comp2, int comp3) { + static int ONE; + static int TWO; + static int THREE; + static int ChangeMe; +} diff --git a/t/t4018/java-sealed b/t/t4018/java-sealed new file mode 100644 index 0000000000..785fbc62bc --- /dev/null +++ b/t/t4018/java-sealed @@ -0,0 +1,7 @@ +public abstract sealed class Sealed { // RIGHT + static int ONE; + static int TWO; + static int THREE; + public final class ChangeMe extends Sealed { + } +} diff --git a/t/t4018/java-sealed-permits b/t/t4018/java-sealed-permits new file mode 100644 index 0000000000..18dd4894cf --- /dev/null +++ b/t/t4018/java-sealed-permits @@ -0,0 +1,6 @@ +public abstract sealed class RIGHT permits PermittedA, PermittedB { + static int ONE; + static int TWO; + static int THREE; + private int ChangeMe; +} diff --git a/t/t4018/java-sealed-type-parameters b/t/t4018/java-sealed-type-parameters new file mode 100644 index 0000000000..e6530c47c3 --- /dev/null +++ b/t/t4018/java-sealed-type-parameters @@ -0,0 +1,6 @@ +public abstract sealed class RIGHT<A, B> { + static int ONE; + static int TWO; + static int THREE; + private int ChangeMe; +} diff --git a/t/t4018/java-sealed-type-parameters-implements-permits b/t/t4018/java-sealed-type-parameters-implements-permits new file mode 100644 index 0000000000..bd6e6d3582 --- /dev/null +++ b/t/t4018/java-sealed-type-parameters-implements-permits @@ -0,0 +1,6 @@ +public abstract sealed class RIGHT<A, B> implements List<A> permits PermittedA, PermittedB { + static int ONE; + static int TWO; + static int THREE; + private int ChangeMe; +} diff --git a/t/t4018/java-sealed-type-parameters-permits b/t/t4018/java-sealed-type-parameters-permits new file mode 100644 index 0000000000..25a0da6442 --- /dev/null +++ b/t/t4018/java-sealed-type-parameters-permits @@ -0,0 +1,6 @@ +public abstract sealed class RIGHT<A, B> permits PermittedA, PermittedB { + static int ONE; + static int TWO; + static int THREE; + private int ChangeMe; +} diff --git a/t/t4022-diff-rewrite.sh b/t/t4022-diff-rewrite.sh index 1c89050a97..6fed993ea0 100755 --- a/t/t4022-diff-rewrite.sh +++ b/t/t4022-diff-rewrite.sh @@ -24,7 +24,7 @@ test_expect_success setup ' test_expect_success 'detect rewrite' ' actual=$(git diff-files -B --summary test) && - verbose expr "$actual" : " rewrite test ([0-9]*%)$" + expr "$actual" : " rewrite test ([0-9]*%)$" ' 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/t4034-diff-words.sh b/t/t4034-diff-words.sh index 15764ee9ac..74586f3813 100755 --- a/t/t4034-diff-words.sh +++ b/t/t4034-diff-words.sh @@ -69,6 +69,10 @@ test_language_driver () { echo "* diff='"$lang"'" >.gitattributes && word_diff --color-words ' + test_expect_success "diff driver '$lang' in Islandic" ' + LANG=is_IS.UTF-8 LANGUAGE=is LC_ALL="$is_IS_locale" \ + word_diff --color-words + ' } test_expect_success setup ' diff --git a/t/t4038-diff-combined.sh b/t/t4038-diff-combined.sh index 9a292bac70..2ce26e585c 100755 --- a/t/t4038-diff-combined.sh +++ b/t/t4038-diff-combined.sh @@ -80,11 +80,21 @@ test_expect_success 'check combined output (1)' ' verify_helper sidewithone ' +test_expect_success 'check combined output (1) with git diff <rev>^!' ' + git diff sidewithone^! -- >sidewithone && + verify_helper sidewithone +' + test_expect_success 'check combined output (2)' ' git show sidesansone -- >sidesansone && verify_helper sidesansone ' +test_expect_success 'check combined output (2) with git diff <rev>^!' ' + git diff sidesansone^! -- >sidesansone && + verify_helper sidesansone +' + test_expect_success 'diagnose truncated file' ' >file && git add file && diff --git a/t/t4040-whitespace-status.sh b/t/t4040-whitespace-status.sh index e70e020ae9..eec3d73dc2 100755 --- a/t/t4040-whitespace-status.sh +++ b/t/t4040-whitespace-status.sh @@ -28,8 +28,7 @@ test_expect_success 'diff-tree --exit-code' ' test_expect_success 'diff-tree -b --exit-code' ' git diff -b --exit-code HEAD^ HEAD && - git diff-tree -b -p --exit-code HEAD^ HEAD && - git diff-tree -b --exit-code HEAD^ HEAD + git diff-tree -b -p --exit-code HEAD^ HEAD ' test_expect_success 'diff-index --cached --exit-code' ' diff --git a/t/t4044-diff-index-unique-abbrev.sh b/t/t4044-diff-index-unique-abbrev.sh index 29e49d2290..9f6043daba 100755 --- a/t/t4044-diff-index-unique-abbrev.sh +++ b/t/t4044-diff-index-unique-abbrev.sh @@ -34,12 +34,12 @@ test_expect_success 'setup' ' 100644 blob $(test_oid hash2) foo EOF - echo "$(test_oid val1)" > foo && + test_oid val1 > foo && git add foo && git commit -m "initial" && git cat-file -p HEAD: > actual && test_cmp expect_initial actual && - echo "$(test_oid val2)" > foo && + test_oid val2 > foo && git commit -a -m "update" && git cat-file -p HEAD: > actual && test_cmp expect_update actual diff --git a/t/t4045-diff-relative.sh b/t/t4045-diff-relative.sh index fab351b48a..9b46c4c1be 100755 --- a/t/t4045-diff-relative.sh +++ b/t/t4045-diff-relative.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='diff --relative tests' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' @@ -162,6 +164,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/t4046-diff-unmerged.sh b/t/t4046-diff-unmerged.sh index 0ae0cd3a52..ffaf69335f 100755 --- a/t/t4046-diff-unmerged.sh +++ b/t/t4046-diff-unmerged.sh @@ -86,4 +86,14 @@ test_expect_success 'diff-files -3' ' test_cmp diff-files-3.expect diff-files-3.actual ' +test_expect_success 'diff --stat' ' + for path in $paths + do + echo " $path | Unmerged" || return 1 + done >diff-stat.expect && + echo " 0 files changed" >>diff-stat.expect && + git diff --cached --stat >diff-stat.actual && + test_cmp diff-stat.expect diff-stat.actual +' + test_done diff --git a/t/t4047-diff-dirstat.sh b/t/t4047-diff-dirstat.sh index 7fec2cb9cd..70224c3da1 100755 --- a/t/t4047-diff-dirstat.sh +++ b/t/t4047-diff-dirstat.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='diff --dirstat tests' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # set up two commits where the second commit has these files diff --git a/t/t4052-stat-output.sh b/t/t4052-stat-output.sh index b5c281edaa..3ee27e277d 100755 --- a/t/t4052-stat-output.sh +++ b/t/t4052-stat-output.sh @@ -8,6 +8,7 @@ test_description='test --stat output of various commands' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-terminal.sh diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh index 3feadf0e35..5f059f65fc 100755 --- a/t/t4053-diff-no-index.sh +++ b/t/t4053-diff-no-index.sh @@ -2,6 +2,7 @@ test_description='diff --no-index' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' @@ -204,4 +205,83 @@ test_expect_success POSIXPERM,SYMLINKS 'diff --no-index normalizes: mode not lik test_cmp expected actual ' +test_expect_success "diff --no-index treats '-' as stdin" ' + cat >expect <<-EOF && + diff --git a/- b/a/1 + index $ZERO_OID..$(git hash-object --stdin <a/1) 100644 + --- a/- + +++ b/a/1 + @@ -1 +1 @@ + -x + +1 + EOF + + test_write_lines x | test_expect_code 1 \ + git -c core.abbrev=no diff --no-index -- - a/1 >actual && + test_cmp expect actual && + + test_write_lines 1 | git diff --no-index -- a/1 - >actual && + test_must_be_empty actual +' + +test_expect_success "diff --no-index -R treats '-' as stdin" ' + cat >expect <<-EOF && + diff --git b/a/1 a/- + index $(git hash-object --stdin <a/1)..$ZERO_OID 100644 + --- b/a/1 + +++ a/- + @@ -1 +1 @@ + -1 + +x + EOF + + test_write_lines x | test_expect_code 1 \ + git -c core.abbrev=no diff --no-index -R -- - a/1 >actual && + test_cmp expect actual && + + test_write_lines 1 | git diff --no-index -R -- a/1 - >actual && + test_must_be_empty actual +' + +test_expect_success 'diff --no-index refuses to diff stdin and a directory' ' + test_must_fail git diff --no-index -- - a </dev/null 2>err && + grep "fatal: cannot compare stdin to a directory" err +' + +test_expect_success PIPE 'diff --no-index refuses to diff a named pipe and a directory' ' + test_when_finished "rm -f pipe" && + mkfifo pipe && + test_must_fail git diff --no-index -- pipe a 2>err && + grep "fatal: cannot compare a named pipe to a directory" err +' + +test_expect_success PIPE,SYMLINKS 'diff --no-index reads from pipes' ' + test_when_finished "rm -f old new new-link" && + mkfifo old && + mkfifo new && + ln -s new new-link && + { + (test_write_lines a b c >old) & + } && + test_when_finished "kill $! || :" && + { + (test_write_lines a x c >new) & + } && + test_when_finished "kill $! || :" && + + cat >expect <<-EOF && + diff --git a/old b/new-link + --- a/old + +++ b/new-link + @@ -1,3 +1,3 @@ + a + -b + +x + c + EOF + + test_expect_code 1 git diff --no-index old new-link >actual && + test_cmp expect actual +' + test_done diff --git a/t/t4054-diff-bogus-tree.sh b/t/t4054-diff-bogus-tree.sh index 294fb55313..05c88f8cdf 100755 --- a/t/t4054-diff-bogus-tree.sh +++ b/t/t4054-diff-bogus-tree.sh @@ -10,7 +10,7 @@ test_expect_success 'create bogus tree' ' bogus_tree=$( printf "100644 fooQ$name" | q_to_nul | - git hash-object -w --stdin -t tree + git hash-object --literally -w --stdin -t tree ) ' diff --git a/t/t4058-diff-duplicates.sh b/t/t4058-diff-duplicates.sh index 54614b814d..2501c89c1c 100755 --- a/t/t4058-diff-duplicates.sh +++ b/t/t4058-diff-duplicates.sh @@ -29,7 +29,7 @@ make_tree () { make_tree_entry "$1" "$2" "$3" shift; shift; shift done | - git hash-object -w -t tree --stdin + git hash-object --literally -w -t tree --stdin } # this is kind of a convoluted setup, but matches diff --git a/t/t4062-diff-pickaxe.sh b/t/t4062-diff-pickaxe.sh index 9aaa068ed9..a90b46b678 100755 --- a/t/t4062-diff-pickaxe.sh +++ b/t/t4062-diff-pickaxe.sh @@ -24,7 +24,7 @@ test_expect_success '-G matches' ' test_expect_success '-S --pickaxe-regex' ' git diff --name-only -S0 --pickaxe-regex HEAD^ >out && - verbose test 4096-zeroes.txt = "$(cat out)" + test 4096-zeroes.txt = "$(cat out)" ' test_done diff --git a/t/t4067-diff-partial-clone.sh b/t/t4067-diff-partial-clone.sh index 28f42a4046..7af3a08862 100755 --- a/t/t4067-diff-partial-clone.sh +++ b/t/t4067-diff-partial-clone.sh @@ -2,6 +2,7 @@ test_description='behavior of diff when reading objects in a partial clone' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'git show batches blobs' ' @@ -150,7 +151,7 @@ test_expect_success 'diff does not fetch anything if inexact rename detection is # Ensure no fetches. GIT_TRACE_PACKET="$(pwd)/trace" git -C client diff --raw -M HEAD^ HEAD && - ! test_path_exists trace + test_path_is_missing trace ' test_expect_success 'diff --break-rewrites fetches only if necessary, and batches blobs if it does' ' @@ -170,7 +171,7 @@ test_expect_success 'diff --break-rewrites fetches only if necessary, and batche # Ensure no fetches. GIT_TRACE_PACKET="$(pwd)/trace" git -C client diff --raw -M HEAD^ HEAD && - ! test_path_exists trace && + test_path_is_missing trace && # But with --break-rewrites, ensure that there is exactly 1 negotiation # by checking that there is only 1 "done" line sent. ("done" marks the diff --git a/t/t4111-apply-subdir.sh b/t/t4111-apply-subdir.sh index 1618a6dbc7..e9a87d761d 100755 --- a/t/t4111-apply-subdir.sh +++ b/t/t4111-apply-subdir.sh @@ -2,6 +2,7 @@ test_description='patching from inconvenient places' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh index e95e6d4e7d..a22a90d552 100755 --- a/t/t4115-apply-symlink.sh +++ b/t/t4115-apply-symlink.sh @@ -74,7 +74,7 @@ test_expect_success SYMLINKS 'symlink escape when creating new files' ' 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_path_is_missing .git/create-me ' test_expect_success SYMLINKS 'symlink escape when modifying file' ' diff --git a/t/t4135-apply-weird-filenames.sh b/t/t4135-apply-weird-filenames.sh index 6bc3fb97a7..d3502c6fdd 100755 --- a/t/t4135-apply-weird-filenames.sh +++ b/t/t4135-apply-weird-filenames.sh @@ -2,6 +2,7 @@ test_description='git apply with weird postimage filenames' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t4141-apply-too-large.sh b/t/t4141-apply-too-large.sh new file mode 100755 index 0000000000..20cc1209f6 --- /dev/null +++ b/t/t4141-apply-too-large.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +test_description='git apply with too-large patch' + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +test_expect_success EXPENSIVE 'git apply rejects patches that are too large' ' + sz=$((1024 * 1024 * 1023)) && + { + cat <<-\EOF && + diff --git a/file b/file + new file mode 100644 + --- /dev/null + +++ b/file + @@ -0,0 +1 @@ + EOF + test-tool genzeros + } | test_copy_bytes $sz | test_must_fail git apply 2>err && + grep "patch too large" err +' + +test_done diff --git a/t/t4150-am.sh b/t/t4150-am.sh index cdad4b6880..2935fe1b2d 100755 --- a/t/t4150-am.sh +++ b/t/t4150-am.sh @@ -103,7 +103,7 @@ test_expect_success setup ' git format-patch --stdout first >patch1 && { - echo "Message-Id: <1226501681-24923-1-git-send-email-bda@mnsspb.ru>" && + echo "Message-ID: <1226501681-24923-1-git-send-email-bda@mnsspb.ru>" && echo "X-Fake-Field: Line One" && echo "X-Fake-Field: Line Two" && echo "X-Fake-Field: Line Three" && @@ -345,6 +345,21 @@ test_expect_success 'am with failing applypatch-msg hook' ' test_cmp_rev first HEAD ' +test_expect_success 'am with failing applypatch-msg hook (no verify)' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + test_hook applypatch-msg <<-\EOF && + echo hook-message >"$1" + exit 1 + EOF + git am --no-verify patch1 && + test_path_is_missing .git/rebase-apply && + git diff --exit-code second && + git log -1 --format=format:%B >actual && + test_cmp msg actual +' + test_expect_success 'am with pre-applypatch hook' ' rm -fr .git/rebase-apply && git reset --hard && @@ -374,6 +389,23 @@ test_expect_success 'am with failing pre-applypatch hook' ' test_cmp_rev first HEAD ' +test_expect_success 'am with failing pre-applypatch hook (no verify)' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + touch empty-file && + test_hook pre-applypatch <<-\EOF && + rm empty-file + exit 1 + EOF + git am --no-verify patch1 && + test_path_is_missing .git/rebase-apply && + test_path_is_file empty-file && + git diff --exit-code second && + git log -1 --format=format:%B >actual && + test_cmp msg actual +' + test_expect_success 'am with post-applypatch hook' ' rm -fr .git/rebase-apply && git reset --hard && @@ -910,7 +942,7 @@ test_expect_success 'am --message-id really adds the message id' ' git am --message-id patch1.eml && test_path_is_missing .git/rebase-apply && git cat-file commit HEAD | tail -n1 >actual && - grep Message-Id patch1.eml >expected && + grep Message-ID patch1.eml >expected && test_cmp expected actual ' @@ -922,7 +954,7 @@ test_expect_success 'am.messageid really adds the message id' ' git am patch1.eml && test_path_is_missing .git/rebase-apply && git cat-file commit HEAD | tail -n1 >actual && - grep Message-Id patch1.eml >expected && + grep Message-ID patch1.eml >expected && test_cmp expected actual ' @@ -933,7 +965,7 @@ test_expect_success 'am --message-id -s signs off after the message id' ' git am -s --message-id patch1.eml && test_path_is_missing .git/rebase-apply && git cat-file commit HEAD | tail -n2 | head -n1 >actual && - grep Message-Id patch1.eml >expected && + grep Message-ID patch1.eml >expected && test_cmp expected actual ' @@ -1033,7 +1065,7 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' ' >From extra escape for reversibility INPUT_END git commit -F msg && - git format-patch --pretty=mboxrd --stdout -1 >mboxrd1 && + git -c format.mboxrd format-patch --stdout -1 >mboxrd1 && grep "^>From could trip up a loose mbox parser" mboxrd1 && git checkout -f first && git am --patch-format=mboxrd mboxrd1 && diff --git a/t/t4152-am-subjects.sh b/t/t4152-am-subjects.sh index 4c68245aca..9f2edba1f8 100755 --- a/t/t4152-am-subjects.sh +++ b/t/t4152-am-subjects.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test subject preservation with format-patch | am' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh make_patches() { diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh index 3095b1b2ff..8e4effebdb 100755 --- a/t/t4201-shortlog.sh +++ b/t/t4201-shortlog.sh @@ -83,6 +83,13 @@ test_expect_success 'pretty format' ' test_cmp expect log.predictable ' +test_expect_success 'pretty format (with --date)' ' + sed "s/SUBJECT/2005-04-07 OBJECT_NAME/" expect.template >expect && + git shortlog --format="%ad %H" --date=short HEAD >log && + fuzz log >log.predictable && + test_cmp expect log.predictable +' + test_expect_success '--abbrev' ' sed s/SUBJECT/OBJID/ expect.template >expect && git shortlog --format="%h" --abbrev=35 HEAD >log && @@ -237,6 +244,26 @@ test_expect_success 'shortlog --group=trailer:signed-off-by' ' test_cmp expect actual ' +test_expect_success 'shortlog --group=format' ' + git shortlog -s --date="format:%Y" --group="format:%cN (%cd)" \ + HEAD >actual && + cat >expect <<-\EOF && + 4 C O Mitter (2005) + 1 Sin Nombre (2005) + EOF + test_cmp expect actual +' + +test_expect_success 'shortlog --group=<format> DWIM' ' + git shortlog -s --date="format:%Y" --group="%cN (%cd)" HEAD >actual && + test_cmp expect actual +' + +test_expect_success 'shortlog bogus --group' ' + test_must_fail git shortlog --group=bogus HEAD 2>err && + grep "unknown group type" err +' + test_expect_success 'trailer idents are split' ' cat >expect <<-\EOF && 2 C O Mitter @@ -319,6 +346,18 @@ test_expect_success 'shortlog can match multiple groups' ' test_cmp expect actual ' +test_expect_success 'shortlog can match multiple format groups' ' + GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME" \ + git commit --allow-empty -m "identical names" && + test_tick && + cat >expect <<-\EOF && + 2 A U Thor + 1 C O Mitter + EOF + git shortlog -ns --group="%cn" --group="%an" -2 HEAD >actual && + test_cmp expect actual +' + test_expect_success 'set up option selection tests' ' git commit --allow-empty -F - <<-\EOF subject diff --git a/t/t4202-log.sh b/t/t4202-log.sh index cc15cb4ff6..af4a123cd2 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -187,6 +187,21 @@ test_expect_success 'git config log.follow does not die with no paths' ' git log -- ' +test_expect_success 'git log --follow rejects unsupported pathspec magic' ' + test_must_fail git log --follow ":(top,glob,icase)ichi" 2>stderr && + # check full error message; we want to be sure we mention both + # of the rejected types (glob,icase), but not the allowed one (top) + echo "fatal: pathspec magic not supported by --follow: ${SQ}glob${SQ}, ${SQ}icase${SQ}" >expect && + test_cmp expect stderr +' + +test_expect_success 'log.follow disabled with unsupported pathspec magic' ' + test_config log.follow true && + git log --format=%s ":(glob,icase)ichi" >actual && + echo third >expect && + test_cmp expect actual +' + test_expect_success 'git config log.follow is overridden by --no-follow' ' test_config log.follow true && git log --no-follow --pretty="format:%s" ichi >actual && @@ -249,6 +264,15 @@ test_expect_success 'log --grep' ' test_cmp expect actual ' +for noop_opt in --invert-grep --all-match +do + test_expect_success "log $noop_opt without --grep is a NOOP" ' + git log >expect && + git log $noop_opt >actual && + test_cmp expect actual + ' +done + cat > expect << EOF second initial @@ -826,6 +850,21 @@ test_expect_success 'log.decorate configuration' ' ' +test_expect_success 'parse log.excludeDecoration with no value' ' + cp .git/config .git/config.orig && + test_when_finished mv .git/config.orig .git/config && + + cat >>.git/config <<-\EOF && + [log] + excludeDecoration + EOF + cat >expect <<-\EOF && + error: missing value for '\''log.excludeDecoration'\'' + EOF + git log --decorate=short 2>actual && + test_cmp expect actual +' + test_expect_success 'decorate-refs with glob' ' cat >expect.decorate <<-\EOF && Merge-tag-reach @@ -2319,10 +2358,10 @@ test_expect_success 'log --decorate does not include things outside filter' ' ' test_expect_success 'log --end-of-options' ' - git update-ref refs/heads/--source HEAD && - git log --end-of-options --source >actual && - git log >expect && - test_cmp expect actual + git update-ref refs/heads/--source HEAD && + git log --end-of-options --source >actual && + git log >expect && + test_cmp expect actual ' test_expect_success 'set up commits with different authors' ' diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh index cd1cab3e54..2016132f51 100755 --- a/t/t4203-mailmap.sh +++ b/t/t4203-mailmap.sh @@ -466,7 +466,7 @@ test_expect_success 'gitmailmap(5) example output: example #1' ' Author Jane Doe <jane@laptop.(none)> maps to Jane Doe <jane@laptop.(none)> Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com> - Author Jane D <jane@desktop.(none)> maps to Jane Doe <jane@desktop.(none)> + Author Jane D. <jane@desktop.(none)> maps to Jane Doe <jane@desktop.(none)> Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com> EOF git -C doc log --reverse --pretty=format:"Author %an <%ae> maps to %aN <%aE>%nCommitter %cn <%ce> maps to %cN <%cE>%n" >actual && @@ -494,7 +494,7 @@ test_expect_success 'gitmailmap(5) example output: example #2' ' Author Jane Doe <jane@laptop.(none)> maps to Jane Doe <jane@example.com> Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com> - Author Jane D <jane@desktop.(none)> maps to Jane Doe <jane@example.com> + Author Jane D. <jane@desktop.(none)> maps to Jane Doe <jane@example.com> Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com> EOF git -C doc log --reverse --pretty=format:"Author %an <%ae> maps to %aN <%aE>%nCommitter %cn <%ce> maps to %cN <%cE>%n" >actual && @@ -1022,4 +1022,69 @@ test_expect_success '--mailmap enables mailmap in cat-file for annotated tag obj test_cmp expect actual ' +test_expect_success 'git cat-file -s returns correct size with --use-mailmap' ' + test_when_finished "rm .mailmap" && + cat >.mailmap <<-\EOF && + C O Mitter <committer@example.com> Orig <orig@example.com> + EOF + git cat-file commit HEAD >commit.out && + echo $(wc -c <commit.out) >expect && + git cat-file --use-mailmap commit HEAD >commit.out && + echo $(wc -c <commit.out) >>expect && + git cat-file -s HEAD >actual && + git cat-file --use-mailmap -s HEAD >>actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file -s returns correct size with --use-mailmap for tag objects' ' + test_when_finished "rm .mailmap" && + cat >.mailmap <<-\EOF && + Orig <orig@example.com> C O Mitter <committer@example.com> + EOF + git tag -a -m "annotated tag" v3 && + git cat-file tag v3 >tag.out && + echo $(wc -c <tag.out) >expect && + git cat-file --use-mailmap tag v3 >tag.out && + echo $(wc -c <tag.out) >>expect && + git cat-file -s v3 >actual && + git cat-file --use-mailmap -s v3 >>actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file --batch-check returns correct size with --use-mailmap' ' + test_when_finished "rm .mailmap" && + cat >.mailmap <<-\EOF && + C O Mitter <committer@example.com> Orig <orig@example.com> + EOF + git cat-file commit HEAD >commit.out && + commit_size=$(wc -c <commit.out) && + commit_sha=$(git rev-parse HEAD) && + echo $commit_sha commit $commit_size >expect && + git cat-file --use-mailmap commit HEAD >commit.out && + commit_size=$(wc -c <commit.out) && + echo $commit_sha commit $commit_size >>expect && + echo "HEAD" >in && + git cat-file --batch-check <in >actual && + git cat-file --use-mailmap --batch-check <in >>actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file --batch-command returns correct size with --use-mailmap' ' + test_when_finished "rm .mailmap" && + cat >.mailmap <<-\EOF && + C O Mitter <committer@example.com> Orig <orig@example.com> + EOF + git cat-file commit HEAD >commit.out && + commit_size=$(wc -c <commit.out) && + commit_sha=$(git rev-parse HEAD) && + echo $commit_sha commit $commit_size >expect && + git cat-file --use-mailmap commit HEAD >commit.out && + commit_size=$(wc -c <commit.out) && + echo $commit_sha commit $commit_size >>expect && + echo "info HEAD" >in && + git cat-file --batch-command <in >actual && + git cat-file --use-mailmap --batch-command <in >>actual && + test_cmp expect actual +' + test_done diff --git a/t/t4204-patch-id.sh b/t/t4204-patch-id.sh index a730c0db98..a7fa94ce0a 100755 --- a/t/t4204-patch-id.sh +++ b/t/t4204-patch-id.sh @@ -8,13 +8,13 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . ./test-lib.sh test_expect_success 'setup' ' - as="a a a a a a a a" && # eight a - test_write_lines $as >foo && - test_write_lines $as >bar && + str="ab cd ef gh ij kl mn op" && + test_write_lines $str >foo && + test_write_lines $str >bar && git add foo bar && git commit -a -m initial && - test_write_lines $as b >foo && - test_write_lines $as b >bar && + test_write_lines $str b >foo && + test_write_lines $str b >bar && git commit -a -m first && git checkout -b same main && git commit --amend -m same-msg && @@ -22,8 +22,23 @@ test_expect_success 'setup' ' echo c >foo && echo c >bar && git commit --amend -a -m notsame-msg && + git checkout -b with_space main~ && + cat >foo <<-\EOF && + a b + c d + e f + g h + i j + k l + m n + op + EOF + cp foo bar && + git add foo bar && + git commit --amend -m "with spaces" && test_write_lines bar foo >bar-then-foo && test_write_lines foo bar >foo-then-bar + ' test_expect_success 'patch-id output is well-formed' ' @@ -42,7 +57,7 @@ calc_patch_id () { } get_top_diff () { - git log -p -1 "$@" -O bar-then-foo -- + git log -p -1 "$@" -O bar-then-foo --full-index -- } get_patch_id () { @@ -61,6 +76,33 @@ test_expect_success 'patch-id detects inequality' ' get_patch_id notsame && ! test_cmp patch-id_main patch-id_notsame ' +test_expect_success 'patch-id detects equality binary' ' + cat >.gitattributes <<-\EOF && + foo binary + bar binary + EOF + get_patch_id main && + get_patch_id same && + git log -p -1 --binary main >top-diff.output && + calc_patch_id <top-diff.output main_binpatch && + git log -p -1 --binary same >top-diff.output && + calc_patch_id <top-diff.output same_binpatch && + test_cmp patch-id_main patch-id_main_binpatch && + test_cmp patch-id_same patch-id_same_binpatch && + test_cmp patch-id_main patch-id_same && + test_when_finished "rm .gitattributes" +' + +test_expect_success 'patch-id detects inequality binary' ' + cat >.gitattributes <<-\EOF && + foo binary + bar binary + EOF + get_patch_id main && + get_patch_id notsame && + ! test_cmp patch-id_main patch-id_notsame && + test_when_finished "rm .gitattributes" +' test_expect_success 'patch-id supports git-format-patch output' ' get_patch_id main && @@ -101,9 +143,21 @@ test_patch_id_file_order () { git format-patch -1 --stdout -O foo-then-bar >format-patch.output && calc_patch_id <format-patch.output "ordered-$name" "$@" && cmp_patch_id $relevant "$name" "ordered-$name" +} +test_patch_id_whitespace () { + relevant="$1" + shift + name="ws-${1}-$relevant" + shift + get_top_diff "main~" >top-diff.output && + calc_patch_id <top-diff.output "$name" "$@" && + get_top_diff "with_space" >top-diff.output && + calc_patch_id <top-diff.output "ws-$name" "$@" && + cmp_patch_id $relevant "$name" "ws-$name" } + # combined test for options: add more tests here to make them # run with all options test_patch_id () { @@ -119,6 +173,14 @@ test_expect_success 'file order is relevant with --unstable' ' test_patch_id_file_order relevant --unstable --unstable ' +test_expect_success 'whitespace is relevant with --verbatim' ' + test_patch_id_whitespace relevant --verbatim --verbatim +' + +test_expect_success 'whitespace is irrelevant without --verbatim' ' + test_patch_id_whitespace irrelevant --stable --stable +' + #Now test various option combinations. test_expect_success 'default is unstable' ' test_patch_id relevant default @@ -134,6 +196,17 @@ test_expect_success 'patchid.stable = false is unstable' ' test_patch_id relevant patchid.stable=false ' +test_expect_success 'patchid.verbatim = true is correct and stable' ' + test_config patchid.verbatim true && + test_patch_id_whitespace relevant patchid.verbatim=true && + test_patch_id irrelevant patchid.verbatim=true +' + +test_expect_success 'patchid.verbatim = false is unstable' ' + test_config patchid.verbatim false && + test_patch_id relevant patchid.verbatim=false +' + test_expect_success '--unstable overrides patchid.stable = true' ' test_config patchid.stable true && test_patch_id relevant patchid.stable=true--unstable --unstable @@ -144,6 +217,11 @@ test_expect_success '--stable overrides patchid.stable = false' ' test_patch_id irrelevant patchid.stable=false--stable --stable ' +test_expect_success '--verbatim overrides patchid.stable = false' ' + test_config patchid.stable false && + test_patch_id_whitespace relevant stable=false--verbatim --verbatim +' + test_expect_success 'patch-id supports git-format-patch MIME output' ' get_patch_id main && git checkout same && @@ -198,7 +276,10 @@ test_expect_success 'patch-id handles no-nl-at-eof markers' ' EOF calc_patch_id nonl <nonl && calc_patch_id withnl <withnl && - test_cmp patch-id_nonl patch-id_withnl + test_cmp patch-id_nonl patch-id_withnl && + calc_patch_id nonl-inc-ws --verbatim <nonl && + calc_patch_id withnl-inc-ws --verbatim <withnl && + ! test_cmp patch-id_nonl-inc-ws patch-id_withnl-inc-ws ' test_expect_success 'patch-id handles diffs with one line of before/after' ' diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh index fedb7ca749..16626e4fe9 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 @@ -576,6 +576,38 @@ test_expect_success 'clean log decoration' ' test_cmp expected actual1 ' +test_expect_success 'pretty format %decorate' ' + git checkout -b foo && + git commit --allow-empty -m "new commit" && + git tag bar && + git branch qux && + + echo " (HEAD -> foo, tag: bar, qux)" >expect1 && + git log --format="%(decorate)" -1 >actual1 && + test_cmp expect1 actual1 && + + echo "HEAD -> foo, tag: bar, qux" >expect2 && + git log --format="%(decorate:prefix=,suffix=)" -1 >actual2 && + test_cmp expect2 actual2 && + + echo "[ HEAD -> foo; tag: bar; qux ]" >expect3 && + git log --format="%(decorate:prefix=[ ,suffix= ],separator=%x3B )" \ + -1 >actual3 && + test_cmp expect3 actual3 && + + # Try with a typo (in "separator"), in which case the placeholder should + # not be replaced. + echo "%(decorate:prefix=[ ,suffix= ],separater=; )" >expect4 && + git log --format="%(decorate:prefix=[ ,suffix= ],separater=%x3B )" \ + -1 >actual4 && + test_cmp expect4 actual4 && + + echo "HEAD->foo bar qux" >expect5 && + git log --format="%(decorate:prefix=,suffix=,separator= ,tag=,pointer=->)" \ + -1 >actual5 && + test_cmp expect5 actual5 +' + cat >trailers <<EOF Signed-off-by: A U Thor <author@example.com> Acked-by: A U Thor <author@example.com> @@ -1012,10 +1044,25 @@ test_expect_success '%(describe:tags) vs git describe --tags' ' test_expect_success '%(describe:abbrev=...) vs git describe --abbrev=...' ' test_when_finished "git tag -d tagname" && + + # Case 1: We have commits between HEAD and the most recent tag + # reachable from it + test_commit --no-tag file && + git describe --abbrev=15 >expect && + git log -1 --format="%(describe:abbrev=15)" >actual && + test_cmp expect actual && + + # Make sure the hash used is at least 15 digits long + sed -e "s/^.*-g\([0-9a-f]*\)$/\1/" <actual >hexpart && + test 16 -le $(wc -c <hexpart) && + + # Case 2: We have a tag at HEAD, describe directly gives the + # name of the tag git tag -a -m tagged tagname && git describe --abbrev=15 >expect && git log -1 --format="%(describe:abbrev=15)" >actual && - test_cmp expect actual + test_cmp expect actual && + test tagname = $(cat actual) ' test_expect_success 'log --pretty with space stealing' ' @@ -1094,4 +1141,31 @@ test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit mes test_cmp expect error ' +# pretty-formats note wide char limitations, and add tests +test_expect_failure 'wide and decomposed characters column counting' ' + +# from t/lib-unicode-nfc-nfd.sh hex values converted to octal + utf8_nfc=$(printf "\303\251") && # e acute combined. + utf8_nfd=$(printf "\145\314\201") && # e with a combining acute (i.e. decomposed) + utf8_emoji=$(printf "\360\237\221\250") && + +# replacement character when requesting a wide char fits in a single display colum. +# "half wide" alternative could be a plain ASCII dot `.` + utf8_vert_ell=$(printf "\342\213\256") && + +# use ${xxx} here! + nfc10="${utf8_nfc}${utf8_nfc}${utf8_nfc}${utf8_nfc}${utf8_nfc}${utf8_nfc}${utf8_nfc}${utf8_nfc}${utf8_nfc}${utf8_nfc}" && + nfd10="${utf8_nfd}${utf8_nfd}${utf8_nfd}${utf8_nfd}${utf8_nfd}${utf8_nfd}${utf8_nfd}${utf8_nfd}${utf8_nfd}${utf8_nfd}" && + emoji5="${utf8_emoji}${utf8_emoji}${utf8_emoji}${utf8_emoji}${utf8_emoji}" && +# emoji5 uses 10 display columns + + test_commit "abcdefghij" && + test_commit --no-tag "${nfc10}" && + test_commit --no-tag "${nfd10}" && + test_commit --no-tag "${emoji5}" && + printf "${utf8_emoji}..${utf8_emoji}${utf8_vert_ell}\n${utf8_nfd}..${utf8_nfd}${utf8_nfd}\n${utf8_nfc}..${utf8_nfc}${utf8_nfc}\na..ij\n" >expected && + git log --format="%<(5,mtrunc)%s" -4 >actual && + test_cmp expected actual +' + test_done diff --git a/t/t4206-log-follow-harder-copies.sh b/t/t4206-log-follow-harder-copies.sh index 33ecf82c7f..9167b0351f 100755 --- a/t/t4206-log-follow-harder-copies.sh +++ b/t/t4206-log-follow-harder-copies.sh @@ -16,29 +16,29 @@ Line 2 Line 3 ' -test_expect_success \ - 'add a file path0 and commit.' \ - 'git add path0 && - git commit -m "Add path0"' +test_expect_success 'add a file path0 and commit.' ' + git add path0 && + git commit -m "Add path0" +' echo >path0 'New line 1 New line 2 New line 3 ' -test_expect_success \ - 'Change path0.' \ - 'git add path0 && - git commit -m "Change path0"' +test_expect_success 'Change path0.' ' + git add path0 && + git commit -m "Change path0" +' cat <path0 >path1 -test_expect_success \ - 'copy path0 to path1.' \ - 'git add path1 && - git commit -m "Copy path1 from path0"' +test_expect_success 'copy path0 to path1.' ' + git add path1 && + git commit -m "Copy path1 from path0" +' -test_expect_success \ - 'find the copy path0 -> path1 harder' \ - 'git log --follow --name-status --pretty="format:%s" path1 > current' +test_expect_success 'find the copy path0 -> path1 harder' ' + git log --follow --name-status --pretty="format:%s" path1 > current +' cat >expected <<\EOF Copy path1 from path0 @@ -51,8 +51,8 @@ Add path0 A path0 EOF -test_expect_success \ - 'validate the output.' \ - 'compare_diff_patch current expected' +test_expect_success 'validate the output.' ' + compare_diff_patch current expected +' test_done diff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh index ded33a82e2..21986a866d 100755 --- a/t/t4207-log-decoration-colors.sh +++ b/t/t4207-log-decoration-colors.sh @@ -53,15 +53,17 @@ cmp_filtered_decorations () { # to this test since it does not contain any decoration, hence --first-parent test_expect_success 'commit decorations colored correctly' ' cat >expect <<-EOF && - ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD -> \ -${c_reset}${c_branch}main${c_reset}${c_commit}, \ -${c_reset}${c_tag}tag: v1.0${c_reset}${c_commit}, \ -${c_reset}${c_tag}tag: B${c_reset}${c_commit})${c_reset} B -${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A1${c_reset}${c_commit}, \ + ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}\ +${c_commit} -> ${c_reset}${c_branch}main${c_reset}${c_commit}, \ +${c_reset}${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_commit}, \ +${c_reset}${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_commit})${c_reset} B +${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\ +${c_tag}tag: ${c_reset}${c_tag}A1${c_reset}${c_commit}, \ ${c_reset}${c_remoteBranch}other/main${c_reset}${c_commit})${c_reset} A1 - ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_stash}refs/stash${c_reset}${c_commit})${c_reset} \ -On main: Changes to A.t - ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A${c_reset}${c_commit})${c_reset} A + ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\ +${c_stash}refs/stash${c_reset}${c_commit})${c_reset} On main: Changes to A.t + ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\ +${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A EOF git log --first-parent --no-abbrev --decorate --oneline --color=always --all >actual && @@ -76,12 +78,14 @@ test_expect_success 'test coloring with replace-objects' ' git replace HEAD~1 HEAD~2 && cat >expect <<-EOF && - ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD -> \ -${c_reset}${c_branch}main${c_reset}${c_commit}, \ -${c_reset}${c_tag}tag: D${c_reset}${c_commit})${c_reset} D - ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: C${c_reset}${c_commit}, \ + ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}\ +${c_commit} -> ${c_reset}${c_branch}main${c_reset}${c_commit}, \ +${c_reset}${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_commit})${c_reset} D + ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\ +${c_tag}tag: ${c_reset}${c_tag}C${c_reset}${c_commit}, \ ${c_reset}${c_grafted}replaced${c_reset}${c_commit})${c_reset} B - ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A${c_reset}${c_commit})${c_reset} A + ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\ +${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A EOF git log --first-parent --no-abbrev --decorate --oneline --color=always HEAD >actual && @@ -100,13 +104,15 @@ test_expect_success 'test coloring with grafted commit' ' git replace --graft HEAD HEAD~2 && cat >expect <<-EOF && - ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD -> \ -${c_reset}${c_branch}main${c_reset}${c_commit}, \ -${c_reset}${c_tag}tag: D${c_reset}${c_commit}, \ + ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}\ +${c_commit} -> ${c_reset}${c_branch}main${c_reset}${c_commit}, \ +${c_reset}${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_commit}, \ ${c_reset}${c_grafted}replaced${c_reset}${c_commit})${c_reset} D - ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: v1.0${c_reset}${c_commit}, \ -${c_reset}${c_tag}tag: B${c_reset}${c_commit})${c_reset} B - ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A${c_reset}${c_commit})${c_reset} A + ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\ +${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_commit}, \ +${c_reset}${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_commit})${c_reset} B + ${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\ +${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A EOF git log --first-parent --no-abbrev --decorate --oneline --color=always HEAD >actual && 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/t4212-log-corrupt.sh b/t/t4212-log-corrupt.sh index 30a219894b..85e90acb09 100755 --- a/t/t4212-log-corrupt.sh +++ b/t/t4212-log-corrupt.sh @@ -8,9 +8,10 @@ TEST_PASSES_SANITIZE_LEAK=true test_expect_success 'setup' ' test_commit foo && - git cat-file commit HEAD | - sed "/^author /s/>/>-<>/" >broken_email.commit && - git hash-object -w -t commit broken_email.commit >broken_email.hash && + git cat-file commit HEAD >ok.commit && + sed "s/>/>-<>/" <ok.commit >broken_email.commit && + + git hash-object --literally -w -t commit broken_email.commit >broken_email.hash && git update-ref refs/heads/broken_email $(cat broken_email.hash) ' @@ -43,10 +44,15 @@ test_expect_success 'git log --format with broken author email' ' test_must_be_empty actual.err ' +test_expect_success '--until handles broken email' ' + git rev-list --until=1980-01-01 broken_email >actual && + test_must_be_empty actual +' + munge_author_date () { git cat-file commit "$1" >commit.orig && sed "s/^\(author .*>\) [0-9]*/\1 $2/" <commit.orig >commit.munge && - git hash-object -w -t commit commit.munge + git hash-object --literally -w -t commit commit.munge } test_expect_success 'unparsable dates produce sentinel value' ' @@ -86,4 +92,45 @@ test_expect_success 'absurdly far-in-future date' ' git log -1 --format=%ad $commit ' +test_expect_success 'create commits with whitespace committer dates' ' + # It is important that this subject line is numeric, since we want to + # be sure we are not confused by skipping whitespace and accidentally + # parsing the subject as a timestamp. + # + # Do not use munge_author_date here. Besides not hitting the committer + # line, it leaves the timezone intact, and we want nothing but + # whitespace. + # + # We will make two munged commits here. The first, ws_commit, will + # be purely spaces. The second contains a vertical tab, which is + # considered a space by strtoumax(), but not by our isspace(). + test_commit 1234567890 && + git cat-file commit HEAD >commit.orig && + sed "s/>.*/> /" <commit.orig >commit.munge && + ws_commit=$(git hash-object --literally -w -t commit commit.munge) && + sed "s/>.*/> $(printf "\013")/" <commit.orig >commit.munge && + vt_commit=$(git hash-object --literally -w -t commit commit.munge) +' + +test_expect_success '--until treats whitespace date as sentinel' ' + echo $ws_commit >expect && + git rev-list --until=1980-01-01 $ws_commit >actual && + test_cmp expect actual && + + echo $vt_commit >expect && + git rev-list --until=1980-01-01 $vt_commit >actual && + test_cmp expect actual +' + +test_expect_success 'pretty-printer handles whitespace date' ' + # as with the %ad test above, we will show these as the empty string, + # not the 1970 epoch date. This is intentional; see 7d9a281941 (t4212: + # test bogus timestamps with git-log, 2014-02-24) for more discussion. + echo : >expect && + git log -1 --format="%at:%ct" $ws_commit >actual && + test_cmp expect actual && + git log -1 --format="%at:%ct" $vt_commit >actual && + test_cmp expect actual +' + test_done diff --git a/t/t4213-log-tabexpand.sh b/t/t4213-log-tabexpand.sh index 53a4af3244..590fce95e9 100755 --- a/t/t4213-log-tabexpand.sh +++ b/t/t4213-log-tabexpand.sh @@ -2,6 +2,7 @@ test_description='log/show --expand-tabs' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh HT=" " diff --git a/t/t4254-am-corrupt.sh b/t/t4254-am-corrupt.sh index 54be7da161..45f1d4f95e 100755 --- a/t/t4254-am-corrupt.sh +++ b/t/t4254-am-corrupt.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='git am with corrupt input' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh make_mbox_with_nul () { diff --git a/t/t4256-am-format-flowed.sh b/t/t4256-am-format-flowed.sh index 2369c4e17a..1015273bc8 100755 --- a/t/t4256-am-format-flowed.sh +++ b/t/t4256-am-format-flowed.sh @@ -2,6 +2,7 @@ test_description='test format=flowed support of git am' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t4257-am-interactive.sh b/t/t4257-am-interactive.sh index aed8f4de3d..f26d7fd2db 100755 --- a/t/t4257-am-interactive.sh +++ b/t/t4257-am-interactive.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='am --interactive tests' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'set up patches to apply' ' diff --git a/t/t4258/mbox b/t/t4258/mbox index c62819f3d2..1ae528ba78 100644 --- a/t/t4258/mbox +++ b/t/t4258/mbox @@ -2,7 +2,7 @@ From: A U Thor <mail@example.com> To: list@example.org Subject: [PATCH v2] sample Date: Mon, 3 Aug 2020 22:40:55 +0700 -Message-Id: <msg-id@example.com> +Message-ID: <msg-id@example.com> Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 diff --git a/t/t4300-merge-tree.sh b/t/t4300-merge-tree.sh index c52c8a21fa..57c4f26e46 100755 --- a/t/t4300-merge-tree.sh +++ b/t/t4300-merge-tree.sh @@ -334,4 +334,22 @@ test_expect_success 'turn tree to file' ' test_cmp expect actual ' +test_expect_success 'merge-tree respects core.useReplaceRefs=false' ' + test_commit merge-to && + test_commit valid base && + git reset --hard HEAD^ && + test_commit malicious base && + + test_when_finished "git replace -d $(git rev-parse valid^0)" && + git replace valid^0 malicious^0 && + + tree=$(git -c core.useReplaceRefs=true merge-tree --write-tree merge-to valid) && + merged=$(git cat-file -p $tree:base) && + test malicious = $merged && + + tree=$(git -c core.useReplaceRefs=false merge-tree --write-tree merge-to valid) && + merged=$(git cat-file -p $tree:base) && + test valid = $merged +' + test_done diff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh index 013b77144b..250f721795 100755 --- a/t/t4301-merge-tree-write-tree.sh +++ b/t/t4301-merge-tree-write-tree.sh @@ -141,7 +141,7 @@ test_expect_success 'test conflict notices and such' ' # Commit O: foo, olddir/{a,b,c} # Commit A: modify foo, newdir/{a,b,c} # Commit B: modify foo differently & rename foo -> olddir/bar -# Expected: CONFLICT(content) for for newdir/bar (not olddir/bar or foo) +# Expected: CONFLICT(content) for newdir/bar (not olddir/bar or foo) test_expect_success 'directory rename + content conflict' ' # Setup @@ -653,7 +653,7 @@ test_expect_success 'mod6: chains of rename/rename(1to2) and add/add via collidi # Commit O: foo, olddir/{a,b,c} # Commit A: delete foo, rename olddir/ -> newdir/, add newdir/bar/file # Commit B: modify foo & rename foo -> olddir/bar -# Expected: CONFLICT(content) for for newdir/bar (not olddir/bar or foo) +# Expected: CONFLICT(content) for newdir/bar (not olddir/bar or foo) test_expect_success 'directory rename + rename/delete + modify/delete + directory/file conflict' ' # Setup @@ -819,4 +819,107 @@ test_expect_success SANITY 'merge-ort fails gracefully in a read-only repository test_must_fail git -C read-only merge-tree side1 side2 ' +test_expect_success '--stdin with both a successful and a conflicted merge' ' + printf "side1 side3\nside1 side2" | git merge-tree --stdin >actual && + + git checkout side1^0 && + git merge side3 && + + printf "1\0" >expect && + git rev-parse HEAD^{tree} | lf_to_nul >>expect && + printf "\0" >>expect && + + git checkout side1^0 && + test_must_fail git merge side2 && + sed s/HEAD/side1/ greeting >tmp && + mv tmp greeting && + git add -u && + git mv whatever~HEAD whatever~side1 && + + printf "0\0" >>expect && + git write-tree | lf_to_nul >>expect && + + cat <<-EOF | q_to_tab | lf_to_nul >>expect && + 100644 $(git rev-parse side1~1:greeting) 1Qgreeting + 100644 $(git rev-parse side1:greeting) 2Qgreeting + 100644 $(git rev-parse side2:greeting) 3Qgreeting + 100644 $(git rev-parse side1~1:whatever) 1Qwhatever~side1 + 100644 $(git rev-parse side1:whatever) 2Qwhatever~side1 + EOF + + q_to_nul <<-EOF >>expect && + Q1QgreetingQAuto-mergingQAuto-merging greeting + Q1QgreetingQCONFLICT (contents)QCONFLICT (content): Merge conflict in greeting + Q1QnumbersQAuto-mergingQAuto-merging numbers + Q2Qwhatever~side1QwhateverQCONFLICT (file/directory)QCONFLICT (file/directory): directory in the way of whatever from side1; moving it to whatever~side1 instead. + Q1Qwhatever~side1QCONFLICT (modify/delete)QCONFLICT (modify/delete): whatever~side1 deleted in side2 and modified in side1. Version side1 of whatever~side1 left in tree. + EOF + + printf "\0\0" >>expect && + + test_cmp expect actual +' + + +test_expect_success '--merge-base is incompatible with --stdin' ' + test_must_fail git merge-tree --merge-base=side1 --stdin 2>expect && + + grep "^fatal: --merge-base is incompatible with --stdin" expect +' + +# specify merge-base as parent of branch2 +# git merge-tree --write-tree --merge-base=c2 c1 c3 +# Commit c1: add file1 +# Commit c2: add file2 after c1 +# Commit c3: add file3 after c2 +# Expected: add file3, and file2 does NOT appear + +test_expect_success 'specify merge-base as parent of branch2' ' + # Setup + test_when_finished "rm -rf base-b2-p" && + git init base-b2-p && + test_commit -C base-b2-p c1 file1 && + test_commit -C base-b2-p c2 file2 && + test_commit -C base-b2-p c3 file3 && + + # Testing + TREE_OID=$(git -C base-b2-p merge-tree --write-tree --merge-base=c2 c1 c3) && + + q_to_tab <<-EOF >expect && + 100644 blob $(git -C base-b2-p rev-parse c1:file1)Qfile1 + 100644 blob $(git -C base-b2-p rev-parse c3:file3)Qfile3 + EOF + + git -C base-b2-p ls-tree $TREE_OID >actual && + test_cmp expect actual +' + +# Since the earlier tests have verified that individual merge-tree calls +# are doing the right thing, this test case is only used to verify that +# we can also trigger merges via --stdin, and that when we do we get +# the same answer as running a bunch of separate merges. + +test_expect_success 'check the input format when --stdin is passed' ' + test_when_finished "rm -rf repo" && + git init repo && + test_commit -C repo c1 && + test_commit -C repo c2 && + test_commit -C repo c3 && + printf "c1 c3\nc2 -- c1 c3\nc2 c3" | git -C repo merge-tree --stdin >actual && + + printf "1\0" >expect && + git -C repo merge-tree --write-tree -z c1 c3 >>expect && + printf "\0" >>expect && + + printf "1\0" >>expect && + git -C repo merge-tree --write-tree -z --merge-base=c2 c1 c3 >>expect && + printf "\0" >>expect && + + printf "1\0" >>expect && + git -C repo merge-tree --write-tree -z c2 c3 >>expect && + printf "\0" >>expect && + + test_cmp expect actual +' + test_done diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index eaa0b22ece..4b4c3315d8 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -105,6 +105,18 @@ check_added() { ' } +check_mtime() { + dir=$1 + path_in_archive=$2 + mtime=$3 + + test_expect_success " validate mtime of $path_in_archive" ' + test-tool chmtime --get $dir/$path_in_archive >actual.mtime && + echo $mtime >expect.mtime && + test_cmp expect.mtime actual.mtime + ' +} + test_expect_success 'setup' ' test_oid_cache <<-EOF obj sha1:19f9c8273ec45a8938e6999cb59b3ff66739902a @@ -173,6 +185,14 @@ test_expect_success 'git archive' ' ' check_tar b +check_mtime b a/a 1117231200 + +test_expect_success 'git archive --mtime' ' + git archive --mtime=2002-02-02T02:02:02-0200 HEAD >with_mtime.tar +' + +check_tar with_mtime +check_mtime with_mtime a/a 1012622522 test_expect_success 'git archive --prefix=prefix/' ' git archive --prefix=prefix/ HEAD >with_prefix.tar @@ -238,14 +258,6 @@ test_expect_success 'git archive --remote with configured remote' ' test_cmp_bin b.tar b5-nick.tar ' -test_expect_success 'validate file modification time' ' - mkdir extract && - "$TAR" xf b.tar -C extract a/a && - test-tool chmtime --get extract/a/a >b.mtime && - echo "1117231200" >expected.mtime && - test_cmp expected.mtime b.mtime -' - test_expect_success 'git get-tar-commit-id' ' git get-tar-commit-id <b.tar >actual && git rev-parse HEAD >expect && @@ -342,6 +354,13 @@ test_expect_success 'only enabled filters are available remotely' ' test_cmp_bin remote.bar config.bar ' +test_expect_success 'invalid filter is reported only once' ' + test_must_fail git -c tar.invalid.command= archive --format=invalid \ + HEAD >out 2>err && + test_must_be_empty out && + test_line_count = 1 err +' + test_expect_success 'git archive --format=tgz' ' git archive --format=tgz HEAD >j.tgz ' @@ -395,11 +414,11 @@ test_expect_success GZIP 'extract tgz file (external gzip)' ' test_expect_success 'archive and :(glob)' ' git archive -v HEAD -- ":(glob)**/sh" >/dev/null 2>actual && - cat >expect <<EOF && -a/ -a/bin/ -a/bin/sh -EOF + cat >expect <<-\EOF && + a/ + a/bin/ + a/bin/sh + EOF test_cmp expect actual ' @@ -407,6 +426,19 @@ test_expect_success 'catch non-matching pathspec' ' test_must_fail git archive -v HEAD -- "*.abc" >/dev/null ' +test_expect_success 'reject paths outside the current directory' ' + test_must_fail git -C a/bin archive HEAD .. >/dev/null 2>err && + grep "outside the current directory" err +' + +test_expect_success 'allow pathspecs that resolve to the current directory' ' + git -C a/bin archive -v HEAD ../bin >/dev/null 2>actual && + cat >expect <<-\EOF && + sh + EOF + test_cmp expect actual +' + # Pull the size and date of each entry in a tarfile using the system tar. # # We'll pull out only the year from the date; that avoids any question of diff --git a/t/t5001-archive-attr.sh b/t/t5001-archive-attr.sh index 2f6eef5e37..0ff47a239d 100755 --- a/t/t5001-archive-attr.sh +++ b/t/t5001-archive-attr.sh @@ -3,6 +3,7 @@ test_description='git archive attribute tests' TEST_CREATE_REPO_NO_TEMPLATE=1 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh SUBSTFORMAT='%H (%h)%n' @@ -32,6 +33,13 @@ test_expect_success 'setup' ' echo ignored-by-tree.d export-ignore >>.gitattributes && git add ignored-by-tree ignored-by-tree.d .gitattributes && + mkdir subdir && + >subdir/included && + >subdir/ignored-by-subtree && + >subdir/ignored-by-tree && + echo ignored-by-subtree export-ignore >subdir/.gitattributes && + git add subdir && + echo ignored by worktree >ignored-by-worktree && echo ignored-by-worktree export-ignore >.gitattributes && git add ignored-by-worktree && @@ -92,6 +100,15 @@ test_expect_exists archive-pathspec-wildcard/ignored-by-worktree test_expect_missing archive-pathspec-wildcard/excluded-by-pathspec.d test_expect_missing archive-pathspec-wildcard/excluded-by-pathspec.d/file +test_expect_success 'git -C subdir archive' ' + git -C subdir archive HEAD >archive-subdir.tar && + extract_tar_to_dir archive-subdir +' + +test_expect_exists archive-subdir/included +test_expect_missing archive-subdir/ignored-by-subtree +test_expect_missing archive-subdir/ignored-by-tree + test_expect_success 'git archive with worktree attributes' ' git archive --worktree-attributes HEAD >worktree.tar && (mkdir worktree && cd worktree && "$TAR" xf -) <worktree.tar diff --git a/t/t5004-archive-corner-cases.sh b/t/t5004-archive-corner-cases.sh index ae508e2162..9f2c6da80e 100755 --- a/t/t5004-archive-corner-cases.sh +++ b/t/t5004-archive-corner-cases.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test corner cases of git-archive' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # the 10knuls.tar file is used to test for an empty git generated tar diff --git a/t/t5100/msg0002 b/t/t5100/msg0002 index e2546ec733..1089382425 100644 --- a/t/t5100/msg0002 +++ b/t/t5100/msg0002 @@ -3,7 +3,7 @@ message: From: Nit Picker <nit.picker@example.net> Subject: foo is too old -Message-Id: <nitpicker.12121212@example.net> +Message-ID: <nitpicker.12121212@example.net> Hopefully this would fix the problem stated there. diff --git a/t/t5100/msg0003 b/t/t5100/msg0003 index 1ac68101b1..3402b534a6 100644 --- a/t/t5100/msg0003 +++ b/t/t5100/msg0003 @@ -3,7 +3,7 @@ message: From: Nit Picker <nit.picker@example.net> Subject: foo is too old -Message-Id: <nitpicker.12121212@example.net> +Message-ID: <nitpicker.12121212@example.net> Hopefully this would fix the problem stated there. diff --git a/t/t5100/msg0012--message-id b/t/t5100/msg0012--message-id index 376e26e9ae..44482958ce 100644 --- a/t/t5100/msg0012--message-id +++ b/t/t5100/msg0012--message-id @@ -5,4 +5,4 @@ docutils заменён на python-docutils python-docutils. В то время как сам rest2web не нужен. Signed-off-by: Dmitriy Blinov <bda@mnsspb.ru> -Message-Id: <1226501681-24923-1-git-send-email-bda@mnsspb.ru> +Message-ID: <1226501681-24923-1-git-send-email-bda@mnsspb.ru> diff --git a/t/t5100/quoted-cr.mbox b/t/t5100/quoted-cr.mbox index 909021bb7a..a529d4de08 100644 --- a/t/t5100/quoted-cr.mbox +++ b/t/t5100/quoted-cr.mbox @@ -3,7 +3,7 @@ From: A U Thor <mail@example.com> To: list@example.org Subject: [PATCH v2] sample Date: Mon, 3 Aug 2020 22:40:55 +0700 -Message-Id: <msg-id@example.com> +Message-ID: <msg-id@example.com> Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 @@ -27,7 +27,7 @@ From: A U Thor <mail@example.com> To: list@example.org Subject: [PATCH v2] sample Date: Mon, 3 Aug 2020 22:40:55 +0700 -Message-Id: <msg-id2@example.com> +Message-ID: <msg-id2@example.com> Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 diff --git a/t/t5100/sample.mbox b/t/t5100/sample.mbox index 6d4d0e4474..4a54ee5171 100644 --- a/t/t5100/sample.mbox +++ b/t/t5100/sample.mbox @@ -35,7 +35,7 @@ message: From: Nit Picker <nit.picker@example.net> Subject: foo is too old -Message-Id: <nitpicker.12121212@example.net> +Message-ID: <nitpicker.12121212@example.net> Hopefully this would fix the problem stated there. @@ -78,7 +78,7 @@ message: From: Nit Picker <nit.picker@example.net> Subject: foo is too old -Message-Id: <nitpicker.12121212@example.net> +Message-ID: <nitpicker.12121212@example.net> Hopefully this would fix the problem stated there. @@ -508,7 +508,7 @@ From bda@mnsspb.ru Wed Nov 12 17:54:41 2008 From: Dmitriy Blinov <bda@mnsspb.ru> To: navy-patches@dinar.mns.mnsspb.ru Date: Wed, 12 Nov 2008 17:54:41 +0300 -Message-Id: <1226501681-24923-1-git-send-email-bda@mnsspb.ru> +Message-ID: <1226501681-24923-1-git-send-email-bda@mnsspb.ru> X-Mailer: git-send-email 1.5.6.5 MIME-Version: 1.0 Content-Type: text/plain; diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index f8a0f309e2..745089479c 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -208,7 +208,7 @@ test_expect_success 'unpack with OFS_DELTA' ' ' test_expect_success 'unpack with OFS_DELTA (core.fsyncmethod=batch)' ' - check_unpack test-3-${packname_3} obj-list "$BATCH_CONFIGURATION" + check_unpack test-3-${packname_3} obj-list "$BATCH_CONFIGURATION" ' test_expect_success 'compare delta flavors' ' @@ -263,97 +263,97 @@ test_expect_success 'survive missing objects/pack directory' ' ) ' -test_expect_success \ - 'verify pack' \ - 'git verify-pack test-1-${packname_1}.idx \ - test-2-${packname_2}.idx \ - test-3-${packname_3}.idx' - -test_expect_success \ - 'verify pack -v' \ - 'git verify-pack -v test-1-${packname_1}.idx \ - test-2-${packname_2}.idx \ - test-3-${packname_3}.idx' - -test_expect_success \ - 'verify-pack catches mismatched .idx and .pack files' \ - 'cat test-1-${packname_1}.idx >test-3.idx && - cat test-2-${packname_2}.pack >test-3.pack && - if git verify-pack test-3.idx - then false - else :; - fi' - -test_expect_success \ - 'verify-pack catches a corrupted pack signature' \ - 'cat test-1-${packname_1}.pack >test-3.pack && - echo | dd of=test-3.pack count=1 bs=1 conv=notrunc seek=2 && - if git verify-pack test-3.idx - then false - else :; - fi' - -test_expect_success \ - 'verify-pack catches a corrupted pack version' \ - 'cat test-1-${packname_1}.pack >test-3.pack && - echo | dd of=test-3.pack count=1 bs=1 conv=notrunc seek=7 && - if git verify-pack test-3.idx - then false - else :; - fi' - -test_expect_success \ - 'verify-pack catches a corrupted type/size of the 1st packed object data' \ - 'cat test-1-${packname_1}.pack >test-3.pack && - echo | dd of=test-3.pack count=1 bs=1 conv=notrunc seek=12 && - if git verify-pack test-3.idx - then false - else :; - fi' - -test_expect_success \ - 'verify-pack catches a corrupted sum of the index file itself' \ - 'l=$(wc -c <test-3.idx) && - l=$(expr $l - 20) && - cat test-1-${packname_1}.pack >test-3.pack && - printf "%20s" "" | dd of=test-3.idx count=20 bs=1 conv=notrunc seek=$l && - if git verify-pack test-3.pack - then false - else :; - fi' - -test_expect_success \ - 'build pack index for an existing pack' \ - 'cat test-1-${packname_1}.pack >test-3.pack && - git index-pack -o tmp.idx test-3.pack && - cmp tmp.idx test-1-${packname_1}.idx && - - git index-pack --promisor=message test-3.pack && - cmp test-3.idx test-1-${packname_1}.idx && - echo message >expect && - test_cmp expect test-3.promisor && - - cat test-2-${packname_2}.pack >test-3.pack && - git index-pack -o tmp.idx test-2-${packname_2}.pack && - cmp tmp.idx test-2-${packname_2}.idx && - - git index-pack test-3.pack && - cmp test-3.idx test-2-${packname_2}.idx && - - cat test-3-${packname_3}.pack >test-3.pack && - git index-pack -o tmp.idx test-3-${packname_3}.pack && - cmp tmp.idx test-3-${packname_3}.idx && - - git index-pack test-3.pack && - cmp test-3.idx test-3-${packname_3}.idx && - - cat test-1-${packname_1}.pack >test-4.pack && - rm -f test-4.keep && - git index-pack --keep=why test-4.pack && - cmp test-1-${packname_1}.idx test-4.idx && - test -f test-4.keep && - - :' +test_expect_success 'verify pack' ' + git verify-pack test-1-${packname_1}.idx \ + test-2-${packname_2}.idx \ + test-3-${packname_3}.idx +' + +test_expect_success 'verify pack -v' ' + git verify-pack -v test-1-${packname_1}.idx \ + test-2-${packname_2}.idx \ + test-3-${packname_3}.idx +' + +test_expect_success 'verify-pack catches mismatched .idx and .pack files' ' + cat test-1-${packname_1}.idx >test-3.idx && + cat test-2-${packname_2}.pack >test-3.pack && + if git verify-pack test-3.idx + then false + else :; + fi +' + +test_expect_success 'verify-pack catches a corrupted pack signature' ' + cat test-1-${packname_1}.pack >test-3.pack && + echo | dd of=test-3.pack count=1 bs=1 conv=notrunc seek=2 && + if git verify-pack test-3.idx + then false + else :; + fi +' + +test_expect_success 'verify-pack catches a corrupted pack version' ' + cat test-1-${packname_1}.pack >test-3.pack && + echo | dd of=test-3.pack count=1 bs=1 conv=notrunc seek=7 && + if git verify-pack test-3.idx + then false + else :; + fi +' + +test_expect_success 'verify-pack catches a corrupted type/size of the 1st packed object data' ' + cat test-1-${packname_1}.pack >test-3.pack && + echo | dd of=test-3.pack count=1 bs=1 conv=notrunc seek=12 && + if git verify-pack test-3.idx + then false + else :; + fi +' + +test_expect_success 'verify-pack catches a corrupted sum of the index file itself' ' + l=$(wc -c <test-3.idx) && + l=$(expr $l - 20) && + cat test-1-${packname_1}.pack >test-3.pack && + printf "%20s" "" | dd of=test-3.idx count=20 bs=1 conv=notrunc seek=$l && + if git verify-pack test-3.pack + then false + else :; + fi +' + +test_expect_success 'build pack index for an existing pack' ' + cat test-1-${packname_1}.pack >test-3.pack && + git index-pack -o tmp.idx test-3.pack && + cmp tmp.idx test-1-${packname_1}.idx && + + git index-pack --promisor=message test-3.pack && + cmp test-3.idx test-1-${packname_1}.idx && + echo message >expect && + test_cmp expect test-3.promisor && + + cat test-2-${packname_2}.pack >test-3.pack && + git index-pack -o tmp.idx test-2-${packname_2}.pack && + cmp tmp.idx test-2-${packname_2}.idx && + + git index-pack test-3.pack && + cmp test-3.idx test-2-${packname_2}.idx && + + cat test-3-${packname_3}.pack >test-3.pack && + git index-pack -o tmp.idx test-3-${packname_3}.pack && + cmp tmp.idx test-3-${packname_3}.idx && + + git index-pack test-3.pack && + cmp test-3.idx test-3-${packname_3}.idx && + + cat test-1-${packname_1}.pack >test-4.pack && + rm -f test-4.keep && + git index-pack --keep=why test-4.pack && + cmp test-1-${packname_1}.idx test-4.idx && + test -f test-4.keep && + + : +' test_expect_success 'unpacking with --strict' ' @@ -589,141 +589,6 @@ test_expect_success 'prefetch objects' ' test_line_count = 1 donelines ' -test_expect_success 'setup for --stdin-packs tests' ' - git init stdin-packs && - ( - cd stdin-packs && - - test_commit A && - test_commit B && - test_commit C && - - for id in A B C - do - git pack-objects .git/objects/pack/pack-$id \ - --incremental --revs <<-EOF || exit 1 - refs/tags/$id - EOF - done && - - ls -la .git/objects/pack - ) -' - -test_expect_success '--stdin-packs with excluded packs' ' - ( - cd stdin-packs && - - PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" && - PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" && - PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" && - - git pack-objects test --stdin-packs <<-EOF && - $PACK_A - ^$PACK_B - $PACK_C - EOF - - ( - git show-index <$(ls .git/objects/pack/pack-A-*.idx) && - git show-index <$(ls .git/objects/pack/pack-C-*.idx) - ) >expect.raw && - git show-index <$(ls test-*.idx) >actual.raw && - - cut -d" " -f2 <expect.raw | sort >expect && - cut -d" " -f2 <actual.raw | sort >actual && - test_cmp expect actual - ) -' - -test_expect_success '--stdin-packs is incompatible with --filter' ' - ( - cd stdin-packs && - test_must_fail git pack-objects --stdin-packs --stdout \ - --filter=blob:none </dev/null 2>err && - test_i18ngrep "cannot use --filter with --stdin-packs" err - ) -' - -test_expect_success '--stdin-packs is incompatible with --revs' ' - ( - cd stdin-packs && - test_must_fail git pack-objects --stdin-packs --revs out \ - </dev/null 2>err && - test_i18ngrep "cannot use internal rev list with --stdin-packs" err - ) -' - -test_expect_success '--stdin-packs with loose objects' ' - ( - cd stdin-packs && - - PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" && - PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" && - PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" && - - test_commit D && # loose - - git pack-objects test2 --stdin-packs --unpacked <<-EOF && - $PACK_A - ^$PACK_B - $PACK_C - EOF - - ( - git show-index <$(ls .git/objects/pack/pack-A-*.idx) && - git show-index <$(ls .git/objects/pack/pack-C-*.idx) && - git rev-list --objects --no-object-names \ - refs/tags/C..refs/tags/D - - ) >expect.raw && - ls -la . && - git show-index <$(ls test2-*.idx) >actual.raw && - - cut -d" " -f2 <expect.raw | sort >expect && - cut -d" " -f2 <actual.raw | sort >actual && - test_cmp expect actual - ) -' - -test_expect_success '--stdin-packs with broken links' ' - ( - cd stdin-packs && - - # make an unreachable object with a bogus parent - git cat-file -p HEAD >commit && - sed "s/$(git rev-parse HEAD^)/$(test_oid zero)/" <commit | - git hash-object -w -t commit --stdin >in && - - git pack-objects .git/objects/pack/pack-D <in && - - PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" && - PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" && - PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" && - PACK_D="$(basename .git/objects/pack/pack-D-*.pack)" && - - git pack-objects test3 --stdin-packs --unpacked <<-EOF && - $PACK_A - ^$PACK_B - $PACK_C - $PACK_D - EOF - - ( - git show-index <$(ls .git/objects/pack/pack-A-*.idx) && - git show-index <$(ls .git/objects/pack/pack-C-*.idx) && - git show-index <$(ls .git/objects/pack/pack-D-*.idx) && - git rev-list --objects --no-object-names \ - refs/tags/C..refs/tags/D - ) >expect.raw && - git show-index <$(ls test3-*.idx) >actual.raw && - - cut -d" " -f2 <expect.raw | sort >expect && - cut -d" " -f2 <actual.raw | sort >actual && - test_cmp expect actual - ) -' - test_expect_success 'negative window clamps to 0' ' git pack-objects --progress --window=-1 neg-window <obj-list 2>stderr && check_deltas stderr = 0 diff --git a/t/t5301-sliding-window.sh b/t/t5301-sliding-window.sh index 3ccaaeb397..226490d60d 100755 --- a/t/t5301-sliding-window.sh +++ b/t/t5301-sliding-window.sh @@ -8,55 +8,55 @@ test_description='mmap sliding window tests' TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh -test_expect_success \ - 'setup' \ - 'rm -f .git/index* && - for i in a b c - do - echo $i >$i && - test-tool genrandom "$i" 32768 >>$i && - git update-index --add $i || return 1 - done && - echo d >d && cat c >>d && git update-index --add d && - tree=$(git write-tree) && - commit1=$(git commit-tree $tree </dev/null) && - git update-ref HEAD $commit1 && - git repack -a -d && - test "$(git count-objects)" = "0 objects, 0 kilobytes" && - pack1=$(ls .git/objects/pack/*.pack) && - test -f "$pack1"' - -test_expect_success \ - 'verify-pack -v, defaults' \ - 'git verify-pack -v "$pack1"' - -test_expect_success \ - 'verify-pack -v, packedGitWindowSize == 1 page' \ - 'git config core.packedGitWindowSize 512 && - git verify-pack -v "$pack1"' - -test_expect_success \ - 'verify-pack -v, packedGit{WindowSize,Limit} == 1 page' \ - 'git config core.packedGitWindowSize 512 && - git config core.packedGitLimit 512 && - git verify-pack -v "$pack1"' - -test_expect_success \ - 'repack -a -d, packedGit{WindowSize,Limit} == 1 page' \ - 'git config core.packedGitWindowSize 512 && - git config core.packedGitLimit 512 && - commit2=$(git commit-tree $tree -p $commit1 </dev/null) && - git update-ref HEAD $commit2 && - git repack -a -d && - test "$(git count-objects)" = "0 objects, 0 kilobytes" && - pack2=$(ls .git/objects/pack/*.pack) && - test -f "$pack2" && - test "$pack1" \!= "$pack2"' - -test_expect_success \ - 'verify-pack -v, defaults' \ - 'git config --unset core.packedGitWindowSize && - git config --unset core.packedGitLimit && - git verify-pack -v "$pack2"' +test_expect_success 'setup' ' + rm -f .git/index* && + for i in a b c + do + echo $i >$i && + test-tool genrandom "$i" 32768 >>$i && + git update-index --add $i || return 1 + done && + echo d >d && cat c >>d && git update-index --add d && + tree=$(git write-tree) && + commit1=$(git commit-tree $tree </dev/null) && + git update-ref HEAD $commit1 && + git repack -a -d && + test "$(git count-objects)" = "0 objects, 0 kilobytes" && + pack1=$(ls .git/objects/pack/*.pack) && + test -f "$pack1" +' + +test_expect_success 'verify-pack -v, defaults' ' + git verify-pack -v "$pack1" +' + +test_expect_success 'verify-pack -v, packedGitWindowSize == 1 page' ' + git config core.packedGitWindowSize 512 && + git verify-pack -v "$pack1" +' + +test_expect_success 'verify-pack -v, packedGit{WindowSize,Limit} == 1 page' ' + git config core.packedGitWindowSize 512 && + git config core.packedGitLimit 512 && + git verify-pack -v "$pack1" +' + +test_expect_success 'repack -a -d, packedGit{WindowSize,Limit} == 1 page' ' + git config core.packedGitWindowSize 512 && + git config core.packedGitLimit 512 && + commit2=$(git commit-tree $tree -p $commit1 </dev/null) && + git update-ref HEAD $commit2 && + git repack -a -d && + test "$(git count-objects)" = "0 objects, 0 kilobytes" && + pack2=$(ls .git/objects/pack/*.pack) && + test -f "$pack2" && + test "$pack1" \!= "$pack2" +' + +test_expect_success 'verify-pack -v, defaults' ' + git config --unset core.packedGitWindowSize && + git config --unset core.packedGitLimit && + git verify-pack -v "$pack2" +' test_done diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh index b0095ab41d..f89809be53 100755 --- a/t/t5302-pack-index.sh +++ b/t/t5302-pack-index.sh @@ -4,6 +4,8 @@ # test_description='pack index with 64-bit offsets and object CRC' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' @@ -263,7 +265,7 @@ tag guten tag This is an invalid tag. EOF - tag=$(git hash-object -t tag -w --stdin <wrong-tag) && + tag=$(git hash-object -t tag -w --stdin --literally <wrong-tag) && pack1=$(echo $tag $sha | git pack-objects tag-test) && echo remove tag object && thirtyeight=${tag#??} && diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh index 2926e8dfc4..61469ef4a6 100755 --- a/t/t5303-pack-corruption-resilience.sh +++ b/t/t5303-pack-corruption-resilience.sh @@ -59,304 +59,304 @@ do_corrupt_object() { printf '\0' > zero -test_expect_success \ - 'initial setup validation' \ - 'create_test_files && - create_new_pack && - git prune-packed && - git cat-file blob $blob_1 > /dev/null && - git cat-file blob $blob_2 > /dev/null && - git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - 'create corruption in header of first object' \ - 'do_corrupt_object $blob_1 0 < zero && - test_must_fail git cat-file blob $blob_1 > /dev/null && - test_must_fail git cat-file blob $blob_2 > /dev/null && - test_must_fail git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - '... but having a loose copy allows for full recovery' \ - 'mv ${pack}.idx tmp && - git hash-object -t blob -w file_1 && - mv tmp ${pack}.idx && - git cat-file blob $blob_1 > /dev/null && - git cat-file blob $blob_2 > /dev/null && - git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - '... and loose copy of first delta allows for partial recovery' \ - 'git prune-packed && - test_must_fail git cat-file blob $blob_2 > /dev/null && - mv ${pack}.idx tmp && - git hash-object -t blob -w file_2 && - mv tmp ${pack}.idx && - test_must_fail git cat-file blob $blob_1 > /dev/null && - git cat-file blob $blob_2 > /dev/null && - git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - 'create corruption in data of first object' \ - 'create_new_pack && - git prune-packed && - chmod +w ${pack}.pack && - perl -i.bak -pe "s/ base /abcdef/" ${pack}.pack && - test_must_fail git cat-file blob $blob_1 > /dev/null && - test_must_fail git cat-file blob $blob_2 > /dev/null && - test_must_fail git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - '... but having a loose copy allows for full recovery' \ - 'mv ${pack}.idx tmp && - git hash-object -t blob -w file_1 && - mv tmp ${pack}.idx && - git cat-file blob $blob_1 > /dev/null && - git cat-file blob $blob_2 > /dev/null && - git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - '... and loose copy of second object allows for partial recovery' \ - 'git prune-packed && - test_must_fail git cat-file blob $blob_2 > /dev/null && - mv ${pack}.idx tmp && - git hash-object -t blob -w file_2 && - mv tmp ${pack}.idx && - test_must_fail git cat-file blob $blob_1 > /dev/null && - git cat-file blob $blob_2 > /dev/null && - git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - 'create corruption in header of first delta' \ - 'create_new_pack && - git prune-packed && - do_corrupt_object $blob_2 0 < zero && - git cat-file blob $blob_1 > /dev/null && - test_must_fail git cat-file blob $blob_2 > /dev/null && - test_must_fail git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - '... but having a loose copy allows for full recovery' \ - 'mv ${pack}.idx tmp && - git hash-object -t blob -w file_2 && - mv tmp ${pack}.idx && - git cat-file blob $blob_1 > /dev/null && - git cat-file blob $blob_2 > /dev/null && - git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - '... and then a repack "clears" the corruption' \ - 'do_repack && - git prune-packed && - git verify-pack ${pack}.pack && - git cat-file blob $blob_1 > /dev/null && - git cat-file blob $blob_2 > /dev/null && - git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - 'create corruption in data of first delta' \ - 'create_new_pack && - git prune-packed && - chmod +w ${pack}.pack && - perl -i.bak -pe "s/ delta1 /abcdefgh/" ${pack}.pack && - git cat-file blob $blob_1 > /dev/null && - test_must_fail git cat-file blob $blob_2 > /dev/null && - test_must_fail git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - '... but having a loose copy allows for full recovery' \ - 'mv ${pack}.idx tmp && - git hash-object -t blob -w file_2 && - mv tmp ${pack}.idx && - git cat-file blob $blob_1 > /dev/null && - git cat-file blob $blob_2 > /dev/null && - git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - '... and then a repack "clears" the corruption' \ - 'do_repack && - git prune-packed && - git verify-pack ${pack}.pack && - git cat-file blob $blob_1 > /dev/null && - git cat-file blob $blob_2 > /dev/null && - git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - 'corruption in delta base reference of first delta (OBJ_REF_DELTA)' \ - 'create_new_pack && - git prune-packed && - do_corrupt_object $blob_2 2 < zero && - git cat-file blob $blob_1 > /dev/null && - test_must_fail git cat-file blob $blob_2 > /dev/null && - test_must_fail git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - '... but having a loose copy allows for full recovery' \ - 'mv ${pack}.idx tmp && - git hash-object -t blob -w file_2 && - mv tmp ${pack}.idx && - git cat-file blob $blob_1 > /dev/null && - git cat-file blob $blob_2 > /dev/null && - git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - '... and then a repack "clears" the corruption' \ - 'do_repack && - git prune-packed && - git verify-pack ${pack}.pack && - git cat-file blob $blob_1 > /dev/null && - git cat-file blob $blob_2 > /dev/null && - git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - 'corruption #0 in delta base reference of first delta (OBJ_OFS_DELTA)' \ - 'create_new_pack --delta-base-offset && - git prune-packed && - do_corrupt_object $blob_2 2 < zero && - git cat-file blob $blob_1 > /dev/null && - test_must_fail git cat-file blob $blob_2 > /dev/null && - test_must_fail git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - '... but having a loose copy allows for full recovery' \ - 'mv ${pack}.idx tmp && - git hash-object -t blob -w file_2 && - mv tmp ${pack}.idx && - git cat-file blob $blob_1 > /dev/null && - git cat-file blob $blob_2 > /dev/null && - git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - '... and then a repack "clears" the corruption' \ - 'do_repack --delta-base-offset && - git prune-packed && - git verify-pack ${pack}.pack && - git cat-file blob $blob_1 > /dev/null && - git cat-file blob $blob_2 > /dev/null && - git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - 'corruption #1 in delta base reference of first delta (OBJ_OFS_DELTA)' \ - 'create_new_pack --delta-base-offset && - git prune-packed && - printf "\001" | do_corrupt_object $blob_2 2 && - git cat-file blob $blob_1 > /dev/null && - test_must_fail git cat-file blob $blob_2 > /dev/null && - test_must_fail git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - '... but having a loose copy allows for full recovery' \ - 'mv ${pack}.idx tmp && - git hash-object -t blob -w file_2 && - mv tmp ${pack}.idx && - git cat-file blob $blob_1 > /dev/null && - git cat-file blob $blob_2 > /dev/null && - git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - '... and then a repack "clears" the corruption' \ - 'do_repack --delta-base-offset && - git prune-packed && - git verify-pack ${pack}.pack && - git cat-file blob $blob_1 > /dev/null && - git cat-file blob $blob_2 > /dev/null && - git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - '... and a redundant pack allows for full recovery too' \ - 'do_corrupt_object $blob_2 2 < zero && - git cat-file blob $blob_1 > /dev/null && - test_must_fail git cat-file blob $blob_2 > /dev/null && - test_must_fail git cat-file blob $blob_3 > /dev/null && - mv ${pack}.idx tmp && - git hash-object -t blob -w file_1 && - git hash-object -t blob -w file_2 && - printf "$blob_1\n$blob_2\n" | git pack-objects .git/objects/pack/pack && - git prune-packed && - mv tmp ${pack}.idx && - git cat-file blob $blob_1 > /dev/null && - git cat-file blob $blob_2 > /dev/null && - git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - 'corruption of delta base reference pointing to wrong object' \ - 'create_new_pack --delta-base-offset && - git prune-packed && - printf "\220\033" | do_corrupt_object $blob_3 2 && - git cat-file blob $blob_1 >/dev/null && - git cat-file blob $blob_2 >/dev/null && - test_must_fail git cat-file blob $blob_3 >/dev/null' - -test_expect_success \ - '... but having a loose copy allows for full recovery' \ - 'mv ${pack}.idx tmp && - git hash-object -t blob -w file_3 && - mv tmp ${pack}.idx && - git cat-file blob $blob_1 > /dev/null && - git cat-file blob $blob_2 > /dev/null && - git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - '... and then a repack "clears" the corruption' \ - 'do_repack --delta-base-offset --no-reuse-delta && - git prune-packed && - git verify-pack ${pack}.pack && - git cat-file blob $blob_1 > /dev/null && - git cat-file blob $blob_2 > /dev/null && - git cat-file blob $blob_3 > /dev/null' - -test_expect_success \ - 'corrupting header to have too small output buffer fails unpack' \ - 'create_new_pack && - git prune-packed && - printf "\262\001" | do_corrupt_object $blob_1 0 && - test_must_fail git cat-file blob $blob_1 > /dev/null && - test_must_fail git cat-file blob $blob_2 > /dev/null && - test_must_fail git cat-file blob $blob_3 > /dev/null' +test_expect_success 'initial setup validation' ' + create_test_files && + create_new_pack && + git prune-packed && + git cat-file blob $blob_1 > /dev/null && + git cat-file blob $blob_2 > /dev/null && + git cat-file blob $blob_3 > /dev/null +' + +test_expect_success 'create corruption in header of first object' ' + do_corrupt_object $blob_1 0 < zero && + test_must_fail git cat-file blob $blob_1 > /dev/null && + test_must_fail git cat-file blob $blob_2 > /dev/null && + test_must_fail git cat-file blob $blob_3 > /dev/null +' + +test_expect_success '... but having a loose copy allows for full recovery' ' + mv ${pack}.idx tmp && + git hash-object -t blob -w file_1 && + mv tmp ${pack}.idx && + git cat-file blob $blob_1 > /dev/null && + git cat-file blob $blob_2 > /dev/null && + git cat-file blob $blob_3 > /dev/null +' + +test_expect_success '... and loose copy of first delta allows for partial recovery' ' + git prune-packed && + test_must_fail git cat-file blob $blob_2 > /dev/null && + mv ${pack}.idx tmp && + git hash-object -t blob -w file_2 && + mv tmp ${pack}.idx && + test_must_fail git cat-file blob $blob_1 > /dev/null && + git cat-file blob $blob_2 > /dev/null && + git cat-file blob $blob_3 > /dev/null +' + +test_expect_success 'create corruption in data of first object' ' + create_new_pack && + git prune-packed && + chmod +w ${pack}.pack && + perl -i.bak -pe "s/ base /abcdef/" ${pack}.pack && + test_must_fail git cat-file blob $blob_1 > /dev/null && + test_must_fail git cat-file blob $blob_2 > /dev/null && + test_must_fail git cat-file blob $blob_3 > /dev/null +' + +test_expect_success '... but having a loose copy allows for full recovery' ' + mv ${pack}.idx tmp && + git hash-object -t blob -w file_1 && + mv tmp ${pack}.idx && + git cat-file blob $blob_1 > /dev/null && + git cat-file blob $blob_2 > /dev/null && + git cat-file blob $blob_3 > /dev/null +' + +test_expect_success '... and loose copy of second object allows for partial recovery' ' + git prune-packed && + test_must_fail git cat-file blob $blob_2 > /dev/null && + mv ${pack}.idx tmp && + git hash-object -t blob -w file_2 && + mv tmp ${pack}.idx && + test_must_fail git cat-file blob $blob_1 > /dev/null && + git cat-file blob $blob_2 > /dev/null && + git cat-file blob $blob_3 > /dev/null +' + +test_expect_success 'create corruption in header of first delta' ' + create_new_pack && + git prune-packed && + do_corrupt_object $blob_2 0 < zero && + git cat-file blob $blob_1 > /dev/null && + test_must_fail git cat-file blob $blob_2 > /dev/null && + test_must_fail git cat-file blob $blob_3 > /dev/null +' + +test_expect_success '... but having a loose copy allows for full recovery' ' + mv ${pack}.idx tmp && + git hash-object -t blob -w file_2 && + mv tmp ${pack}.idx && + git cat-file blob $blob_1 > /dev/null && + git cat-file blob $blob_2 > /dev/null && + git cat-file blob $blob_3 > /dev/null +' + +test_expect_success '... and then a repack "clears" the corruption' ' + do_repack && + git prune-packed && + git verify-pack ${pack}.pack && + git cat-file blob $blob_1 > /dev/null && + git cat-file blob $blob_2 > /dev/null && + git cat-file blob $blob_3 > /dev/null +' + +test_expect_success 'create corruption in data of first delta' ' + create_new_pack && + git prune-packed && + chmod +w ${pack}.pack && + perl -i.bak -pe "s/ delta1 /abcdefgh/" ${pack}.pack && + git cat-file blob $blob_1 > /dev/null && + test_must_fail git cat-file blob $blob_2 > /dev/null && + test_must_fail git cat-file blob $blob_3 > /dev/null +' + +test_expect_success '... but having a loose copy allows for full recovery' ' + mv ${pack}.idx tmp && + git hash-object -t blob -w file_2 && + mv tmp ${pack}.idx && + git cat-file blob $blob_1 > /dev/null && + git cat-file blob $blob_2 > /dev/null && + git cat-file blob $blob_3 > /dev/null +' + +test_expect_success '... and then a repack "clears" the corruption' ' + do_repack && + git prune-packed && + git verify-pack ${pack}.pack && + git cat-file blob $blob_1 > /dev/null && + git cat-file blob $blob_2 > /dev/null && + git cat-file blob $blob_3 > /dev/null +' + +test_expect_success 'corruption in delta base reference of first delta (OBJ_REF_DELTA)' ' + create_new_pack && + git prune-packed && + do_corrupt_object $blob_2 2 < zero && + git cat-file blob $blob_1 > /dev/null && + test_must_fail git cat-file blob $blob_2 > /dev/null && + test_must_fail git cat-file blob $blob_3 > /dev/null +' + +test_expect_success '... but having a loose copy allows for full recovery' ' + mv ${pack}.idx tmp && + git hash-object -t blob -w file_2 && + mv tmp ${pack}.idx && + git cat-file blob $blob_1 > /dev/null && + git cat-file blob $blob_2 > /dev/null && + git cat-file blob $blob_3 > /dev/null +' + +test_expect_success '... and then a repack "clears" the corruption' ' + do_repack && + git prune-packed && + git verify-pack ${pack}.pack && + git cat-file blob $blob_1 > /dev/null && + git cat-file blob $blob_2 > /dev/null && + git cat-file blob $blob_3 > /dev/null +' + +test_expect_success 'corruption #0 in delta base reference of first delta (OBJ_OFS_DELTA)' ' + create_new_pack --delta-base-offset && + git prune-packed && + do_corrupt_object $blob_2 2 < zero && + git cat-file blob $blob_1 > /dev/null && + test_must_fail git cat-file blob $blob_2 > /dev/null && + test_must_fail git cat-file blob $blob_3 > /dev/null +' + +test_expect_success '... but having a loose copy allows for full recovery' ' + mv ${pack}.idx tmp && + git hash-object -t blob -w file_2 && + mv tmp ${pack}.idx && + git cat-file blob $blob_1 > /dev/null && + git cat-file blob $blob_2 > /dev/null && + git cat-file blob $blob_3 > /dev/null +' + +test_expect_success '... and then a repack "clears" the corruption' ' + do_repack --delta-base-offset && + git prune-packed && + git verify-pack ${pack}.pack && + git cat-file blob $blob_1 > /dev/null && + git cat-file blob $blob_2 > /dev/null && + git cat-file blob $blob_3 > /dev/null +' + +test_expect_success 'corruption #1 in delta base reference of first delta (OBJ_OFS_DELTA)' ' + create_new_pack --delta-base-offset && + git prune-packed && + printf "\001" | do_corrupt_object $blob_2 2 && + git cat-file blob $blob_1 > /dev/null && + test_must_fail git cat-file blob $blob_2 > /dev/null && + test_must_fail git cat-file blob $blob_3 > /dev/null +' + +test_expect_success '... but having a loose copy allows for full recovery' ' + mv ${pack}.idx tmp && + git hash-object -t blob -w file_2 && + mv tmp ${pack}.idx && + git cat-file blob $blob_1 > /dev/null && + git cat-file blob $blob_2 > /dev/null && + git cat-file blob $blob_3 > /dev/null +' + +test_expect_success '... and then a repack "clears" the corruption' ' + do_repack --delta-base-offset && + git prune-packed && + git verify-pack ${pack}.pack && + git cat-file blob $blob_1 > /dev/null && + git cat-file blob $blob_2 > /dev/null && + git cat-file blob $blob_3 > /dev/null +' + +test_expect_success '... and a redundant pack allows for full recovery too' ' + do_corrupt_object $blob_2 2 < zero && + git cat-file blob $blob_1 > /dev/null && + test_must_fail git cat-file blob $blob_2 > /dev/null && + test_must_fail git cat-file blob $blob_3 > /dev/null && + mv ${pack}.idx tmp && + git hash-object -t blob -w file_1 && + git hash-object -t blob -w file_2 && + printf "$blob_1\n$blob_2\n" | git pack-objects .git/objects/pack/pack && + git prune-packed && + mv tmp ${pack}.idx && + git cat-file blob $blob_1 > /dev/null && + git cat-file blob $blob_2 > /dev/null && + git cat-file blob $blob_3 > /dev/null +' + +test_expect_success 'corruption of delta base reference pointing to wrong object' ' + create_new_pack --delta-base-offset && + git prune-packed && + printf "\220\033" | do_corrupt_object $blob_3 2 && + git cat-file blob $blob_1 >/dev/null && + git cat-file blob $blob_2 >/dev/null && + test_must_fail git cat-file blob $blob_3 >/dev/null +' + +test_expect_success '... but having a loose copy allows for full recovery' ' + mv ${pack}.idx tmp && + git hash-object -t blob -w file_3 && + mv tmp ${pack}.idx && + git cat-file blob $blob_1 > /dev/null && + git cat-file blob $blob_2 > /dev/null && + git cat-file blob $blob_3 > /dev/null +' + +test_expect_success '... and then a repack "clears" the corruption' ' + do_repack --delta-base-offset --no-reuse-delta && + git prune-packed && + git verify-pack ${pack}.pack && + git cat-file blob $blob_1 > /dev/null && + git cat-file blob $blob_2 > /dev/null && + git cat-file blob $blob_3 > /dev/null +' + +test_expect_success 'corrupting header to have too small output buffer fails unpack' ' + create_new_pack && + git prune-packed && + printf "\262\001" | do_corrupt_object $blob_1 0 && + test_must_fail git cat-file blob $blob_1 > /dev/null && + test_must_fail git cat-file blob $blob_2 > /dev/null && + test_must_fail git cat-file blob $blob_3 > /dev/null +' # \0 - empty base # \1 - one byte in result # \1 - one literal byte (X) -test_expect_success \ - 'apply good minimal delta' \ - 'printf "\0\1\1X" > minimal_delta && - test-tool delta -p /dev/null minimal_delta /dev/null' +test_expect_success 'apply good minimal delta' ' + printf "\0\1\1X" > minimal_delta && + test-tool delta -p /dev/null minimal_delta /dev/null +' # \0 - empty base # \1 - 1 byte in result # \2 - two literal bytes (one too many) -test_expect_success \ - 'apply delta with too many literal bytes' \ - 'printf "\0\1\2XX" > too_big_literal && - test_must_fail test-tool delta -p /dev/null too_big_literal /dev/null' +test_expect_success 'apply delta with too many literal bytes' ' + printf "\0\1\2XX" > too_big_literal && + test_must_fail test-tool delta -p /dev/null too_big_literal /dev/null +' # \4 - four bytes in base # \1 - one byte in result # \221 - copy, one byte offset, one byte size # \0 - copy from offset 0 # \2 - copy two bytes (one too many) -test_expect_success \ - 'apply delta with too many copied bytes' \ - 'printf "\4\1\221\0\2" > too_big_copy && - printf base >base && - test_must_fail test-tool delta -p base too_big_copy /dev/null' +test_expect_success 'apply delta with too many copied bytes' ' + printf "\4\1\221\0\2" > too_big_copy && + printf base >base && + test_must_fail test-tool delta -p base too_big_copy /dev/null +' # \0 - empty base # \2 - two bytes in result # \2 - two literal bytes (we are short one) -test_expect_success \ - 'apply delta with too few literal bytes' \ - 'printf "\0\2\2X" > truncated_delta && - test_must_fail test-tool delta -p /dev/null truncated_delta /dev/null' +test_expect_success 'apply delta with too few literal bytes' ' + printf "\0\2\2X" > truncated_delta && + test_must_fail test-tool delta -p /dev/null truncated_delta /dev/null +' # \0 - empty base # \1 - one byte in result # \221 - copy, one byte offset, one byte size # \0 - copy from offset 0 # \1 - copy one byte (we are short one) -test_expect_success \ - 'apply delta with too few bytes in base' \ - 'printf "\0\1\221\0\1" > truncated_base && - test_must_fail test-tool delta -p /dev/null truncated_base /dev/null' +test_expect_success 'apply delta with too few bytes in base' ' + printf "\0\1\221\0\1" > truncated_base && + test_must_fail test-tool delta -p /dev/null truncated_base /dev/null +' # \4 - four bytes in base # \2 - two bytes in result @@ -366,20 +366,20 @@ test_expect_success \ # # Note that the literal byte is necessary to get past the uninteresting minimum # delta size check. -test_expect_success \ - 'apply delta with truncated copy parameters' \ - 'printf "\4\2\1X\221" > truncated_copy_delta && - printf base >base && - test_must_fail test-tool delta -p base truncated_copy_delta /dev/null' +test_expect_success 'apply delta with truncated copy parameters' ' + printf "\4\2\1X\221" > truncated_copy_delta && + printf base >base && + test_must_fail test-tool delta -p base truncated_copy_delta /dev/null +' # \0 - empty base # \1 - one byte in result # \1 - one literal byte (X) # \1 - trailing garbage command -test_expect_success \ - 'apply delta with trailing garbage literal' \ - 'printf "\0\1\1X\1" > tail_garbage_literal && - test_must_fail test-tool delta -p /dev/null tail_garbage_literal /dev/null' +test_expect_success 'apply delta with trailing garbage literal' ' + printf "\0\1\1X\1" > tail_garbage_literal && + test_must_fail test-tool delta -p /dev/null tail_garbage_literal /dev/null +' # \4 - four bytes in base # \1 - one byte in result @@ -387,19 +387,19 @@ test_expect_success \ # \221 - copy, one byte offset, one byte size # \0 - copy from offset 0 # \1 - copy 1 byte -test_expect_success \ - 'apply delta with trailing garbage copy' \ - 'printf "\4\1\1X\221\0\1" > tail_garbage_copy && - printf base >base && - test_must_fail test-tool delta -p /dev/null tail_garbage_copy /dev/null' +test_expect_success 'apply delta with trailing garbage copy' ' + printf "\4\1\1X\221\0\1" > tail_garbage_copy && + printf base >base && + test_must_fail test-tool delta -p /dev/null tail_garbage_copy /dev/null +' # \0 - empty base # \1 - one byte in result # \1 - one literal byte (X) # \0 - bogus opcode -test_expect_success \ - 'apply delta with trailing garbage opcode' \ - 'printf "\0\1\1X\0" > tail_garbage_opcode && - test_must_fail test-tool delta -p /dev/null tail_garbage_opcode /dev/null' +test_expect_success 'apply delta with trailing garbage opcode' ' + printf "\0\1\1X\0" > tail_garbage_opcode && + test_must_fail test-tool delta -p /dev/null tail_garbage_opcode /dev/null +' test_done diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh index 8ae314af58..b4df545e5a 100755 --- a/t/t5304-prune.sh +++ b/t/t5304-prune.sh @@ -16,7 +16,7 @@ add_blob() { before=$(git count-objects | sed "s/ .*//") && BLOB=$(echo aleph_0 | git hash-object -w --stdin) && BLOB_FILE=.git/objects/$(echo $BLOB | sed "s/^../&\//") && - verbose test $((1 + $before)) = $(git count-objects | sed "s/ .*//") && + test $((1 + $before)) = $(git count-objects | sed "s/ .*//") && test_path_is_file $BLOB_FILE && test-tool chmtime =+0 $BLOB_FILE } @@ -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 && @@ -43,34 +51,42 @@ test_expect_success 'prune stale packs' ' test_expect_success 'prune --expire' ' add_blob && git prune --expire=1.hour.ago && - verbose test $((1 + $before)) = $(git count-objects | sed "s/ .*//") && + test $((1 + $before)) = $(git count-objects | sed "s/ .*//") && test_path_is_file $BLOB_FILE && test-tool chmtime =-86500 $BLOB_FILE && git prune --expire 1.day && - verbose test $before = $(git count-objects | sed "s/ .*//") && + test $before = $(git count-objects | sed "s/ .*//") && test_path_is_missing $BLOB_FILE ' test_expect_success 'gc: implicit prune --expire' ' add_blob && test-tool chmtime =-$((2*$week-30)) $BLOB_FILE && - git gc && - verbose test $((1 + $before)) = $(git count-objects | sed "s/ .*//") && + git gc --no-cruft && + test $((1 + $before)) = $(git count-objects | sed "s/ .*//") && test_path_is_file $BLOB_FILE && test-tool chmtime =-$((2*$week+1)) $BLOB_FILE && - git gc && - verbose test $before = $(git count-objects | sed "s/ .*//") && + git gc --no-cruft && + test $before = $(git count-objects | sed "s/ .*//") && test_path_is_missing $BLOB_FILE ' test_expect_success 'gc: refuse to start with invalid gc.pruneExpire' ' - git config gc.pruneExpire invalid && - test_must_fail git gc + test_when_finished "rm -rf repo" && + git init repo && + >repo/.git/config && + git -C repo config gc.pruneExpire invalid && + cat >expect <<-\EOF && + error: Invalid gc.pruneexpire: '\''invalid'\'' + fatal: bad config variable '\''gc.pruneexpire'\'' in file '\''.git/config'\'' at line 2 + EOF + test_must_fail git -C repo gc 2>actual && + test_cmp expect actual ' test_expect_success 'gc: start with ok gc.pruneExpire' ' git config gc.pruneExpire 2.days.ago && - git gc + git gc --no-cruft ' test_expect_success 'prune: prune nonsense parameters' ' @@ -121,44 +137,44 @@ test_expect_success 'gc --no-prune' ' add_blob && test-tool chmtime =-$((5001*$day)) $BLOB_FILE && git config gc.pruneExpire 2.days.ago && - git gc --no-prune && - verbose test 1 = $(git count-objects | sed "s/ .*//") && + git gc --no-prune --no-cruft && + test 1 = $(git count-objects | sed "s/ .*//") && test_path_is_file $BLOB_FILE ' test_expect_success 'gc respects gc.pruneExpire' ' git config gc.pruneExpire 5002.days.ago && - git gc && + git gc --no-cruft && test_path_is_file $BLOB_FILE && git config gc.pruneExpire 5000.days.ago && - git gc && + git gc --no-cruft && test_path_is_missing $BLOB_FILE ' test_expect_success 'gc --prune=<date>' ' add_blob && test-tool chmtime =-$((5001*$day)) $BLOB_FILE && - git gc --prune=5002.days.ago && + git gc --prune=5002.days.ago --no-cruft && test_path_is_file $BLOB_FILE && - git gc --prune=5000.days.ago && + git gc --prune=5000.days.ago --no-cruft && test_path_is_missing $BLOB_FILE ' test_expect_success 'gc --prune=never' ' add_blob && - git gc --prune=never && + git gc --prune=never --no-cruft && test_path_is_file $BLOB_FILE && - git gc --prune=now && + git gc --prune=now --no-cruft && test_path_is_missing $BLOB_FILE ' test_expect_success 'gc respects gc.pruneExpire=never' ' git config gc.pruneExpire never && add_blob && - git gc && + git gc --no-cruft && test_path_is_file $BLOB_FILE && git config gc.pruneExpire now && - git gc && + git gc --no-cruft && test_path_is_missing $BLOB_FILE ' @@ -176,10 +192,10 @@ test_expect_success 'gc: prune old objects after local clone' ' git clone --no-hardlinks . aclone && ( cd aclone && - verbose test 1 = $(git count-objects | sed "s/ .*//") && + test 1 = $(git count-objects | sed "s/ .*//") && test_path_is_file $BLOB_FILE && - git gc --prune && - verbose test 0 = $(git count-objects | sed "s/ .*//") && + git gc --prune --no-cruft && + test 0 = $(git count-objects | sed "s/ .*//") && test_path_is_missing $BLOB_FILE ) ' @@ -221,7 +237,7 @@ test_expect_success 'clean pack garbage with gc' ' >.git/objects/pack/fake2.keep && >.git/objects/pack/fake2.idx && >.git/objects/pack/fake3.keep && - git gc && + git gc --no-cruft && git count-objects -v 2>stderr && grep "^warning:" stderr | sort >actual && cat >expected <<\EOF && @@ -334,4 +350,18 @@ test_expect_success 'old reachable-from-recent retained with bitmaps' ' test_must_fail git cat-file -e $to_drop ' +test_expect_success 'gc.recentObjectsHook' ' + add_blob && + test-tool chmtime =-86500 $BLOB_FILE && + + write_script precious-objects <<-EOF && + echo $BLOB + EOF + test_config gc.recentObjectsHook ./precious-objects && + + git prune --expire=now && + + git cat-file -p $BLOB +' + test_done diff --git a/t/t5306-pack-nobase.sh b/t/t5306-pack-nobase.sh index 51973f4a51..0d50c6b4bc 100755 --- a/t/t5306-pack-nobase.sh +++ b/t/t5306-pack-nobase.sh @@ -6,22 +6,23 @@ test_description='git-pack-object with missing base ' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Create A-B chain # -test_expect_success \ - 'setup base' \ - 'test_write_lines a b c d e f g h i >text && - echo side >side && - git update-index --add text side && - A=$(echo A | git commit-tree $(git write-tree)) && +test_expect_success 'setup base' ' + test_write_lines a b c d e f g h i >text && + echo side >side && + git update-index --add text side && + A=$(echo A | git commit-tree $(git write-tree)) && - echo m >>text && - git update-index text && - B=$(echo B | git commit-tree $(git write-tree) -p $A) && - git update-ref HEAD $B - ' + echo m >>text && + git update-index text && + B=$(echo B | git commit-tree $(git write-tree) -p $A) && + git update-ref HEAD $B +' # Create repository with C whose parent is B. # Repository contains C, C^{tree}, C:text, B, B^{tree}. @@ -29,52 +30,49 @@ test_expect_success \ # Repository is missing A (parent of B). # Repository is missing A:side. # -test_expect_success \ - 'setup patch_clone' \ - 'base_objects=$(pwd)/.git/objects && - (mkdir patch_clone && - cd patch_clone && - git init && - echo "$base_objects" >.git/objects/info/alternates && - echo q >>text && - git read-tree $B && - git update-index text && - git update-ref HEAD $(echo C | git commit-tree $(git write-tree) -p $B) && - rm .git/objects/info/alternates && +test_expect_success 'setup patch_clone' ' + base_objects=$(pwd)/.git/objects && + (mkdir patch_clone && + cd patch_clone && + git init && + echo "$base_objects" >.git/objects/info/alternates && + echo q >>text && + git read-tree $B && + git update-index text && + git update-ref HEAD $(echo C | git commit-tree $(git write-tree) -p $B) && + rm .git/objects/info/alternates && - git --git-dir=../.git cat-file commit $B | - git hash-object -t commit -w --stdin && + git --git-dir=../.git cat-file commit $B | + git hash-object -t commit -w --stdin && - git --git-dir=../.git cat-file tree "$B^{tree}" | - git hash-object -t tree -w --stdin - ) && - C=$(git --git-dir=patch_clone/.git rev-parse HEAD) - ' + git --git-dir=../.git cat-file tree "$B^{tree}" | + git hash-object -t tree -w --stdin + ) && + C=$(git --git-dir=patch_clone/.git rev-parse HEAD) +' # Clone patch_clone indirectly by cloning base and fetching. # -test_expect_success \ - 'indirectly clone patch_clone' \ - '(mkdir user_clone && - cd user_clone && - git init && - git pull ../.git && - test $(git rev-parse HEAD) = $B && +test_expect_success 'indirectly clone patch_clone' ' + (mkdir user_clone && + cd user_clone && + git init && + git pull ../.git && + test $(git rev-parse HEAD) = $B && - git pull ../patch_clone/.git && - test $(git rev-parse HEAD) = $C - ) - ' + git pull ../patch_clone/.git && + test $(git rev-parse HEAD) = $C + ) +' # Cloning the patch_clone directly should fail. # -test_expect_success \ - 'clone of patch_clone is incomplete' \ - '(mkdir user_direct && - cd user_direct && - git init && - test_must_fail git fetch ../patch_clone/.git - ) - ' +test_expect_success 'clone of patch_clone is incomplete' ' + (mkdir user_direct && + cd user_direct && + git init && + test_must_fail git fetch ../patch_clone/.git + ) +' test_done diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh index 6d693eef82..78c1c6c923 100755 --- a/t/t5310-pack-bitmaps.sh +++ b/t/t5310-pack-bitmaps.sh @@ -9,6 +9,10 @@ test_description='exercise basic bitmap functionality' # their place. GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 +# Likewise, allow individual tests to control whether or not they use +# the boundary-based traversal. +sane_unset GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL + objpath () { echo ".git/objects/$(echo "$1" | sed -e 's|\(..\)|\1/|')" } @@ -404,6 +408,26 @@ test_bitmap_cases () { ) ' + test_expect_success 'pack.preferBitmapTips' ' + git init repo && + test_when_finished "rm -rf repo" && + ( + cd repo && + git config pack.writeBitmapLookupTable '"$writeLookupTable"' && + test_commit_bulk --message="%s" 103 && + + cat >>.git/config <<-\EOF && + [pack] + preferBitmapTips + EOF + cat >expect <<-\EOF && + error: missing value for '\''pack.preferbitmaptips'\'' + EOF + git repack -adb 2>actual && + test_cmp expect actual + ) + ' + test_expect_success 'complains about multiple pack bitmaps' ' rm -fr repo && git init repo && @@ -428,14 +452,22 @@ test_bitmap_cases () { test_line_count = 2 packs && test_line_count = 2 bitmaps && - git rev-list --use-bitmap-index HEAD 2>err && - grep "ignoring extra bitmap file" err + GIT_TRACE2_EVENT=$(pwd)/trace2.txt git rev-list --use-bitmap-index HEAD && + grep "opened bitmap" trace2.txt && + grep "ignoring extra bitmap" trace2.txt ) ' } test_bitmap_cases +GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL=1 +export GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL + +test_bitmap_cases + +sane_unset GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL + test_expect_success 'incremental repack fails when bitmaps are requested' ' test_commit more-1 && test_must_fail git repack -d 2>err && @@ -447,6 +479,33 @@ test_expect_success 'incremental repack can disable bitmaps' ' git repack -d --no-write-bitmap-index ' +test_expect_success 'boundary-based traversal is used when requested' ' + git repack -a -d --write-bitmap-index && + + for argv in \ + "git -c pack.useBitmapBoundaryTraversal=true" \ + "git -c feature.experimental=true" \ + "GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL=1 git" + do + eval "GIT_TRACE2_EVENT=1 $argv rev-list --objects \ + --use-bitmap-index second..other 2>perf" && + grep "\"region_enter\".*\"label\":\"haves/boundary\"" perf || + return 1 + done && + + for argv in \ + "git -c pack.useBitmapBoundaryTraversal=false" \ + "git -c feature.experimental=true -c pack.useBitmapBoundaryTraversal=false" \ + "GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL=0 git -c pack.useBitmapBoundaryTraversal=true" \ + "GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL=0 git -c feature.experimental=true" + do + eval "GIT_TRACE2_EVENT=1 $argv rev-list --objects \ + --use-bitmap-index second..other 2>perf" && + grep "\"region_enter\".*\"label\":\"haves/classic\"" perf || + return 1 + done +' + test_bitmap_cases "pack.writeBitmapLookupTable" test_expect_success 'verify writing bitmap lookup table when enabled' ' diff --git a/t/t5312-prune-corruption.sh b/t/t5312-prune-corruption.sh index 9d8e249ae8..230cb38712 100755 --- a/t/t5312-prune-corruption.sh +++ b/t/t5312-prune-corruption.sh @@ -14,6 +14,7 @@ what currently happens. If that changes, these tests should be revisited. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'disable reflogs' ' diff --git a/t/t5313-pack-bounds-checks.sh b/t/t5313-pack-bounds-checks.sh index cc4cfaa9d3..ceaa6700a2 100755 --- a/t/t5313-pack-bounds-checks.sh +++ b/t/t5313-pack-bounds-checks.sh @@ -59,7 +59,7 @@ test_expect_success 'setup' ' test_expect_success 'set up base packfile and variables' ' # the hash of this content starts with ff, which # makes some later computations much simpler - echo $(test_oid oidfff) >file && + test_oid oidfff >file && git add file && git commit -m base && git repack -ad && 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/t5317-pack-objects-filter-objects.sh b/t/t5317-pack-objects-filter-objects.sh index bb633c9b09..b26d476c64 100755 --- a/t/t5317-pack-objects-filter-objects.sh +++ b/t/t5317-pack-objects-filter-objects.sh @@ -5,6 +5,7 @@ test_description='git pack-objects using object filtering' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Test blob:none filter. @@ -24,8 +25,9 @@ parse_verify_pack_blob_oid () { } test_expect_success 'verify blob count in normal packfile' ' - git -C r1 ls-files -s file.1 file.2 file.3 file.4 file.5 | - test_parse_ls_files_stage_oids | + git -C r1 ls-files -s file.1 file.2 file.3 file.4 file.5 \ + >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && git -C r1 pack-objects --revs --stdout >all.pack <<-EOF && @@ -123,8 +125,8 @@ test_expect_success 'setup r2' ' ' test_expect_success 'verify blob count in normal packfile' ' - git -C r2 ls-files -s large.1000 large.10000 | - test_parse_ls_files_stage_oids | + git -C r2 ls-files -s large.1000 large.10000 >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && git -C r2 pack-objects --revs --stdout >all.pack <<-EOF && @@ -161,8 +163,8 @@ test_expect_success 'verify blob:limit=1000' ' ' test_expect_success 'verify blob:limit=1001' ' - git -C r2 ls-files -s large.1000 | - test_parse_ls_files_stage_oids | + git -C r2 ls-files -s large.1000 >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && git -C r2 pack-objects --revs --stdout --filter=blob:limit=1001 >filter.pack <<-EOF && @@ -179,8 +181,8 @@ test_expect_success 'verify blob:limit=1001' ' ' test_expect_success 'verify blob:limit=10001' ' - git -C r2 ls-files -s large.1000 large.10000 | - test_parse_ls_files_stage_oids | + git -C r2 ls-files -s large.1000 large.10000 >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && git -C r2 pack-objects --revs --stdout --filter=blob:limit=10001 >filter.pack <<-EOF && @@ -197,8 +199,8 @@ test_expect_success 'verify blob:limit=10001' ' ' test_expect_success 'verify blob:limit=1k' ' - git -C r2 ls-files -s large.1000 | - test_parse_ls_files_stage_oids | + git -C r2 ls-files -s large.1000 >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && git -C r2 pack-objects --revs --stdout --filter=blob:limit=1k >filter.pack <<-EOF && @@ -215,8 +217,8 @@ test_expect_success 'verify blob:limit=1k' ' ' test_expect_success 'verify explicitly specifying oversized blob in input' ' - git -C r2 ls-files -s large.1000 large.10000 | - test_parse_ls_files_stage_oids | + git -C r2 ls-files -s large.1000 large.10000 >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && echo HEAD >objects && @@ -233,8 +235,8 @@ test_expect_success 'verify explicitly specifying oversized blob in input' ' ' test_expect_success 'verify blob:limit=1m' ' - git -C r2 ls-files -s large.1000 large.10000 | - test_parse_ls_files_stage_oids | + git -C r2 ls-files -s large.1000 large.10000 >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && git -C r2 pack-objects --revs --stdout --filter=blob:limit=1m >filter.pack <<-EOF && @@ -264,6 +266,44 @@ test_expect_success 'verify normal and blob:limit packfiles have same commits/tr test_cmp expected observed ' +test_expect_success 'verify small limit and big limit results in small limit' ' + git -C r2 ls-files -s large.1000 >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | + sort >expected && + + git -C r2 pack-objects --revs --stdout --filter=blob:limit=1001 \ + --filter=blob:limit=10001 >filter.pack <<-EOF && + HEAD + EOF + git -C r2 index-pack ../filter.pack && + + git -C r2 verify-pack -v ../filter.pack >verify_result && + grep blob verify_result | + parse_verify_pack_blob_oid | + sort >observed && + + test_cmp expected observed +' + +test_expect_success 'verify big limit and small limit results in small limit' ' + git -C r2 ls-files -s large.1000 >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | + sort >expected && + + git -C r2 pack-objects --revs --stdout --filter=blob:limit=10001 \ + --filter=blob:limit=1001 >filter.pack <<-EOF && + HEAD + EOF + git -C r2 index-pack ../filter.pack && + + git -C r2 verify-pack -v ../filter.pack >verify_result && + grep blob verify_result | + parse_verify_pack_blob_oid | + sort >observed && + + test_cmp expected observed +' + # Test sparse:path=<path> filter. # !!!! # NOTE: sparse:path filter support has been dropped for security reasons, @@ -289,8 +329,9 @@ test_expect_success 'setup r3' ' ' test_expect_success 'verify blob count in normal packfile' ' - git -C r3 ls-files -s sparse1 sparse2 dir1/sparse1 dir1/sparse2 | - test_parse_ls_files_stage_oids | + git -C r3 ls-files -s sparse1 sparse2 dir1/sparse1 dir1/sparse2 \ + >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && git -C r3 pack-objects --revs --stdout >all.pack <<-EOF && @@ -341,8 +382,9 @@ test_expect_success 'setup r4' ' ' test_expect_success 'verify blob count in normal packfile' ' - git -C r4 ls-files -s pattern sparse1 sparse2 dir1/sparse1 dir1/sparse2 | - test_parse_ls_files_stage_oids | + git -C r4 ls-files -s pattern sparse1 sparse2 dir1/sparse1 dir1/sparse2 \ + >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && git -C r4 pack-objects --revs --stdout >all.pack <<-EOF && @@ -359,8 +401,8 @@ test_expect_success 'verify blob count in normal packfile' ' ' test_expect_success 'verify sparse:oid=OID' ' - git -C r4 ls-files -s dir1/sparse1 dir1/sparse2 | - test_parse_ls_files_stage_oids | + git -C r4 ls-files -s dir1/sparse1 dir1/sparse2 >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && git -C r4 ls-files -s pattern >staged && @@ -379,8 +421,8 @@ test_expect_success 'verify sparse:oid=OID' ' ' test_expect_success 'verify sparse:oid=oid-ish' ' - git -C r4 ls-files -s dir1/sparse1 dir1/sparse2 | - test_parse_ls_files_stage_oids | + git -C r4 ls-files -s dir1/sparse1 dir1/sparse2 >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && git -C r4 pack-objects --revs --stdout --filter=sparse:oid=main:pattern >filter.pack <<-EOF && @@ -400,8 +442,9 @@ test_expect_success 'verify sparse:oid=oid-ish' ' # This models previously omitted objects that we did not receive. test_expect_success 'setup r1 - delete loose blobs' ' - git -C r1 ls-files -s file.1 file.2 file.3 file.4 file.5 | - test_parse_ls_files_stage_oids | + git -C r1 ls-files -s file.1 file.2 file.3 file.4 file.5 \ + >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && for id in `cat expected | sed "s|..|&/|"` diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh index 049c5fc8ea..ba65f17dd9 100755 --- a/t/t5318-commit-graph.sh +++ b/t/t5318-commit-graph.sh @@ -24,12 +24,10 @@ test_expect_success 'usage shown with an error on unknown sub-command' ' test_cmp expect actual ' +objdir=".git/objects" + test_expect_success 'setup full repo' ' - mkdir full && - cd "$TRASH_DIRECTORY/full" && - git init && - git config core.commitGraph true && - objdir=".git/objects" + git init full ' test_expect_success POSIXPERM 'tweak umask for modebit tests' ' @@ -37,31 +35,28 @@ test_expect_success POSIXPERM 'tweak umask for modebit tests' ' ' test_expect_success 'verify graph with no graph file' ' - cd "$TRASH_DIRECTORY/full" && - git commit-graph verify + git -C full commit-graph verify ' test_expect_success 'write graph with no packs' ' - cd "$TRASH_DIRECTORY/full" && - git commit-graph write --object-dir $objdir && - test_path_is_missing $objdir/info/commit-graph + git -C full commit-graph write --object-dir $objdir && + test_path_is_missing full/$objdir/info/commit-graph ' test_expect_success 'exit with correct error on bad input to --stdin-packs' ' - cd "$TRASH_DIRECTORY/full" && echo doesnotexist >in && - test_expect_code 1 git commit-graph write --stdin-packs <in 2>stderr && + test_expect_code 1 git -C full commit-graph write --stdin-packs \ + <in 2>stderr && test_i18ngrep "error adding pack" stderr ' test_expect_success 'create commits and repack' ' - cd "$TRASH_DIRECTORY/full" && for i in $(test_seq 3) do - test_commit $i && - git branch commits/$i || return 1 + test_commit -C full $i && + git -C full branch commits/$i || return 1 done && - git repack + git -C full repack ' . "$TEST_DIRECTORY"/lib-commit-graph.sh @@ -69,117 +64,106 @@ test_expect_success 'create commits and repack' ' graph_git_behavior 'no graph' full commits/3 commits/1 test_expect_success 'exit with correct error on bad input to --stdin-commits' ' - cd "$TRASH_DIRECTORY/full" && # invalid, non-hex OID - echo HEAD >in && - test_expect_code 1 git commit-graph write --stdin-commits <in 2>stderr && + echo HEAD | test_expect_code 1 git -C full commit-graph write \ + --stdin-commits 2>stderr && test_i18ngrep "unexpected non-hex object ID: HEAD" stderr && # non-existent OID - echo $ZERO_OID >in && - test_expect_code 1 git commit-graph write --stdin-commits <in 2>stderr && + echo $ZERO_OID | test_expect_code 1 git -C full commit-graph write \ + --stdin-commits 2>stderr && test_i18ngrep "invalid object" stderr && # valid commit and tree OID - git rev-parse HEAD HEAD^{tree} >in && - git commit-graph write --stdin-commits <in && - graph_read_expect 3 generation_data + git -C full rev-parse HEAD HEAD^{tree} >in && + git -C full commit-graph write --stdin-commits <in && + graph_read_expect -C full 3 generation_data ' test_expect_success 'write graph' ' - cd "$TRASH_DIRECTORY/full" && - git commit-graph write && - test_path_is_file $objdir/info/commit-graph && - graph_read_expect "3" generation_data + git -C full commit-graph write && + test_path_is_file full/$objdir/info/commit-graph && + graph_read_expect -C full 3 generation_data ' test_expect_success POSIXPERM 'write graph has correct permissions' ' - test_path_is_file $objdir/info/commit-graph && + test_path_is_file full/$objdir/info/commit-graph && echo "-r--r--r--" >expect && - test_modebits $objdir/info/commit-graph >actual && + test_modebits full/$objdir/info/commit-graph >actual && test_cmp expect actual ' graph_git_behavior 'graph exists' full commits/3 commits/1 test_expect_success 'Add more commits' ' - cd "$TRASH_DIRECTORY/full" && - git reset --hard commits/1 && + git -C full reset --hard commits/1 && for i in $(test_seq 4 5) do - test_commit $i && - git branch commits/$i || return 1 + test_commit -C full $i && + git -C full branch commits/$i || return 1 done && - git reset --hard commits/2 && + git -C full reset --hard commits/2 && for i in $(test_seq 6 7) do - test_commit $i && - git branch commits/$i || return 1 + test_commit -C full $i && + git -C full branch commits/$i || return 1 done && - git reset --hard commits/2 && - git merge commits/4 && - git branch merge/1 && - git reset --hard commits/4 && - git merge commits/6 && - git branch merge/2 && - git reset --hard commits/3 && - git merge commits/5 commits/7 && - git branch merge/3 && - git repack + git -C full reset --hard commits/2 && + git -C full merge commits/4 && + git -C full branch merge/1 && + git -C full reset --hard commits/4 && + git -C full merge commits/6 && + git -C full branch merge/2 && + git -C full reset --hard commits/3 && + git -C full merge commits/5 commits/7 && + git -C full branch merge/3 && + git -C full repack ' test_expect_success 'commit-graph write progress off for redirected stderr' ' - cd "$TRASH_DIRECTORY/full" && - git commit-graph write 2>err && + git -C full commit-graph write 2>err && test_must_be_empty err ' test_expect_success 'commit-graph write force progress on for stderr' ' - cd "$TRASH_DIRECTORY/full" && - GIT_PROGRESS_DELAY=0 git commit-graph write --progress 2>err && + GIT_PROGRESS_DELAY=0 git -C full commit-graph write --progress 2>err && test_file_not_empty err ' test_expect_success 'commit-graph write with the --no-progress option' ' - cd "$TRASH_DIRECTORY/full" && - git commit-graph write --no-progress 2>err && + git -C full commit-graph write --no-progress 2>err && test_must_be_empty err ' test_expect_success 'commit-graph write --stdin-commits progress off for redirected stderr' ' - cd "$TRASH_DIRECTORY/full" && - git rev-parse commits/5 >in && - git commit-graph write --stdin-commits <in 2>err && + git -C full rev-parse commits/5 >in && + git -C full commit-graph write --stdin-commits <in 2>err && test_must_be_empty err ' test_expect_success 'commit-graph write --stdin-commits force progress on for stderr' ' - cd "$TRASH_DIRECTORY/full" && - git rev-parse commits/5 >in && - GIT_PROGRESS_DELAY=0 git commit-graph write --stdin-commits --progress <in 2>err && + git -C full rev-parse commits/5 >in && + GIT_PROGRESS_DELAY=0 git -C full commit-graph write --stdin-commits \ + --progress <in 2>err && test_i18ngrep "Collecting commits from input" err ' test_expect_success 'commit-graph write --stdin-commits with the --no-progress option' ' - cd "$TRASH_DIRECTORY/full" && - git rev-parse commits/5 >in && - git commit-graph write --stdin-commits --no-progress <in 2>err && + git -C full rev-parse commits/5 >in && + git -C full commit-graph write --stdin-commits --no-progress <in 2>err && test_must_be_empty err ' test_expect_success 'commit-graph verify progress off for redirected stderr' ' - cd "$TRASH_DIRECTORY/full" && - git commit-graph verify 2>err && + git -C full commit-graph verify 2>err && test_must_be_empty err ' test_expect_success 'commit-graph verify force progress on for stderr' ' - cd "$TRASH_DIRECTORY/full" && - GIT_PROGRESS_DELAY=0 git commit-graph verify --progress 2>err && + GIT_PROGRESS_DELAY=0 git -C full commit-graph verify --progress 2>err && test_file_not_empty err ' test_expect_success 'commit-graph verify with the --no-progress option' ' - cd "$TRASH_DIRECTORY/full" && - git commit-graph verify --no-progress 2>err && + git -C full commit-graph verify --no-progress 2>err && test_must_be_empty err ' @@ -194,10 +178,9 @@ test_expect_success 'commit-graph verify with the --no-progress option' ' # 1 test_expect_success 'write graph with merges' ' - cd "$TRASH_DIRECTORY/full" && - git commit-graph write && - test_path_is_file $objdir/info/commit-graph && - graph_read_expect "10" "generation_data extra_edges" + git -C full commit-graph write && + test_path_is_file full/$objdir/info/commit-graph && + graph_read_expect -C full 10 "generation_data extra_edges" ' graph_git_behavior 'merge 1 vs 2' full merge/1 merge/2 @@ -205,12 +188,11 @@ graph_git_behavior 'merge 1 vs 3' full merge/1 merge/3 graph_git_behavior 'merge 2 vs 3' full merge/2 merge/3 test_expect_success 'Add one more commit' ' - cd "$TRASH_DIRECTORY/full" && - test_commit 8 && - git branch commits/8 && - ls $objdir/pack | grep idx >existing-idx && - git repack && - ls $objdir/pack| grep idx | grep -v -f existing-idx >new-idx + test_commit -C full 8 && + git -C full branch commits/8 && + ls full/$objdir/pack | grep idx >existing-idx && + git -C full repack && + ls full/$objdir/pack| grep idx | grep -v -f existing-idx >new-idx ' # Current graph structure: @@ -229,114 +211,101 @@ graph_git_behavior 'mixed mode, commit 8 vs merge 1' full commits/8 merge/1 graph_git_behavior 'mixed mode, commit 8 vs merge 2' full commits/8 merge/2 test_expect_success 'write graph with new commit' ' - cd "$TRASH_DIRECTORY/full" && - git commit-graph write && - test_path_is_file $objdir/info/commit-graph && - graph_read_expect "11" "generation_data extra_edges" + git -C full commit-graph write && + test_path_is_file full/$objdir/info/commit-graph && + graph_read_expect -C full 11 "generation_data extra_edges" ' graph_git_behavior 'full graph, commit 8 vs merge 1' full commits/8 merge/1 graph_git_behavior 'full graph, commit 8 vs merge 2' full commits/8 merge/2 test_expect_success 'write graph with nothing new' ' - cd "$TRASH_DIRECTORY/full" && - git commit-graph write && - test_path_is_file $objdir/info/commit-graph && - graph_read_expect "11" "generation_data extra_edges" + git -C full commit-graph write && + test_path_is_file full/$objdir/info/commit-graph && + graph_read_expect -C full 11 "generation_data extra_edges" ' graph_git_behavior 'cleared graph, commit 8 vs merge 1' full commits/8 merge/1 graph_git_behavior 'cleared graph, commit 8 vs merge 2' full commits/8 merge/2 test_expect_success 'build graph from latest pack with closure' ' - cd "$TRASH_DIRECTORY/full" && - cat new-idx | git commit-graph write --stdin-packs && - test_path_is_file $objdir/info/commit-graph && - graph_read_expect "9" "generation_data extra_edges" + git -C full commit-graph write --stdin-packs <new-idx && + test_path_is_file full/$objdir/info/commit-graph && + graph_read_expect -C full 9 "generation_data extra_edges" ' graph_git_behavior 'graph from pack, commit 8 vs merge 1' full commits/8 merge/1 graph_git_behavior 'graph from pack, commit 8 vs merge 2' full commits/8 merge/2 test_expect_success 'build graph from commits with closure' ' - cd "$TRASH_DIRECTORY/full" && - git tag -a -m "merge" tag/merge merge/2 && - git rev-parse tag/merge >commits-in && - git rev-parse merge/1 >>commits-in && - cat commits-in | git commit-graph write --stdin-commits && - test_path_is_file $objdir/info/commit-graph && - graph_read_expect "6" "generation_data" + git -C full tag -a -m "merge" tag/merge merge/2 && + git -C full rev-parse tag/merge >commits-in && + git -C full rev-parse merge/1 >>commits-in && + git -C full commit-graph write --stdin-commits <commits-in && + test_path_is_file full/$objdir/info/commit-graph && + graph_read_expect -C full 6 "generation_data" ' graph_git_behavior 'graph from commits, commit 8 vs merge 1' full commits/8 merge/1 graph_git_behavior 'graph from commits, commit 8 vs merge 2' full commits/8 merge/2 test_expect_success 'build graph from commits with append' ' - cd "$TRASH_DIRECTORY/full" && - git rev-parse merge/3 | git commit-graph write --stdin-commits --append && - test_path_is_file $objdir/info/commit-graph && - graph_read_expect "10" "generation_data extra_edges" + git -C full rev-parse merge/3 >in && + git -C full commit-graph write --stdin-commits --append <in && + test_path_is_file full/$objdir/info/commit-graph && + graph_read_expect -C full 10 "generation_data extra_edges" ' graph_git_behavior 'append graph, commit 8 vs merge 1' full commits/8 merge/1 graph_git_behavior 'append graph, commit 8 vs merge 2' full commits/8 merge/2 test_expect_success 'build graph using --reachable' ' - cd "$TRASH_DIRECTORY/full" && - git commit-graph write --reachable && - test_path_is_file $objdir/info/commit-graph && - graph_read_expect "11" "generation_data extra_edges" + git -C full commit-graph write --reachable && + test_path_is_file full/$objdir/info/commit-graph && + graph_read_expect -C full 11 "generation_data extra_edges" ' graph_git_behavior 'append graph, commit 8 vs merge 1' full commits/8 merge/1 graph_git_behavior 'append graph, commit 8 vs merge 2' full commits/8 merge/2 test_expect_success 'setup bare repo' ' - cd "$TRASH_DIRECTORY" && - git clone --bare --no-local full bare && - cd bare && - git config core.commitGraph true && - baredir="./objects" + git clone --bare --no-local full bare ' graph_git_behavior 'bare repo, commit 8 vs merge 1' bare commits/8 merge/1 graph_git_behavior 'bare repo, commit 8 vs merge 2' bare commits/8 merge/2 test_expect_success 'write graph in bare repo' ' - cd "$TRASH_DIRECTORY/bare" && - git commit-graph write && - test_path_is_file $baredir/info/commit-graph && - graph_read_expect "11" "generation_data extra_edges" + git -C bare commit-graph write && + test_path_is_file bare/objects/info/commit-graph && + graph_read_expect -C bare 11 "generation_data extra_edges" ' graph_git_behavior 'bare repo with graph, commit 8 vs merge 1' bare commits/8 merge/1 graph_git_behavior 'bare repo with graph, commit 8 vs merge 2' bare commits/8 merge/2 test_expect_success 'perform fast-forward merge in full repo' ' - cd "$TRASH_DIRECTORY/full" && - git checkout -b merge-5-to-8 commits/5 && - git merge commits/8 && - git show-ref -s merge-5-to-8 >output && - git show-ref -s commits/8 >expect && + git -C full checkout -b merge-5-to-8 commits/5 && + git -C full merge commits/8 && + git -C full show-ref -s merge-5-to-8 >output && + git -C full show-ref -s commits/8 >expect && test_cmp expect output ' test_expect_success 'check that gc computes commit-graph' ' - cd "$TRASH_DIRECTORY/full" && - git commit --allow-empty -m "blank" && - git commit-graph write --reachable && - cp $objdir/info/commit-graph commit-graph-before-gc && - git reset --hard HEAD~1 && - git config gc.writeCommitGraph true && - git gc && - cp $objdir/info/commit-graph commit-graph-after-gc && + test_commit -C full --no-tag blank && + git -C full commit-graph write --reachable && + cp full/$objdir/info/commit-graph commit-graph-before-gc && + git -C full reset --hard HEAD~1 && + test_config -C full gc.writeCommitGraph true && + git -C full gc && + cp full/$objdir/info/commit-graph commit-graph-after-gc && ! test_cmp_bin commit-graph-before-gc commit-graph-after-gc && - git commit-graph write --reachable && - test_cmp_bin commit-graph-after-gc $objdir/info/commit-graph + git -C full commit-graph write --reachable && + test_cmp_bin commit-graph-after-gc full/$objdir/info/commit-graph ' test_expect_success 'replace-objects invalidates commit-graph' ' - cd "$TRASH_DIRECTORY" && test_when_finished rm -rf replace && git clone full replace && ( @@ -359,7 +328,6 @@ test_expect_success 'replace-objects invalidates commit-graph' ' ' test_expect_success 'commit grafts invalidate commit-graph' ' - cd "$TRASH_DIRECTORY" && test_when_finished rm -rf graft && git clone --template= full graft && ( @@ -384,7 +352,6 @@ test_expect_success 'commit grafts invalidate commit-graph' ' ' test_expect_success 'replace-objects invalidates commit-graph' ' - cd "$TRASH_DIRECTORY" && test_when_finished rm -rf shallow && git clone --depth 2 "file://$TRASH_DIRECTORY/full" shallow && ( @@ -427,24 +394,25 @@ test_expect_success 'warn on improper hash version' ' ' test_expect_success TIME_IS_64BIT,TIME_T_IS_64BIT 'lower layers have overflow chunk' ' - cd "$TRASH_DIRECTORY/full" && UNIX_EPOCH_ZERO="@0 +0000" && FUTURE_DATE="@4147483646 +0000" && - rm -f .git/objects/info/commit-graph && - test_commit --date "$FUTURE_DATE" future-1 && - test_commit --date "$UNIX_EPOCH_ZERO" old-1 && - git commit-graph write --reachable && - test_commit --date "$FUTURE_DATE" future-2 && - test_commit --date "$UNIX_EPOCH_ZERO" old-2 && - git commit-graph write --reachable --split=no-merge && - test_commit extra && - git commit-graph write --reachable --split=no-merge && - git commit-graph write --reachable && - graph_read_expect 16 "generation_data generation_data_overflow extra_edges" && - mv .git/objects/info/commit-graph commit-graph-upgraded && - git commit-graph write --reachable && - graph_read_expect 16 "generation_data generation_data_overflow extra_edges" && - test_cmp .git/objects/info/commit-graph commit-graph-upgraded + rm -f full/.git/objects/info/commit-graph && + test_commit -C full --date "$FUTURE_DATE" future-1 && + test_commit -C full --date "$UNIX_EPOCH_ZERO" old-1 && + git -C full commit-graph write --reachable && + test_commit -C full --date "$FUTURE_DATE" future-2 && + test_commit -C full --date "$UNIX_EPOCH_ZERO" old-2 && + git -C full commit-graph write --reachable --split=no-merge && + test_commit -C full extra && + git -C full commit-graph write --reachable --split=no-merge && + git -C full commit-graph write --reachable && + graph_read_expect -C full 16 \ + "generation_data generation_data_overflow extra_edges" && + mv full/.git/objects/info/commit-graph commit-graph-upgraded && + git -C full commit-graph write --reachable && + graph_read_expect -C full 16 \ + "generation_data generation_data_overflow extra_edges" && + test_cmp full/.git/objects/info/commit-graph commit-graph-upgraded ' # the verify tests below expect the commit-graph to contain @@ -454,10 +422,11 @@ test_expect_success TIME_IS_64BIT,TIME_T_IS_64BIT 'lower layers have overflow ch # and the tests will likely break. test_expect_success 'git commit-graph verify' ' - cd "$TRASH_DIRECTORY/full" && - git rev-parse commits/8 | git -c commitGraph.generationVersion=1 commit-graph write --stdin-commits && - git commit-graph verify >output && - graph_read_expect 9 extra_edges 1 + git -C full rev-parse commits/8 >in && + git -C full -c commitGraph.generationVersion=1 commit-graph write \ + --stdin-commits <in && + git -C full commit-graph verify >output && + graph_read_expect -C full 9 extra_edges 1 ' NUM_COMMITS=9 @@ -481,39 +450,39 @@ GRAPH_BYTE_FANOUT2=$(($GRAPH_FANOUT_OFFSET + 4 * 255)) GRAPH_OID_LOOKUP_OFFSET=$(($GRAPH_FANOUT_OFFSET + 4 * 256)) GRAPH_BYTE_OID_LOOKUP_ORDER=$(($GRAPH_OID_LOOKUP_OFFSET + $HASH_LEN * 8)) GRAPH_BYTE_OID_LOOKUP_MISSING=$(($GRAPH_OID_LOOKUP_OFFSET + $HASH_LEN * 4 + 10)) +GRAPH_COMMIT_DATA_WIDTH=$(($HASH_LEN + 16)) GRAPH_COMMIT_DATA_OFFSET=$(($GRAPH_OID_LOOKUP_OFFSET + $HASH_LEN * $NUM_COMMITS)) GRAPH_BYTE_COMMIT_TREE=$GRAPH_COMMIT_DATA_OFFSET GRAPH_BYTE_COMMIT_PARENT=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN)) GRAPH_BYTE_COMMIT_EXTRA_PARENT=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN + 4)) GRAPH_BYTE_COMMIT_WRONG_PARENT=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN + 3)) GRAPH_BYTE_COMMIT_GENERATION=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN + 11)) +GRAPH_BYTE_COMMIT_GENERATION_LAST=$(($GRAPH_BYTE_COMMIT_GENERATION + $(($NUM_COMMITS - 1)) * $GRAPH_COMMIT_DATA_WIDTH)) GRAPH_BYTE_COMMIT_DATE=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN + 12)) -GRAPH_COMMIT_DATA_WIDTH=$(($HASH_LEN + 16)) GRAPH_OCTOPUS_DATA_OFFSET=$(($GRAPH_COMMIT_DATA_OFFSET + \ $GRAPH_COMMIT_DATA_WIDTH * $NUM_COMMITS)) GRAPH_BYTE_OCTOPUS=$(($GRAPH_OCTOPUS_DATA_OFFSET + 4)) GRAPH_BYTE_FOOTER=$(($GRAPH_OCTOPUS_DATA_OFFSET + 4 * $NUM_OCTOPUS_EDGES)) corrupt_graph_setup() { - cd "$TRASH_DIRECTORY/full" && - test_when_finished mv commit-graph-backup $objdir/info/commit-graph && - cp $objdir/info/commit-graph commit-graph-backup && - chmod u+w $objdir/info/commit-graph + test_when_finished mv commit-graph-backup full/$objdir/info/commit-graph && + cp full/$objdir/info/commit-graph commit-graph-backup && + chmod u+w full/$objdir/info/commit-graph } corrupt_graph_verify() { grepstr=$1 - test_must_fail git commit-graph verify 2>test_err && + test_must_fail git -C full commit-graph verify 2>test_err && grep -v "^+" test_err >err && test_i18ngrep "$grepstr" err && if test "$2" != "no-copy" then - cp $objdir/info/commit-graph commit-graph-pre-write-test + cp full/$objdir/info/commit-graph commit-graph-pre-write-test fi && - git status --short && - GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE=true git commit-graph write && - chmod u+w $objdir/info/commit-graph && - git commit-graph verify + git -C full status --short && + GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE=true git -C full commit-graph write && + chmod u+w full/$objdir/info/commit-graph && + git -C full commit-graph verify } # usage: corrupt_graph_and_verify <position> <data> <string> [<zero_pos>] @@ -527,24 +496,24 @@ corrupt_graph_and_verify() { data="${2:-\0}" grepstr=$3 corrupt_graph_setup && - orig_size=$(wc -c < $objdir/info/commit-graph) && + orig_size=$(wc -c <full/$objdir/info/commit-graph) && zero_pos=${4:-${orig_size}} && - printf "$data" | dd of="$objdir/info/commit-graph" bs=1 seek="$pos" conv=notrunc && - dd of="$objdir/info/commit-graph" bs=1 seek="$zero_pos" if=/dev/null && - test-tool genzeros $(($orig_size - $zero_pos)) >>"$objdir/info/commit-graph" && + printf "$data" | dd of="full/$objdir/info/commit-graph" bs=1 seek="$pos" conv=notrunc && + dd of="full/$objdir/info/commit-graph" bs=1 seek="$zero_pos" if=/dev/null && + test-tool genzeros $(($orig_size - $zero_pos)) >>"full/$objdir/info/commit-graph" && corrupt_graph_verify "$grepstr" } test_expect_success POSIXPERM,SANITY 'detect permission problem' ' corrupt_graph_setup && - chmod 000 $objdir/info/commit-graph && + chmod 000 full/$objdir/info/commit-graph && corrupt_graph_verify "Could not open" "no-copy" ' test_expect_success 'detect too small' ' corrupt_graph_setup && - echo "a small graph" >$objdir/info/commit-graph && + echo "a small graph" >full/$objdir/info/commit-graph && corrupt_graph_verify "too small" ' @@ -628,11 +597,6 @@ test_expect_success 'detect incorrect generation number' ' "generation for commit" ' -test_expect_success 'detect incorrect generation number' ' - corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_GENERATION "\01" \ - "non-zero generation number" -' - test_expect_success 'detect incorrect commit date' ' corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_DATE "\01" \ "commit date" @@ -654,34 +618,51 @@ test_expect_success 'detect incorrect chunk count' ' $GRAPH_CHUNK_LOOKUP_OFFSET ' +test_expect_success 'detect mixed generation numbers (non-zero to zero)' ' + corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_GENERATION_LAST "\0\0\0\0" \ + "both zero and non-zero generations" +' + +test_expect_success 'detect mixed generation numbers (zero to non-zero)' ' + corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_GENERATION "\0\0\0\0" \ + "both zero and non-zero generations" +' + test_expect_success 'git fsck (checks commit-graph when config set to true)' ' - cd "$TRASH_DIRECTORY/full" && - git fsck && + git -C full fsck && corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \ "incorrect checksum" && - cp commit-graph-pre-write-test $objdir/info/commit-graph && - test_must_fail git -c core.commitGraph=true fsck + cp commit-graph-pre-write-test full/$objdir/info/commit-graph && + test_must_fail git -C full -c core.commitGraph=true fsck ' test_expect_success 'git fsck (ignores commit-graph when config set to false)' ' - cd "$TRASH_DIRECTORY/full" && - git fsck && + git -C full fsck && corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \ "incorrect checksum" && - cp commit-graph-pre-write-test $objdir/info/commit-graph && - git -c core.commitGraph=false fsck + cp commit-graph-pre-write-test full/$objdir/info/commit-graph && + git -C full -c core.commitGraph=false fsck ' test_expect_success 'git fsck (checks commit-graph when config unset)' ' - cd "$TRASH_DIRECTORY/full" && - test_when_finished "git config core.commitGraph true" && + test_when_finished "git -C full config core.commitGraph true" && - git fsck && + git -C full fsck && corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \ "incorrect checksum" && - test_unconfig core.commitGraph && - cp commit-graph-pre-write-test $objdir/info/commit-graph && - test_must_fail git fsck + test_unconfig -C full core.commitGraph && + cp commit-graph-pre-write-test full/$objdir/info/commit-graph && + test_must_fail git -C full fsck +' + +test_expect_success 'git fsck shows commit-graph output with --progress' ' + git -C "$TRASH_DIRECTORY/full" fsck --progress 2>err && + grep "Verifying commits in commit graph" err +' + +test_expect_success 'git fsck suppresses commit-graph output with --no-progress' ' + git -C "$TRASH_DIRECTORY/full" fsck --no-progress 2>err && + ! grep "Verifying commits in commit graph" err ' test_expect_success 'setup non-the_repository tests' ' @@ -782,32 +763,33 @@ test_expect_success 'corrupt commit-graph write (missing tree)' ' # test_expect_success 'set up and verify repo with generation data overflow chunk' ' - objdir=".git/objects" && UNIX_EPOCH_ZERO="@0 +0000" && FUTURE_DATE="@2147483646 +0000" && - cd "$TRASH_DIRECTORY" && - mkdir repo && - cd repo && - git init && - test_commit --date "$UNIX_EPOCH_ZERO" 1 && - test_commit 2 && - test_commit --date "$UNIX_EPOCH_ZERO" 3 && - git commit-graph write --reachable && - graph_read_expect 3 generation_data && - test_commit --date "$FUTURE_DATE" 4 && - test_commit 5 && - test_commit --date "$UNIX_EPOCH_ZERO" 6 && - git branch left && - git reset --hard 3 && - test_commit 7 && - test_commit --date "$FUTURE_DATE" 8 && - test_commit 9 && - git branch right && - git reset --hard 3 && - test_merge M left right && - git commit-graph write --reachable && - graph_read_expect 10 "generation_data generation_data_overflow" && - git commit-graph verify + + git init repo && + ( + cd repo && + + test_commit --date "$UNIX_EPOCH_ZERO" 1 && + test_commit 2 && + test_commit --date "$UNIX_EPOCH_ZERO" 3 && + git commit-graph write --reachable && + graph_read_expect 3 generation_data && + test_commit --date "$FUTURE_DATE" 4 && + test_commit 5 && + test_commit --date "$UNIX_EPOCH_ZERO" 6 && + git branch left && + git reset --hard 3 && + test_commit 7 && + test_commit --date "$FUTURE_DATE" 8 && + test_commit 9 && + git branch right && + git reset --hard 3 && + test_merge M left right && + git commit-graph write --reachable && + graph_read_expect 10 "generation_data generation_data_overflow" && + git commit-graph verify + ) ' graph_git_behavior 'generation data overflow chunk repo' repo left right diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh index b5f9b10922..1bcc02004d 100755 --- a/t/t5319-multi-pack-index.sh +++ b/t/t5319-multi-pack-index.sh @@ -183,6 +183,18 @@ test_expect_success 'write midx with --stdin-packs' ' compare_results_with_midx "mixed mode (one pack + extra)" +test_expect_success 'write with no objects and preferred pack' ' + test_when_finished "rm -rf empty" && + git init empty && + test_must_fail git -C empty multi-pack-index write \ + --stdin-packs --preferred-pack=does-not-exist </dev/null 2>err && + cat >expect <<-EOF && + warning: unknown preferred pack: ${SQ}does-not-exist${SQ} + error: no pack files to index. + EOF + test_cmp expect err +' + test_expect_success 'write progress off for redirected stderr' ' git multi-pack-index --object-dir=$objdir write 2>err && test_line_count = 0 err @@ -473,6 +485,18 @@ test_expect_success 'git-fsck incorrect offset' ' git -c core.multiPackIndex=false fsck ' +test_expect_success 'git fsck shows MIDX output with --progress' ' + git fsck --progress 2>err && + grep "Verifying OID order in multi-pack-index" err && + grep "Verifying object offsets" err +' + +test_expect_success 'git fsck suppresses MIDX output with --no-progress' ' + git fsck --no-progress 2>err && + ! grep "Verifying OID order in multi-pack-index" err && + ! grep "Verifying object offsets" err +' + test_expect_success 'corrupt MIDX is not reused' ' corrupt_midx_and_verify $MIDX_BYTE_OFFSET "\377" $objdir \ "incorrect object offset" && @@ -1015,4 +1039,20 @@ test_expect_success 'complains when run outside of a repository' ' grep "not a git repository" err ' +test_expect_success 'repack with delta islands' ' + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + + test_commit first && + git repack && + test_commit second && + git repack && + + git multi-pack-index write && + git -c repack.useDeltaIslands=true multi-pack-index repack + ) +' + test_done diff --git a/t/t5320-delta-islands.sh b/t/t5320-delta-islands.sh index 124d47603d..406363381f 100755 --- a/t/t5320-delta-islands.sh +++ b/t/t5320-delta-islands.sh @@ -134,7 +134,7 @@ test_expect_success 'island core places core objects first' ' repack -adfi && git verify-pack -v .git/objects/pack/*.pack | cut -d" " -f1 | - egrep "$root|$two" >actual && + grep -E "$root|$two" >actual && test_cmp expect actual ' diff --git a/t/t5324-split-commit-graph.sh b/t/t5324-split-commit-graph.sh index 669ddc645f..36c4141e67 100755 --- a/t/t5324-split-commit-graph.sh +++ b/t/t5324-split-commit-graph.sh @@ -351,7 +351,8 @@ test_expect_success 'add octopus merge' ' git branch merge/octopus && git commit-graph write --reachable --split && git commit-graph verify --progress 2>err && - test_line_count = 3 err && + test_line_count = 1 err && + grep "Verifying commits in commit graph: 100% (18/18)" err && test_i18ngrep ! warning err && test_line_count = 3 $graphdir/commit-graph-chain ' diff --git a/t/t5325-reverse-index.sh b/t/t5325-reverse-index.sh index d042d26f2b..431a603ca0 100755 --- a/t/t5325-reverse-index.sh +++ b/t/t5325-reverse-index.sh @@ -1,17 +1,20 @@ #!/bin/sh test_description='on-disk reverse index' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # The below tests want control over the 'pack.writeReverseIndex' setting # themselves to assert various combinations of it with other options. -sane_unset GIT_TEST_WRITE_REV_INDEX +sane_unset GIT_TEST_NO_WRITE_REV_INDEX packdir=.git/objects/pack test_expect_success 'setup' ' test_commit base && + test_config pack.writeReverseIndex false && pack=$(git pack-objects --all $packdir/pack) && rev=$packdir/pack-$pack.rev && @@ -94,6 +97,17 @@ test_expect_success 'reverse index is not generated when available on disk' ' --batch-check="%(objectsize:disk)" <tip ' +test_expect_success 'reverse index is ignored when pack.readReverseIndex is false' ' + test_index_pack true && + test_path_is_file $rev && + + test_config pack.readReverseIndex false && + + git rev-parse HEAD >tip && + GIT_TEST_REV_INDEX_DIE_ON_DISK=1 git cat-file \ + --batch-check="%(objectsize:disk)" <tip +' + test_expect_success 'revindex in-memory vs on-disk' ' git init repo && test_when_finished "rm -fr repo" && @@ -117,4 +131,78 @@ test_expect_success 'revindex in-memory vs on-disk' ' test_cmp on-disk in-core ) ' + +test_expect_success 'fsck succeeds on good rev-index' ' + test_when_finished rm -fr repo && + git init repo && + ( + cd repo && + + test_commit commit && + git -c pack.writeReverseIndex=true repack -ad && + git fsck 2>err && + test_must_be_empty err + ) +' + +test_expect_success 'set up rev-index corruption tests' ' + git init corrupt && + ( + cd corrupt && + + test_commit commit && + git -c pack.writeReverseIndex=true repack -ad && + + revfile=$(ls .git/objects/pack/pack-*.rev) && + chmod a+w $revfile && + cp $revfile $revfile.bak + ) +' + +corrupt_rev_and_verify () { + ( + pos="$1" && + value="$2" && + error="$3" && + + cd corrupt && + revfile=$(ls .git/objects/pack/pack-*.rev) && + + # Reset to original rev-file. + cp $revfile.bak $revfile && + + printf "$value" | dd of=$revfile bs=1 seek="$pos" conv=notrunc && + test_must_fail git fsck 2>err && + grep "$error" err + ) +} + +test_expect_success 'fsck catches invalid checksum' ' + revfile=$(ls corrupt/.git/objects/pack/pack-*.rev) && + orig_size=$(wc -c <$revfile) && + hashpos=$((orig_size - 10)) && + corrupt_rev_and_verify $hashpos bogus \ + "invalid checksum" +' + +test_expect_success 'fsck catches invalid row position' ' + corrupt_rev_and_verify 14 "\07" \ + "invalid rev-index position" +' + +test_expect_success 'fsck catches invalid header: magic number' ' + corrupt_rev_and_verify 1 "\07" \ + "reverse-index file .* has unknown signature" +' + +test_expect_success 'fsck catches invalid header: version' ' + corrupt_rev_and_verify 7 "\02" \ + "reverse-index file .* has unsupported version" +' + +test_expect_success 'fsck catches invalid header: hash function' ' + corrupt_rev_and_verify 11 "\03" \ + "reverse-index file .* has unsupported hash id" +' + test_done diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh index ad6eea5fa0..70d1b58709 100755 --- a/t/t5326-multi-pack-bitmaps.sh +++ b/t/t5326-multi-pack-bitmaps.sh @@ -410,4 +410,107 @@ test_expect_success 'preferred pack change with existing MIDX bitmap' ' ) ' +test_expect_success 'tagged commits are selected for bitmapping' ' + rm -fr repo && + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + + test_commit --annotate base && + git repack -d && + + # Remove refs/heads/main which points at the commit directly, + # leaving only a reference to the annotated tag. + git branch -M main && + git checkout base && + git branch -d main && + + git multi-pack-index write --bitmap && + + git rev-parse HEAD >want && + test-tool bitmap list-commits >actual && + grep $(cat want) actual + ) +' + +corrupt_file () { + chmod a+w "$1" && + printf "bogus" | dd of="$1" bs=1 seek="12" conv=notrunc +} + +test_expect_success 'git fsck correctly identifies good and bad bitmaps' ' + git init valid && + test_when_finished rm -rf valid && + + test_commit_bulk 20 && + git repack -adbf && + + # Move pack-bitmap aside so it is not deleted + # in next repack. + packbitmap=$(ls .git/objects/pack/pack-*.bitmap) && + mv "$packbitmap" "$packbitmap.bak" && + + test_commit_bulk 10 && + git repack -b --write-midx && + midxbitmap=$(ls .git/objects/pack/multi-pack-index-*.bitmap) && + + # Copy MIDX bitmap to backup. Copy pack bitmap from backup. + cp "$midxbitmap" "$midxbitmap.bak" && + cp "$packbitmap.bak" "$packbitmap" && + + # fsck works at first + git fsck 2>err && + test_must_be_empty err && + + corrupt_file "$packbitmap" && + test_must_fail git fsck 2>err && + grep "bitmap file '\''$packbitmap'\'' has invalid checksum" err && + + cp "$packbitmap.bak" "$packbitmap" && + corrupt_file "$midxbitmap" && + test_must_fail git fsck 2>err && + grep "bitmap file '\''$midxbitmap'\'' has invalid checksum" err && + + corrupt_file "$packbitmap" && + test_must_fail git fsck 2>err && + grep "bitmap file '\''$midxbitmap'\'' has invalid checksum" err && + grep "bitmap file '\''$packbitmap'\'' has invalid checksum" err +' + +test_expect_success 'corrupt MIDX with bitmap causes fallback' ' + git init corrupt-midx-bitmap && + ( + cd corrupt-midx-bitmap && + + test_commit first && + git repack -d && + test_commit second && + git repack -d && + + git multi-pack-index write --bitmap && + checksum=$(midx_checksum $objdir) && + for f in $midx $midx-$checksum.bitmap + do + mv $f $f.bak || return 1 + done && + + # pack everything together, invalidating the MIDX + git repack -ad && + # then restore the now-stale MIDX + for f in $midx $midx-$checksum.bitmap + do + mv $f.bak $f || return 1 + done && + + git rev-list --count --objects --use-bitmap-index HEAD >out 2>err && + # should attempt opening the broken pack twice (once + # from the attempt to load it via the stale bitmap, and + # again when attempting to load it from the stale MIDX) + # before falling back to the non-MIDX case + test 2 -eq $(grep -c "could not open pack" err) && + test 6 -eq $(cat out) + ) +' + test_done diff --git a/t/t5328-commit-graph-64bit-time.sh b/t/t5328-commit-graph-64bit-time.sh index 093f0c067a..e9c521c061 100755 --- a/t/t5328-commit-graph-64bit-time.sh +++ b/t/t5328-commit-graph-64bit-time.sh @@ -37,30 +37,39 @@ test_expect_success 'lower layers have overflow chunk' ' graph_git_behavior 'overflow' '' HEAD~2 HEAD test_expect_success 'set up and verify repo with generation data overflow chunk' ' - mkdir repo && - cd repo && - git init && - test_commit --date "$UNIX_EPOCH_ZERO" 1 && - test_commit 2 && - test_commit --date "$UNIX_EPOCH_ZERO" 3 && - git commit-graph write --reachable && - graph_read_expect 3 generation_data && - test_commit --date "$FUTURE_DATE" 4 && - test_commit 5 && - test_commit --date "$UNIX_EPOCH_ZERO" 6 && - git branch left && - git reset --hard 3 && - test_commit 7 && - test_commit --date "$FUTURE_DATE" 8 && - test_commit 9 && - git branch right && - git reset --hard 3 && - test_merge M left right && - git commit-graph write --reachable && - graph_read_expect 10 "generation_data generation_data_overflow" && - git commit-graph verify + git init repo && + ( + cd repo && + test_commit --date "$UNIX_EPOCH_ZERO" 1 && + test_commit 2 && + test_commit --date "$UNIX_EPOCH_ZERO" 3 && + git commit-graph write --reachable && + graph_read_expect 3 generation_data && + test_commit --date "$FUTURE_DATE" 4 && + test_commit 5 && + test_commit --date "$UNIX_EPOCH_ZERO" 6 && + git branch left && + git reset --hard 3 && + test_commit 7 && + test_commit --date "$FUTURE_DATE" 8 && + test_commit 9 && + git branch right && + git reset --hard 3 && + test_merge M left right && + git commit-graph write --reachable && + graph_read_expect 10 "generation_data generation_data_overflow" && + git commit-graph verify + ) ' graph_git_behavior 'overflow 2' repo left right +test_expect_success 'single commit with generation data exceeding UINT32_MAX' ' + git init repo-uint32-max && + test_commit -C repo-uint32-max --date "@4294967297 +0000" 1 && + git -C repo-uint32-max commit-graph write --reachable && + graph_read_expect -C repo-uint32-max 1 "generation_data" && + git -C repo-uint32-max commit-graph verify +' + test_done diff --git a/t/t5329-pack-objects-cruft.sh b/t/t5329-pack-objects-cruft.sh index 303f7a5d84..fc5fedbe9b 100755 --- a/t/t5329-pack-objects-cruft.sh +++ b/t/t5329-pack-objects-cruft.sh @@ -573,23 +573,54 @@ test_expect_success 'cruft repack with no reachable objects' ' ) ' -test_expect_success 'cruft repack ignores --max-pack-size' ' +write_blob () { + test-tool genrandom "$@" >in && + git hash-object -w -t blob in +} + +find_pack () { + for idx in $(ls $packdir/pack-*.idx) + do + git show-index <$idx >out && + if grep -q "$1" out + then + echo $idx + fi || return 1 + done +} + +test_expect_success 'cruft repack with --max-pack-size' ' git init max-pack-size && ( cd max-pack-size && test_commit base && + # two cruft objects which exceed the maximum pack size - test-tool genrandom foo 1048576 | git hash-object --stdin -w && - test-tool genrandom bar 1048576 | git hash-object --stdin -w && + foo=$(write_blob foo 1048576) && + bar=$(write_blob bar 1048576) && + test-tool chmtime --get -1000 \ + "$objdir/$(test_oid_to_path $foo)" >foo.mtime && + test-tool chmtime --get -2000 \ + "$objdir/$(test_oid_to_path $bar)" >bar.mtime && git repack --cruft --max-pack-size=1M && find $packdir -name "*.mtimes" >cruft && - test_line_count = 1 cruft && - test-tool pack-mtimes "$(basename "$(cat cruft)")" >objects && - test_line_count = 2 objects + test_line_count = 2 cruft && + + foo_mtimes="$(basename $(find_pack $foo) .idx).mtimes" && + bar_mtimes="$(basename $(find_pack $bar) .idx).mtimes" && + test-tool pack-mtimes $foo_mtimes >foo.actual && + test-tool pack-mtimes $bar_mtimes >bar.actual && + + echo "$foo $(cat foo.mtime)" >foo.expect && + echo "$bar $(cat bar.mtime)" >bar.expect && + + test_cmp foo.expect foo.actual && + test_cmp bar.expect bar.actual && + test "$foo_mtimes" != "$bar_mtimes" ) ' -test_expect_success 'cruft repack ignores pack.packSizeLimit' ' +test_expect_success 'cruft repack with pack.packSizeLimit' ' ( cd max-pack-size && # repack everything back together to remove the existing cruft @@ -599,9 +630,12 @@ test_expect_success 'cruft repack ignores pack.packSizeLimit' ' # ensure the same post condition is met when --max-pack-size # would otherwise be inferred from the configuration find $packdir -name "*.mtimes" >cruft && - test_line_count = 1 cruft && - test-tool pack-mtimes "$(basename "$(cat cruft)")" >objects && - test_line_count = 2 objects + test_line_count = 2 cruft && + for pack in $(cat cruft) + do + test-tool pack-mtimes "$(basename $pack)" >objects && + test_line_count = 1 objects || return 1 + done ) ' @@ -739,4 +773,175 @@ test_expect_success 'cruft objects are freshend via loose' ' ) ' +test_expect_success 'gc.recentObjectsHook' ' + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + + # Create a handful of objects. + # + # - one reachable commit, "base", designated for the reachable + # pack + # - one unreachable commit, "cruft.discard", which is marked + # for deletion + # - one unreachable commit, "cruft.old", which would be marked + # for deletion, but is rescued as an extra cruft tip + # - one unreachable commit, "cruft.new", which is not marked + # for deletion + test_commit base && + git branch -M main && + + git checkout --orphan discard && + git rm -fr . && + test_commit --no-tag cruft.discard && + + git checkout --orphan old && + git rm -fr . && + test_commit --no-tag cruft.old && + cruft_old="$(git rev-parse HEAD)" && + + git checkout --orphan new && + git rm -fr . && + test_commit --no-tag cruft.new && + cruft_new="$(git rev-parse HEAD)" && + + git checkout main && + git branch -D discard old new && + git reflog expire --all --expire=all && + + # mark cruft.old with an mtime that is many minutes + # older than the expiration period, and mark cruft.new + # with an mtime that is in the future (and thus not + # eligible for pruning). + test-tool chmtime -2000 "$objdir/$(test_oid_to_path $cruft_old)" && + test-tool chmtime +1000 "$objdir/$(test_oid_to_path $cruft_new)" && + + # Write the list of cruft objects we expect to + # accumulate, which is comprised of everything reachable + # from cruft.old and cruft.new, but not cruft.discard. + git rev-list --objects --no-object-names \ + $cruft_old $cruft_new >cruft.raw && + sort cruft.raw >cruft.expect && + + # Write the script to list extra tips, which are limited + # to cruft.old, in this case. + write_script extra-tips <<-EOF && + echo $cruft_old + EOF + git config gc.recentObjectsHook ./extra-tips && + + git repack --cruft --cruft-expiration=now -d && + + mtimes="$(ls .git/objects/pack/pack-*.mtimes)" && + git show-index <${mtimes%.mtimes}.idx >cruft && + cut -d" " -f2 cruft | sort >cruft.actual && + test_cmp cruft.expect cruft.actual && + + # Ensure that the "old" objects are removed after + # dropping the gc.recentObjectsHook hook. + git config --unset gc.recentObjectsHook && + git repack --cruft --cruft-expiration=now -d && + + mtimes="$(ls .git/objects/pack/pack-*.mtimes)" && + git show-index <${mtimes%.mtimes}.idx >cruft && + cut -d" " -f2 cruft | sort >cruft.actual && + + git rev-list --objects --no-object-names $cruft_new >cruft.raw && + cp cruft.expect cruft.old && + sort cruft.raw >cruft.expect && + test_cmp cruft.expect cruft.actual && + + # ensure objects which are no longer in the cruft pack were + # removed from the repository + for object in $(comm -13 cruft.expect cruft.old) + do + test_must_fail git cat-file -t $object || return 1 + done + ) +' + +test_expect_success 'multi-valued gc.recentObjectsHook' ' + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + + test_commit base && + git branch -M main && + + git checkout --orphan cruft.a && + git rm -fr . && + test_commit --no-tag cruft.a && + cruft_a="$(git rev-parse HEAD)" && + + git checkout --orphan cruft.b && + git rm -fr . && + test_commit --no-tag cruft.b && + cruft_b="$(git rev-parse HEAD)" && + + git checkout main && + git branch -D cruft.a cruft.b && + git reflog expire --all --expire=all && + + echo "echo $cruft_a" | write_script extra-tips.a && + echo "echo $cruft_b" | write_script extra-tips.b && + echo "false" | write_script extra-tips.c && + + git rev-list --objects --no-object-names $cruft_a $cruft_b \ + >cruft.raw && + sort cruft.raw >cruft.expect && + + # ensure that each extra cruft tip is saved by its + # respective hook + git config --add gc.recentObjectsHook ./extra-tips.a && + git config --add gc.recentObjectsHook ./extra-tips.b && + git repack --cruft --cruft-expiration=now -d && + + mtimes="$(ls .git/objects/pack/pack-*.mtimes)" && + git show-index <${mtimes%.mtimes}.idx >cruft && + cut -d" " -f2 cruft | sort >cruft.actual && + test_cmp cruft.expect cruft.actual && + + # ensure that a dirty exit halts cruft pack generation + git config --add gc.recentObjectsHook ./extra-tips.c && + test_must_fail git repack --cruft --cruft-expiration=now -d 2>err && + grep "unable to enumerate additional recent objects" err && + + # and that the existing cruft pack is left alone + test_path_is_file "$mtimes" + ) +' + +test_expect_success 'additional cruft blobs via gc.recentObjectsHook' ' + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + + test_commit base && + + blob=$(echo "unreachable" | git hash-object -w --stdin) && + + # mark the unreachable blob we wrote above as having + # aged out of the retention period + test-tool chmtime -2000 "$objdir/$(test_oid_to_path $blob)" && + + # Write the script to list extra tips, which is just the + # extra blob as above. + write_script extra-tips <<-EOF && + echo $blob + EOF + git config gc.recentObjectsHook ./extra-tips && + + git repack --cruft --cruft-expiration=now -d && + + mtimes="$(ls .git/objects/pack/pack-*.mtimes)" && + git show-index <${mtimes%.mtimes}.idx >cruft && + cut -d" " -f2 cruft >actual && + echo $blob >expect && + test_cmp expect actual + ) +' + test_done diff --git a/t/t5330-no-lazy-fetch-with-commit-graph.sh b/t/t5330-no-lazy-fetch-with-commit-graph.sh index 2cc7fd7a47..5eb28f0512 100755 --- a/t/t5330-no-lazy-fetch-with-commit-graph.sh +++ b/t/t5330-no-lazy-fetch-with-commit-graph.sh @@ -2,6 +2,7 @@ test_description='test for no lazy fetch with the commit-graph' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup: prepare a repository with a commit' ' diff --git a/t/t5331-pack-objects-stdin.sh b/t/t5331-pack-objects-stdin.sh new file mode 100755 index 0000000000..acab31667a --- /dev/null +++ b/t/t5331-pack-objects-stdin.sh @@ -0,0 +1,240 @@ +#!/bin/sh + +test_description='pack-objects --stdin' +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +packed_objects () { + git show-index <"$1" >tmp-object-list && + cut -d' ' -f2 tmp-object-list | sort && + rm tmp-object-list + } + +test_expect_success 'setup for --stdin-packs tests' ' + git init stdin-packs && + ( + cd stdin-packs && + + test_commit A && + test_commit B && + test_commit C && + + for id in A B C + do + git pack-objects .git/objects/pack/pack-$id \ + --incremental --revs <<-EOF || exit 1 + refs/tags/$id + EOF + done && + + ls -la .git/objects/pack + ) +' + +test_expect_success '--stdin-packs with excluded packs' ' + ( + cd stdin-packs && + + PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" && + PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" && + PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" && + + git pack-objects test --stdin-packs <<-EOF && + $PACK_A + ^$PACK_B + $PACK_C + EOF + + ( + git show-index <$(ls .git/objects/pack/pack-A-*.idx) && + git show-index <$(ls .git/objects/pack/pack-C-*.idx) + ) >expect.raw && + git show-index <$(ls test-*.idx) >actual.raw && + + cut -d" " -f2 <expect.raw | sort >expect && + cut -d" " -f2 <actual.raw | sort >actual && + test_cmp expect actual + ) +' + +test_expect_success '--stdin-packs is incompatible with --filter' ' + ( + cd stdin-packs && + test_must_fail git pack-objects --stdin-packs --stdout \ + --filter=blob:none </dev/null 2>err && + test_i18ngrep "cannot use --filter with --stdin-packs" err + ) +' + +test_expect_success '--stdin-packs is incompatible with --revs' ' + ( + cd stdin-packs && + test_must_fail git pack-objects --stdin-packs --revs out \ + </dev/null 2>err && + test_i18ngrep "cannot use internal rev list with --stdin-packs" err + ) +' + +test_expect_success '--stdin-packs with loose objects' ' + ( + cd stdin-packs && + + PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" && + PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" && + PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" && + + test_commit D && # loose + + git pack-objects test2 --stdin-packs --unpacked <<-EOF && + $PACK_A + ^$PACK_B + $PACK_C + EOF + + ( + git show-index <$(ls .git/objects/pack/pack-A-*.idx) && + git show-index <$(ls .git/objects/pack/pack-C-*.idx) && + git rev-list --objects --no-object-names \ + refs/tags/C..refs/tags/D + + ) >expect.raw && + ls -la . && + git show-index <$(ls test2-*.idx) >actual.raw && + + cut -d" " -f2 <expect.raw | sort >expect && + cut -d" " -f2 <actual.raw | sort >actual && + test_cmp expect actual + ) +' + +test_expect_success '--stdin-packs with broken links' ' + ( + cd stdin-packs && + + # make an unreachable object with a bogus parent + git cat-file -p HEAD >commit && + sed "s/$(git rev-parse HEAD^)/$(test_oid zero)/" <commit | + git hash-object -w -t commit --stdin >in && + + git pack-objects .git/objects/pack/pack-D <in && + + PACK_A="$(basename .git/objects/pack/pack-A-*.pack)" && + PACK_B="$(basename .git/objects/pack/pack-B-*.pack)" && + PACK_C="$(basename .git/objects/pack/pack-C-*.pack)" && + PACK_D="$(basename .git/objects/pack/pack-D-*.pack)" && + + git pack-objects test3 --stdin-packs --unpacked <<-EOF && + $PACK_A + ^$PACK_B + $PACK_C + $PACK_D + EOF + + ( + git show-index <$(ls .git/objects/pack/pack-A-*.idx) && + git show-index <$(ls .git/objects/pack/pack-C-*.idx) && + git show-index <$(ls .git/objects/pack/pack-D-*.idx) && + git rev-list --objects --no-object-names \ + refs/tags/C..refs/tags/D + ) >expect.raw && + git show-index <$(ls test3-*.idx) >actual.raw && + + cut -d" " -f2 <expect.raw | sort >expect && + cut -d" " -f2 <actual.raw | sort >actual && + test_cmp expect actual + ) +' + +test_expect_success 'pack-objects --stdin with duplicate packfile' ' + test_when_finished "rm -fr repo" && + + git init repo && + ( + cd repo && + test_commit "commit" && + git repack -ad && + + { + basename .git/objects/pack/pack-*.pack && + basename .git/objects/pack/pack-*.pack + } >packfiles && + + git pack-objects --stdin-packs generated-pack <packfiles && + packed_objects .git/objects/pack/pack-*.idx >expect && + packed_objects generated-pack-*.idx >actual && + test_cmp expect actual + ) +' + +test_expect_success 'pack-objects --stdin with same packfile excluded and included' ' + test_when_finished "rm -fr repo" && + + git init repo && + ( + cd repo && + test_commit "commit" && + git repack -ad && + + { + basename .git/objects/pack/pack-*.pack && + printf "^%s\n" "$(basename .git/objects/pack/pack-*.pack)" + } >packfiles && + + git pack-objects --stdin-packs generated-pack <packfiles && + packed_objects generated-pack-*.idx >packed-objects && + test_must_be_empty packed-objects + ) +' + +test_expect_success 'pack-objects --stdin with packfiles from alternate object database' ' + test_when_finished "rm -fr shared member" && + + # Set up a shared repository with a single packfile. + git init shared && + test_commit -C shared "shared-objects" && + git -C shared repack -ad && + basename shared/.git/objects/pack/pack-*.pack >packfile && + + # Set up a repository that is connected to the shared repository. This + # repository has no objects on its own, but we still expect to be able + # to pack objects from its alternate. + git clone --shared shared member && + git -C member pack-objects --stdin-packs generated-pack <packfile && + test_cmp shared/.git/objects/pack/pack-*.pack member/generated-pack-*.pack +' + +test_expect_success 'pack-objects --stdin with packfiles from main and alternate object database' ' + test_when_finished "rm -fr shared member" && + + # Set up a shared repository with a single packfile. + git init shared && + test_commit -C shared "shared-commit" && + git -C shared repack -ad && + + # Set up a repository that is connected to the shared repository. This + # repository has a second packfile so that we can verify that it is + # possible to write packs that include packfiles from different object + # databases. + git clone --shared shared member && + test_commit -C member "local-commit" && + git -C member repack -dl && + + { + basename shared/.git/objects/pack/pack-*.pack && + basename member/.git/objects/pack/pack-*.pack + } >packfiles && + + { + packed_objects shared/.git/objects/pack/pack-*.idx && + packed_objects member/.git/objects/pack/pack-*.idx + } | sort >expected-objects && + + git -C member pack-objects --stdin-packs generated-pack <packfiles && + packed_objects member/generated-pack-*.idx >actual-objects && + test_cmp expected-objects actual-objects +' + +test_done diff --git a/t/t5351-unpack-large-objects.sh b/t/t5351-unpack-large-objects.sh index 8c8af99b84..43cbcd5d49 100755 --- a/t/t5351-unpack-large-objects.sh +++ b/t/t5351-unpack-large-objects.sh @@ -55,7 +55,7 @@ check_fsync_events () { cat >expect && sed -n \ - -e '/^{"event":"data",.*"category":"fsync",/ { + -e '/^{"event":"counter",.*"category":"fsync",/ { s/.*"category":"fsync",//; s/}$//; p; @@ -78,8 +78,8 @@ test_expect_success 'unpack big object in stream (core.fsyncmethod=batch)' ' flush_count=1 fi && check_fsync_events trace2.txt <<-EOF && - "key":"fsync/writeout-only","value":"6" - "key":"fsync/hardware-flush","value":"$flush_count" + "name":"writeout-only","count":6 + "name":"hardware-flush","count":$flush_count EOF test_dir_is_empty dest.git/objects/pack && diff --git a/t/t5403-post-checkout-hook.sh b/t/t5403-post-checkout-hook.sh index 978f240cda..cfaae54739 100755 --- a/t/t5403-post-checkout-hook.sh +++ b/t/t5403-post-checkout-hook.sh @@ -7,6 +7,7 @@ test_description='Test the post-checkout hook.' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t5404-tracking-branches.sh b/t/t5404-tracking-branches.sh index cc07889667..51737eeafe 100755 --- a/t/t5404-tracking-branches.sh +++ b/t/t5404-tracking-branches.sh @@ -5,6 +5,7 @@ test_description='tracking branch update checks for git push' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t5405-send-pack-rewind.sh b/t/t5405-send-pack-rewind.sh index 11f03239a0..1686ac13aa 100755 --- a/t/t5405-send-pack-rewind.sh +++ b/t/t5405-send-pack-rewind.sh @@ -5,6 +5,7 @@ test_description='forced push to replace commit we do not have' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t5406-remote-rejects.sh b/t/t5406-remote-rejects.sh index dcbeb42082..d6a9946633 100755 --- a/t/t5406-remote-rejects.sh +++ b/t/t5406-remote-rejects.sh @@ -2,6 +2,7 @@ test_description='remote push rejects are reported by client' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh index 5f3ff051ca..ad7f8c6f00 100755 --- a/t/t5407-post-rewrite-hook.sh +++ b/t/t5407-post-rewrite-hook.sh @@ -17,6 +17,12 @@ test_expect_success 'setup' ' git checkout A^0 && test_commit E bar E && test_commit F foo F && + git checkout B && + git merge E && + git tag merge-E && + test_commit G G && + test_commit H H && + test_commit I I && git checkout main && test_hook --setup post-rewrite <<-EOF @@ -173,6 +179,48 @@ test_fail_interactive_rebase () { ) } +test_expect_success 'git rebase with failed pick' ' + clear_hook_input && + cat >todo <<-\EOF && + exec >bar + merge -C merge-E E + exec >G + pick G + exec >H 2>I + pick H + fixup I + EOF + + ( + set_replace_editor todo && + test_must_fail git rebase -i D D 2>err + ) && + grep "would be overwritten" err && + rm bar && + + test_must_fail git rebase --continue 2>err && + grep "would be overwritten" err && + rm G && + + test_must_fail git rebase --continue 2>err && + grep "would be overwritten" err && + rm H && + + test_must_fail git rebase --continue 2>err && + grep "would be overwritten" err && + rm I && + + git rebase --continue && + echo rebase >expected.args && + cat >expected.data <<-EOF && + $(git rev-parse merge-E) $(git rev-parse HEAD~2) + $(git rev-parse G) $(git rev-parse HEAD~1) + $(git rev-parse H) $(git rev-parse HEAD) + $(git rev-parse I) $(git rev-parse HEAD) + EOF + verify_hook_input +' + test_expect_success 'git rebase -i (unchanged)' ' git reset --hard D && clear_hook_input && diff --git a/t/t5502-quickfetch.sh b/t/t5502-quickfetch.sh index b160f8b7fb..7b3ff21b98 100755 --- a/t/t5502-quickfetch.sh +++ b/t/t5502-quickfetch.sh @@ -5,6 +5,7 @@ test_description='test quickfetch from local' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh index ac4099ca89..0b8ab4afdb 100755 --- a/t/t5504-fetch-receive-strict.sh +++ b/t/t5504-fetch-receive-strict.sh @@ -4,6 +4,7 @@ test_description='fetch/receive strict mode' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup and inject "corrupt or missing" object' ' @@ -138,7 +139,7 @@ This commit object intentionally broken EOF test_expect_success 'setup bogus commit' ' - commit="$(git hash-object -t commit -w --stdin <bogus-commit)" + commit="$(git hash-object --literally -t commit -w --stdin <bogus-commit)" ' test_expect_success 'fsck with no skipList input' ' diff --git a/t/t5506-remote-groups.sh b/t/t5506-remote-groups.sh index 5bac03ede8..0e176175a3 100755 --- a/t/t5506-remote-groups.sh +++ b/t/t5506-remote-groups.sh @@ -99,4 +99,13 @@ test_expect_success 'updating remote name updates that remote' ' ! repo_fetched two ' +test_expect_success 'updating group in parallel with a duplicate remote does not fail (fetch)' ' + mark fetch-group-duplicate && + update_repo one && + git config --add remotes.duplicate one && + git config --add remotes.duplicate one && + git -c fetch.parallel=2 remote update duplicate && + repo_fetched one +' + test_done diff --git a/t/t5507-remote-environment.sh b/t/t5507-remote-environment.sh index e6149295b1..c6a6957c50 100755 --- a/t/t5507-remote-environment.sh +++ b/t/t5507-remote-environment.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='check environment showed to remote side of transports' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'set up "remote" push situation' ' diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index c0b745e33b..19c36b57f4 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -806,6 +806,14 @@ test_expect_success 'fetch.writeCommitGraph with submodules' ' ) ' +# fetches from first configured url +test_expect_success 'fetch from multiple configured URLs in single remote' ' + git init url1 && + git remote add multipleurls url1 && + git remote set-url --add multipleurls url2 && + git fetch multipleurls +' + # configured prune tests set_config_tristate () { @@ -1110,58 +1118,60 @@ test_expect_success 'fetching with auto-gc does not lock up' ' ) ' -test_expect_success 'fetch aligned output' ' - git clone . full-output && - test_commit looooooooooooong-tag && - ( - cd full-output && - git -c fetch.output=full fetch origin >actual 2>&1 && - grep -e "->" actual | cut -c 22- >../actual - ) && - cat >expect <<-\EOF && - main -> origin/main - looooooooooooong-tag -> looooooooooooong-tag - EOF - test_cmp expect actual -' +for section in fetch transfer +do + test_expect_success "$section.hideRefs affects connectivity check" ' + GIT_TRACE="$PWD"/trace git -c $section.hideRefs=refs -c \ + $section.hideRefs="!refs/tags/" fetch && + grep "git rev-list .*--exclude-hidden=fetch" trace + ' +done + +test_expect_success 'prepare source branch' ' + echo one >onebranch && + git checkout --orphan onebranch && + git rm --cached -r . && + git add onebranch && + git commit -m onebranch && + git rev-list --objects onebranch -- >actual && + # 3 objects should be created, at least ... + test 3 -le $(wc -l <actual) +' + +validate_store_type () { + git -C dest count-objects -v >actual && + case "$store_type" in + packed) + grep "^count: 0$" actual ;; + loose) + grep "^packs: 0$" actual ;; + esac || { + echo "store_type is $store_type" + cat actual + false + } +} -test_expect_success 'fetch compact output' ' - git clone . compact && - test_commit extraaa && - ( - cd compact && - git -c fetch.output=compact fetch origin >actual 2>&1 && - grep -e "->" actual | cut -c 22- >../actual - ) && - cat >expect <<-\EOF && - main -> origin/* - extraaa -> * - EOF - test_cmp expect actual -' +test_unpack_limit () { + store_type=$1 -test_expect_success '--no-show-forced-updates' ' - mkdir forced-updates && - ( - cd forced-updates && - git init && - test_commit 1 && - test_commit 2 - ) && - git clone forced-updates forced-update-clone && - git clone forced-updates no-forced-update-clone && - git -C forced-updates reset --hard HEAD~1 && - ( - cd forced-update-clone && - git fetch --show-forced-updates origin 2>output && - test_i18ngrep "(forced update)" output - ) && - ( - cd no-forced-update-clone && - git fetch --no-show-forced-updates origin 2>output && - test_i18ngrep ! "(forced update)" output - ) -' + case "$store_type" in + packed) fetch_limit=1 transfer_limit=10000 ;; + loose) fetch_limit=10000 transfer_limit=1 ;; + esac + + test_expect_success "fetch trumps transfer limit" ' + rm -fr dest && + git --bare init dest && + git -C dest config fetch.unpacklimit $fetch_limit && + git -C dest config transfer.unpacklimit $transfer_limit && + git -C dest fetch .. onebranch && + validate_store_type + ' +} + +test_unpack_limit packed +test_unpack_limit loose setup_negotiation_tip () { SERVER="$1" diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh index 20d063fb9a..151c76eb09 100755 --- a/t/t5512-ls-remote.sh +++ b/t/t5512-ls-remote.sh @@ -15,6 +15,19 @@ generate_references () { done } +test_expect_success 'set up fake upload-pack' ' + # This can be used to simulate an upload-pack that just shows the + # contents of the "input" file (prepared with the test-tool pkt-line + # helper), and does not do any negotiation (since ls-remote does not + # need it). + write_script cat-input <<-\EOF + # send our initial advertisement/response + cat input + # soak up the flush packet from the client + cat + EOF +' + test_expect_success 'dies when no remote found' ' test_must_fail git ls-remote ' @@ -231,22 +244,25 @@ test_expect_success 'protocol v2 supports hiderefs' ' test_expect_success 'ls-remote --symref' ' git fetch origin && - echo "ref: refs/heads/main HEAD" >expect && + echo "ref: refs/heads/main HEAD" >expect.v2 && generate_references \ HEAD \ - refs/heads/main >>expect && + refs/heads/main >>expect.v2 && + echo "ref: refs/remotes/origin/main refs/remotes/origin/HEAD" >>expect.v2 && oid=$(git rev-parse HEAD) && - echo "$oid refs/remotes/origin/HEAD" >>expect && + echo "$oid refs/remotes/origin/HEAD" >>expect.v2 && generate_references \ refs/remotes/origin/main \ refs/tags/mark \ refs/tags/mark1.1 \ refs/tags/mark1.10 \ - refs/tags/mark1.2 >>expect && - # Protocol v2 supports sending symrefs for refs other than HEAD, so use - # protocol v0 here. - GIT_TEST_PROTOCOL_VERSION=0 git ls-remote --symref >actual && - test_cmp expect actual + refs/tags/mark1.2 >>expect.v2 && + # v0 does not show non-HEAD symrefs + grep -v "ref: refs/remotes" <expect.v2 >expect.v0 && + git -c protocol.version=0 ls-remote --symref >actual.v0 && + test_cmp expect.v0 actual.v0 && + git -c protocol.version=2 ls-remote --symref >actual.v2 && + test_cmp expect.v2 actual.v2 ' test_expect_success 'ls-remote with filtered symref (refname)' ' @@ -255,76 +271,41 @@ test_expect_success 'ls-remote with filtered symref (refname)' ' ref: refs/heads/main HEAD $rev HEAD EOF - # Protocol v2 supports sending symrefs for refs other than HEAD, so use - # protocol v0 here. - GIT_TEST_PROTOCOL_VERSION=0 git ls-remote --symref . HEAD >actual && + git ls-remote --symref . HEAD >actual && test_cmp expect actual ' -test_expect_failure 'ls-remote with filtered symref (--heads)' ' +test_expect_success 'ls-remote with filtered symref (--heads)' ' git symbolic-ref refs/heads/foo refs/tags/mark && - cat >expect <<-EOF && + cat >expect.v2 <<-EOF && ref: refs/tags/mark refs/heads/foo $rev refs/heads/foo $rev refs/heads/main EOF - # Protocol v2 supports sending symrefs for refs other than HEAD, so use - # protocol v0 here. - GIT_TEST_PROTOCOL_VERSION=0 git ls-remote --symref --heads . >actual && - test_cmp expect actual + grep -v "^ref: refs/tags/" <expect.v2 >expect.v0 && + git -c protocol.version=0 ls-remote --symref --heads . >actual.v0 && + test_cmp expect.v0 actual.v0 && + git -c protocol.version=2 ls-remote --symref --heads . >actual.v2 && + test_cmp expect.v2 actual.v2 ' -test_expect_success 'ls-remote --symref omits filtered-out matches' ' - cat >expect <<-EOF && - $rev refs/heads/foo - $rev refs/heads/main +test_expect_success 'indicate no refs in v0 standards-compliant empty remote' ' + # Git does not produce an output like this, but it does match the + # standard and is produced by other implementations like JGit. So + # hard-code the case we care about. + # + # The actual capabilities do not matter; there are none that would + # change how ls-remote behaves. + oid=0000000000000000000000000000000000000000 && + test-tool pkt-line pack >input.q <<-EOF && + $oid capabilities^{}Qcaps-go-here + 0000 EOF - # Protocol v2 supports sending symrefs for refs other than HEAD, so use - # protocol v0 here. - GIT_TEST_PROTOCOL_VERSION=0 git ls-remote --symref --heads . >actual && - test_cmp expect actual && - GIT_TEST_PROTOCOL_VERSION=0 git ls-remote --symref . "refs/heads/*" >actual && - test_cmp expect actual -' - -test_lazy_prereq GIT_DAEMON ' - test_bool_env GIT_TEST_GIT_DAEMON true -' + q_to_nul <input.q >input && -# This test spawns a daemon, so run it only if the user would be OK with -# testing with git-daemon. -test_expect_success PIPE,JGIT,GIT_DAEMON 'indicate no refs in standards-compliant empty remote' ' - test_set_port JGIT_DAEMON_PORT && - JGIT_DAEMON_PID= && - git init --bare empty.git && - >empty.git/git-daemon-export-ok && - mkfifo jgit_daemon_output && - { - jgit daemon --port="$JGIT_DAEMON_PORT" . >jgit_daemon_output & - JGIT_DAEMON_PID=$! - } && - test_when_finished kill "$JGIT_DAEMON_PID" && - { - read line && - case $line in - Exporting*) - ;; - *) - echo "Expected: Exporting" && - false;; - esac && - read line && - case $line in - "Listening on"*) - ;; - *) - echo "Expected: Listening on" && - false;; - esac - } <jgit_daemon_output && # --exit-code asks the command to exit with 2 when no # matching refs are found. - test_expect_code 2 git ls-remote --exit-code git://localhost:$JGIT_DAEMON_PORT/empty.git + test_expect_code 2 git ls-remote --exit-code --upload-pack=./cat-input . ' test_expect_success 'ls-remote works outside repository' ' @@ -345,8 +326,8 @@ test_expect_success 'ls-remote --sort fails gracefully outside repository' ' test_expect_success 'ls-remote patterns work with all protocol versions' ' git for-each-ref --format="%(objectname) %(refname)" \ refs/heads/main refs/remotes/origin/main >expect && - git -c protocol.version=1 ls-remote . main >actual.v1 && - test_cmp expect actual.v1 && + git -c protocol.version=0 ls-remote . main >actual.v0 && + test_cmp expect actual.v0 && git -c protocol.version=2 ls-remote . main >actual.v2 && test_cmp expect actual.v2 ' @@ -354,10 +335,49 @@ test_expect_success 'ls-remote patterns work with all protocol versions' ' test_expect_success 'ls-remote prefixes work with all protocol versions' ' git for-each-ref --format="%(objectname) %(refname)" \ refs/heads/ refs/tags/ >expect && - git -c protocol.version=1 ls-remote --heads --tags . >actual.v1 && - test_cmp expect actual.v1 && + git -c protocol.version=0 ls-remote --heads --tags . >actual.v0 && + test_cmp expect actual.v0 && git -c protocol.version=2 ls-remote --heads --tags . >actual.v2 && test_cmp expect actual.v2 ' +test_expect_success 'v0 clients can handle multiple symrefs' ' + # Modern versions of Git will not return multiple symref capabilities + # for v0, so we have to hard-code the response. Note that we will + # always use both v0 and object-format=sha1 here, as the hard-coded + # response reflects a server that only supports those. + oid=1234567890123456789012345678901234567890 && + symrefs="symref=refs/remotes/origin/HEAD:refs/remotes/origin/main" && + symrefs="$symrefs symref=HEAD:refs/heads/main" && + + # Likewise we want to make sure our parser is not fooled by the string + # "symref" appearing as part of an earlier cap. But there is no way to + # do that via upload-pack, as arbitrary strings can appear only in a + # "symref" value itself (where we skip past the values as a whole) + # and "agent" (which always appears after "symref", so putting our + # parser in a confused state is less interesting). + caps="some other caps including a-fake-symref-cap" && + + test-tool pkt-line pack >input.q <<-EOF && + $oid HEADQ$caps $symrefs + $oid refs/heads/main + $oid refs/remotes/origin/HEAD + $oid refs/remotes/origin/main + 0000 + EOF + q_to_nul <input.q >input && + + cat >expect <<-EOF && + ref: refs/heads/main HEAD + $oid HEAD + $oid refs/heads/main + ref: refs/remotes/origin/main refs/remotes/origin/HEAD + $oid refs/remotes/origin/HEAD + $oid refs/remotes/origin/main + EOF + + git ls-remote --symref --upload-pack=./cat-input . >actual && + test_cmp expect actual +' + test_done diff --git a/t/t5514-fetch-multiple.sh b/t/t5514-fetch-multiple.sh index 511ba3bd45..98f034aa77 100755 --- a/t/t5514-fetch-multiple.sh +++ b/t/t5514-fetch-multiple.sh @@ -58,6 +58,13 @@ test_expect_success 'git fetch --all' ' test_cmp expect output) ' +test_expect_success 'git fetch --all --no-write-fetch-head' ' + (cd test && + rm -f .git/FETCH_HEAD && + git fetch --all --no-write-fetch-head && + test_path_is_missing .git/FETCH_HEAD) +' + test_expect_success 'git fetch --all should continue if a remote has errors' ' (git clone one test2 && cd test2 && @@ -197,4 +204,9 @@ test_expect_success 'parallel' ' test_i18ngrep "could not fetch .two.*128" err ' +test_expect_success 'git fetch --multiple --jobs=0 picks a default' ' + (cd test && + git fetch --multiple --jobs=0) +' + test_done diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 79dc470c01..87163d7745 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -120,6 +120,17 @@ test_expect_success setup ' ' +for cmd in push fetch +do + for opt in ipv4 ipv6 + do + test_expect_success "reject 'git $cmd --no-$opt'" ' + test_must_fail git $cmd --no-$opt 2>err && + grep "unknown option .no-$opt" err + ' + done +done + test_expect_success 'fetch without wildcard' ' mk_empty testrepo && ( @@ -401,6 +412,11 @@ test_expect_success 'push with ambiguity' ' ' +test_expect_success 'push with onelevel ref' ' + mk_test testrepo heads/main && + test_must_fail git push testrepo HEAD:refs/onelevel +' + test_expect_success 'push with colon-less refspec (1)' ' mk_test testrepo heads/frotz tags/frotz && @@ -898,6 +914,13 @@ test_expect_success 'push --delete refuses empty string' ' test_must_fail git push testrepo --delete "" ' +test_expect_success 'push --delete onelevel refspecs' ' + mk_test testrepo heads/main && + git -C testrepo update-ref refs/onelevel refs/heads/main && + git push testrepo --delete refs/onelevel && + test_must_fail git -C testrepo rev-parse --verify refs/onelevel +' + test_expect_success 'warn on push to HEAD of non-bare repository' ' mk_test testrepo heads/main && ( @@ -1853,55 +1876,24 @@ test_expect_success 'refuse to push a hidden ref, and make sure do not pollute t test_dir_is_empty testrepo/.git/objects/pack ' -test_expect_success LIBCURL 'fetch warns or fails when using username:password' ' - message="URL '\''https://username:<redacted>@localhost/'\'' uses plaintext credentials" && - test_must_fail git -c transfer.credentialsInUrl=allow fetch https://username:password@localhost 2>err && - ! grep "$message" err && - - test_must_fail git -c transfer.credentialsInUrl=warn fetch https://username:password@localhost 2>err && - grep "warning: $message" err >warnings && - test_line_count = 3 warnings && - - test_must_fail git -c transfer.credentialsInUrl=die fetch https://username:password@localhost 2>err && - grep "fatal: $message" err >warnings && - test_line_count = 1 warnings && - - test_must_fail git -c transfer.credentialsInUrl=die fetch https://username:@localhost 2>err && - grep "fatal: $message" err >warnings && - test_line_count = 1 warnings -' - - -test_expect_success LIBCURL 'push warns or fails when using username:password' ' - message="URL '\''https://username:<redacted>@localhost/'\'' uses plaintext credentials" && - test_must_fail git -c transfer.credentialsInUrl=allow push https://username:password@localhost 2>err && - ! grep "$message" err && - - test_must_fail git -c transfer.credentialsInUrl=warn push https://username:password@localhost 2>err && - grep "warning: $message" err >warnings && - test_must_fail git -c transfer.credentialsInUrl=die push https://username:password@localhost 2>err && - grep "fatal: $message" err >warnings && - test_line_count = 1 warnings -' - test_expect_success 'push with config push.useBitmaps' ' mk_test testrepo heads/main && 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/t5517-push-mirror.sh b/t/t5517-push-mirror.sh index a448e169bd..6d4944a728 100755 --- a/t/t5517-push-mirror.sh +++ b/t/t5517-push-mirror.sh @@ -5,6 +5,7 @@ test_description='pushing to a mirror repository' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh D=$(pwd) diff --git a/t/t5522-pull-symlink.sh b/t/t5522-pull-symlink.sh index bcff460d0a..cc5496e28f 100755 --- a/t/t5522-pull-symlink.sh +++ b/t/t5522-pull-symlink.sh @@ -2,6 +2,7 @@ test_description='pulling from symlinked subdir' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # The scenario we are building: @@ -78,7 +79,9 @@ test_expect_success SYMLINKS 'pushing from symlinked subdir' ' git commit -m push ./file && git push ) && - test push = $(git show HEAD:subdir/file) + echo push >expect && + git show HEAD:subdir/file >actual && + test_cmp expect actual ' test_done diff --git a/t/t5523-push-upstream.sh b/t/t5523-push-upstream.sh index fdb4292056..1b8d609879 100755 --- a/t/t5523-push-upstream.sh +++ b/t/t5523-push-upstream.sh @@ -4,6 +4,7 @@ test_description='push with --set-upstream' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-terminal.sh @@ -60,12 +61,20 @@ test_expect_success 'push -u :topic_2' ' check_config topic_2 upstream refs/heads/other2 ' -test_expect_success 'push -u --all' ' +test_expect_success 'push -u --all(the same behavior with--branches)' ' git branch all1 && git branch all2 && git push -u --all && check_config all1 upstream refs/heads/all1 && - check_config all2 upstream refs/heads/all2 + check_config all2 upstream refs/heads/all2 && + git config --get-regexp branch.all* > expect && + git config --remove-section branch.all1 && + git config --remove-section branch.all2 && + git push -u --branches && + check_config all1 upstream refs/heads/all1 && + check_config all2 upstream refs/heads/all2 && + git config --get-regexp branch.all* > actual && + test_cmp expect actual ' test_expect_success 'push -u HEAD' ' diff --git a/t/t5525-fetch-tagopt.sh b/t/t5525-fetch-tagopt.sh index 45815f7378..3a28f1ded5 100755 --- a/t/t5525-fetch-tagopt.sh +++ b/t/t5525-fetch-tagopt.sh @@ -2,6 +2,7 @@ test_description='tagopt variable affects "git fetch" and is overridden by commandline.' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh setup_clone () { diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh index 3c44f19612..26e933f93a 100755 --- a/t/t5526-fetch-submodules.sh +++ b/t/t5526-fetch-submodules.sh @@ -167,6 +167,19 @@ test_expect_success "fetch --recurse-submodules recurses into submodules" ' verify_fetch_result actual.err ' +test_expect_success "fetch --recurse-submodules honors --no-write-fetch-head" ' + ( + cd downstream && + git submodule foreach --recursive \ + sh -c "cd \"\$(git rev-parse --git-dir)\" && rm -f FETCH_HEAD" && + + git fetch --recurse-submodules --no-write-fetch-head && + + git submodule foreach --recursive \ + sh -c "cd \"\$(git rev-parse --git-dir)\" && ! test -f FETCH_HEAD" + ) +' + test_expect_success "submodule.recurse option triggers recursive fetch" ' add_submodule_commits && ( @@ -178,6 +191,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,17 +719,30 @@ 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 + grep "9 tasks" trace.out && + >trace.out && + + GIT_TRACE=$(pwd)/trace.out git -c submodule.fetchJobs=0 fetch && + grep "preparing to run up to [0-9]* tasks" trace.out && + ! grep "up to 0 tasks" trace.out && + >trace.out ) ' @@ -1153,4 +1180,17 @@ test_expect_success 'fetch --all with --recurse-submodules with multiple' ' test_line_count = 2 fetch-subs ' +test_expect_success "fetch --all with --no-recurse-submodules only fetches superproject" ' + test_when_finished "rm -rf src_clone" && + + git clone --recurse-submodules src src_clone && + ( + cd src_clone && + git remote add secondary ../src && + git config submodule.recurse true && + git fetch --all --no-recurse-submodules 2>../fetch-log + ) && + ! grep "Fetching submodule" fetch-log +' + test_done diff --git a/t/t5527-fetch-odd-refs.sh b/t/t5527-fetch-odd-refs.sh index e2770e4541..98ece27c6a 100755 --- a/t/t5527-fetch-odd-refs.sh +++ b/t/t5527-fetch-odd-refs.sh @@ -4,6 +4,7 @@ test_description='test fetching of oddly-named refs' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # afterwards we will have: diff --git a/t/t5529-push-errors.sh b/t/t5529-push-errors.sh index ce85fd30ad..0247137cb3 100755 --- a/t/t5529-push-errors.sh +++ b/t/t5529-push-errors.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='detect some push errors early (before contacting remote)' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup commits' ' 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/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh index fbad2d5ff5..d0211cd8be 100755 --- a/t/t5541-http-push-smart.sh +++ b/t/t5541-http-push-smart.sh @@ -36,28 +36,6 @@ test_expect_success 'setup remote repository' ' setup_askpass_helper -cat >exp <<EOF -GET /smart/test_repo.git/info/refs?service=git-upload-pack HTTP/1.1 200 -POST /smart/test_repo.git/git-upload-pack HTTP/1.1 200 -EOF -test_expect_success 'no empty path components' ' - # Clear the log, so that it does not affect the "used receive-pack - # service" test which reads the log too. - test_when_finished ">\"\$HTTPD_ROOT_PATH\"/access.log" && - - # In the URL, add a trailing slash, and see if git appends yet another - # slash. - cd "$ROOT_PATH" && - git clone $HTTPD_URL/smart/test_repo.git/ test_repo_clone && - - # NEEDSWORK: If the overspecification of the expected result is reduced, we - # might be able to run this test in all protocol versions. - if test "$GIT_TEST_PROTOCOL_VERSION" = 0 - then - check_access_log exp - fi -' - test_expect_success 'clone remote repository' ' rm -rf test_repo_clone && git clone $HTTPD_URL/smart/test_repo.git test_repo_clone && @@ -67,6 +45,10 @@ test_expect_success 'clone remote repository' ' ' test_expect_success 'push to remote repository (standard)' ' + # Clear the log, so that the "used receive-pack service" test below + # sees just what we did here. + >"$HTTPD_ROOT_PATH"/access.log && + cd "$ROOT_PATH"/test_repo_clone && : >path2 && git add path2 && @@ -80,6 +62,15 @@ test_expect_success 'push to remote repository (standard)' ' test $HEAD = $(git rev-parse --verify HEAD)) ' +test_expect_success 'used receive-pack service' ' + cat >exp <<-\EOF && + GET /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200 + POST /smart/test_repo.git/git-receive-pack HTTP/1.1 200 + EOF + + check_access_log exp +' + test_expect_success 'push to remote repository (standard) with sending Accept-Language' ' cat >exp <<-\EOF && => Send header: Accept-Language: ko-KR, *;q=0.9 @@ -141,28 +132,6 @@ test_expect_success 'rejected update prints status' ' ' rm -f "$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update" -cat >exp <<EOF -GET /smart/test_repo.git/info/refs?service=git-upload-pack HTTP/1.1 200 -POST /smart/test_repo.git/git-upload-pack HTTP/1.1 200 -GET /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200 -POST /smart/test_repo.git/git-receive-pack HTTP/1.1 200 -GET /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200 -GET /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200 -POST /smart/test_repo.git/git-receive-pack HTTP/1.1 200 -GET /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200 -POST /smart/test_repo.git/git-receive-pack HTTP/1.1 200 -GET /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200 -POST /smart/test_repo.git/git-receive-pack HTTP/1.1 200 -EOF -test_expect_success 'used receive-pack service' ' - # NEEDSWORK: If the overspecification of the expected result is reduced, we - # might be able to run this test in all protocol versions. - if test "$GIT_TEST_PROTOCOL_VERSION" = 0 - then - check_access_log exp - fi -' - test_http_push_nonff "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git \ "$ROOT_PATH"/test_repo_clone main success diff --git a/t/t5543-atomic-push.sh b/t/t5543-atomic-push.sh index 70431122a4..04b47ad84a 100755 --- a/t/t5543-atomic-push.sh +++ b/t/t5543-atomic-push.sh @@ -117,7 +117,10 @@ test_expect_success 'atomic push fails if one branch fails' ' test_commit five && git checkout main && test_commit six && - test_must_fail git push --atomic --all up + test_must_fail git push --atomic --all up >output-all 2>&1 && + # --all and --branches have the same behavior when be combined with --atomic + test_must_fail git push --atomic --branches up >output-branches 2>&1 && + test_cmp output-all output-branches ) && test_refs main HEAD@{7} && test_refs second HEAD@{4} diff --git a/t/t5544-pack-objects-hook.sh b/t/t5544-pack-objects-hook.sh index 54f54f8d2e..1a9e14bbcc 100755 --- a/t/t5544-pack-objects-hook.sh +++ b/t/t5544-pack-objects-hook.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test custom script in place of pack-objects' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'create some history to fetch' ' diff --git a/t/t5546-receive-limits.sh b/t/t5546-receive-limits.sh index 0b0e987fdb..9fc9ba552f 100755 --- a/t/t5546-receive-limits.sh +++ b/t/t5546-receive-limits.sh @@ -1,16 +1,34 @@ #!/bin/sh test_description='check receive input limits' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Let's run tests with different unpack limits: 1 and 10000 # When the limit is 1, `git receive-pack` will call `git index-pack`. # When the limit is 10000, `git receive-pack` will call `git unpack-objects`. +validate_store_type () { + git -C dest count-objects -v >actual && + case "$store_type" in + index) + grep "^count: 0$" actual ;; + unpack) + grep "^packs: 0$" actual ;; + esac || { + echo "store_type is $store_type" + cat actual + false; + } +} + test_pack_input_limit () { - case "$1" in - index) unpack_limit=1 ;; - unpack) unpack_limit=10000 ;; + store_type=$1 + + case "$store_type" in + index) unpack_limit=1 other_limit=10000 ;; + unpack) unpack_limit=10000 other_limit=1 ;; esac test_expect_success 'prepare destination repository' ' @@ -41,6 +59,19 @@ test_pack_input_limit () { git --git-dir=dest config receive.maxInputSize 0 && git push dest HEAD ' + + test_expect_success 'prepare destination repository (once more)' ' + rm -fr dest && + git --bare init dest + ' + + test_expect_success 'receive trumps transfer' ' + git --git-dir=dest config receive.unpacklimit "$unpack_limit" && + git --git-dir=dest config transfer.unpacklimit "$other_limit" && + git push dest HEAD && + validate_store_type + ' + } test_expect_success "create known-size (1024 bytes) commit" ' diff --git a/t/t5547-push-quarantine.sh b/t/t5547-push-quarantine.sh index 1876fb34e5..9f899b8c7d 100755 --- a/t/t5547-push-quarantine.sh +++ b/t/t5547-push-quarantine.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='check quarantine of objects during push' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'create picky dest repo' ' diff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh index d7cf85ffea..8f182a3cbf 100755 --- a/t/t5550-http-fetch-dumb.sh +++ b/t/t5550-http-fetch-dumb.sh @@ -234,7 +234,7 @@ test_expect_success 'http-fetch --packfile' ' --index-pack-arg=--keep \ "$HTTPD_URL"/dumb/repo_pack.git/$p >out && - grep "^keep.[0-9a-f]\{16,\}$" out && + grep -E "^keep.[0-9a-f]{16,}$" out && cut -c6- out >packhash && # Ensure that the expected files are generated diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh index 6a38294a47..21b7767cbd 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/1.1} +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 && @@ -27,35 +33,71 @@ test_expect_success 'create http-accessible bare repository' ' setup_askpass_helper test_expect_success 'clone http repository' ' - cat >exp <<-\EOF && - > GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1 - > Accept: */* - > Accept-Encoding: ENCODINGS - > Accept-Language: ko-KR, *;q=0.9 - > Pragma: no-cache - < HTTP/1.1 200 OK - < Pragma: no-cache - < Cache-Control: no-cache, max-age=0, must-revalidate - < Content-Type: application/x-git-upload-pack-advertisement - > POST /smart/repo.git/git-upload-pack HTTP/1.1 - > Accept-Encoding: ENCODINGS - > Content-Type: application/x-git-upload-pack-request - > Accept: application/x-git-upload-pack-result - > Accept-Language: ko-KR, *;q=0.9 - > Content-Length: xxx - < HTTP/1.1 200 OK - < Pragma: no-cache - < Cache-Control: no-cache, max-age=0, must-revalidate - < Content-Type: application/x-git-upload-pack-result + if test_have_prereq HTTP2 && test "$HTTPD_PROTO" = "https" + then + # ALPN lets us immediately use HTTP/2; likewise, POSTs with + # bodies can use it because they do not need to upgrade + INITIAL_PROTO=HTTP/2 + else + # either we are not using HTTP/2, or the initial + # request is sent via HTTP/1.1 and asks for upgrade + INITIAL_PROTO=HTTP/1.1 + fi && + + cat >exp.raw <<-EOF && + > GET /smart/repo.git/info/refs?service=git-upload-pack $INITIAL_PROTO + > accept: */* + > accept-encoding: ENCODINGS + > accept-language: ko-KR, *;q=0.9 + > pragma: no-cache + {V2} > git-protocol: version=2 + < $HTTP_PROTO 200 OK + < pragma: no-cache + < cache-control: no-cache, max-age=0, must-revalidate + < content-type: application/x-git-upload-pack-advertisement + > POST /smart/repo.git/git-upload-pack $INITIAL_PROTO + > accept-encoding: ENCODINGS + > content-type: application/x-git-upload-pack-request + > accept: application/x-git-upload-pack-result + > accept-language: ko-KR, *;q=0.9 + {V2} > git-protocol: version=2 + > content-length: xxx + < $INITIAL_PROTO 200 OK + < pragma: no-cache + < cache-control: no-cache, max-age=0, must-revalidate + < content-type: application/x-git-upload-pack-result + {V2} > POST /smart/repo.git/git-upload-pack $INITIAL_PROTO + {V2} > accept-encoding: ENCODINGS + {V2} > content-type: application/x-git-upload-pack-request + {V2} > accept: application/x-git-upload-pack-result + {V2} > accept-language: ko-KR, *;q=0.9 + {V2} > git-protocol: version=2 + {V2} > content-length: xxx + {V2} < $INITIAL_PROTO 200 OK + {V2} < pragma: no-cache + {V2} < cache-control: no-cache, max-age=0, must-revalidate + {V2} < content-type: application/x-git-upload-pack-result EOF - GIT_TRACE_CURL=true GIT_TEST_PROTOCOL_VERSION=0 LANGUAGE="ko_KR.UTF-8" \ + if test "$GIT_TEST_PROTOCOL_VERSION" = 0 + then + sed "/^{V2}/d" <exp.raw >exp + else + sed "s/^{V2} //" <exp.raw >exp + fi && + + GIT_TRACE_CURL=true LANGUAGE="ko_KR.UTF-8" \ git clone --quiet $HTTPD_URL/smart/repo.git clone 2>err && test_cmp file clone/file && tr '\''\015'\'' Q <err | + perl -pe '\'' + s/(Send|Recv) header: ([A-Za-z0-9-]+):/ + "$1 header: " . lc($2) . ":" + /e; + '\'' | sed -e " s/Q\$// - /^[*] /d + /^[^<=]/d /^== Info:/d /^=> Send header, /d /^=> Send header:$/d @@ -65,6 +107,8 @@ test_expect_success 'clone http repository' ' s/= Recv header:// /^<= Recv data/d /^=> Send data/d + /^<= Recv SSL data/d + /^=> Send SSL data/d /^$/d /^< $/d @@ -72,36 +116,35 @@ test_expect_success 'clone http repository' ' s/^/> / } - /^> User-Agent: /d - /^> Host: /d + /^< HTTP/ { + s/200$/200 OK/ + } + /^< HTTP\\/1.1 101/d + /^[><] connection: /d + /^[><] upgrade: /d + /^> http2-settings: /d + + /^> user-agent: /d + /^> host: /d /^> POST /,$ { /^> Accept: [*]\\/[*]/d } - s/^> Content-Length: .*/> Content-Length: xxx/ + s/^> content-length: .*/> content-length: xxx/ /^> 00..want /d /^> 00.*done/d - /^< Server: /d - /^< Expires: /d - /^< Date: /d - /^< Content-Length: /d - /^< Transfer-Encoding: /d + /^< server: /d + /^< expires: /d + /^< date: /d + /^< content-length: /d + /^< transfer-encoding: /d " >actual && - # NEEDSWORK: If the overspecification of the expected result is reduced, we - # might be able to run this test in all protocol versions. - if test "$GIT_TEST_PROTOCOL_VERSION" = 0 - then - sed -e "s/^> Accept-Encoding: .*/> Accept-Encoding: ENCODINGS/" \ - actual >actual.smudged && - test_cmp exp actual.smudged && - - grep "Accept-Encoding:.*gzip" actual >actual.gzip && - test_line_count = 2 actual.gzip && + sed -e "s/^> accept-encoding: .*/> accept-encoding: ENCODINGS/" \ + actual >actual.smudged && + test_cmp exp actual.smudged && - grep "Accept-Language: ko-KR, *" actual >actual.language && - test_line_count = 2 actual.language - fi + grep "accept-encoding:.*gzip" actual >actual.gzip ' test_expect_success 'fetch changes via http' ' @@ -113,19 +156,9 @@ test_expect_success 'fetch changes via http' ' ' test_expect_success 'used upload-pack service' ' - cat >exp <<-\EOF && - GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1 200 - POST /smart/repo.git/git-upload-pack HTTP/1.1 200 - GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1 200 - POST /smart/repo.git/git-upload-pack HTTP/1.1 200 - EOF - - # NEEDSWORK: If the overspecification of the expected result is reduced, we - # might be able to run this test in all protocol versions. - if test "$GIT_TEST_PROTOCOL_VERSION" = 0 - then - check_access_log exp - fi + strip_access_log >log && + grep "GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/[0-9.]* 200" log && + grep "POST /smart/repo.git/git-upload-pack HTTP/[0-9.]* 200" log ' test_expect_success 'follow redirects (301)' ' @@ -274,21 +307,23 @@ test_expect_success 'cookies stored in http.cookiefile when http.savecookies set 127.0.0.1 FALSE /smart_cookies/ FALSE 0 othername othervalue EOF sort >expect_cookies.txt <<-\EOF && - 127.0.0.1 FALSE /smart_cookies/ FALSE 0 othername othervalue + 127.0.0.1 FALSE /smart_cookies/repo.git/ FALSE 0 name value 127.0.0.1 FALSE /smart_cookies/repo.git/info/ FALSE 0 name value EOF git config http.cookiefile cookies.txt && git config http.savecookies true && - git ls-remote $HTTPD_URL/smart_cookies/repo.git main && - # NEEDSWORK: If the overspecification of the expected result is reduced, we - # might be able to run this test in all protocol versions. - if test "$GIT_TEST_PROTOCOL_VERSION" = 0 - then - tail -3 cookies.txt | sort >cookies_tail.txt && - test_cmp expect_cookies.txt cookies_tail.txt - fi + test_when_finished " + git --git-dir=\"\$HTTPD_DOCUMENT_ROOT_PATH/repo.git\" \ + tag -d cookie-tag + " && + git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \ + tag -m "foo" cookie-tag && + git fetch $HTTPD_URL/smart_cookies/repo.git cookie-tag && + + grep "^[^#]" cookies.txt | sort >cookies_stripped.txt && + test_cmp expect_cookies.txt cookies_stripped.txt ' test_expect_success 'transfer.hiderefs works over smart-http' ' @@ -347,7 +382,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' ' @@ -573,6 +611,33 @@ test_expect_success 'client falls back from v2 to v0 to match server' ' grep symref=HEAD:refs/heads/ trace ' +test_expect_success 'create empty http-accessible SHA-256 repository' ' + mkdir "$HTTPD_DOCUMENT_ROOT_PATH/sha256.git" && + (cd "$HTTPD_DOCUMENT_ROOT_PATH/sha256.git" && + git --bare init --object-format=sha256 + ) +' + +test_expect_success 'clone empty SHA-256 repository with protocol v2' ' + rm -fr sha256 && + echo sha256 >expected && + git -c protocol.version=2 clone "$HTTPD_URL/smart/sha256.git" && + git -C sha256 rev-parse --show-object-format >actual && + test_cmp actual expected && + git ls-remote "$HTTPD_URL/smart/sha256.git" >actual && + test_must_be_empty actual +' + +test_expect_success 'clone empty SHA-256 repository with protocol v0' ' + rm -fr sha256 && + echo sha256 >expected && + GIT_TRACE=1 GIT_TRACE_PACKET=1 git -c protocol.version=0 clone "$HTTPD_URL/smart/sha256.git" && + git -C sha256 rev-parse --show-object-format >actual && + test_cmp actual expected && + git ls-remote "$HTTPD_URL/smart/sha256.git" >actual && + test_must_be_empty actual +' + test_expect_success 'passing hostname resolution information works' ' BOGUS_HOST=gitbogusexamplehost.invalid && BOGUS_HTTPD_URL=$HTTPD_PROTO://$BOGUS_HOST:$LIB_HTTPD_PORT && @@ -580,4 +645,90 @@ test_expect_success 'passing hostname resolution information works' ' git -c "http.curloptResolve=$BOGUS_HOST:$LIB_HTTPD_PORT:127.0.0.1" ls-remote "$BOGUS_HTTPD_URL/smart/repo.git" >/dev/null ' +# here user%40host is the URL-encoded version of user@host, +# which is our intentionally-odd username to catch parsing errors +url_user=$HTTPD_URL_USER/auth/smart/repo.git +url_userpass=$HTTPD_URL_USER_PASS/auth/smart/repo.git +url_userblank=$HTTPD_PROTO://user%40host:@$HTTPD_DEST/auth/smart/repo.git +message="URL .*:<redacted>@.* uses plaintext credentials" + +test_expect_success 'clone warns or fails when using username:password' ' + test_when_finished "rm -rf attempt*" && + + git -c transfer.credentialsInUrl=allow \ + clone $url_userpass attempt1 2>err && + ! grep "$message" err && + + git -c transfer.credentialsInUrl=warn \ + clone $url_userpass attempt2 2>err && + grep "warning: $message" err >warnings && + test_line_count -ge 1 warnings && + + test_must_fail git -c transfer.credentialsInUrl=die \ + clone $url_userpass attempt3 2>err && + grep "fatal: $message" err >warnings && + test_line_count -ge 1 warnings && + + test_must_fail git -c transfer.credentialsInUrl=die \ + clone $url_userblank attempt4 2>err && + grep "fatal: $message" err >warnings && + test_line_count -ge 1 warnings +' + +test_expect_success 'clone does not detect username:password when it is https://username@domain:port/' ' + test_when_finished "rm -rf attempt1" && + + # we are relying on lib-httpd for url construction, so document our + # assumptions + case "$HTTPD_URL_USER" in + *:[0-9]*) : ok ;; + *) BUG "httpd url does not have port: $HTTPD_URL_USER" + esac && + + git -c transfer.credentialsInUrl=warn clone $url_user attempt1 2>err && + ! grep "uses plaintext credentials" err +' + +test_expect_success 'fetch warns or fails when using username:password' ' + git -c transfer.credentialsInUrl=allow fetch $url_userpass 2>err && + ! grep "$message" err && + + git -c transfer.credentialsInUrl=warn fetch $url_userpass 2>err && + grep "warning: $message" err >warnings && + test_line_count -ge 1 warnings && + + test_must_fail git -c transfer.credentialsInUrl=die \ + fetch $url_userpass 2>err && + grep "fatal: $message" err >warnings && + test_line_count -ge 1 warnings && + + test_must_fail git -c transfer.credentialsInUrl=die \ + fetch $url_userblank 2>err && + grep "fatal: $message" err >warnings && + test_line_count -ge 1 warnings +' + + +test_expect_success 'push warns or fails when using username:password' ' + git -c transfer.credentialsInUrl=allow push $url_userpass 2>err && + ! grep "$message" err && + + git -c transfer.credentialsInUrl=warn push $url_userpass 2>err && + grep "warning: $message" err >warnings && + + test_must_fail git -c transfer.credentialsInUrl=die \ + push $url_userpass 2>err && + grep "fatal: $message" err >warnings && + test_line_count -ge 1 warnings +' + +test_expect_success 'no empty path components' ' + # In the URL, add a trailing slash, and see if git appends yet another + # slash. + git clone $HTTPD_URL/smart/repo.git/ clone-with-slash && + + strip_access_log >log && + ! grep "//" log +' + test_done diff --git a/t/t5552-skipping-fetch-negotiator.sh b/t/t5552-skipping-fetch-negotiator.sh index 165427d57e..b55a9f65e6 100755 --- a/t/t5552-skipping-fetch-negotiator.sh +++ b/t/t5552-skipping-fetch-negotiator.sh @@ -3,6 +3,22 @@ test_description='test skipping fetch negotiator' . ./test-lib.sh +test_expect_success 'fetch.negotiationalgorithm config' ' + test_when_finished "rm -rf repo" && + git init repo && + cat >repo/.git/config <<-\EOF && + [fetch] + negotiationAlgorithm + EOF + cat >expect <<-\EOF && + error: missing value for '\''fetch.negotiationalgorithm'\'' + fatal: bad config variable '\''fetch.negotiationalgorithm'\'' in file '\''.git/config'\'' at line 2 + EOF + test_expect_code 128 git -C repo fetch >out 2>actual && + test_must_be_empty out && + test_cmp expect actual +' + have_sent () { while test "$#" -ne 0 do diff --git a/t/t5554-noop-fetch-negotiator.sh b/t/t5554-noop-fetch-negotiator.sh index 2ac7b5859e..06991e8e8a 100755 --- a/t/t5554-noop-fetch-negotiator.sh +++ b/t/t5554-noop-fetch-negotiator.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test noop fetch negotiator' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'noop negotiator does not emit any "have"' ' diff --git a/t/t5558-clone-bundle-uri.sh b/t/t5558-clone-bundle-uri.sh index ad666a2d28..996a08e90c 100755 --- a/t/t5558-clone-bundle-uri.sh +++ b/t/t5558-clone-bundle-uri.sh @@ -41,6 +41,215 @@ test_expect_success 'clone with file:// bundle' ' test_cmp expect actual ' +# To get interesting tests for bundle lists, we need to construct a +# somewhat-interesting commit history. +# +# ---------------- bundle-4 +# +# 4 +# / \ +# ----|---|------- bundle-3 +# | | +# | 3 +# | | +# ----|---|------- bundle-2 +# | | +# 2 | +# | | +# ----|---|------- bundle-1 +# \ / +# 1 +# | +# (previous commits) +test_expect_success 'construct incremental bundle list' ' + ( + cd clone-from && + git checkout -b base && + test_commit 1 && + git checkout -b left && + test_commit 2 && + git checkout -b right base && + test_commit 3 && + git checkout -b merge left && + git merge right -m "4" && + + git bundle create bundle-1.bundle base && + git bundle create bundle-2.bundle base..left && + git bundle create bundle-3.bundle base..right && + git bundle create bundle-4.bundle merge --not left right + ) +' + +test_expect_success 'clone bundle list (file, no heuristic)' ' + cat >bundle-list <<-EOF && + [bundle] + version = 1 + mode = all + + [bundle "bundle-1"] + uri = file://$(pwd)/clone-from/bundle-1.bundle + + [bundle "bundle-2"] + uri = file://$(pwd)/clone-from/bundle-2.bundle + + [bundle "bundle-3"] + uri = file://$(pwd)/clone-from/bundle-3.bundle + + [bundle "bundle-4"] + uri = file://$(pwd)/clone-from/bundle-4.bundle + EOF + + git clone --bundle-uri="file://$(pwd)/bundle-list" \ + clone-from clone-list-file 2>err && + ! grep "Repository lacks these prerequisite commits" err && + + git -C clone-from for-each-ref --format="%(objectname)" >oids && + git -C clone-list-file cat-file --batch-check <oids && + + git -C clone-list-file for-each-ref --format="%(refname)" >refs && + grep "refs/bundles/" refs >actual && + cat >expect <<-\EOF && + refs/bundles/base + refs/bundles/left + refs/bundles/merge + refs/bundles/right + EOF + test_cmp expect actual +' + +test_expect_success 'clone bundle list (file, all mode, some failures)' ' + cat >bundle-list <<-EOF && + [bundle] + version = 1 + mode = all + + # Does not exist. Should be skipped. + [bundle "bundle-0"] + uri = file://$(pwd)/clone-from/bundle-0.bundle + + [bundle "bundle-1"] + uri = file://$(pwd)/clone-from/bundle-1.bundle + + [bundle "bundle-2"] + uri = file://$(pwd)/clone-from/bundle-2.bundle + + # No bundle-3 means bundle-4 will not apply. + + [bundle "bundle-4"] + uri = file://$(pwd)/clone-from/bundle-4.bundle + + # Does not exist. Should be skipped. + [bundle "bundle-5"] + uri = file://$(pwd)/clone-from/bundle-5.bundle + EOF + + GIT_TRACE2_PERF=1 \ + git clone --bundle-uri="file://$(pwd)/bundle-list" \ + clone-from clone-all-some 2>err && + ! grep "Repository lacks these prerequisite commits" err && + ! grep "fatal" err && + grep "warning: failed to download bundle from URI" err && + + git -C clone-from for-each-ref --format="%(objectname)" >oids && + git -C clone-all-some cat-file --batch-check <oids && + + git -C clone-all-some for-each-ref --format="%(refname)" >refs && + grep "refs/bundles/" refs >actual && + cat >expect <<-\EOF && + refs/bundles/base + refs/bundles/left + EOF + test_cmp expect actual +' + +test_expect_success 'clone bundle list (file, all mode, all failures)' ' + cat >bundle-list <<-EOF && + [bundle] + version = 1 + mode = all + + # Does not exist. Should be skipped. + [bundle "bundle-0"] + uri = file://$(pwd)/clone-from/bundle-0.bundle + + # Does not exist. Should be skipped. + [bundle "bundle-5"] + uri = file://$(pwd)/clone-from/bundle-5.bundle + EOF + + git clone --bundle-uri="file://$(pwd)/bundle-list" \ + clone-from clone-all-fail 2>err && + ! grep "Repository lacks these prerequisite commits" err && + ! grep "fatal" err && + grep "warning: failed to download bundle from URI" err && + + git -C clone-from for-each-ref --format="%(objectname)" >oids && + git -C clone-all-fail cat-file --batch-check <oids && + + git -C clone-all-fail for-each-ref --format="%(refname)" >refs && + ! grep "refs/bundles/" refs +' + +test_expect_success 'clone bundle list (file, any mode)' ' + cat >bundle-list <<-EOF && + [bundle] + version = 1 + mode = any + + # Does not exist. Should be skipped. + [bundle "bundle-0"] + uri = file://$(pwd)/clone-from/bundle-0.bundle + + [bundle "bundle-1"] + uri = file://$(pwd)/clone-from/bundle-1.bundle + + # Does not exist. Should be skipped. + [bundle "bundle-5"] + uri = file://$(pwd)/clone-from/bundle-5.bundle + EOF + + git clone --bundle-uri="file://$(pwd)/bundle-list" \ + clone-from clone-any-file 2>err && + ! grep "Repository lacks these prerequisite commits" err && + + git -C clone-from for-each-ref --format="%(objectname)" >oids && + git -C clone-any-file cat-file --batch-check <oids && + + git -C clone-any-file for-each-ref --format="%(refname)" >refs && + grep "refs/bundles/" refs >actual && + cat >expect <<-\EOF && + refs/bundles/base + EOF + test_cmp expect actual +' + +test_expect_success 'clone bundle list (file, any mode, all failures)' ' + cat >bundle-list <<-EOF && + [bundle] + version = 1 + mode = any + + # Does not exist. Should be skipped. + [bundle "bundle-0"] + uri = $HTTPD_URL/bundle-0.bundle + + # Does not exist. Should be skipped. + [bundle "bundle-5"] + uri = $HTTPD_URL/bundle-5.bundle + EOF + + git clone --bundle-uri="file://$(pwd)/bundle-list" \ + clone-from clone-any-fail 2>err && + ! grep "fatal" err && + grep "warning: failed to download bundle from URI" err && + + git -C clone-from for-each-ref --format="%(objectname)" >oids && + git -C clone-any-fail cat-file --batch-check <oids && + + git -C clone-any-fail for-each-ref --format="%(refname)" >refs && + ! grep "refs/bundles/" refs +' + ######################################################################### # HTTP tests begin here @@ -75,6 +284,774 @@ test_expect_success 'clone HTTP bundle' ' test_config -C clone-http log.excludedecoration refs/bundle/ ' +test_expect_success 'clone bundle list (HTTP, no heuristic)' ' + test_when_finished rm -f trace*.txt && + + cp clone-from/bundle-*.bundle "$HTTPD_DOCUMENT_ROOT_PATH/" && + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = all + + [bundle "bundle-1"] + uri = $HTTPD_URL/bundle-1.bundle + + [bundle "bundle-2"] + uri = $HTTPD_URL/bundle-2.bundle + + [bundle "bundle-3"] + uri = $HTTPD_URL/bundle-3.bundle + + [bundle "bundle-4"] + uri = $HTTPD_URL/bundle-4.bundle + EOF + + GIT_TRACE2_EVENT="$(pwd)/trace-clone.txt" \ + git clone --bundle-uri="$HTTPD_URL/bundle-list" \ + clone-from clone-list-http 2>err && + ! grep "Repository lacks these prerequisite commits" err && + + git -C clone-from for-each-ref --format="%(objectname)" >oids && + git -C clone-list-http cat-file --batch-check <oids && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-1.bundle + $HTTPD_URL/bundle-2.bundle + $HTTPD_URL/bundle-3.bundle + $HTTPD_URL/bundle-4.bundle + $HTTPD_URL/bundle-list + EOF + + # Sort the list, since the order is not well-defined + # without a heuristic. + test_remote_https_urls <trace-clone.txt | sort >actual && + test_cmp expect actual +' + +test_expect_success 'clone bundle list (HTTP, any mode)' ' + cp clone-from/bundle-*.bundle "$HTTPD_DOCUMENT_ROOT_PATH/" && + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = any + + # Does not exist. Should be skipped. + [bundle "bundle-0"] + uri = $HTTPD_URL/bundle-0.bundle + + [bundle "bundle-1"] + uri = $HTTPD_URL/bundle-1.bundle + + # Does not exist. Should be skipped. + [bundle "bundle-5"] + uri = $HTTPD_URL/bundle-5.bundle + EOF + + git clone --bundle-uri="$HTTPD_URL/bundle-list" \ + clone-from clone-any-http 2>err && + ! grep "fatal" err && + grep "warning: failed to download bundle from URI" err && + + git -C clone-from for-each-ref --format="%(objectname)" >oids && + git -C clone-any-http cat-file --batch-check <oids && + + git -C clone-list-file for-each-ref --format="%(refname)" >refs && + grep "refs/bundles/" refs >actual && + cat >expect <<-\EOF && + refs/bundles/base + refs/bundles/left + refs/bundles/merge + refs/bundles/right + EOF + test_cmp expect actual +' + +test_expect_success 'clone bundle list (http, creationToken)' ' + test_when_finished rm -f trace*.txt && + + cp clone-from/bundle-*.bundle "$HTTPD_DOCUMENT_ROOT_PATH/" && + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = bundle-1.bundle + creationToken = 1 + + [bundle "bundle-2"] + uri = bundle-2.bundle + creationToken = 2 + + [bundle "bundle-3"] + uri = bundle-3.bundle + creationToken = 3 + + [bundle "bundle-4"] + uri = bundle-4.bundle + creationToken = 4 + EOF + + GIT_TRACE2_EVENT="$(pwd)/trace-clone.txt" git \ + clone --bundle-uri="$HTTPD_URL/bundle-list" \ + "$HTTPD_URL/smart/fetch.git" clone-list-http-2 && + + git -C clone-from for-each-ref --format="%(objectname)" >oids && + git -C clone-list-http-2 cat-file --batch-check <oids && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/bundle-4.bundle + $HTTPD_URL/bundle-3.bundle + $HTTPD_URL/bundle-2.bundle + $HTTPD_URL/bundle-1.bundle + EOF + + test_remote_https_urls <trace-clone.txt >actual && + test_cmp expect actual +' + +test_expect_success 'clone incomplete bundle list (http, creationToken)' ' + test_when_finished rm -f trace*.txt && + + cp clone-from/bundle-*.bundle "$HTTPD_DOCUMENT_ROOT_PATH/" && + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = bundle-1.bundle + creationToken = 1 + EOF + + GIT_TRACE2_EVENT=$(pwd)/trace-clone.txt \ + git clone --bundle-uri="$HTTPD_URL/bundle-list" \ + --single-branch --branch=base --no-tags \ + "$HTTPD_URL/smart/fetch.git" clone-token-http && + + test_cmp_config -C clone-token-http "$HTTPD_URL/bundle-list" fetch.bundleuri && + test_cmp_config -C clone-token-http 1 fetch.bundlecreationtoken && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/bundle-1.bundle + EOF + + test_remote_https_urls <trace-clone.txt >actual && + test_cmp expect actual && + + # We now have only one bundle ref. + git -C clone-token-http for-each-ref --format="%(refname)" "refs/bundles/*" >refs && + cat >expect <<-\EOF && + refs/bundles/base + EOF + test_cmp expect refs && + + # Add remaining bundles, exercising the "deepening" strategy + # for downloading via the creationToken heurisitc. + cat >>"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle "bundle-2"] + uri = bundle-2.bundle + creationToken = 2 + + [bundle "bundle-3"] + uri = bundle-3.bundle + creationToken = 3 + + [bundle "bundle-4"] + uri = bundle-4.bundle + creationToken = 4 + EOF + + GIT_TRACE2_EVENT="$(pwd)/trace1.txt" \ + git -C clone-token-http fetch origin --no-tags \ + refs/heads/merge:refs/heads/merge && + test_cmp_config -C clone-token-http 4 fetch.bundlecreationtoken && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/bundle-4.bundle + $HTTPD_URL/bundle-3.bundle + $HTTPD_URL/bundle-2.bundle + EOF + + test_remote_https_urls <trace1.txt >actual && + test_cmp expect actual && + + # We now have all bundle refs. + git -C clone-token-http for-each-ref --format="%(refname)" "refs/bundles/*" >refs && + + cat >expect <<-\EOF && + refs/bundles/base + refs/bundles/left + refs/bundles/merge + refs/bundles/right + EOF + test_cmp expect refs +' + +test_expect_success 'http clone with bundle.heuristic creates fetch.bundleURI' ' + test_when_finished rm -rf fetch-http-4 trace*.txt && + + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = bundle-1.bundle + creationToken = 1 + EOF + + GIT_TRACE2_EVENT="$(pwd)/trace-clone.txt" \ + git clone --single-branch --branch=base \ + --bundle-uri="$HTTPD_URL/bundle-list" \ + "$HTTPD_URL/smart/fetch.git" fetch-http-4 && + + test_cmp_config -C fetch-http-4 "$HTTPD_URL/bundle-list" fetch.bundleuri && + test_cmp_config -C fetch-http-4 1 fetch.bundlecreationtoken && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/bundle-1.bundle + EOF + + test_remote_https_urls <trace-clone.txt >actual && + test_cmp expect actual && + + # only received base ref from bundle-1 + git -C fetch-http-4 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && + cat >expect <<-\EOF && + refs/bundles/base + EOF + test_cmp expect refs && + + cat >>"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle "bundle-2"] + uri = bundle-2.bundle + creationToken = 2 + EOF + + # Fetch the objects for bundle-2 _and_ bundle-3. + GIT_TRACE2_EVENT="$(pwd)/trace1.txt" \ + git -C fetch-http-4 fetch origin --no-tags \ + refs/heads/left:refs/heads/left \ + refs/heads/right:refs/heads/right && + test_cmp_config -C fetch-http-4 2 fetch.bundlecreationtoken && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/bundle-2.bundle + EOF + + test_remote_https_urls <trace1.txt >actual && + test_cmp expect actual && + + # received left from bundle-2 + git -C fetch-http-4 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && + cat >expect <<-\EOF && + refs/bundles/base + refs/bundles/left + EOF + test_cmp expect refs && + + # No-op fetch + GIT_TRACE2_EVENT="$(pwd)/trace1b.txt" \ + git -C fetch-http-4 fetch origin --no-tags \ + refs/heads/left:refs/heads/left \ + refs/heads/right:refs/heads/right && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + EOF + test_remote_https_urls <trace1b.txt >actual && + test_cmp expect actual && + + cat >>"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle "bundle-3"] + uri = bundle-3.bundle + creationToken = 3 + + [bundle "bundle-4"] + uri = bundle-4.bundle + creationToken = 4 + EOF + + # This fetch should skip bundle-3.bundle, since its objects are + # already local (we have the requisite commits for bundle-4.bundle). + GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ + git -C fetch-http-4 fetch origin --no-tags \ + refs/heads/merge:refs/heads/merge && + test_cmp_config -C fetch-http-4 4 fetch.bundlecreationtoken && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/bundle-4.bundle + EOF + + test_remote_https_urls <trace2.txt >actual && + test_cmp expect actual && + + # received merge ref from bundle-4, but right is missing + # because we did not download bundle-3. + git -C fetch-http-4 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && + + cat >expect <<-\EOF && + refs/bundles/base + refs/bundles/left + refs/bundles/merge + EOF + test_cmp expect refs && + + # No-op fetch + GIT_TRACE2_EVENT="$(pwd)/trace2b.txt" \ + git -C fetch-http-4 fetch origin && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + EOF + test_remote_https_urls <trace2b.txt >actual && + test_cmp expect actual +' + +test_expect_success 'creationToken heuristic with failed downloads (clone)' ' + test_when_finished rm -rf download-* trace*.txt && + + # Case 1: base bundle does not exist, nothing can unbundle + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = fake.bundle + creationToken = 1 + + [bundle "bundle-2"] + uri = bundle-2.bundle + creationToken = 2 + + [bundle "bundle-3"] + uri = bundle-3.bundle + creationToken = 3 + + [bundle "bundle-4"] + uri = bundle-4.bundle + creationToken = 4 + EOF + + GIT_TRACE2_EVENT="$(pwd)/trace-clone-1.txt" \ + git clone --single-branch --branch=base \ + --bundle-uri="$HTTPD_URL/bundle-list" \ + "$HTTPD_URL/smart/fetch.git" download-1 && + + # Bundle failure does not set these configs. + test_must_fail git -C download-1 config fetch.bundleuri && + test_must_fail git -C download-1 config fetch.bundlecreationtoken && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/bundle-4.bundle + $HTTPD_URL/bundle-3.bundle + $HTTPD_URL/bundle-2.bundle + $HTTPD_URL/fake.bundle + EOF + test_remote_https_urls <trace-clone-1.txt >actual && + test_cmp expect actual && + + # All bundles failed to unbundle + git -C download-1 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && + test_must_be_empty refs && + + # Case 2: middle bundle does not exist, only two bundles can unbundle + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = bundle-1.bundle + creationToken = 1 + + [bundle "bundle-2"] + uri = fake.bundle + creationToken = 2 + + [bundle "bundle-3"] + uri = bundle-3.bundle + creationToken = 3 + + [bundle "bundle-4"] + uri = bundle-4.bundle + creationToken = 4 + EOF + + GIT_TRACE2_EVENT="$(pwd)/trace-clone-2.txt" \ + git clone --single-branch --branch=base \ + --bundle-uri="$HTTPD_URL/bundle-list" \ + "$HTTPD_URL/smart/fetch.git" download-2 && + + # Bundle failure does not set these configs. + test_must_fail git -C download-2 config fetch.bundleuri && + test_must_fail git -C download-2 config fetch.bundlecreationtoken && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/bundle-4.bundle + $HTTPD_URL/bundle-3.bundle + $HTTPD_URL/fake.bundle + $HTTPD_URL/bundle-1.bundle + EOF + test_remote_https_urls <trace-clone-2.txt >actual && + test_cmp expect actual && + + # bundle-1 and bundle-3 could unbundle, but bundle-4 could not + git -C download-2 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && + cat >expect <<-EOF && + refs/bundles/base + refs/bundles/right + EOF + test_cmp expect refs && + + # Case 3: top bundle does not exist, rest unbundle fine. + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = bundle-1.bundle + creationToken = 1 + + [bundle "bundle-2"] + uri = bundle-2.bundle + creationToken = 2 + + [bundle "bundle-3"] + uri = bundle-3.bundle + creationToken = 3 + + [bundle "bundle-4"] + uri = fake.bundle + creationToken = 4 + EOF + + GIT_TRACE2_EVENT="$(pwd)/trace-clone-3.txt" \ + git clone --single-branch --branch=base \ + --bundle-uri="$HTTPD_URL/bundle-list" \ + "$HTTPD_URL/smart/fetch.git" download-3 && + + # As long as we have continguous successful downloads, + # we _do_ set these configs. + test_cmp_config -C download-3 "$HTTPD_URL/bundle-list" fetch.bundleuri && + test_cmp_config -C download-3 3 fetch.bundlecreationtoken && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/fake.bundle + $HTTPD_URL/bundle-3.bundle + $HTTPD_URL/bundle-2.bundle + $HTTPD_URL/bundle-1.bundle + EOF + test_remote_https_urls <trace-clone-3.txt >actual && + test_cmp expect actual && + + # fake.bundle did not unbundle, but the others did. + git -C download-3 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && + cat >expect <<-EOF && + refs/bundles/base + refs/bundles/left + refs/bundles/right + EOF + test_cmp expect refs +' + +# Expand the bundle list to include other interesting shapes, specifically +# interesting for use when fetching from a previous state. +# +# ---------------- bundle-7 +# 7 +# _/|\_ +# ---/--|--\------ bundle-6 +# 5 | 6 +# --|---|---|----- bundle-4 +# | 4 | +# | / \ / +# --|-|---|/------ bundle-3 (the client will be caught up to this point.) +# \ | 3 +# ---\|---|------- bundle-2 +# 2 | +# ----|---|------- bundle-1 +# \ / +# 1 +# | +# (previous commits) +test_expect_success 'expand incremental bundle list' ' + ( + cd clone-from && + git checkout -b lefter left && + test_commit 5 && + git checkout -b righter right && + test_commit 6 && + git checkout -b top lefter && + git merge -m "7" merge righter && + + git bundle create bundle-6.bundle lefter righter --not left right && + git bundle create bundle-7.bundle top --not lefter merge righter && + + cp bundle-*.bundle "$HTTPD_DOCUMENT_ROOT_PATH/" + ) && + git -C "$HTTPD_DOCUMENT_ROOT_PATH/fetch.git" fetch origin +refs/heads/*:refs/heads/* +' + +test_expect_success 'creationToken heuristic with failed downloads (fetch)' ' + test_when_finished rm -rf download-* trace*.txt && + + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = bundle-1.bundle + creationToken = 1 + + [bundle "bundle-2"] + uri = bundle-2.bundle + creationToken = 2 + + [bundle "bundle-3"] + uri = bundle-3.bundle + creationToken = 3 + EOF + + git clone --single-branch --branch=left \ + --bundle-uri="$HTTPD_URL/bundle-list" \ + "$HTTPD_URL/smart/fetch.git" fetch-base && + test_cmp_config -C fetch-base "$HTTPD_URL/bundle-list" fetch.bundleURI && + test_cmp_config -C fetch-base 3 fetch.bundleCreationToken && + + # Case 1: all bundles exist: successful unbundling of all bundles + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = bundle-1.bundle + creationToken = 1 + + [bundle "bundle-2"] + uri = bundle-2.bundle + creationToken = 2 + + [bundle "bundle-3"] + uri = bundle-3.bundle + creationToken = 3 + + [bundle "bundle-4"] + uri = bundle-4.bundle + creationToken = 4 + + [bundle "bundle-6"] + uri = bundle-6.bundle + creationToken = 6 + + [bundle "bundle-7"] + uri = bundle-7.bundle + creationToken = 7 + EOF + + cp -r fetch-base fetch-1 && + GIT_TRACE2_EVENT="$(pwd)/trace-fetch-1.txt" \ + git -C fetch-1 fetch origin && + test_cmp_config -C fetch-1 7 fetch.bundlecreationtoken && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/bundle-7.bundle + $HTTPD_URL/bundle-6.bundle + $HTTPD_URL/bundle-4.bundle + EOF + test_remote_https_urls <trace-fetch-1.txt >actual && + test_cmp expect actual && + + # Check which bundles have unbundled by refs + git -C fetch-1 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && + cat >expect <<-EOF && + refs/bundles/base + refs/bundles/left + refs/bundles/lefter + refs/bundles/merge + refs/bundles/right + refs/bundles/righter + refs/bundles/top + EOF + test_cmp expect refs && + + # Case 2: middle bundle does not exist, only bundle-4 can unbundle + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = bundle-1.bundle + creationToken = 1 + + [bundle "bundle-2"] + uri = bundle-2.bundle + creationToken = 2 + + [bundle "bundle-3"] + uri = bundle-3.bundle + creationToken = 3 + + [bundle "bundle-4"] + uri = bundle-4.bundle + creationToken = 4 + + [bundle "bundle-6"] + uri = fake.bundle + creationToken = 6 + + [bundle "bundle-7"] + uri = bundle-7.bundle + creationToken = 7 + EOF + + cp -r fetch-base fetch-2 && + GIT_TRACE2_EVENT="$(pwd)/trace-fetch-2.txt" \ + git -C fetch-2 fetch origin && + + # Since bundle-7 fails to unbundle, do not update creation token. + test_cmp_config -C fetch-2 3 fetch.bundlecreationtoken && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/bundle-7.bundle + $HTTPD_URL/fake.bundle + $HTTPD_URL/bundle-4.bundle + EOF + test_remote_https_urls <trace-fetch-2.txt >actual && + test_cmp expect actual && + + # Check which bundles have unbundled by refs + git -C fetch-2 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && + cat >expect <<-EOF && + refs/bundles/base + refs/bundles/left + refs/bundles/merge + refs/bundles/right + EOF + test_cmp expect refs && + + # Case 3: top bundle does not exist, rest unbundle fine. + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = bundle-1.bundle + creationToken = 1 + + [bundle "bundle-2"] + uri = bundle-2.bundle + creationToken = 2 + + [bundle "bundle-3"] + uri = bundle-3.bundle + creationToken = 3 + + [bundle "bundle-4"] + uri = bundle-4.bundle + creationToken = 4 + + [bundle "bundle-6"] + uri = bundle-6.bundle + creationToken = 6 + + [bundle "bundle-7"] + uri = fake.bundle + creationToken = 7 + EOF + + cp -r fetch-base fetch-3 && + GIT_TRACE2_EVENT="$(pwd)/trace-fetch-3.txt" \ + git -C fetch-3 fetch origin && + + # As long as we have continguous successful downloads, + # we _do_ set the maximum creation token. + test_cmp_config -C fetch-3 6 fetch.bundlecreationtoken && + + # NOTE: the fetch skips bundle-4 since bundle-6 successfully + # unbundles itself and bundle-7 failed to download. + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/fake.bundle + $HTTPD_URL/bundle-6.bundle + EOF + test_remote_https_urls <trace-fetch-3.txt >actual && + test_cmp expect actual && + + # Check which bundles have unbundled by refs + git -C fetch-3 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && + cat >expect <<-EOF && + refs/bundles/base + refs/bundles/left + refs/bundles/lefter + refs/bundles/right + refs/bundles/righter + EOF + test_cmp expect refs +' + +test_expect_success 'bundles are downloaded once during fetch --all' ' + test_when_finished rm -rf download-* trace*.txt fetch-mult && + + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = bundle-1.bundle + creationToken = 1 + + [bundle "bundle-2"] + uri = bundle-2.bundle + creationToken = 2 + + [bundle "bundle-3"] + uri = bundle-3.bundle + creationToken = 3 + EOF + + git clone --single-branch --branch=left \ + --bundle-uri="$HTTPD_URL/bundle-list" \ + "$HTTPD_URL/smart/fetch.git" fetch-mult && + git -C fetch-mult remote add dup1 "$HTTPD_URL/smart/fetch.git" && + git -C fetch-mult remote add dup2 "$HTTPD_URL/smart/fetch.git" && + + GIT_TRACE2_EVENT="$(pwd)/trace-mult.txt" \ + git -C fetch-mult fetch --all && + grep "\"child_start\".*\"git-remote-https\",\"$HTTPD_URL/bundle-list\"" \ + trace-mult.txt >bundle-fetches && + test_line_count = 1 bundle-fetches +' # Do not add tests here unless they use the HTTP server, as they will # not run unless the HTTP dependencies exist. diff --git a/t/t5559-http-fetch-smart-http2.sh b/t/t5559-http-fetch-smart-http2.sh new file mode 100755 index 0000000000..54aa9d3bff --- /dev/null +++ b/t/t5559-http-fetch-smart-http2.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +HTTP_PROTO=HTTP/2 +LIB_HTTPD_SSL=1 +. ./t5551-http-fetch-smart.sh diff --git a/t/t5560-http-backend-noserver.sh b/t/t5560-http-backend-noserver.sh index d30cf4f5b8..f75068de64 100755 --- a/t/t5560-http-backend-noserver.sh +++ b/t/t5560-http-backend-noserver.sh @@ -4,6 +4,7 @@ test_description='test git-http-backend-noserver' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh HTTPD_DOCUMENT_ROOT_PATH="$TRASH_DIRECTORY" diff --git a/t/t5561-http-backend.sh b/t/t5561-http-backend.sh index 9c57d84315..e1d3b8caed 100755 --- a/t/t5561-http-backend.sh +++ b/t/t5561-http-backend.sh @@ -4,6 +4,7 @@ test_description='test git-http-backend' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-httpd.sh diff --git a/t/t5562-http-backend-content-length.sh b/t/t5562-http-backend-content-length.sh index b68ec22d3f..7ee9858a78 100755 --- a/t/t5562-http-backend-content-length.sh +++ b/t/t5562-http-backend-content-length.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test git-http-backend respects CONTENT_LENGTH' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_lazy_prereq GZIP 'gzip --version' diff --git a/t/t5563-simple-http-auth.sh b/t/t5563-simple-http-auth.sh new file mode 100755 index 0000000000..ab8a721ccc --- /dev/null +++ b/t/t5563-simple-http-auth.sh @@ -0,0 +1,329 @@ +#!/bin/sh + +test_description='test http auth header and credential helper interop' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-httpd.sh + +enable_cgipassauth +if ! test_have_prereq CGIPASSAUTH +then + skip_all="no CGIPassAuth support" + test_done +fi +start_httpd + +test_expect_success 'setup_credential_helper' ' + mkdir "$TRASH_DIRECTORY/bin" && + PATH=$PATH:"$TRASH_DIRECTORY/bin" && + export PATH && + + CREDENTIAL_HELPER="$TRASH_DIRECTORY/bin/git-credential-test-helper" && + write_script "$CREDENTIAL_HELPER" <<-\EOF + cmd=$1 + teefile=$cmd-query.cred + catfile=$cmd-reply.cred + sed -n -e "/^$/q" -e "p" >>$teefile + if test "$cmd" = "get" + then + cat $catfile + fi + EOF +' + +set_credential_reply () { + cat >"$TRASH_DIRECTORY/$1-reply.cred" +} + +expect_credential_query () { + cat >"$TRASH_DIRECTORY/$1-expect.cred" && + test_cmp "$TRASH_DIRECTORY/$1-expect.cred" \ + "$TRASH_DIRECTORY/$1-query.cred" +} + +per_test_cleanup () { + rm -f *.cred && + rm -f "$HTTPD_ROOT_PATH"/custom-auth.valid \ + "$HTTPD_ROOT_PATH"/custom-auth.challenge +} + +test_expect_success 'setup repository' ' + test_commit foo && + git init --bare "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + git push --mirror "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" +' + +test_expect_success 'access using basic auth' ' + test_when_finished "per_test_cleanup" && + + set_credential_reply get <<-EOF && + username=alice + password=secret-passwd + EOF + + # Basic base64(alice:secret-passwd) + cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && + Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== + EOF + + cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && + WWW-Authenticate: Basic realm="example.com" + EOF + + test_config_global credential.helper test-helper && + git ls-remote "$HTTPD_URL/custom_auth/repo.git" && + + expect_credential_query get <<-EOF && + protocol=http + host=$HTTPD_DEST + wwwauth[]=Basic realm="example.com" + EOF + + expect_credential_query store <<-EOF + protocol=http + host=$HTTPD_DEST + username=alice + password=secret-passwd + EOF +' + +test_expect_success 'access using basic auth invalid credentials' ' + test_when_finished "per_test_cleanup" && + + set_credential_reply get <<-EOF && + username=baduser + password=wrong-passwd + EOF + + # Basic base64(alice:secret-passwd) + cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && + Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== + EOF + + cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && + WWW-Authenticate: Basic realm="example.com" + EOF + + test_config_global credential.helper test-helper && + test_must_fail git ls-remote "$HTTPD_URL/custom_auth/repo.git" && + + expect_credential_query get <<-EOF && + protocol=http + host=$HTTPD_DEST + wwwauth[]=Basic realm="example.com" + EOF + + expect_credential_query erase <<-EOF + protocol=http + host=$HTTPD_DEST + username=baduser + password=wrong-passwd + wwwauth[]=Basic realm="example.com" + EOF +' + +test_expect_success 'access using basic auth with extra challenges' ' + test_when_finished "per_test_cleanup" && + + set_credential_reply get <<-EOF && + username=alice + password=secret-passwd + EOF + + # Basic base64(alice:secret-passwd) + cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && + Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== + EOF + + cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && + WWW-Authenticate: FooBar param1="value1" param2="value2" + WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0 + WWW-Authenticate: Basic realm="example.com" + EOF + + test_config_global credential.helper test-helper && + git ls-remote "$HTTPD_URL/custom_auth/repo.git" && + + expect_credential_query get <<-EOF && + protocol=http + host=$HTTPD_DEST + wwwauth[]=FooBar param1="value1" param2="value2" + wwwauth[]=Bearer authorize_uri="id.example.com" p=1 q=0 + wwwauth[]=Basic realm="example.com" + EOF + + expect_credential_query store <<-EOF + protocol=http + host=$HTTPD_DEST + username=alice + password=secret-passwd + EOF +' + +test_expect_success 'access using basic auth mixed-case wwwauth header name' ' + test_when_finished "per_test_cleanup" && + + set_credential_reply get <<-EOF && + username=alice + password=secret-passwd + EOF + + # Basic base64(alice:secret-passwd) + cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && + Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== + EOF + + cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && + www-authenticate: foobar param1="value1" param2="value2" + WWW-AUTHENTICATE: BEARER authorize_uri="id.example.com" p=1 q=0 + WwW-aUtHeNtIcAtE: baSiC realm="example.com" + EOF + + test_config_global credential.helper test-helper && + git ls-remote "$HTTPD_URL/custom_auth/repo.git" && + + expect_credential_query get <<-EOF && + protocol=http + host=$HTTPD_DEST + wwwauth[]=foobar param1="value1" param2="value2" + wwwauth[]=BEARER authorize_uri="id.example.com" p=1 q=0 + wwwauth[]=baSiC realm="example.com" + EOF + + expect_credential_query store <<-EOF + protocol=http + host=$HTTPD_DEST + username=alice + password=secret-passwd + EOF +' + +test_expect_success 'access using basic auth with wwwauth header continuations' ' + test_when_finished "per_test_cleanup" && + + set_credential_reply get <<-EOF && + username=alice + password=secret-passwd + EOF + + # Basic base64(alice:secret-passwd) + cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && + Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== + EOF + + # Note that leading and trailing whitespace is important to correctly + # simulate a continuation/folded header. + cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && + WWW-Authenticate: FooBar param1="value1" + param2="value2" + WWW-Authenticate: Bearer authorize_uri="id.example.com" + p=1 + q=0 + WWW-Authenticate: Basic realm="example.com" + EOF + + test_config_global credential.helper test-helper && + git ls-remote "$HTTPD_URL/custom_auth/repo.git" && + + expect_credential_query get <<-EOF && + protocol=http + host=$HTTPD_DEST + wwwauth[]=FooBar param1="value1" param2="value2" + wwwauth[]=Bearer authorize_uri="id.example.com" p=1 q=0 + wwwauth[]=Basic realm="example.com" + EOF + + expect_credential_query store <<-EOF + protocol=http + host=$HTTPD_DEST + username=alice + password=secret-passwd + EOF +' + +test_expect_success 'access using basic auth with wwwauth header empty continuations' ' + test_when_finished "per_test_cleanup" && + + set_credential_reply get <<-EOF && + username=alice + password=secret-passwd + EOF + + # Basic base64(alice:secret-passwd) + cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && + Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== + EOF + + CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" && + + # Note that leading and trailing whitespace is important to correctly + # simulate a continuation/folded header. + printf "WWW-Authenticate: FooBar param1=\"value1\"\r\n" >"$CHALLENGE" && + printf " \r\n" >>"$CHALLENGE" && + printf " param2=\"value2\"\r\n" >>"$CHALLENGE" && + printf "WWW-Authenticate: Bearer authorize_uri=\"id.example.com\"\r\n" >>"$CHALLENGE" && + printf " p=1\r\n" >>"$CHALLENGE" && + printf " \r\n" >>"$CHALLENGE" && + printf " q=0\r\n" >>"$CHALLENGE" && + printf "WWW-Authenticate: Basic realm=\"example.com\"\r\n" >>"$CHALLENGE" && + + test_config_global credential.helper test-helper && + git ls-remote "$HTTPD_URL/custom_auth/repo.git" && + + expect_credential_query get <<-EOF && + protocol=http + host=$HTTPD_DEST + wwwauth[]=FooBar param1="value1" param2="value2" + wwwauth[]=Bearer authorize_uri="id.example.com" p=1 q=0 + wwwauth[]=Basic realm="example.com" + EOF + + expect_credential_query store <<-EOF + protocol=http + host=$HTTPD_DEST + username=alice + password=secret-passwd + EOF +' + +test_expect_success 'access using basic auth with wwwauth header mixed line-endings' ' + test_when_finished "per_test_cleanup" && + + set_credential_reply get <<-EOF && + username=alice + password=secret-passwd + EOF + + # Basic base64(alice:secret-passwd) + cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && + Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== + EOF + + CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" && + + # Note that leading and trailing whitespace is important to correctly + # simulate a continuation/folded header. + printf "WWW-Authenticate: FooBar param1=\"value1\"\r\n" >"$CHALLENGE" && + printf " \r\n" >>"$CHALLENGE" && + printf "\tparam2=\"value2\"\r\n" >>"$CHALLENGE" && + printf "WWW-Authenticate: Basic realm=\"example.com\"" >>"$CHALLENGE" && + + test_config_global credential.helper test-helper && + git ls-remote "$HTTPD_URL/custom_auth/repo.git" && + + expect_credential_query get <<-EOF && + protocol=http + host=$HTTPD_DEST + wwwauth[]=FooBar param1="value1" param2="value2" + wwwauth[]=Basic realm="example.com" + EOF + + expect_credential_query store <<-EOF + protocol=http + host=$HTTPD_DEST + username=alice + password=secret-passwd + EOF +' + +test_done diff --git a/t/t5564-http-proxy.sh b/t/t5564-http-proxy.sh new file mode 100755 index 0000000000..9da5134614 --- /dev/null +++ b/t/t5564-http-proxy.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +test_description="test fetching through http proxy" + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-httpd.sh + +LIB_HTTPD_PROXY=1 +start_httpd + +test_expect_success 'setup repository' ' + test_commit foo && + git init --bare "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + git push --mirror "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" +' + +setup_askpass_helper + +# sanity check that our test setup is correctly using proxy +test_expect_success 'proxy requires password' ' + test_config_global http.proxy $HTTPD_DEST && + test_must_fail git clone $HTTPD_URL/smart/repo.git 2>err && + grep "error.*407" err +' + +test_expect_success 'clone through proxy with auth' ' + test_when_finished "rm -rf clone" && + test_config_global http.proxy http://proxuser:proxpass@$HTTPD_DEST && + GIT_TRACE_CURL=$PWD/trace git clone $HTTPD_URL/smart/repo.git clone && + grep -i "Proxy-Authorization: Basic <redacted>" trace +' + +test_expect_success 'clone can prompt for proxy password' ' + test_when_finished "rm -rf clone" && + test_config_global http.proxy http://proxuser@$HTTPD_DEST && + set_askpass nobody proxpass && + GIT_TRACE_CURL=$PWD/trace git clone $HTTPD_URL/smart/repo.git clone && + expect_askpass pass proxuser +' + +test_done diff --git a/t/t5571-pre-push-hook.sh b/t/t5571-pre-push-hook.sh index a11b20e378..448134c4bf 100755 --- a/t/t5571-pre-push-hook.sh +++ b/t/t5571-pre-push-hook.sh @@ -4,6 +4,7 @@ test_description='check pre-push hooks' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh index 09097eff3f..4e917bf87d 100755 --- a/t/t5572-pull-submodule.sh +++ b/t/t5572-pull-submodule.sh @@ -121,7 +121,7 @@ test_expect_success "fetch.recurseSubmodules option triggers recursive fetch (bu sub_oid=$(git -C child rev-parse HEAD) && git -C super/sub cat-file -e $sub_oid && # Check that the submodule worktree did not update - ! test_path_is_file super/sub/merge_strategy_5.t + test_path_is_missing super/sub/merge_strategy_5.t ' test_expect_success "fetch.recurseSubmodules takes precedence over submodule.recurse" ' @@ -134,7 +134,7 @@ test_expect_success "fetch.recurseSubmodules takes precedence over submodule.rec sub_oid=$(git -C child rev-parse HEAD) && git -C super/sub cat-file -e $sub_oid && # Check that the submodule worktree did not update - ! test_path_is_file super/sub/merge_strategy_6.t + test_path_is_missing super/sub/merge_strategy_6.t ' test_expect_success 'pull --rebase --recurse-submodules (remote superproject submodule changes, local submodule changes)' ' diff --git a/t/t5573-pull-verify-signatures.sh b/t/t5573-pull-verify-signatures.sh index a53dd8550d..1221ac0597 100755 --- a/t/t5573-pull-verify-signatures.sh +++ b/t/t5573-pull-verify-signatures.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='pull signature verification tests' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY/lib-gpg.sh" diff --git a/t/t5574-fetch-output.sh b/t/t5574-fetch-output.sh new file mode 100755 index 0000000000..90e6dcb9a7 --- /dev/null +++ b/t/t5574-fetch-output.sh @@ -0,0 +1,293 @@ +#!/bin/sh + +test_description='git fetch output format' + +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +. ./test-lib.sh + +test_expect_success 'fetch with invalid output format configuration' ' + test_when_finished "rm -rf clone" && + git clone . clone && + + test_must_fail git -C clone -c fetch.output fetch origin 2>actual.err && + cat >expect <<-EOF && + error: missing value for ${SQ}fetch.output${SQ} + fatal: unable to parse ${SQ}fetch.output${SQ} from command-line config + EOF + test_cmp expect actual.err && + + test_must_fail git -C clone -c fetch.output= fetch origin 2>actual.err && + cat >expect <<-EOF && + fatal: invalid value for ${SQ}fetch.output${SQ}: ${SQ}${SQ} + EOF + test_cmp expect actual.err && + + test_must_fail git -C clone -c fetch.output=garbage fetch origin 2>actual.err && + cat >expect <<-EOF && + fatal: invalid value for ${SQ}fetch.output${SQ}: ${SQ}garbage${SQ} + EOF + test_cmp expect actual.err +' + +test_expect_success 'fetch aligned output' ' + git clone . full-output && + test_commit looooooooooooong-tag && + ( + cd full-output && + git -c fetch.output=full fetch origin >actual 2>&1 && + grep -e "->" actual | cut -c 22- >../actual + ) && + cat >expect <<-\EOF && + main -> origin/main + looooooooooooong-tag -> looooooooooooong-tag + EOF + test_cmp expect actual +' + +test_expect_success 'fetch compact output' ' + git clone . compact && + test_commit extraaa && + ( + cd compact && + git -c fetch.output=compact fetch origin >actual 2>&1 && + grep -e "->" actual | cut -c 22- >../actual + ) && + cat >expect <<-\EOF && + main -> origin/* + extraaa -> * + EOF + test_cmp expect actual +' + +test_expect_success 'fetch porcelain output' ' + test_when_finished "rm -rf porcelain" && + + # Set up a bunch of references that we can use to demonstrate different + # kinds of flag symbols in the output format. + MAIN_OLD=$(git rev-parse HEAD) && + git branch "fast-forward" && + git branch "deleted-branch" && + git checkout -b force-updated && + test_commit --no-tag force-update-old && + FORCE_UPDATED_OLD=$(git rev-parse HEAD) && + git checkout main && + + # Clone and pre-seed the repositories. We fetch references into two + # namespaces so that we can test that rejected and force-updated + # references are reported properly. + refspecs="refs/heads/*:refs/unforced/* +refs/heads/*:refs/forced/*" && + git clone . porcelain && + git -C porcelain fetch origin $refspecs && + + # Now that we have set up the client repositories we can change our + # local references. + git branch new-branch && + git branch -d deleted-branch && + git checkout fast-forward && + test_commit --no-tag fast-forward-new && + FAST_FORWARD_NEW=$(git rev-parse HEAD) && + git checkout force-updated && + git reset --hard HEAD~ && + test_commit --no-tag force-update-new && + FORCE_UPDATED_NEW=$(git rev-parse HEAD) && + + cat >expect <<-EOF && + - $MAIN_OLD $ZERO_OID refs/forced/deleted-branch + - $MAIN_OLD $ZERO_OID refs/unforced/deleted-branch + $MAIN_OLD $FAST_FORWARD_NEW refs/unforced/fast-forward + ! $FORCE_UPDATED_OLD $FORCE_UPDATED_NEW refs/unforced/force-updated + * $ZERO_OID $MAIN_OLD refs/unforced/new-branch + $MAIN_OLD $FAST_FORWARD_NEW refs/forced/fast-forward + + $FORCE_UPDATED_OLD $FORCE_UPDATED_NEW refs/forced/force-updated + * $ZERO_OID $MAIN_OLD refs/forced/new-branch + $MAIN_OLD $FAST_FORWARD_NEW refs/remotes/origin/fast-forward + + $FORCE_UPDATED_OLD $FORCE_UPDATED_NEW refs/remotes/origin/force-updated + * $ZERO_OID $MAIN_OLD refs/remotes/origin/new-branch + EOF + + # Execute a dry-run fetch first. We do this to assert that the dry-run + # and non-dry-run fetches produces the same output. Execution of the + # fetch is expected to fail as we have a rejected reference update. + test_must_fail git -C porcelain fetch \ + --porcelain --dry-run --prune origin $refspecs >actual && + test_cmp expect actual && + + # And now we perform a non-dry-run fetch. + test_must_fail git -C porcelain fetch \ + --porcelain --prune origin $refspecs >actual 2>stderr && + test_cmp expect actual && + test_must_be_empty stderr +' + +test_expect_success 'fetch porcelain with multiple remotes' ' + test_when_finished "rm -rf porcelain" && + + git switch --create multiple-remotes && + git clone . porcelain && + git -C porcelain remote add second-remote "$PWD" && + git -C porcelain fetch second-remote && + + test_commit --no-tag multi-commit && + old_commit=$(git rev-parse HEAD~) && + new_commit=$(git rev-parse HEAD) && + + cat >expect <<-EOF && + $old_commit $new_commit refs/remotes/origin/multiple-remotes + $old_commit $new_commit refs/remotes/second-remote/multiple-remotes + EOF + + git -C porcelain fetch --porcelain --all >actual 2>stderr && + test_cmp expect actual && + test_must_be_empty stderr +' + +test_expect_success 'fetch porcelain refuses to work with submodules' ' + test_when_finished "rm -rf porcelain" && + + cat >expect <<-EOF && + fatal: options ${SQ}--porcelain${SQ} and ${SQ}--recurse-submodules${SQ} cannot be used together + EOF + + git init porcelain && + test_must_fail git -C porcelain fetch --porcelain --recurse-submodules=yes 2>stderr && + test_cmp expect stderr && + + test_must_fail git -C porcelain fetch --porcelain --recurse-submodules=on-demand 2>stderr && + test_cmp expect stderr +' + +test_expect_success 'fetch porcelain overrides fetch.output config' ' + test_when_finished "rm -rf porcelain" && + + git switch --create config-override && + git clone . porcelain && + test_commit new-commit && + old_commit=$(git rev-parse HEAD~) && + new_commit=$(git rev-parse HEAD) && + + cat >expect <<-EOF && + $old_commit $new_commit refs/remotes/origin/config-override + * $ZERO_OID $new_commit refs/tags/new-commit + EOF + + git -C porcelain -c fetch.output=compact fetch --porcelain >stdout 2>stderr && + test_must_be_empty stderr && + test_cmp expect stdout +' + +test_expect_success 'fetch --no-porcelain overrides previous --porcelain' ' + test_when_finished "rm -rf no-porcelain" && + + git switch --create no-porcelain && + git clone . no-porcelain && + test_commit --no-tag no-porcelain && + old_commit=$(git rev-parse --short HEAD~) && + new_commit=$(git rev-parse --short HEAD) && + + cat >expect <<-EOF && + From $(test-tool path-utils real_path .)/. + $old_commit..$new_commit no-porcelain -> origin/no-porcelain + EOF + + git -C no-porcelain fetch --porcelain --no-porcelain >stdout 2>stderr && + test_cmp expect stderr && + test_must_be_empty stdout +' + +test_expect_success 'fetch output with HEAD' ' + test_when_finished "rm -rf head" && + git clone . head && + + git -C head fetch --dry-run origin HEAD >actual.out 2>actual.err && + cat >expect <<-EOF && + From $(test-tool path-utils real_path .)/. + * branch HEAD -> FETCH_HEAD + EOF + test_must_be_empty actual.out && + test_cmp expect actual.err && + + git -C head fetch origin HEAD >actual.out 2>actual.err && + test_must_be_empty actual.out && + test_cmp expect actual.err && + + git -C head fetch --dry-run origin HEAD:foo >actual.out 2>actual.err && + cat >expect <<-EOF && + From $(test-tool path-utils real_path .)/. + * [new ref] HEAD -> foo + EOF + test_must_be_empty actual.out && + test_cmp expect actual.err && + + git -C head fetch origin HEAD:foo >actual.out 2>actual.err && + test_must_be_empty actual.out && + test_cmp expect actual.err +' + +test_expect_success 'fetch porcelain output with HEAD' ' + test_when_finished "rm -rf head" && + git clone . head && + COMMIT_ID=$(git rev-parse HEAD) && + + git -C head fetch --porcelain --dry-run origin HEAD >actual && + cat >expect <<-EOF && + * $ZERO_OID $COMMIT_ID FETCH_HEAD + EOF + test_cmp expect actual && + + git -C head fetch --porcelain origin HEAD >actual && + test_cmp expect actual && + + git -C head fetch --porcelain --dry-run origin HEAD:foo >actual && + cat >expect <<-EOF && + * $ZERO_OID $COMMIT_ID refs/heads/foo + EOF + test_cmp expect actual && + + git -C head fetch --porcelain origin HEAD:foo >actual && + test_cmp expect actual +' + +test_expect_success 'fetch output with object ID' ' + test_when_finished "rm -rf object-id" && + git clone . object-id && + commit=$(git rev-parse HEAD) && + + git -C object-id fetch --dry-run origin $commit:object-id >actual.out 2>actual.err && + cat >expect <<-EOF && + From $(test-tool path-utils real_path .)/. + * [new ref] $commit -> object-id + EOF + test_must_be_empty actual.out && + test_cmp expect actual.err && + + git -C object-id fetch origin $commit:object-id >actual.out 2>actual.err && + test_must_be_empty actual.out && + test_cmp expect actual.err +' + +test_expect_success '--no-show-forced-updates' ' + mkdir forced-updates && + ( + cd forced-updates && + git init && + test_commit 1 && + test_commit 2 + ) && + git clone forced-updates forced-update-clone && + git clone forced-updates no-forced-update-clone && + git -C forced-updates reset --hard HEAD~1 && + ( + cd forced-update-clone && + git fetch --show-forced-updates origin 2>output && + test_i18ngrep "(forced update)" output + ) && + ( + cd no-forced-update-clone && + git fetch --no-show-forced-updates origin 2>output && + test_i18ngrep ! "(forced update)" output + ) +' + +test_done diff --git a/t/t5583-push-branches.sh b/t/t5583-push-branches.sh new file mode 100755 index 0000000000..320f49c753 --- /dev/null +++ b/t/t5583-push-branches.sh @@ -0,0 +1,116 @@ +#!/bin/sh + +test_description='check the consisitency of behavior of --all and --branches' + +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +delete_refs() { + dir=$1 + shift + rm -rf deletes + for arg in $* + do + echo "delete ${arg}" >>deletes + done + git -C $dir update-ref --stdin < deletes +} + +test_expect_success 'setup bare remote' ' + git init --bare remote-1 && + git -C remote-1 config gc.auto 0 && + test_commit one && + git push remote-1 HEAD +' + +test_expect_success 'setup different types of references' ' + cat >refs <<-EOF && + update refs/heads/branch-1 HEAD + update refs/heads/branch-2 HEAD + EOF + + git tag -a -m "annotated" annotated-1 HEAD && + git tag -a -m "annotated" annotated-2 HEAD && + git update-ref --stdin < refs +' + +test_expect_success '--all and --branches have the same behavior' ' + test_when_finished "delete_refs remote-1 \ + refs/heads/branch-1 \ + refs/heads/branch-2" && + git push remote-1 --all && + commit=$(git rev-parse HEAD) && + cat >expect <<-EOF && + $commit refs/heads/branch-1 + $commit refs/heads/branch-2 + $commit refs/heads/main + EOF + + git -C remote-1 show-ref --heads >actual.all && + delete_refs remote-1 refs/heads/branch-1 refs/heads/branch-2 && + git push remote-1 --branches && + git -C remote-1 show-ref --heads >actual.branches && + test_cmp actual.all actual.branches && + test_cmp expect actual.all +' + +test_expect_success '--all or --branches can not be combined with refspecs' ' + test_must_fail git push remote-1 --all main >actual.all 2>&1 && + test_must_fail git push remote-1 --branches main >actual.branches 2>&1 && + test_cmp actual.all actual.branches && + grep "be combined with refspecs" actual.all +' + +test_expect_success '--all or --branches can not be combined with --mirror' ' + test_must_fail git push remote-1 --all --mirror >actual.all 2>&1 && + test_must_fail git push remote-1 --branches --mirror >actual.branches 2>&1 && + test_cmp actual.all actual.branches && + grep "cannot be used together" actual.all +' + +test_expect_success '--all or --branches can not be combined with --tags' ' + test_must_fail git push remote-1 --all --tags >actual.all 2>&1 && + test_must_fail git push remote-1 --branches --tags >actual.branches 2>&1 && + test_cmp actual.all actual.branches && + grep "cannot be used together" actual.all +' + + +test_expect_success '--all or --branches can not be combined with --delete' ' + test_must_fail git push remote-1 --all --delete >actual.all 2>&1 && + test_must_fail git push remote-1 --branches --delete >actual.branches 2>&1 && + test_cmp actual.all actual.branches && + grep "cannot be used together" actual.all +' + +test_expect_success '--all or --branches combines with --follow-tags have same behavior' ' + test_when_finished "delete_refs remote-1 \ + refs/heads/branch-1 \ + refs/heads/branch-2 \ + refs/tags/annotated-1 \ + refs/tags/annotated-2" && + git push remote-1 --all --follow-tags && + git -C remote-1 show-ref > actual.all && + cat >expect <<-EOF && + $commit refs/heads/branch-1 + $commit refs/heads/branch-2 + $commit refs/heads/main + $(git rev-parse annotated-1) refs/tags/annotated-1 + $(git rev-parse annotated-2) refs/tags/annotated-2 + EOF + + delete_refs remote-1 \ + refs/heads/branch-1 \ + refs/heads/branch-2 \ + refs/tags/annotated-1 \ + refs/tags/annotated-2 && + git push remote-1 --branches --follow-tags && + git -C remote-1 show-ref >actual.branches && + test_cmp actual.all actual.branches && + test_cmp expect actual.all +' + +test_done diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index 45f0803ed4..b7d5551262 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -71,29 +71,6 @@ test_expect_success 'clone respects GIT_WORK_TREE' ' ' -test_expect_success LIBCURL 'clone warns or fails when using username:password' ' - message="URL '\''https://username:<redacted>@localhost/'\'' uses plaintext credentials" && - test_must_fail git -c transfer.credentialsInUrl=allow clone https://username:password@localhost attempt1 2>err && - ! grep "$message" err && - - test_must_fail git -c transfer.credentialsInUrl=warn clone https://username:password@localhost attempt2 2>err && - grep "warning: $message" err >warnings && - test_line_count = 2 warnings && - - test_must_fail git -c transfer.credentialsInUrl=die clone https://username:password@localhost attempt3 2>err && - grep "fatal: $message" err >warnings && - test_line_count = 1 warnings && - - test_must_fail git -c transfer.credentialsInUrl=die clone https://username:@localhost attempt3 2>err && - grep "fatal: $message" err >warnings && - test_line_count = 1 warnings -' - -test_expect_success LIBCURL 'clone does not detect username:password when it is https://username@domain:port/' ' - test_must_fail git -c transfer.credentialsInUrl=warn clone https://username@localhost:8080 attempt3 2>err && - ! grep "uses plaintext credentials" err -' - test_expect_success 'clone from hooks' ' test_create_repo r0 && @@ -795,6 +772,111 @@ test_expect_success 'reject cloning shallow repository using HTTP' ' git clone --no-reject-shallow $HTTPD_URL/smart/repo.git repo ' +test_expect_success 'auto-discover bundle URI from HTTP clone' ' + test_when_finished rm -rf trace.txt repo2 "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" && + git -C src bundle create "$HTTPD_DOCUMENT_ROOT_PATH/everything.bundle" --all && + git clone --bare --no-local src "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" && + + git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \ + uploadpack.advertiseBundleURIs true && + git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \ + bundle.version 1 && + git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \ + bundle.mode all && + git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \ + bundle.everything.uri "$HTTPD_URL/everything.bundle" && + + GIT_TRACE2_EVENT="$(pwd)/trace.txt" \ + git -c protocol.version=2 \ + -c transfer.bundleURI=true clone \ + $HTTPD_URL/smart/repo2.git repo2 && + cat >pattern <<-EOF && + "event":"child_start".*"argv":\["git-remote-https","$HTTPD_URL/everything.bundle"\] + EOF + grep -f pattern trace.txt +' + +test_expect_success 'auto-discover multiple bundles from HTTP clone' ' + test_when_finished rm -rf trace.txt repo3 "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" && + + test_commit -C src new && + git -C src bundle create "$HTTPD_DOCUMENT_ROOT_PATH/new.bundle" HEAD~1..HEAD && + git clone --bare --no-local src "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" && + + git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \ + uploadpack.advertiseBundleURIs true && + git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \ + bundle.version 1 && + git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \ + bundle.mode all && + + git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \ + bundle.everything.uri "$HTTPD_URL/everything.bundle" && + git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \ + bundle.new.uri "$HTTPD_URL/new.bundle" && + + GIT_TRACE2_EVENT="$(pwd)/trace.txt" \ + git -c protocol.version=2 \ + -c transfer.bundleURI=true clone \ + $HTTPD_URL/smart/repo3.git repo3 && + + # We should fetch _both_ bundles + cat >pattern <<-EOF && + "event":"child_start".*"argv":\["git-remote-https","$HTTPD_URL/everything.bundle"\] + EOF + grep -f pattern trace.txt && + cat >pattern <<-EOF && + "event":"child_start".*"argv":\["git-remote-https","$HTTPD_URL/new.bundle"\] + EOF + grep -f pattern trace.txt +' + +test_expect_success 'auto-discover multiple bundles from HTTP clone: creationToken heuristic' ' + test_when_finished rm -rf "$HTTPD_DOCUMENT_ROOT_PATH/repo4.git" && + test_when_finished rm -rf clone-heuristic trace*.txt && + + test_commit -C src newest && + git -C src bundle create "$HTTPD_DOCUMENT_ROOT_PATH/newest.bundle" HEAD~1..HEAD && + git clone --bare --no-local src "$HTTPD_DOCUMENT_ROOT_PATH/repo4.git" && + + cat >>"$HTTPD_DOCUMENT_ROOT_PATH/repo4.git/config" <<-EOF && + [uploadPack] + advertiseBundleURIs = true + + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "everything"] + uri = $HTTPD_URL/everything.bundle + creationtoken = 1 + + [bundle "new"] + uri = $HTTPD_URL/new.bundle + creationtoken = 2 + + [bundle "newest"] + uri = $HTTPD_URL/newest.bundle + creationtoken = 3 + EOF + + GIT_TRACE2_EVENT="$(pwd)/trace-clone.txt" \ + git -c protocol.version=2 \ + -c transfer.bundleURI=true clone \ + "$HTTPD_URL/smart/repo4.git" clone-heuristic && + + cat >expect <<-EOF && + $HTTPD_URL/newest.bundle + $HTTPD_URL/new.bundle + $HTTPD_URL/everything.bundle + EOF + + # We should fetch all bundles in the expected order. + test_remote_https_urls <trace-clone.txt >actual && + test_cmp expect actual +' + # DO NOT add non-httpd-specific tests here, because the last part of this # test script is only executed when httpd is available and enabled. diff --git a/t/t5604-clone-reference.sh b/t/t5604-clone-reference.sh index 7ccebb40c3..9845fc04d5 100755 --- a/t/t5604-clone-reference.sh +++ b/t/t5604-clone-reference.sh @@ -7,6 +7,7 @@ test_description='test clone --reference' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh base_dir=$(pwd) @@ -357,7 +358,7 @@ test_expect_success SYMLINKS 'clone repo with symlinked objects directory' ' test_must_fail git clone --local malicious clone 2>err && test_path_is_missing clone && - grep "failed to start iterator over" err + grep "is a symlink, refusing to clone with --local" err ' test_done diff --git a/t/t5605-clone-local.sh b/t/t5605-clone-local.sh index 38b850c10e..1d7b1abda1 100755 --- a/t/t5605-clone-local.sh +++ b/t/t5605-clone-local.sh @@ -15,8 +15,12 @@ test_expect_success 'preparing origin repository' ' : >file && git add . && git commit -m1 && git clone --bare . a.git && git clone --bare . x && - test "$(cd a.git && git config --bool core.bare)" = true && - test "$(cd x && git config --bool core.bare)" = true && + echo true >expect && + git -C a.git config --bool core.bare >actual && + test_cmp expect actual && + echo true >expect && + git -C x config --bool core.bare >actual && + test_cmp expect actual && git bundle create b1.bundle --all && git bundle create b2.bundle main && mkdir dir && @@ -29,7 +33,9 @@ test_expect_success 'preparing origin repository' ' test_expect_success 'local clone without .git suffix' ' git clone -l -s a b && (cd b && - test "$(git config --bool core.bare)" = false && + echo false >expect && + git config --bool core.bare >actual && + test_cmp expect actual && git fetch) ' diff --git a/t/t5606-clone-options.sh b/t/t5606-clone-options.sh index cf221e92c4..5890319b97 100755 --- a/t/t5606-clone-options.sh +++ b/t/t5606-clone-options.sh @@ -4,6 +4,7 @@ test_description='basic clone options' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' @@ -119,6 +120,16 @@ test_expect_success 'prefers -c config over --template config' ' ' +test_expect_failure 'prefers --template config even for core.bare' ' + + template="$TRASH_DIRECTORY/template-with-bare-config" && + mkdir "$template" && + git config --file "$template/config" core.bare true && + git clone "--template=$template" parent clone-bare-config && + test "$(git -C clone-bare-config config --local core.bare)" = "true" && + test_path_is_file clone-bare-config/HEAD +' + test_expect_success 'prefers config "clone.defaultRemoteName" over default' ' test_config_global clone.defaultRemoteName from_config && diff --git a/t/t5610-clone-detached.sh b/t/t5610-clone-detached.sh index a7ec21eda5..022ed3d87c 100755 --- a/t/t5610-clone-detached.sh +++ b/t/t5610-clone-detached.sh @@ -4,6 +4,7 @@ test_description='test cloning a repository with detached HEAD' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh head_is_detached() { diff --git a/t/t5611-clone-config.sh b/t/t5611-clone-config.sh index 4b3877216e..727caff443 100755 --- a/t/t5611-clone-config.sh +++ b/t/t5611-clone-config.sh @@ -4,6 +4,7 @@ test_description='tests for git clone -c key=value' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'clone -c sets config in cloned repo' ' diff --git a/t/t5613-info-alternate.sh b/t/t5613-info-alternate.sh index 895f46bb91..7708cbafa9 100755 --- a/t/t5613-info-alternate.sh +++ b/t/t5613-info-alternate.sh @@ -4,6 +4,8 @@ # test_description='test transitive info/alternate entries' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'preparing first repository' ' diff --git a/t/t5614-clone-submodules-shallow.sh b/t/t5614-clone-submodules-shallow.sh index 0c85ef834a..c2a2bb453e 100755 --- a/t/t5614-clone-submodules-shallow.sh +++ b/t/t5614-clone-submodules-shallow.sh @@ -2,6 +2,7 @@ test_description='Test shallow cloning of repos with submodules' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh pwd=$(pwd) diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh index 037941b95d..8759fc2853 100755 --- a/t/t5616-partial-clone.sh +++ b/t/t5616-partial-clone.sh @@ -257,8 +257,8 @@ test_expect_success 'partial clone with transfer.fsckobjects=1 works with submod test_commit -C submodule mycommit && test_create_repo src_with_sub && - test_config -C src_with_sub uploadpack.allowfilter 1 && - test_config -C src_with_sub uploadpack.allowanysha1inwant 1 && + git -C src_with_sub config uploadpack.allowfilter 1 && + git -C src_with_sub config uploadpack.allowanysha1inwant 1 && test_config_global protocol.file.allow always && @@ -270,6 +270,12 @@ test_expect_success 'partial clone with transfer.fsckobjects=1 works with submod test_when_finished rm -rf dst ' +test_expect_success 'lazily fetched .gitmodules works' ' + git clone --filter="blob:none" --no-checkout "file://$(pwd)/src_with_sub" dst && + git -C dst fetch && + test_when_finished rm -rf dst +' + test_expect_success 'partial clone with transfer.fsckobjects=1 uses index-pack --fsck-objects' ' git init src && test_commit -C src x && @@ -644,6 +650,49 @@ test_expect_success 'repack does not loosen promisor objects' ' grep "loosen_unused_packed_objects/loosened:0" trace ' +test_expect_success 'lazy-fetch in submodule succeeds' ' + # setup + test_config_global protocol.file.allow always && + + test_when_finished "rm -rf src-sub" && + git init src-sub && + git -C src-sub config uploadpack.allowfilter 1 && + git -C src-sub config uploadpack.allowanysha1inwant 1 && + + # This blob must be missing in the subsequent commit. + echo foo >src-sub/file && + git -C src-sub add file && + git -C src-sub commit -m "submodule one" && + SUB_ONE=$(git -C src-sub rev-parse HEAD) && + + echo bar >src-sub/file && + git -C src-sub add file && + git -C src-sub commit -m "submodule two" && + SUB_TWO=$(git -C src-sub rev-parse HEAD) && + + test_when_finished "rm -rf src-super" && + git init src-super && + git -C src-super config uploadpack.allowfilter 1 && + git -C src-super config uploadpack.allowanysha1inwant 1 && + git -C src-super submodule add ../src-sub src-sub && + + git -C src-super/src-sub checkout $SUB_ONE && + git -C src-super add src-sub && + git -C src-super commit -m "superproject one" && + + git -C src-super/src-sub checkout $SUB_TWO && + git -C src-super add src-sub && + git -C src-super commit -m "superproject two" && + + # the fetch + test_when_finished "rm -rf client" && + git clone --filter=blob:none --also-filter-submodules \ + --recurse-submodules "file://$(pwd)/src-super" client && + + # Trigger lazy-fetch from the superproject + git -C client restore --recurse-submodules --source=HEAD^ :/ +' + . "$TEST_DIRECTORY"/lib-httpd.sh start_httpd diff --git a/t/t5617-clone-submodules-remote.sh b/t/t5617-clone-submodules-remote.sh index 6884338249..5a4d7936a7 100755 --- a/t/t5617-clone-submodules-remote.sh +++ b/t/t5617-clone-submodules-remote.sh @@ -5,6 +5,7 @@ test_description='Test cloning repos with submodules using remote-tracking branc GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh pwd=$(pwd) diff --git a/t/t5618-alternate-refs.sh b/t/t5618-alternate-refs.sh index 3353216f09..f905db0a3f 100755 --- a/t/t5618-alternate-refs.sh +++ b/t/t5618-alternate-refs.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test handling of --alternate-refs traversal' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Avoid test_commit because we want a specific and known set of refs: diff --git a/t/t5700-protocol-v1.sh b/t/t5700-protocol-v1.sh index 6c8d4c6cf1..a73b4d4ff6 100755 --- a/t/t5700-protocol-v1.sh +++ b/t/t5700-protocol-v1.sh @@ -244,15 +244,28 @@ test_expect_success 'push with ssh:// using protocol v1' ' grep "push< version 1" log ' +test_expect_success 'clone propagates object-format from empty repo' ' + test_when_finished "rm -fr src256 dst256" && + + echo sha256 >expect && + git init --object-format=sha256 src256 && + git clone --no-local src256 dst256 && + git -C dst256 rev-parse --show-object-format >actual && + + test_cmp expect actual +' + # Test protocol v1 with 'http://' transport # . "$TEST_DIRECTORY"/lib-httpd.sh start_httpd -test_expect_success 'create repo to be served by http:// transport' ' +test_expect_success 'create repos to be served by http:// transport' ' git init "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" && git -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" config http.receivepack true && - test_commit -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" one + test_commit -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" one && + git init --object-format=sha256 "$HTTPD_DOCUMENT_ROOT_PATH/sha256" && + git -C "$HTTPD_DOCUMENT_ROOT_PATH/sha256" config http.receivepack true ' test_expect_success 'clone with http:// using protocol v1' ' @@ -269,6 +282,20 @@ test_expect_success 'clone with http:// using protocol v1' ' grep "git< version 1" log ' +test_expect_success 'clone with http:// using protocol v1 with empty SHA-256 repo' ' + GIT_TRACE_PACKET=1 GIT_TRACE_CURL=1 git -c protocol.version=1 \ + clone "$HTTPD_URL/smart/sha256" sha256 2>log && + + echo sha256 >expect && + git -C sha256 rev-parse --show-object-format >actual && + test_cmp expect actual && + + # Client requested to use protocol v1 + grep "Git-Protocol: version=1" log && + # Server responded using protocol v1 + grep "git< version 1" log +' + test_expect_success 'fetch with http:// using protocol v1' ' test_commit -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" two && diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh index 1896f671cb..f21e5e9d33 100755 --- a/t/t5701-git-serve.sh +++ b/t/t5701-git-serve.sh @@ -13,7 +13,7 @@ test_expect_success 'test capability advertisement' ' wrong_algo sha1:sha256 wrong_algo sha256:sha1 EOF - cat >expect <<-EOF && + cat >expect.base <<-EOF && version 2 agent=git/$(git version | cut -d" " -f3) ls-refs=unborn @@ -21,8 +21,11 @@ test_expect_success 'test capability advertisement' ' server-option object-format=$(test_oid algo) object-info + EOF + cat >expect.trailer <<-EOF && 0000 EOF + cat expect.base expect.trailer >expect && GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \ --advertise-capabilities >out && @@ -342,4 +345,39 @@ test_expect_success 'basics of object-info' ' test_cmp expect actual ' +test_expect_success 'test capability advertisement with uploadpack.advertiseBundleURIs' ' + test_config uploadpack.advertiseBundleURIs true && + + cat >expect.extra <<-EOF && + bundle-uri + EOF + cat expect.base \ + expect.extra \ + expect.trailer >expect && + + GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \ + --advertise-capabilities >out && + test-tool pkt-line unpack <out >actual && + test_cmp expect actual +' + +test_expect_success 'basics of bundle-uri: dies if not enabled' ' + test-tool pkt-line pack >in <<-EOF && + command=bundle-uri + 0000 + EOF + + cat >err.expect <<-\EOF && + fatal: invalid command '"'"'bundle-uri'"'"' + EOF + + cat >expect <<-\EOF && + ERR serve: invalid command '"'"'bundle-uri'"'"' + EOF + + test_must_fail test-tool serve-v2 --stateless-rpc <in >out 2>err.actual && + test_cmp err.expect err.actual && + test_must_be_empty out +' + test_done diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh index 5d42a355a8..6af5c2062f 100755 --- a/t/t5702-protocol-v2.sh +++ b/t/t5702-protocol-v2.sh @@ -269,6 +269,17 @@ test_expect_success 'clone propagates unborn HEAD from non-empty repo' ' grep "warning: remote HEAD refers to nonexistent ref" stderr ' +test_expect_success 'clone propagates object-format from empty repo' ' + test_when_finished "rm -fr src256 dst256" && + + echo sha256 >expect && + git init --object-format=sha256 src256 && + git clone src256 dst256 && + git -C dst256 rev-parse --show-object-format >actual && + + test_cmp expect actual +' + test_expect_success 'bare clone propagates unborn HEAD from non-empty repo' ' test_when_finished "rm -rf file_unborn_parent file_unborn_child.git" && @@ -728,6 +739,33 @@ test_expect_success 'file:// --negotiate-only with protocol v0' ' test_i18ngrep "negotiate-only requires protocol v2" err ' +test_expect_success 'push with custom path does not request v2' ' + rm -f env.trace && + git -C client push \ + --receive-pack="env >../env.trace; git-receive-pack" \ + origin HEAD:refs/heads/custom-push-test && + test_path_is_file env.trace && + ! grep ^GIT_PROTOCOL env.trace +' + +test_expect_success 'fetch with custom path does request v2' ' + rm -f env.trace && + git -C client fetch \ + --upload-pack="env >../env.trace; git-upload-pack" \ + origin HEAD && + grep ^GIT_PROTOCOL=version=2 env.trace +' + +test_expect_success 'archive with custom path does not request v2' ' + rm -f env.trace && + git -C client archive \ + --exec="env >../env.trace; git-upload-archive" \ + --remote=origin \ + HEAD >/dev/null && + test_path_is_file env.trace && + ! grep ^GIT_PROTOCOL env.trace +' + # Test protocol v2 with 'http://' transport # . "$TEST_DIRECTORY"/lib-httpd.sh @@ -1001,7 +1039,7 @@ test_expect_success 'part of packfile response provided as URI' ' do git verify-pack --object-format=$(test_oid algo) --verbose $idx >out && { - grep "^[0-9a-f]\{16,\} " out || : + grep -E "^[0-9a-f]{16,} " out || : } >out.objectlist && if test_line_count = 1 out.objectlist then @@ -1114,7 +1152,7 @@ test_expect_success 'packfile-uri with transfer.fsckobjects fails on bad object' This commit object intentionally broken EOF - BOGUS=$(git -C "$P" hash-object -t commit -w --stdin <bogus-commit) && + BOGUS=$(git -C "$P" hash-object -t commit -w --stdin --literally <bogus-commit) && git -C "$P" branch bogus-branch "$BOGUS" && echo my-blob >"$P/my-blob" && diff --git a/t/t5705-session-id-in-capabilities.sh b/t/t5705-session-id-in-capabilities.sh index ed38c76c29..b8a722ec27 100755 --- a/t/t5705-session-id-in-capabilities.sh +++ b/t/t5705-session-id-in-capabilities.sh @@ -2,6 +2,7 @@ test_description='session ID in capabilities' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh REPO="$(pwd)/repo" diff --git a/t/t5730-protocol-v2-bundle-uri-file.sh b/t/t5730-protocol-v2-bundle-uri-file.sh new file mode 100755 index 0000000000..37bdb725bc --- /dev/null +++ b/t/t5730-protocol-v2-bundle-uri-file.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +test_description="Test bundle-uri with protocol v2 and 'file://' transport" + +TEST_NO_CREATE_REPO=1 + +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +. ./test-lib.sh + +# Test protocol v2 with 'file://' transport +# +BUNDLE_URI_PROTOCOL=file +. "$TEST_DIRECTORY"/lib-bundle-uri-protocol.sh + +test_done diff --git a/t/t5731-protocol-v2-bundle-uri-git.sh b/t/t5731-protocol-v2-bundle-uri-git.sh new file mode 100755 index 0000000000..8add1b37ab --- /dev/null +++ b/t/t5731-protocol-v2-bundle-uri-git.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +test_description="Test bundle-uri with protocol v2 and 'git://' transport" + +TEST_NO_CREATE_REPO=1 + +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +. ./test-lib.sh + +# Test protocol v2 with 'git://' transport +# +BUNDLE_URI_PROTOCOL=git +. "$TEST_DIRECTORY"/lib-bundle-uri-protocol.sh + +test_done diff --git a/t/t5732-protocol-v2-bundle-uri-http.sh b/t/t5732-protocol-v2-bundle-uri-http.sh new file mode 100755 index 0000000000..129daa0226 --- /dev/null +++ b/t/t5732-protocol-v2-bundle-uri-http.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +test_description="Test bundle-uri with protocol v2 and 'http://' transport" + +TEST_NO_CREATE_REPO=1 + +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +. ./test-lib.sh + +# Test protocol v2 with 'http://' transport +# +BUNDLE_URI_PROTOCOL=http +. "$TEST_DIRECTORY"/lib-bundle-uri-protocol.sh + +test_done diff --git a/t/t5750-bundle-uri-parse.sh b/t/t5750-bundle-uri-parse.sh new file mode 100755 index 0000000000..81bdf58b94 --- /dev/null +++ b/t/t5750-bundle-uri-parse.sh @@ -0,0 +1,290 @@ +#!/bin/sh + +test_description="Test bundle-uri bundle_uri_parse_line()" + +TEST_NO_CREATE_REPO=1 +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +test_expect_success 'bundle_uri_parse_line() just URIs' ' + cat >in <<-\EOF && + bundle.one.uri=http://example.com/bundle.bdl + bundle.two.uri=https://example.com/bundle.bdl + bundle.three.uri=file:///usr/share/git/bundle.bdl + EOF + + cat >expect <<-\EOF && + [bundle] + version = 1 + mode = all + [bundle "one"] + uri = http://example.com/bundle.bdl + [bundle "two"] + uri = https://example.com/bundle.bdl + [bundle "three"] + uri = file:///usr/share/git/bundle.bdl + EOF + + test-tool bundle-uri parse-key-values in >actual 2>err && + test_must_be_empty err && + test_cmp_config_output expect actual +' + +test_expect_success 'bundle_uri_parse_line(): relative URIs' ' + cat >in <<-\EOF && + bundle.one.uri=bundle.bdl + bundle.two.uri=../bundle.bdl + bundle.three.uri=sub/dir/bundle.bdl + EOF + + cat >expect <<-\EOF && + [bundle] + version = 1 + mode = all + [bundle "one"] + uri = <uri>/bundle.bdl + [bundle "two"] + uri = bundle.bdl + [bundle "three"] + uri = <uri>/sub/dir/bundle.bdl + EOF + + test-tool bundle-uri parse-key-values in >actual 2>err && + test_must_be_empty err && + test_cmp_config_output expect actual +' + +test_expect_success 'bundle_uri_parse_line(): relative URIs and parent paths' ' + cat >in <<-\EOF && + bundle.one.uri=bundle.bdl + bundle.two.uri=../bundle.bdl + bundle.three.uri=../../bundle.bdl + EOF + + cat >expect <<-\EOF && + [bundle] + version = 1 + mode = all + [bundle "one"] + uri = <uri>/bundle.bdl + [bundle "two"] + uri = bundle.bdl + [bundle "three"] + uri = <uri>/../bundle.bdl + EOF + + # TODO: We would prefer if parsing a bundle list would not cause + # a die() and instead would give a warning and allow the rest of + # a Git command to continue. This test_must_fail is necessary for + # now until the interface for relative_url() allows for reporting + # an error instead of die()ing. + test_must_fail test-tool bundle-uri parse-key-values in >actual 2>err && + grep "fatal: cannot strip one component off url" err +' + +test_expect_success 'bundle_uri_parse_line() parsing edge cases: empty key or value' ' + cat >in <<-\EOF && + =bogus-value + bogus-key= + EOF + + cat >err.expect <<-EOF && + error: bundle-uri: line has empty key or value + error: bad line: '\''=bogus-value'\'' + error: bundle-uri: line has empty key or value + error: bad line: '\''bogus-key='\'' + EOF + + cat >expect <<-\EOF && + [bundle] + version = 1 + mode = all + EOF + + test_must_fail test-tool bundle-uri parse-key-values in >actual 2>err && + test_cmp err.expect err && + test_cmp_config_output expect actual +' + +test_expect_success 'bundle_uri_parse_line() parsing edge cases: empty lines' ' + cat >in <<-\EOF && + bundle.one.uri=http://example.com/bundle.bdl + + bundle.two.uri=https://example.com/bundle.bdl + + bundle.three.uri=file:///usr/share/git/bundle.bdl + EOF + + cat >err.expect <<-\EOF && + error: bundle-uri: got an empty line + error: bad line: '\'''\'' + error: bundle-uri: got an empty line + error: bad line: '\'''\'' + EOF + + # We fail, but try to continue parsing regardless + cat >expect <<-\EOF && + [bundle] + version = 1 + mode = all + [bundle "one"] + uri = http://example.com/bundle.bdl + [bundle "two"] + uri = https://example.com/bundle.bdl + [bundle "three"] + uri = file:///usr/share/git/bundle.bdl + EOF + + test_must_fail test-tool bundle-uri parse-key-values in >actual 2>err && + test_cmp err.expect err && + test_cmp_config_output expect actual +' + +test_expect_success 'bundle_uri_parse_line() parsing edge cases: duplicate lines' ' + cat >in <<-\EOF && + bundle.one.uri=http://example.com/bundle.bdl + bundle.two.uri=https://example.com/bundle.bdl + bundle.one.uri=https://example.com/bundle-2.bdl + bundle.three.uri=file:///usr/share/git/bundle.bdl + EOF + + cat >err.expect <<-\EOF && + error: bad line: '\''bundle.one.uri=https://example.com/bundle-2.bdl'\'' + EOF + + # We fail, but try to continue parsing regardless + cat >expect <<-\EOF && + [bundle] + version = 1 + mode = all + [bundle "one"] + uri = http://example.com/bundle.bdl + [bundle "two"] + uri = https://example.com/bundle.bdl + [bundle "three"] + uri = file:///usr/share/git/bundle.bdl + EOF + + test_must_fail test-tool bundle-uri parse-key-values in >actual 2>err && + test_cmp err.expect err && + test_cmp_config_output expect actual +' + +test_expect_success 'parse config format: just URIs' ' + cat >expect <<-\EOF && + [bundle] + version = 1 + mode = all + [bundle "one"] + uri = http://example.com/bundle.bdl + [bundle "two"] + uri = https://example.com/bundle.bdl + [bundle "three"] + uri = file:///usr/share/git/bundle.bdl + EOF + + test-tool bundle-uri parse-config expect >actual 2>err && + test_must_be_empty err && + test_cmp_config_output expect actual +' + +test_expect_success 'parse config format: relative URIs' ' + cat >in <<-\EOF && + [bundle] + version = 1 + mode = all + [bundle "one"] + uri = bundle.bdl + [bundle "two"] + uri = ../bundle.bdl + [bundle "three"] + uri = sub/dir/bundle.bdl + EOF + + cat >expect <<-\EOF && + [bundle] + version = 1 + mode = all + [bundle "one"] + uri = <uri>/bundle.bdl + [bundle "two"] + uri = bundle.bdl + [bundle "three"] + uri = <uri>/sub/dir/bundle.bdl + EOF + + test-tool bundle-uri parse-config in >actual 2>err && + test_must_be_empty err && + test_cmp_config_output expect actual +' + +test_expect_success 'parse config format edge cases: empty key or value' ' + cat >in1 <<-\EOF && + = bogus-value + EOF + + cat >err1 <<-EOF && + error: bad config line 1 in file in1 + EOF + + cat >expect <<-\EOF && + [bundle] + version = 1 + mode = all + EOF + + test_must_fail test-tool bundle-uri parse-config in1 >actual 2>err && + test_cmp err1 err && + test_cmp_config_output expect actual && + + cat >in2 <<-\EOF && + bogus-key = + EOF + + cat >err2 <<-EOF && + error: bad config line 1 in file in2 + EOF + + test_must_fail test-tool bundle-uri parse-config in2 >actual 2>err && + test_cmp err2 err && + test_cmp_config_output expect actual +' + +test_expect_success 'parse config format: creationToken heuristic' ' + cat >expect <<-\EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + [bundle "one"] + uri = http://example.com/bundle.bdl + creationToken = 123456 + [bundle "two"] + uri = https://example.com/bundle.bdl + creationToken = 12345678901234567890 + [bundle "three"] + uri = file:///usr/share/git/bundle.bdl + creationToken = 1 + EOF + + test-tool bundle-uri parse-config expect >actual 2>err && + test_must_be_empty err && + test_cmp_config_output expect actual +' + +test_expect_success 'parse config format edge cases: creationToken heuristic' ' + cat >expect <<-\EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + [bundle "one"] + uri = http://example.com/bundle.bdl + creationToken = bogus + EOF + + test-tool bundle-uri parse-config expect >actual 2>err && + grep "could not parse bundle list key creationToken with value '\''bogus'\''" err +' + +test_done diff --git a/t/t5810-proto-disable-local.sh b/t/t5810-proto-disable-local.sh index c1ef99b85c..862610256f 100755 --- a/t/t5810-proto-disable-local.sh +++ b/t/t5810-proto-disable-local.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test disabling of local paths in clone/fetch' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY/lib-proto-disable.sh" diff --git a/t/t5813-proto-disable-ssh.sh b/t/t5813-proto-disable-ssh.sh index 3f084ee306..2e975dc70e 100755 --- a/t/t5813-proto-disable-ssh.sh +++ b/t/t5813-proto-disable-ssh.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test disabling of git-over-ssh in clone/fetch' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY/lib-proto-disable.sh" diff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh index 1f7d7dd20c..5cf2cee74d 100755 --- a/t/t6003-rev-list-topo-order.sh +++ b/t/t6003-rev-list-topo-order.sh @@ -326,19 +326,16 @@ a2 c3 EOF -# -# this test fails on --topo-order - a fix is required -# -#test_output_expect_success '--max-age=c3, --topo-order' "git rev-list --topo-order --max-age=$(commit_date c3) l5" <<EOF -#l5 -#l4 -#l3 -#a4 -#c3 -#b4 -#a3 -#a2 -#EOF +test_output_expect_success '--max-age=c3, --topo-order' "git rev-list --topo-order --max-age=$(commit_date c3) l5" <<EOF +l5 +l4 +l3 +a4 +c3 +b4 +a3 +a2 +EOF test_output_expect_success 'one specified head reachable from another a4, c3, --topo-order' "list_duplicates git rev-list --topo-order a4 c3" <<EOF EOF diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh index 41d0ca00b1..573eb97a0f 100755 --- a/t/t6006-rev-list-format.sh +++ b/t/t6006-rev-list-format.sh @@ -493,7 +493,7 @@ test_expect_success 'empty email' ' test_tick && C=$(GIT_AUTHOR_EMAIL= git commit-tree HEAD^{tree} </dev/null) && A=$(git show --pretty=format:%an,%ae,%ad%n -s $C) && - verbose test "$A" = "$GIT_AUTHOR_NAME,,Thu Apr 7 15:14:13 2005 -0700" + test "$A" = "$GIT_AUTHOR_NAME,,Thu Apr 7 15:14:13 2005 -0700" ' test_expect_success 'del LF before empty (1)' ' diff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh index bad02cf5b8..b2e422cf0f 100755 --- a/t/t6011-rev-list-with-bad-commit.sh +++ b/t/t6011-rev-list-with-bad-commit.sh @@ -2,6 +2,7 @@ test_description='git rev-list should notice bad commits' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Note: diff --git a/t/t6014-rev-list-all.sh b/t/t6014-rev-list-all.sh index c9bedd29cb..16b8bd1d09 100755 --- a/t/t6014-rev-list-all.sh +++ b/t/t6014-rev-list-all.sh @@ -2,6 +2,7 @@ test_description='--all includes detached HEADs' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh diff --git a/t/t6017-rev-list-stdin.sh b/t/t6017-rev-list-stdin.sh index 05162512a0..a57f1ae2ba 100755 --- a/t/t6017-rev-list-stdin.sh +++ b/t/t6017-rev-list-stdin.sh @@ -48,7 +48,9 @@ test_expect_success setup ' git add file-$i && test_tick && git commit -m side-$i || exit - done + done && + + git update-ref refs/heads/-dashed-branch HEAD ) ' @@ -60,6 +62,12 @@ check side-1 ^side-7 -- file-2 check side-3 ^side-4 -- file-3 check side-3 ^side-2 check side-3 ^side-2 -- file-1 +check --all +check --all --not --branches +check --glob=refs/heads +check --glob=refs/heads -- +check --glob=refs/heads -- file-1 +check --end-of-options -dashed-branch test_expect_success 'not only --stdin' ' cat >expect <<-EOF && @@ -78,4 +86,45 @@ test_expect_success 'not only --stdin' ' test_cmp expect actual ' +test_expect_success 'pseudo-opt with missing value' ' + cat >input <<-EOF && + --glob + refs/heads + EOF + + cat >expect <<-EOF && + fatal: Option ${SQ}--glob${SQ} requires a value + EOF + + test_must_fail git rev-list --stdin <input 2>error && + test_cmp expect error +' + +test_expect_success 'pseudo-opt with invalid value' ' + cat >input <<-EOF && + --no-walk=garbage + EOF + + cat >expect <<-EOF && + error: invalid argument to --no-walk + fatal: invalid option ${SQ}--no-walk=garbage${SQ} in --stdin mode + EOF + + test_must_fail git rev-list --stdin <input 2>error && + test_cmp expect error +' + +test_expect_success 'unknown option without --end-of-options' ' + cat >input <<-EOF && + -dashed-branch + EOF + + cat >expect <<-EOF && + fatal: invalid option ${SQ}-dashed-branch${SQ} in --stdin mode + EOF + + test_must_fail git rev-list --stdin <input 2>error && + test_cmp expect error +' + test_done diff --git a/t/t6018-rev-list-glob.sh b/t/t6018-rev-list-glob.sh index e1abc5c2b3..67d523d405 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 fetch 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..3e6bcbf30c 100755 --- a/t/t6020-bundle-misc.sh +++ b/t/t6020-bundle-misc.sh @@ -10,6 +10,14 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . ./test-lib.sh . "$TEST_DIRECTORY"/lib-bundle.sh +. "$TEST_DIRECTORY"/lib-terminal.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 () { @@ -559,4 +567,88 @@ test_expect_success 'cloning from filtered bundle has useful error' ' grep "cannot clone from filtered bundle" err ' +test_expect_success 'verify catches unreachable, broken prerequisites' ' + test_when_finished rm -rf clone-from clone-to && + git init clone-from && + ( + cd clone-from && + git checkout -b base && + test_commit A && + git checkout -b tip && + git commit --allow-empty -m "will drop by shallow" && + git commit --allow-empty -m "will keep by shallow" && + git commit --allow-empty -m "for bundle, not clone" && + git bundle create tip.bundle tip~1..tip && + git reset --hard HEAD~1 && + git checkout base + ) && + BAD_OID=$(git -C clone-from rev-parse tip~1) && + TIP_OID=$(git -C clone-from rev-parse tip) && + git clone --depth=1 --no-single-branch \ + "file://$(pwd)/clone-from" clone-to && + ( + cd clone-to && + + # Set up broken history by removing shallow markers + git update-ref -d refs/remotes/origin/tip && + rm .git/shallow && + + # Verify should fail + test_must_fail git bundle verify \ + ../clone-from/tip.bundle 2>err && + grep "some prerequisite commits .* are not connected" err && + test_line_count = 1 err && + + # Unbundling should fail + test_must_fail git bundle unbundle \ + ../clone-from/tip.bundle 2>err && + grep "some prerequisite commits .* are not connected" err && + test_line_count = 1 err + ) +' + +test_expect_success 'bundle progress includes write phase' ' + GIT_PROGRESS_DELAY=0 \ + git bundle create --progress out.bundle --all 2>err && + grep 'Writing' err +' + +test_expect_success TTY 'create --quiet disables all bundle progress' ' + test_terminal env GIT_PROGRESS_DELAY=0 \ + git bundle create --quiet out.bundle --all 2>err && + test_must_be_empty err +' + +test_expect_success 'bundle progress with --no-quiet' ' + GIT_PROGRESS_DELAY=0 \ + git bundle create --no-quiet out.bundle --all 2>err && + grep "%" err +' + +test_expect_success 'read bundle over stdin' ' + git bundle create some.bundle HEAD && + + git bundle verify - <some.bundle 2>err && + grep "<stdin> is okay" err && + + git bundle list-heads some.bundle >expect && + git bundle list-heads - <some.bundle >actual && + test_cmp expect actual && + + git bundle unbundle some.bundle >expect && + git bundle unbundle - <some.bundle >actual && + test_cmp expect actual +' + +test_expect_success 'send a bundle to standard output' ' + git bundle create - --all HEAD >bundle-one && + mkdir -p down && + git -C down bundle create - --all HEAD >bundle-two && + git bundle verify bundle-one && + git bundle verify bundle-two && + git ls-remote bundle-one >expect && + git ls-remote bundle-two >actual && + test_cmp expect actual +' + test_done diff --git a/t/t6021-rev-list-exclude-hidden.sh b/t/t6021-rev-list-exclude-hidden.sh new file mode 100755 index 0000000000..1a9d37e638 --- /dev/null +++ b/t/t6021-rev-list-exclude-hidden.sh @@ -0,0 +1,164 @@ +#!/bin/sh + +test_description='git rev-list --exclude-hidden test' + +TEST_PASSES_SANITIZE_LEAK=true +. ./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 fetch 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..fb01bd6abc 100755 --- a/t/t6030-bisect-porcelain.sh +++ b/t/t6030-bisect-porcelain.sh @@ -34,6 +34,36 @@ HASH2= HASH3= HASH4= +test_bisect_usage () { + local code="$1" && + shift && + cat >expect && + test_expect_code $code "$@" >out 2>actual && + test_must_be_empty out && + test_cmp expect actual +} + +test_expect_success 'bisect usage' " + test_bisect_usage 1 git bisect reset extra1 extra2 <<-\EOF && + error: 'git bisect reset' requires either no argument or a commit + EOF + test_bisect_usage 1 git bisect terms extra1 extra2 <<-\EOF && + error: 'git bisect terms' requires 0 or 1 argument + EOF + test_bisect_usage 1 git bisect next extra1 <<-\EOF && + error: 'git bisect next' requires 0 arguments + EOF + test_bisect_usage 1 git bisect log extra1 <<-\EOF && + error: We are not bisecting. + EOF + test_bisect_usage 1 git bisect replay <<-\EOF && + error: no logfile given + EOF + test_bisect_usage 1 git bisect run <<-\EOF + error: 'git bisect run' failed: no command provided. + EOF +" + test_expect_success 'set up basic repo with 1 file (hello) and 4 commits' ' add_line_into_file "1: Hello World" hello && HASH1=$(git rev-parse --verify HEAD) && @@ -92,6 +122,29 @@ test_expect_success 'bisect start without -- takes unknown arg as pathspec' ' grep bar ".git/BISECT_NAMES" ' +test_expect_success 'bisect reset: back in a branch checked out also elsewhere' ' + echo "shared" > branch.expect && + test_bisect_reset() { + git -C $1 bisect start && + git -C $1 bisect good $HASH1 && + git -C $1 bisect bad $HASH3 && + git -C $1 bisect reset && + git -C $1 branch --show-current > branch.output && + cmp branch.expect branch.output + } && + test_when_finished " + git worktree remove wt1 && + git worktree remove wt2 && + git branch -d shared + " && + git worktree add wt1 -b shared && + git worktree add wt2 -f shared && + # we test in both worktrees to ensure that works + # as expected with "first" and "next" worktrees + test_bisect_reset wt1 && + test_bisect_reset wt2 +' + test_expect_success 'bisect reset: back in the main branch' ' git bisect reset && echo "* main" > branch.expect && @@ -252,6 +305,124 @@ test_expect_success 'bisect skip: with commit both bad and skipped' ' grep $HASH4 my_bisect_log.txt ' +test_bisect_run_args () { + test_when_finished "rm -f run.sh actual" && + >actual && + cat >expect.args && + cat <&6 >expect.out && + cat <&7 >expect.err && + write_script run.sh <<-\EOF && + while test $# != 0 + do + echo "<$1>" && + shift + done >actual.args + EOF + + test_when_finished "git bisect reset" && + git bisect start && + git bisect good $HASH1 && + git bisect bad $HASH4 && + git bisect run ./run.sh $@ >actual.out.raw 2>actual.err && + # Prune just the log output + sed -n \ + -e '/^Author:/d' \ + -e '/^Date:/d' \ + -e '/^$/d' \ + -e '/^commit /d' \ + -e '/^ /d' \ + -e 'p' \ + <actual.out.raw >actual.out && + test_cmp expect.out actual.out && + test_cmp expect.err actual.err && + test_cmp expect.args actual.args +} + +test_expect_success 'git bisect run: args, stdout and stderr with no arguments' " + test_bisect_run_args <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR' + EOF_ARGS + running './run.sh' + $HASH4 is the first bad commit + bisect found first bad commit + EOF_OUT + EOF_ERR +" + +test_expect_success 'git bisect run: args, stdout and stderr: "--" argument' " + test_bisect_run_args -- <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR' + <--> + EOF_ARGS + running './run.sh' '--' + $HASH4 is the first bad commit + bisect found first bad commit + EOF_OUT + EOF_ERR +" + +test_expect_success 'git bisect run: args, stdout and stderr: "--log foo --no-log bar" arguments' " + test_bisect_run_args --log foo --no-log bar <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR' + <--log> + <foo> + <--no-log> + <bar> + EOF_ARGS + running './run.sh' '--log' 'foo' '--no-log' 'bar' + $HASH4 is the first bad commit + bisect found first bad commit + EOF_OUT + EOF_ERR +" + +test_expect_success 'git bisect run: args, stdout and stderr: "--bisect-start" argument' " + test_bisect_run_args --bisect-start <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR' + <--bisect-start> + EOF_ARGS + running './run.sh' '--bisect-start' + $HASH4 is the first bad commit + bisect found first bad commit + EOF_OUT + EOF_ERR +" + +test_expect_success 'git bisect run: negative exit code' " + write_script fail.sh <<-'EOF' && + exit 255 + EOF + cat <<-'EOF' >expect && + bisect run failed: exit code -1 from './fail.sh' is < 0 or >= 128 + EOF + test_when_finished 'git bisect reset' && + git bisect start && + git bisect good $HASH1 && + git bisect bad $HASH4 && + ! git bisect run ./fail.sh 2>err && + sed -En 's/.*(bisect.*code) (-?[0-9]+) (from.*)/\1 -1 \3/p' err >actual && + test_cmp expect actual +" + +test_expect_success 'git bisect run: unable to verify on good' " + write_script fail.sh <<-'EOF' && + head=\$(git rev-parse --verify HEAD) + good=\$(git rev-parse --verify $HASH1) + if test "\$head" = "\$good" + then + exit 255 + else + exit 127 + fi + EOF + cat <<-'EOF' >expect && + unable to verify './fail.sh' on good revision + EOF + test_when_finished 'git bisect reset' && + git bisect start && + git bisect good $HASH1 && + git bisect bad $HASH4 && + ! git bisect run ./fail.sh 2>err && + sed -n 's/.*\(unable to verify.*\)/\1/p' err >actual && + test_cmp expect actual +" + # We want to automatically find the commit that # added "Another" into hello. test_expect_success '"git bisect run" simple case' ' @@ -266,6 +437,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"' ' @@ -900,6 +1081,16 @@ test_expect_success 'bisect start with one term1 and term2' ' git bisect reset ' +test_expect_success 'bogus command does not start bisect' ' + git bisect reset && + test_must_fail git bisect --bisect-terms 1 2 2>out && + ! grep "You need to start" out && + test_must_fail git bisect --bisect-terms 2>out && + ! grep "You need to start" out && + grep "git bisect.*visualize" out && + git bisect reset +' + test_expect_success 'bisect replay with term1 and term2' ' git bisect replay log_to_replay.txt >bisect_result && grep "$HASH2 is the first term1 commit" bisect_result && @@ -990,7 +1181,6 @@ test_expect_success 'git bisect reset cleans bisection state properly' ' test_path_is_missing ".git/BISECT_LOG" && test_path_is_missing ".git/BISECT_RUN" && test_path_is_missing ".git/BISECT_TERMS" && - test_path_is_missing ".git/head-name" && test_path_is_missing ".git/BISECT_HEAD" && test_path_is_missing ".git/BISECT_START" ' @@ -1053,4 +1243,14 @@ test_expect_success 'bisect state output with bad commit' ' grep -F "waiting for good commit(s), bad commit known" output ' +test_expect_success 'verify correct error message' ' + git bisect reset && + git bisect start $HASH4 $HASH1 && + write_script test_script.sh <<-\EOF && + rm .git/BISECT* + EOF + test_must_fail git bisect run ./test_script.sh 2>error && + grep "git bisect good.*exited with error code" error +' + test_done diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh index a313849406..7ddbd96e58 100755 --- a/t/t6040-tracking-info.sh +++ b/t/t6040-tracking-info.sh @@ -5,6 +5,7 @@ test_description='remote tracking stats' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh advance () { diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh index 2500acc2ef..c9925edf20 100755 --- a/t/t6050-replace.sh +++ b/t/t6050-replace.sh @@ -62,59 +62,59 @@ HASH6= HASH7= test_expect_success 'set up buggy branch' ' - echo "line 1" >>hello && - echo "line 2" >>hello && - echo "line 3" >>hello && - echo "line 4" >>hello && - add_and_commit_file hello "4 lines" && - HASH1=$(git rev-parse --verify HEAD) && - echo "line BUG" >>hello && - echo "line 6" >>hello && - echo "line 7" >>hello && - echo "line 8" >>hello && - add_and_commit_file hello "4 more lines with a BUG" && - HASH2=$(git rev-parse --verify HEAD) && - echo "line 9" >>hello && - echo "line 10" >>hello && - add_and_commit_file hello "2 more lines" && - HASH3=$(git rev-parse --verify HEAD) && - echo "line 11" >>hello && - add_and_commit_file hello "1 more line" && - HASH4=$(git rev-parse --verify HEAD) && - sed -e "s/BUG/5/" hello >hello.new && - mv hello.new hello && - add_and_commit_file hello "BUG fixed" && - HASH5=$(git rev-parse --verify HEAD) && - echo "line 12" >>hello && - echo "line 13" >>hello && - add_and_commit_file hello "2 more lines" && - HASH6=$(git rev-parse --verify HEAD) && - echo "line 14" >>hello && - echo "line 15" >>hello && - echo "line 16" >>hello && - add_and_commit_file hello "again 3 more lines" && - HASH7=$(git rev-parse --verify HEAD) + echo "line 1" >>hello && + echo "line 2" >>hello && + echo "line 3" >>hello && + echo "line 4" >>hello && + add_and_commit_file hello "4 lines" && + HASH1=$(git rev-parse --verify HEAD) && + echo "line BUG" >>hello && + echo "line 6" >>hello && + echo "line 7" >>hello && + echo "line 8" >>hello && + add_and_commit_file hello "4 more lines with a BUG" && + HASH2=$(git rev-parse --verify HEAD) && + echo "line 9" >>hello && + echo "line 10" >>hello && + add_and_commit_file hello "2 more lines" && + HASH3=$(git rev-parse --verify HEAD) && + echo "line 11" >>hello && + add_and_commit_file hello "1 more line" && + HASH4=$(git rev-parse --verify HEAD) && + sed -e "s/BUG/5/" hello >hello.new && + mv hello.new hello && + add_and_commit_file hello "BUG fixed" && + HASH5=$(git rev-parse --verify HEAD) && + echo "line 12" >>hello && + echo "line 13" >>hello && + add_and_commit_file hello "2 more lines" && + HASH6=$(git rev-parse --verify HEAD) && + echo "line 14" >>hello && + echo "line 15" >>hello && + echo "line 16" >>hello && + add_and_commit_file hello "again 3 more lines" && + HASH7=$(git rev-parse --verify HEAD) ' test_expect_success 'replace the author' ' - git cat-file commit $HASH2 | grep "author A U Thor" && - R=$(git cat-file commit $HASH2 | sed -e "s/A U/O/" | git hash-object -t commit --stdin -w) && - git cat-file commit $R | grep "author O Thor" && - git update-ref refs/replace/$HASH2 $R && - git show HEAD~5 | grep "O Thor" && - git show $HASH2 | grep "O Thor" + git cat-file commit $HASH2 | grep "author A U Thor" && + R=$(git cat-file commit $HASH2 | sed -e "s/A U/O/" | git hash-object -t commit --stdin -w) && + git cat-file commit $R | grep "author O Thor" && + git update-ref refs/replace/$HASH2 $R && + git show HEAD~5 | grep "O Thor" && + git show $HASH2 | grep "O Thor" ' test_expect_success 'test --no-replace-objects option' ' - git cat-file commit $HASH2 | grep "author O Thor" && - git --no-replace-objects cat-file commit $HASH2 | grep "author A U Thor" && - git show $HASH2 | grep "O Thor" && - git --no-replace-objects show $HASH2 | grep "A U Thor" + git cat-file commit $HASH2 | grep "author O Thor" && + git --no-replace-objects cat-file commit $HASH2 | grep "author A U Thor" && + git show $HASH2 | grep "O Thor" && + git --no-replace-objects show $HASH2 | grep "A U Thor" ' test_expect_success 'test GIT_NO_REPLACE_OBJECTS env variable' ' - GIT_NO_REPLACE_OBJECTS=1 git cat-file commit $HASH2 | grep "author A U Thor" && - GIT_NO_REPLACE_OBJECTS=1 git show $HASH2 | grep "A U Thor" + GIT_NO_REPLACE_OBJECTS=1 git cat-file commit $HASH2 | grep "author A U Thor" && + GIT_NO_REPLACE_OBJECTS=1 git show $HASH2 | grep "A U Thor" ' test_expect_success 'test core.usereplacerefs config option' ' @@ -132,64 +132,64 @@ tagger T A Gger <> 0 +0000 EOF test_expect_success 'tag replaced commit' ' - git update-ref refs/tags/mytag $(git mktag <tag.sig) + git update-ref refs/tags/mytag $(git mktag <tag.sig) ' test_expect_success '"git fsck" works' ' - git fsck main >fsck_main.out && - test_i18ngrep "dangling commit $R" fsck_main.out && - test_i18ngrep "dangling tag $(git show-ref -s refs/tags/mytag)" fsck_main.out && - test -z "$(git fsck)" + git fsck main >fsck_main.out && + test_i18ngrep "dangling commit $R" fsck_main.out && + test_i18ngrep "dangling tag $(git show-ref -s refs/tags/mytag)" fsck_main.out && + test -z "$(git fsck)" ' test_expect_success 'repack, clone and fetch work' ' - git repack -a -d && - git clone --no-hardlinks . clone_dir && - ( - cd clone_dir && - git show HEAD~5 | grep "A U Thor" && - git show $HASH2 | grep "A U Thor" && - git cat-file commit $R && - git repack -a -d && - test_must_fail git cat-file commit $R && - git fetch ../ "refs/replace/*:refs/replace/*" && - git show HEAD~5 | grep "O Thor" && - git show $HASH2 | grep "O Thor" && - git cat-file commit $R - ) + git repack -a -d && + git clone --no-hardlinks . clone_dir && + ( + cd clone_dir && + git show HEAD~5 | grep "A U Thor" && + git show $HASH2 | grep "A U Thor" && + git cat-file commit $R && + git repack -a -d && + test_must_fail git cat-file commit $R && + git fetch ../ "refs/replace/*:refs/replace/*" && + git show HEAD~5 | grep "O Thor" && + git show $HASH2 | grep "O Thor" && + git cat-file commit $R + ) ' test_expect_success '"git replace" listing and deleting' ' - test "$HASH2" = "$(git replace -l)" && - test "$HASH2" = "$(git replace)" && - aa=${HASH2%??????????????????????????????????????} && - test "$HASH2" = "$(git replace --list "$aa*")" && - test_must_fail git replace -d $R && - test_must_fail git replace --delete && - test_must_fail git replace -l -d $HASH2 && - git replace -d $HASH2 && - git show $HASH2 | grep "A U Thor" && - test -z "$(git replace -l)" + test "$HASH2" = "$(git replace -l)" && + test "$HASH2" = "$(git replace)" && + aa=${HASH2%??????????????????????????????????????} && + test "$HASH2" = "$(git replace --list "$aa*")" && + test_must_fail git replace -d $R && + test_must_fail git replace --delete && + test_must_fail git replace -l -d $HASH2 && + git replace -d $HASH2 && + git show $HASH2 | grep "A U Thor" && + test -z "$(git replace -l)" ' test_expect_success '"git replace" replacing' ' - git replace $HASH2 $R && - git show $HASH2 | grep "O Thor" && - test_must_fail git replace $HASH2 $R && - git replace -f $HASH2 $R && - test_must_fail git replace -f && - test "$HASH2" = "$(git replace)" + git replace $HASH2 $R && + git show $HASH2 | grep "O Thor" && + test_must_fail git replace $HASH2 $R && + git replace -f $HASH2 $R && + test_must_fail git replace -f && + test "$HASH2" = "$(git replace)" ' test_expect_success '"git replace" resolves sha1' ' - SHORTHASH2=$(git rev-parse --short=8 $HASH2) && - git replace -d $SHORTHASH2 && - git replace $SHORTHASH2 $R && - git show $HASH2 | grep "O Thor" && - test_must_fail git replace $HASH2 $R && - git replace -f $HASH2 $R && - test_must_fail git replace --force && - test "$HASH2" = "$(git replace)" + SHORTHASH2=$(git rev-parse --short=8 $HASH2) && + git replace -d $SHORTHASH2 && + git replace $SHORTHASH2 $R && + git show $HASH2 | grep "O Thor" && + test_must_fail git replace $HASH2 $R && + git replace -f $HASH2 $R && + test_must_fail git replace --force && + test "$HASH2" = "$(git replace)" ' # This creates a side branch where the bug in H2 @@ -207,79 +207,79 @@ test_expect_success '"git replace" resolves sha1' ' # Then we replace H6 with P6. # test_expect_success 'create parallel branch without the bug' ' - git replace -d $HASH2 && - git show $HASH2 | grep "A U Thor" && - git checkout $HASH1 && - git cherry-pick $HASH2 && - git show $HASH5 | git apply && - git commit --amend -m "hello: 4 more lines WITHOUT the bug" hello && - PARA2=$(git rev-parse --verify HEAD) && - git cherry-pick $HASH3 && - PARA3=$(git rev-parse --verify HEAD) && - git cherry-pick $HASH4 && - PARA4=$(git rev-parse --verify HEAD) && - git cherry-pick $HASH6 && - PARA6=$(git rev-parse --verify HEAD) && - git replace $HASH6 $PARA6 && - git checkout main && - cur=$(git rev-parse --verify HEAD) && - test "$cur" = "$HASH7" && - git log --pretty=oneline | grep $PARA2 && - git remote add cloned ./clone_dir + git replace -d $HASH2 && + git show $HASH2 | grep "A U Thor" && + git checkout $HASH1 && + git cherry-pick $HASH2 && + git show $HASH5 | git apply && + git commit --amend -m "hello: 4 more lines WITHOUT the bug" hello && + PARA2=$(git rev-parse --verify HEAD) && + git cherry-pick $HASH3 && + PARA3=$(git rev-parse --verify HEAD) && + git cherry-pick $HASH4 && + PARA4=$(git rev-parse --verify HEAD) && + git cherry-pick $HASH6 && + PARA6=$(git rev-parse --verify HEAD) && + git replace $HASH6 $PARA6 && + git checkout main && + cur=$(git rev-parse --verify HEAD) && + test "$cur" = "$HASH7" && + git log --pretty=oneline | grep $PARA2 && + git remote add cloned ./clone_dir ' test_expect_success 'push to cloned repo' ' - git push cloned $HASH6^:refs/heads/parallel && - ( - cd clone_dir && - git checkout parallel && - git log --pretty=oneline | grep $PARA2 - ) + git push cloned $HASH6^:refs/heads/parallel && + ( + cd clone_dir && + git checkout parallel && + git log --pretty=oneline | grep $PARA2 + ) ' test_expect_success 'push branch with replacement' ' - git cat-file commit $PARA3 | grep "author A U Thor" && - S=$(git cat-file commit $PARA3 | sed -e "s/A U/O/" | git hash-object -t commit --stdin -w) && - git cat-file commit $S | grep "author O Thor" && - git replace $PARA3 $S && - git show $HASH6~2 | grep "O Thor" && - git show $PARA3 | grep "O Thor" && - git push cloned $HASH6^:refs/heads/parallel2 && - ( - cd clone_dir && - git checkout parallel2 && - git log --pretty=oneline | grep $PARA3 && - git show $PARA3 | grep "A U Thor" - ) + git cat-file commit $PARA3 | grep "author A U Thor" && + S=$(git cat-file commit $PARA3 | sed -e "s/A U/O/" | git hash-object -t commit --stdin -w) && + git cat-file commit $S | grep "author O Thor" && + git replace $PARA3 $S && + git show $HASH6~2 | grep "O Thor" && + git show $PARA3 | grep "O Thor" && + git push cloned $HASH6^:refs/heads/parallel2 && + ( + cd clone_dir && + git checkout parallel2 && + git log --pretty=oneline | grep $PARA3 && + git show $PARA3 | grep "A U Thor" + ) ' test_expect_success 'fetch branch with replacement' ' - git branch tofetch $HASH6 && - ( - cd clone_dir && - git fetch origin refs/heads/tofetch:refs/heads/parallel3 && - git log --pretty=oneline parallel3 >output.txt && - ! grep $PARA3 output.txt && - git show $PARA3 >para3.txt && - grep "A U Thor" para3.txt && - git fetch origin "refs/replace/*:refs/replace/*" && - git log --pretty=oneline parallel3 >output.txt && - grep $PARA3 output.txt && - git show $PARA3 >para3.txt && - grep "O Thor" para3.txt - ) + git branch tofetch $HASH6 && + ( + cd clone_dir && + git fetch origin refs/heads/tofetch:refs/heads/parallel3 && + git log --pretty=oneline parallel3 >output.txt && + ! grep $PARA3 output.txt && + git show $PARA3 >para3.txt && + grep "A U Thor" para3.txt && + git fetch origin "refs/replace/*:refs/replace/*" && + git log --pretty=oneline parallel3 >output.txt && + grep $PARA3 output.txt && + git show $PARA3 >para3.txt && + grep "O Thor" para3.txt + ) ' test_expect_success 'bisect and replacements' ' - git bisect start $HASH7 $HASH1 && - test "$PARA3" = "$(git rev-parse --verify HEAD)" && - git bisect reset && - GIT_NO_REPLACE_OBJECTS=1 git bisect start $HASH7 $HASH1 && - test "$HASH4" = "$(git rev-parse --verify HEAD)" && - git bisect reset && - git --no-replace-objects bisect start $HASH7 $HASH1 && - test "$HASH4" = "$(git rev-parse --verify HEAD)" && - git bisect reset + git bisect start $HASH7 $HASH1 && + test "$PARA3" = "$(git rev-parse --verify HEAD)" && + git bisect reset && + GIT_NO_REPLACE_OBJECTS=1 git bisect start $HASH7 $HASH1 && + test "$HASH4" = "$(git rev-parse --verify HEAD)" && + git bisect reset && + git --no-replace-objects bisect start $HASH7 $HASH1 && + test "$HASH4" = "$(git rev-parse --verify HEAD)" && + git bisect reset ' test_expect_success 'index-pack and replacements' ' diff --git a/t/t6060-merge-index.sh b/t/t6060-merge-index.sh index ed449abe55..1a8b64cce1 100755 --- a/t/t6060-merge-index.sh +++ b/t/t6060-merge-index.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='basic git merge-index / git-merge-one-file tests' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup diverging branches' ' 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/t6120-describe.sh b/t/t6120-describe.sh index 9a35e783a7..0a5c487540 100755 --- a/t/t6120-describe.sh +++ b/t/t6120-describe.sh @@ -85,6 +85,7 @@ check_describe e-1-gHASH --tags HEAD^^ check_describe c-2-gHASH --tags HEAD^^2 check_describe B --tags HEAD^^2^ check_describe e --tags HEAD^^^ +check_describe e --tags --exact-match HEAD^^^ check_describe heads/main --all HEAD check_describe tags/c-6-gHASH --all HEAD^ @@ -96,6 +97,13 @@ check_describe A-3-gHASH --long HEAD^^2 check_describe c-7-gHASH --tags check_describe e-3-gHASH --first-parent --tags +check_describe c-7-gHASH --tags --no-exact-match HEAD +check_describe e-3-gHASH --first-parent --tags --no-exact-match HEAD + +test_expect_success '--exact-match failure' ' + test_must_fail git describe --exact-match HEAD 2>err +' + test_expect_success 'describe --contains defaults to HEAD without commit-ish' ' echo "A^0" >expect && git checkout A && @@ -657,4 +665,10 @@ test_expect_success 'setup: describe commits with disjoint bases 2' ' check_describe -C disjoint2 "B-3-gHASH" HEAD +test_expect_success 'setup misleading taggerdates' ' + GIT_COMMITTER_DATE="2006-12-12 12:31" git tag -a -m "another tag" newer-tag-older-commit unique-file~1 +' + +check_describe newer-tag-older-commit~1 --contains unique-file~2 + test_done diff --git a/t/t6132-pathspec-exclude.sh b/t/t6132-pathspec-exclude.sh index cada952f9a..9fdafeb1e9 100755 --- a/t/t6132-pathspec-exclude.sh +++ b/t/t6132-pathspec-exclude.sh @@ -293,11 +293,7 @@ test_expect_success 'add with all negative' ' test_cmp expect actual ' -test_lazy_prereq ADD_I_USE_BUILTIN_OR_PERL ' - test_have_prereq ADD_I_USE_BUILTIN || test_have_prereq PERL -' - -test_expect_success ADD_I_USE_BUILTIN_OR_PERL 'add -p with all negative' ' +test_expect_success 'add -p with all negative' ' H=$(git rev-parse HEAD) && git reset --hard $H && git clean -f && diff --git a/t/t6135-pathspec-with-attrs.sh b/t/t6135-pathspec-with-attrs.sh index 457cc167c7..f70c395e75 100755 --- a/t/t6135-pathspec-with-attrs.sh +++ b/t/t6135-pathspec-with-attrs.sh @@ -65,7 +65,8 @@ test_expect_success 'setup .gitattributes' ' fileValue label=foo fileWrongLabel label☺ EOF - git add .gitattributes && + echo fileSetLabel label1 >sub/.gitattributes && + git add .gitattributes sub/.gitattributes && git commit -m "add attributes" ' @@ -78,7 +79,17 @@ test_expect_success 'check specific set attr' ' test_cmp expect actual ' -test_expect_success 'check specific set attr (2)' ' +test_expect_success 'check set attr with pathspec pattern' ' + echo sub/fileSetLabel >expect && + + git ls-files ":(attr:label)sub" >actual && + test_cmp expect actual && + + git ls-files ":(attr:label)sub/" >actual && + test_cmp expect actual +' + +test_expect_success 'check specific set attr in tree-ish' ' cat <<-\EOF >expect && HEAD:fileSetLabel HEAD:sub/fileSetLabel @@ -87,6 +98,16 @@ test_expect_success 'check specific set attr (2)' ' test_cmp expect actual ' +test_expect_success 'check specific set attr with pathspec pattern in tree-ish' ' + echo HEAD:sub/fileSetLabel >expect && + + git grep -l content HEAD ":(attr:label)sub" >actual && + test_cmp expect actual && + + git grep -l content HEAD ":(attr:label)sub/" >actual && + test_cmp expect actual +' + test_expect_success 'check specific unset attr' ' cat <<-\EOF >expect && fileUnsetLabel @@ -137,6 +158,7 @@ test_expect_success 'check unspecified attr' ' fileC fileNoLabel fileWrongLabel + sub/.gitattributes sub/fileA sub/fileAB sub/fileAC @@ -161,6 +183,7 @@ test_expect_success 'check unspecified attr (2)' ' HEAD:fileC HEAD:fileNoLabel HEAD:fileWrongLabel + HEAD:sub/.gitattributes HEAD:sub/fileA HEAD:sub/fileAB HEAD:sub/fileAC @@ -180,6 +203,7 @@ test_expect_success 'check multiple unspecified attr' ' fileC fileNoLabel fileWrongLabel + sub/.gitattributes sub/fileC sub/fileNoLabel sub/fileWrongLabel @@ -253,4 +277,22 @@ test_expect_success 'backslash cannot be used as a value' ' test_i18ngrep "for value matching" actual ' +test_expect_success 'reading from .gitattributes in a subdirectory (1)' ' + git ls-files ":(attr:label1)" >actual && + test_write_lines "sub/fileSetLabel" >expect && + test_cmp expect actual +' + +test_expect_success 'reading from .gitattributes in a subdirectory (2)' ' + git ls-files ":(attr:label1)sub" >actual && + test_write_lines "sub/fileSetLabel" >expect && + test_cmp expect actual +' + +test_expect_success 'reading from .gitattributes in a subdirectory (3)' ' + git ls-files ":(attr:label1)sub/" >actual && + test_write_lines "sub/fileSetLabel" >expect && + test_cmp expect actual +' + test_done diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh index dcaab7265f..7b943fd34c 100755 --- a/t/t6300-for-each-ref.sh +++ b/t/t6300-for-each-ref.sh @@ -6,6 +6,7 @@ test_description='for-each-ref test' . ./test-lib.sh +GNUPGHOME_NOT_USED=$GNUPGHOME . "$TEST_DIRECTORY"/lib-gpg.sh . "$TEST_DIRECTORY"/lib-terminal.sh @@ -448,6 +449,41 @@ test_expect_success 'exercise glob patterns with prefixes' ' ' cat >expected <<\EOF +refs/tags/bar +refs/tags/baz +refs/tags/testtag +EOF + +test_expect_success 'exercise patterns with prefix exclusions' ' + for tag in foo/one foo/two foo/three bar baz + do + git tag "$tag" || return 1 + done && + test_when_finished "git tag -d foo/one foo/two foo/three bar baz" && + git for-each-ref --format="%(refname)" \ + refs/tags/ --exclude=refs/tags/foo >actual && + test_cmp expected actual +' + +cat >expected <<\EOF +refs/tags/bar +refs/tags/baz +refs/tags/foo/one +refs/tags/testtag +EOF + +test_expect_success 'exercise patterns with pattern exclusions' ' + for tag in foo/one foo/two foo/three bar baz + do + git tag "$tag" || return 1 + done && + test_when_finished "git tag -d foo/one foo/two foo/three bar baz" && + git for-each-ref --format="%(refname)" \ + refs/tags/ --exclude="refs/tags/foo/t*" >actual && + test_cmp expected actual +' + +cat >expected <<\EOF 'refs/heads/main' 'refs/remotes/origin/main' 'refs/tags/testtag' @@ -561,6 +597,144 @@ test_expect_success 'color.ui=always does not override tty check' ' test_cmp expected.bare actual ' +test_expect_success 'setup for describe atom tests' ' + git init -b master describe-repo && + ( + cd describe-repo && + + test_commit --no-tag one && + git tag tagone && + + test_commit --no-tag two && + git tag -a -m "tag two" tagtwo + ) +' + +test_expect_success 'describe atom vs git describe' ' + ( + cd describe-repo && + + git for-each-ref --format="%(objectname)" \ + refs/tags/ >obj && + while read hash + do + if desc=$(git describe $hash) + then + : >expect-contains-good + else + : >expect-contains-bad + fi && + echo "$hash $desc" || return 1 + done <obj >expect && + test_path_exists expect-contains-good && + test_path_exists expect-contains-bad && + + git for-each-ref --format="%(objectname) %(describe)" \ + refs/tags/ >actual 2>err && + test_cmp expect actual && + test_must_be_empty err + ) +' + +test_expect_success 'describe:tags vs describe --tags' ' + ( + cd describe-repo && + git describe --tags >expect && + git for-each-ref --format="%(describe:tags)" \ + refs/heads/master >actual && + test_cmp expect actual + ) +' + +test_expect_success 'describe:abbrev=... vs describe --abbrev=...' ' + ( + cd describe-repo && + + # Case 1: We have commits between HEAD and the most + # recent tag reachable from it + test_commit --no-tag file && + git describe --abbrev=14 >expect && + git for-each-ref --format="%(describe:abbrev=14)" \ + refs/heads/master >actual && + test_cmp expect actual && + + # Make sure the hash used is atleast 14 digits long + sed -e "s/^.*-g\([0-9a-f]*\)$/\1/" <actual >hexpart && + test 15 -le $(wc -c <hexpart) && + + # Case 2: We have a tag at HEAD, describe directly gives + # the name of the tag + git tag -a -m tagged tagname && + git describe --abbrev=14 >expect && + git for-each-ref --format="%(describe:abbrev=14)" \ + refs/heads/master >actual && + test_cmp expect actual && + test tagname = $(cat actual) + ) +' + +test_expect_success 'describe:match=... vs describe --match ...' ' + ( + cd describe-repo && + git tag -a -m "tag foo" tag-foo && + git describe --match "*-foo" >expect && + git for-each-ref --format="%(describe:match="*-foo")" \ + refs/heads/master >actual && + test_cmp expect actual + ) +' + +test_expect_success 'describe:exclude:... vs describe --exclude ...' ' + ( + cd describe-repo && + git tag -a -m "tag bar" tag-bar && + git describe --exclude "*-bar" >expect && + git for-each-ref --format="%(describe:exclude="*-bar")" \ + refs/heads/master >actual && + test_cmp expect actual + ) +' + +test_expect_success 'deref with describe atom' ' + ( + cd describe-repo && + cat >expect <<-\EOF && + + tagname + tagname + tagname + + tagtwo + EOF + git for-each-ref --format="%(*describe)" >actual && + test_cmp expect actual + ) +' + +test_expect_success 'err on bad describe atom arg' ' + ( + cd describe-repo && + + # The bad arg is the only arg passed to describe atom + cat >expect <<-\EOF && + fatal: unrecognized %(describe) argument: baz + EOF + test_must_fail git for-each-ref --format="%(describe:baz)" \ + refs/heads/master 2>actual && + test_cmp expect actual && + + # The bad arg is in the middle of the option string + # passed to the describe atom + cat >expect <<-\EOF && + fatal: unrecognized %(describe) argument: qux=1,abbrev=14 + EOF + test_must_fail git for-each-ref \ + --format="%(describe:tags,qux=1,abbrev=14)" \ + ref/heads/master 2>actual && + test_cmp expect actual + ) +' + cat >expected <<\EOF heads/main tags/main @@ -606,7 +780,7 @@ test_expect_success 'create tag without tagger' ' git tag -a -m "Broken tag" taggerless && git tag -f taggerless $(git cat-file tag taggerless | sed -e "/^tagger /d" | - git hash-object --stdin -w -t tag) + git hash-object --literally --stdin -w -t tag) ' test_atom refs/tags/taggerless type 'commit' @@ -843,16 +1017,16 @@ test_expect_success 'Verify sorts with raw' ' test_expect_success 'Verify sorts with raw:size' ' cat >expected <<-EOF && refs/myblobs/blob8 - refs/myblobs/first refs/myblobs/blob7 - refs/heads/main refs/myblobs/blob4 refs/myblobs/blob1 refs/myblobs/blob2 refs/myblobs/blob3 refs/myblobs/blob5 refs/myblobs/blob6 + refs/myblobs/first refs/mytrees/first + refs/heads/main EOF git for-each-ref --format="%(refname)" --sort=raw:size \ refs/heads/main refs/myblobs/ refs/mytrees/first >actual && @@ -964,6 +1138,17 @@ test_expect_success 'for-each-ref --format compare with cat-file --batch' ' test_cmp expected actual ' +test_expect_success 'verify sorts with contents:size' ' + cat >expect <<-\EOF && + refs/heads/main + refs/heads/newtag + refs/heads/ambiguous + EOF + git for-each-ref --format="%(refname)" \ + --sort=contents:size refs/heads/ >actual && + test_cmp expect actual +' + test_expect_success 'set up multiple-sort tags' ' for when in 100000 200000 do @@ -1242,6 +1427,24 @@ test_expect_success 'basic atom: rest must fail' ' test_must_fail git for-each-ref --format="%(rest)" refs/heads/main ' +test_expect_success 'HEAD atom does not take arguments' ' + test_must_fail git for-each-ref --format="%(HEAD:foo)" 2>err && + echo "fatal: %(HEAD) does not take arguments" >expect && + test_cmp expect err +' + +test_expect_success 'subject atom rejects unknown arguments' ' + test_must_fail git for-each-ref --format="%(subject:foo)" 2>err && + echo "fatal: unrecognized %(subject) argument: foo" >expect && + test_cmp expect err +' + +test_expect_success 'refname atom rejects unknown arguments' ' + test_must_fail git for-each-ref --format="%(refname:foo)" 2>err && + echo "fatal: unrecognized %(refname) argument: foo" >expect && + test_cmp expect err +' + test_expect_success 'trailer parsing not fooled by --- line' ' git commit --allow-empty -F - <<-\EOF && this is the subject @@ -1356,6 +1559,14 @@ test_expect_success 'for-each-ref --ignore-case ignores case' ' test_cmp expect actual ' +test_expect_success 'for-each-ref --omit-empty works' ' + git for-each-ref --format="%(refname)" >actual && + test_line_count -gt 1 actual && + git for-each-ref --format="%(if:equals=refs/heads/main)%(refname)%(then)%(refname)%(end)" --omit-empty >actual && + echo refs/heads/main >expect && + test_cmp expect actual +' + test_expect_success 'for-each-ref --ignore-case works on multiple sort keys' ' # name refs numerically to avoid case-insensitive filesystem conflicts nr=0 && @@ -1406,4 +1617,282 @@ test_expect_success 'for-each-ref reports broken tags' ' refs/tags/broken-tag-* ' +test_expect_success 'set up tag with signature and no blank lines' ' + git tag -F - fake-sig-no-blanks <<-\EOF + this is the subject + -----BEGIN PGP SIGNATURE----- + not a real signature, but we just care about the + subject/body parsing. It is important here that + there are no blank lines in the signature. + -----END PGP SIGNATURE----- + EOF +' + +test_atom refs/tags/fake-sig-no-blanks contents:subject 'this is the subject' +test_atom refs/tags/fake-sig-no-blanks contents:body '' +test_atom refs/tags/fake-sig-no-blanks contents:signature "$sig" + +test_expect_success 'set up tag with CRLF signature' ' + append_cr <<-\EOF | + this is the subject + -----BEGIN PGP SIGNATURE----- + + not a real signature, but we just care about + the subject/body parsing. It is important here + that there is a blank line separating this + from the signature header. + -----END PGP SIGNATURE----- + EOF + git tag -F - --cleanup=verbatim fake-sig-crlf +' + +test_atom refs/tags/fake-sig-crlf contents:subject 'this is the subject' +test_atom refs/tags/fake-sig-crlf contents:body '' + +# CRLF is retained in the signature, so we have to pass our expected value +# through append_cr. But test_atom requires a shell string, which means command +# substitution, and the shell will strip trailing newlines from the output of +# the substitution. Hack around it by adding and then removing a dummy line. +sig_crlf="$(printf "%s" "$sig" | append_cr; echo dummy)" +sig_crlf=${sig_crlf%dummy} +test_atom refs/tags/fake-sig-crlf contents:signature "$sig_crlf" + +test_expect_success 'git for-each-ref --stdin: empty' ' + >in && + git for-each-ref --format="%(refname)" --stdin <in >actual && + git for-each-ref --format="%(refname)" >expect && + test_cmp expect actual +' + +test_expect_success 'git for-each-ref --stdin: fails if extra args' ' + >in && + test_must_fail git for-each-ref --format="%(refname)" \ + --stdin refs/heads/extra <in 2>err && + grep "unknown arguments supplied with --stdin" err +' + +test_expect_success 'git for-each-ref --stdin: matches' ' + cat >in <<-EOF && + refs/tags/multi* + refs/heads/amb* + EOF + + cat >expect <<-EOF && + refs/heads/ambiguous + refs/tags/multi-ref1-100000-user1 + refs/tags/multi-ref1-100000-user2 + refs/tags/multi-ref1-200000-user1 + refs/tags/multi-ref1-200000-user2 + refs/tags/multi-ref2-100000-user1 + refs/tags/multi-ref2-100000-user2 + refs/tags/multi-ref2-200000-user1 + refs/tags/multi-ref2-200000-user2 + refs/tags/multiline + EOF + + git for-each-ref --format="%(refname)" --stdin <in >actual && + test_cmp expect actual +' + +test_expect_success 'git for-each-ref with non-existing refs' ' + cat >in <<-EOF && + refs/heads/this-ref-does-not-exist + refs/tags/bogus + EOF + + git for-each-ref --format="%(refname)" --stdin <in >actual && + test_must_be_empty actual && + + xargs git for-each-ref --format="%(refname)" <in >actual && + test_must_be_empty actual +' + +GRADE_FORMAT="%(signature:grade)%0a%(signature:key)%0a%(signature:signer)%0a%(signature:fingerprint)%0a%(signature:primarykeyfingerprint)" +TRUSTLEVEL_FORMAT="%(signature:trustlevel)%0a%(signature:key)%0a%(signature:signer)%0a%(signature:fingerprint)%0a%(signature:primarykeyfingerprint)" + +test_expect_success GPG 'setup for signature atom using gpg' ' + git checkout -b signed && + + test_when_finished "test_unconfig commit.gpgSign" && + + echo "1" >file && + git add file && + test_tick && + git commit -S -m "file: 1" && + git tag first-signed && + + echo "2" >file && + test_tick && + git commit -a -m "file: 2" && + git tag second-unsigned && + + git config commit.gpgSign 1 && + echo "3" >file && + test_tick && + git commit -a --no-gpg-sign -m "file: 3" && + git tag third-unsigned && + + test_tick && + git rebase -f HEAD^^ && git tag second-signed HEAD^ && + git tag third-signed && + + echo "4" >file && + test_tick && + git commit -a -SB7227189 -m "file: 4" && + git tag fourth-signed && + + echo "5" >file && + test_tick && + git commit -a --no-gpg-sign -m "file: 5" && + git tag fifth-unsigned && + + echo "6" >file && + test_tick && + git commit -a --no-gpg-sign -m "file: 6" && + + test_tick && + git rebase -f HEAD^^ && + git tag fifth-signed HEAD^ && + git tag sixth-signed && + + echo "7" >file && + test_tick && + git commit -a --no-gpg-sign -m "file: 7" && + git tag seventh-unsigned +' + +test_expect_success GPGSSH 'setup for signature atom using ssh' ' + test_when_finished "test_unconfig gpg.format user.signingkey" && + + test_config gpg.format ssh && + test_config user.signingkey "${GPGSSH_KEY_PRIMARY}" && + echo "8" >file && + test_tick && + git add file && + git commit -S -m "file: 8" && + git tag eighth-signed-ssh +' + +test_expect_success GPG2 'bare signature atom' ' + git verify-commit first-signed 2>expect && + echo >>expect && + git for-each-ref refs/tags/first-signed \ + --format="%(signature)" >actual && + test_cmp expect actual +' + +test_expect_success GPG 'show good signature with custom format' ' + git verify-commit first-signed && + cat >expect <<-\EOF && + G + 13B6F51ECDDE430D + C O Mitter <committer@example.com> + 73D758744BE721698EC54E8713B6F51ECDDE430D + 73D758744BE721698EC54E8713B6F51ECDDE430D + EOF + git for-each-ref refs/tags/first-signed \ + --format="$GRADE_FORMAT" >actual && + test_cmp expect actual +' +test_expect_success GPGSSH 'show good signature with custom format + with ssh' ' + test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && + FINGERPRINT=$(ssh-keygen -lf "${GPGSSH_KEY_PRIMARY}" | awk "{print \$2;}") && + cat >expect.tmpl <<-\EOF && + G + FINGERPRINT + principal with number 1 + FINGERPRINT + + EOF + sed "s|FINGERPRINT|$FINGERPRINT|g" expect.tmpl >expect && + git for-each-ref refs/tags/eighth-signed-ssh \ + --format="$GRADE_FORMAT" >actual && + test_cmp expect actual +' + +test_expect_success GPG 'signature atom with grade option and bad signature' ' + git cat-file commit third-signed >raw && + sed -e "s/^file: 3/file: 3 forged/" raw >forged1 && + FORGED1=$(git hash-object -w -t commit forged1) && + git update-ref refs/tags/third-signed "$FORGED1" && + test_must_fail git verify-commit "$FORGED1" && + + cat >expect <<-\EOF && + B + 13B6F51ECDDE430D + C O Mitter <committer@example.com> + + + EOF + git for-each-ref refs/tags/third-signed \ + --format="$GRADE_FORMAT" >actual && + test_cmp expect actual +' + +test_expect_success GPG 'show untrusted signature with custom format' ' + cat >expect <<-\EOF && + U + 65A0EEA02E30CAD7 + Eris Discordia <discord@example.net> + F8364A59E07FFE9F4D63005A65A0EEA02E30CAD7 + D4BE22311AD3131E5EDA29A461092E85B7227189 + EOF + git for-each-ref refs/tags/fourth-signed \ + --format="$GRADE_FORMAT" >actual && + test_cmp expect actual +' + +test_expect_success GPG 'show untrusted signature with undefined trust level' ' + cat >expect <<-\EOF && + undefined + 65A0EEA02E30CAD7 + Eris Discordia <discord@example.net> + F8364A59E07FFE9F4D63005A65A0EEA02E30CAD7 + D4BE22311AD3131E5EDA29A461092E85B7227189 + EOF + git for-each-ref refs/tags/fourth-signed \ + --format="$TRUSTLEVEL_FORMAT" >actual && + test_cmp expect actual +' + +test_expect_success GPG 'show untrusted signature with ultimate trust level' ' + cat >expect <<-\EOF && + ultimate + 13B6F51ECDDE430D + C O Mitter <committer@example.com> + 73D758744BE721698EC54E8713B6F51ECDDE430D + 73D758744BE721698EC54E8713B6F51ECDDE430D + EOF + git for-each-ref refs/tags/sixth-signed \ + --format="$TRUSTLEVEL_FORMAT" >actual && + test_cmp expect actual +' + +test_expect_success GPG 'show unknown signature with custom format' ' + cat >expect <<-\EOF && + E + 13B6F51ECDDE430D + + + + EOF + GNUPGHOME="$GNUPGHOME_NOT_USED" git for-each-ref \ + refs/tags/sixth-signed --format="$GRADE_FORMAT" >actual && + test_cmp expect actual +' + +test_expect_success GPG 'show lack of signature with custom format' ' + cat >expect <<-\EOF && + N + + + + + EOF + git for-each-ref refs/tags/seventh-unsigned \ + --format="$GRADE_FORMAT" >actual && + test_cmp expect actual +' + test_done diff --git a/t/t6301-for-each-ref-errors.sh b/t/t6301-for-each-ref-errors.sh index 40edf9dab5..2667dd13fe 100755 --- a/t/t6301-for-each-ref-errors.sh +++ b/t/t6301-for-each-ref-errors.sh @@ -2,6 +2,7 @@ test_description='for-each-ref errors for broken refs' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh ZEROS=$ZERO_OID @@ -53,4 +54,18 @@ test_expect_success 'Missing objects are reported correctly' ' test_must_be_empty brief-err ' +test_expect_success 'ahead-behind requires an argument' ' + test_must_fail git for-each-ref \ + --format="%(ahead-behind)" 2>err && + echo "fatal: expected format: %(ahead-behind:<committish>)" >expect && + test_cmp expect err +' + +test_expect_success 'missing ahead-behind base' ' + test_must_fail git for-each-ref \ + --format="%(ahead-behind:refs/heads/missing)" 2>err && + echo "fatal: failed to find '\''refs/heads/missing'\''" >expect && + test_cmp expect err +' + test_done diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh index 1ce5f490e9..af223e44d6 100755 --- a/t/t6302-for-each-ref-filter.sh +++ b/t/t6302-for-each-ref-filter.sh @@ -45,6 +45,8 @@ test_expect_success 'check signed tags with --points-at' ' sed -e "s/Z$//" >expect <<-\EOF && refs/heads/side Z refs/tags/annotated-tag four + refs/tags/doubly-annotated-tag An annotated tag + refs/tags/doubly-signed-tag A signed tag refs/tags/four Z refs/tags/signed-tag four EOF diff --git a/t/t6401-merge-criss-cross.sh b/t/t6401-merge-criss-cross.sh index 9d5e992878..1962310408 100755 --- a/t/t6401-merge-criss-cross.sh +++ b/t/t6401-merge-criss-cross.sh @@ -8,6 +8,8 @@ test_description='Test criss-cross merge' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'prepare repository' ' diff --git a/t/t6406-merge-attr.sh b/t/t6406-merge-attr.sh index 8650a88c40..72f8c1722f 100755 --- a/t/t6406-merge-attr.sh +++ b/t/t6406-merge-attr.sh @@ -8,6 +8,7 @@ test_description='per path merge controlled by merge attribute' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' @@ -55,6 +56,12 @@ test_expect_success setup ' ) >"$ours+" cat "$ours+" >"$ours" rm -f "$ours+" + + if test -f ./please-abort + then + echo >>./please-abort killing myself + kill -9 $$ + fi exit "$exit" EOF chmod +x ./custom-merge @@ -161,6 +168,24 @@ test_expect_success 'custom merge backend' ' rm -f $o $a $b ' +test_expect_success !WINDOWS 'custom merge driver that is killed with a signal' ' + test_when_finished "rm -f output please-abort" && + + git reset --hard anchor && + git config --replace-all \ + merge.custom.driver "./custom-merge %O %A %B 0 %P" && + git config --replace-all \ + merge.custom.name "custom merge driver for testing" && + + >./please-abort && + echo "* merge=custom" >.gitattributes && + test_must_fail git merge main 2>err && + grep "^error: failed to execute internal merge" err && + git ls-files -u >output && + git diff --name-only HEAD >>output && + test_must_be_empty output +' + test_expect_success 'up-to-date merge without common ancestor' ' git init repo1 && git init repo2 && diff --git a/t/t6407-merge-binary.sh b/t/t6407-merge-binary.sh index e8a28717ce..0753fc95f4 100755 --- a/t/t6407-merge-binary.sh +++ b/t/t6407-merge-binary.sh @@ -5,6 +5,7 @@ test_description='ask merge-recursive to merge binary files' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t6415-merge-dir-to-symlink.sh b/t/t6415-merge-dir-to-symlink.sh index 2655e295f5..ae00492c76 100755 --- a/t/t6415-merge-dir-to-symlink.sh +++ b/t/t6415-merge-dir-to-symlink.sh @@ -4,6 +4,7 @@ test_description='merging when a directory was replaced with a symlink' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'create a commit where dir a/b changed to symlink' ' diff --git a/t/t6421-merge-partial-clone.sh b/t/t6421-merge-partial-clone.sh index 5413e5dd9d..711b709e75 100755 --- a/t/t6421-merge-partial-clone.sh +++ b/t/t6421-merge-partial-clone.sh @@ -155,7 +155,7 @@ test_setup_repo () { # Commit A: # (Rename leap->jump, rename basename/ -> basename/subdir/, rename dir/ # -> folder/, move e into newsubdir, add newfile.rs, remove f, modify -# both both Makefiles and jumps) +# both Makefiles and jumps) # general/{jump1_A, jump2_A} # basename/subdir/{numbers_A, sequence_A, values_A} # folder/subdir/{a,b,c,d,Makefile_TOP_A} @@ -343,7 +343,7 @@ test_expect_merge_algorithm failure success 'Objects downloaded when a directory # Commit A: # (Rename leap->jump, rename basename/ -> basename/subdir/, rename dir/ # -> folder/, move e into newsubdir, add newfile.rs, remove f, modify -# both both Makefiles and jumps) +# both Makefiles and jumps) # general/{jump1_A, jump2_A} # basename/subdir/{numbers_A, sequence_A, values_A} # folder/subdir/{a,b,c,d,Makefile_TOP_A} diff --git a/t/t6422-merge-rename-corner-cases.sh b/t/t6422-merge-rename-corner-cases.sh index 346253c7c8..076b6a74d5 100755 --- a/t/t6422-merge-rename-corner-cases.sh +++ b/t/t6422-merge-rename-corner-cases.sh @@ -1159,7 +1159,6 @@ test_conflicts_with_adds_and_renames() { # 4) There should not be any three~* files in the working # tree test_setup_collision_conflict () { - #test_expect_success "setup simple $sideL/$sideR conflict" ' git init simple_${sideL}_${sideR} && ( cd simple_${sideL}_${sideR} && @@ -1236,7 +1235,6 @@ test_conflicts_with_adds_and_renames() { fi && test_tick && git commit -m R ) - #' } test_expect_success "check simple $sideL/$sideR conflict" ' diff --git a/t/t6423-merge-rename-directories.sh b/t/t6423-merge-rename-directories.sh index a4941878fe..944de75b80 100755 --- a/t/t6423-merge-rename-directories.sh +++ b/t/t6423-merge-rename-directories.sh @@ -5304,6 +5304,62 @@ test_expect_merge_algorithm failure success '12l (A into B): Rename into each ot ) ' +# Testcase 12m, Directory rename, plus change of parent dir to symlink +# Commit O: dir/subdir/file +# Commit A: renamed-dir/subdir/file +# Commit B: dir/subdir +# In words: +# A: dir/subdir/ -> renamed-dir/subdir +# B: delete dir/subdir/file, add dir/subdir as symlink +# +# Expected: CONFLICT (rename/delete): renamed-dir/subdir/file, +# CONFLICT (file location): renamed-dir/subdir vs. dir/subdir +# CONFLICT (directory/file): renamed-dir/subdir symlink has +# renamed-dir/subdir in the way + +test_setup_12m () { + git init 12m && + ( + cd 12m && + + mkdir -p dir/subdir && + echo 1 >dir/subdir/file && + git add . && + git commit -m "O" && + + git branch O && + git branch A && + git branch B && + + git switch A && + git mv dir/ renamed-dir/ && + git add . && + git commit -m "A" && + + git switch B && + git rm dir/subdir/file && + mkdir dir && + ln -s /dev/null dir/subdir && + git add . && + git commit -m "B" + ) +} + +test_expect_merge_algorithm failure success '12m: Change parent of renamed-dir to symlink on other side' ' + test_setup_12m && + ( + cd 12m && + + git checkout -q A^0 && + + test_must_fail git -c merge.directoryRenames=conflict merge -s recursive B^0 && + + test_stdout_line_count = 3 git ls-files -s && + test_stdout_line_count = 2 ls -1 renamed-dir && + test_path_is_missing dir + ) +' + ########################################################################### # SECTION 13: Checking informational and conflict messages # diff --git a/t/t6426-merge-skip-unneeded-updates.sh b/t/t6426-merge-skip-unneeded-updates.sh index 2bb8e7f09b..fd21c1a486 100755 --- a/t/t6426-merge-skip-unneeded-updates.sh +++ b/t/t6426-merge-skip-unneeded-updates.sh @@ -378,42 +378,30 @@ test_expect_success '2c: Modify b & add c VS rename b->c' ' test_i18ngrep "CONFLICT (.*/add):" out && test_must_be_empty err && - # Make sure c WAS updated + git ls-files -s >index_files && + test_line_count = 2 index_files && + + # Ensure b was removed + test_path_is_missing b && + + # Make sure c WAS updated... test-tool chmtime --get c >new-mtime && - test $(cat old-mtime) -lt $(cat new-mtime) - - # FIXME: rename/add conflicts are horribly broken right now; - # when I get back to my patch series fixing it and - # rename/rename(2to1) conflicts to bring them in line with - # how add/add conflicts behave, then checks like the below - # could be added. But that patch series is waiting until - # the rename-directory-detection series lands, which this - # is part of. And in the mean time, I do not want to further - # enforce broken behavior. So for now, the main test is the - # one above that err is an empty file. - - #git ls-files -s >index_files && - #test_line_count = 2 index_files && - - #git rev-parse >actual :2:c :3:c && - #git rev-parse >expect A:b A:c && - #test_cmp expect actual && - - #git cat-file -p A:b >>merged && - #git cat-file -p A:c >>merge-me && - #>empty && - #test_must_fail git merge-file \ - # -L "Temporary merge branch 1" \ - # -L "" \ - # -L "Temporary merge branch 2" \ - # merged empty merge-me && - #sed -e "s/^\([<=>]\)/\1\1\1/" merged >merged-internal && - - #git hash-object c >actual && - #git hash-object merged-internal >expect && - #test_cmp expect actual && - - #test_path_is_missing b + test $(cat old-mtime) -lt $(cat new-mtime) && + + # ...and has correct index entries and working tree contents + git rev-parse >actual :2:c :3:c && + git rev-parse >expect A:c A:b && + test_cmp expect actual && + + git cat-file -p A:b >>merge-me && + git cat-file -p A:c >>merged && + >empty && + test_must_fail git merge-file \ + -L "HEAD" \ + -L "" \ + -L "B^0" \ + merged empty merge-me && + test_cmp merged c ) ' diff --git a/t/t6435-merge-sparse.sh b/t/t6435-merge-sparse.sh index fde4aa3cd1..78628fb248 100755 --- a/t/t6435-merge-sparse.sh +++ b/t/t6435-merge-sparse.sh @@ -3,6 +3,7 @@ test_description='merge with sparse files' TEST_CREATE_REPO_NO_TEMPLATE=1 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # test_file $filename $content diff --git a/t/t6439-merge-co-error-msgs.sh b/t/t6439-merge-co-error-msgs.sh index 52cf0c8769..0cbec57cda 100755 --- a/t/t6439-merge-co-error-msgs.sh +++ b/t/t6439-merge-co-error-msgs.sh @@ -5,6 +5,7 @@ test_description='unpack-trees error messages' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh index cd6c53360d..69509d0c11 100755 --- a/t/t6500-gc.sh +++ b/t/t6500-gc.sh @@ -202,6 +202,107 @@ test_expect_success 'one of gc.reflogExpire{Unreachable,}=never does not skip "e grep -E "^trace: (built-in|exec|run_command): git reflog expire --" trace.out ' +prepare_cruft_history () { + test_commit base && + + test_commit --no-tag foo && + test_commit --no-tag bar && + git reset HEAD^^ +} + +assert_no_cruft_packs () { + find .git/objects/pack -name "*.mtimes" >mtimes && + test_must_be_empty mtimes +} + +for argv in \ + "gc" \ + "-c gc.cruftPacks=true gc" \ + "-c gc.cruftPacks=false gc --cruft" +do + test_expect_success "git $argv generates a cruft pack" ' + test_when_finished "rm -fr repo" && + git init repo && + ( + cd repo && + + prepare_cruft_history && + git $argv && + + find .git/objects/pack -name "*.mtimes" >mtimes && + sed -e 's/\.mtimes$/\.pack/g' mtimes >packs && + + test_file_not_empty packs && + while read pack + do + test_path_is_file "$pack" || return 1 + done <packs + ) + ' +done + +for argv in \ + "gc --no-cruft" \ + "-c gc.cruftPacks=false gc" \ + "-c gc.cruftPacks=true gc --no-cruft" +do + test_expect_success "git $argv does not generate a cruft pack" ' + test_when_finished "rm -fr repo" && + git init repo && + ( + cd repo && + + prepare_cruft_history && + git $argv && + + assert_no_cruft_packs + ) + ' +done + +test_expect_success '--keep-largest-pack ignores cruft packs' ' + test_when_finished "rm -fr repo" && + git init repo && + ( + cd repo && + + # Generate a pack for reachable objects (of which there + # are 3), and one for unreachable objects (of which + # there are 6). + prepare_cruft_history && + git gc --cruft && + + mtimes="$(find .git/objects/pack -type f -name "pack-*.mtimes")" && + sz="$(test_file_size "${mtimes%.mtimes}.pack")" && + + # Ensure that the cruft pack gets removed (due to + # `--prune=now`) despite it being the largest pack. + git -c gc.bigPackThreshold=$sz gc --cruft --prune=now && + + assert_no_cruft_packs + ) +' + +test_expect_success 'gc.bigPackThreshold ignores cruft packs' ' + test_when_finished "rm -fr repo" && + git init repo && + ( + cd repo && + + # Generate a pack for reachable objects (of which there + # are 3), and one for unreachable objects (of which + # there are 6). + prepare_cruft_history && + git gc --cruft && + + # Ensure that the cruft pack gets removed (due to + # `--prune=now`) despite it being the largest pack. + git gc --cruft --prune=now --keep-largest-pack && + + assert_no_cruft_packs + ) +' + run_and_wait_for_auto_gc () { # We read stdout from gc for the side effect of waiting until the # background gc process exits, closing its fd 9. Furthermore, the diff --git a/t/t6501-freshen-objects.sh b/t/t6501-freshen-objects.sh index 10662456ae..4521508b83 100755 --- a/t/t6501-freshen-objects.sh +++ b/t/t6501-freshen-objects.sh @@ -28,6 +28,7 @@ test_description='check pruning of dependent objects' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # We care about reachability, so we do not want to use @@ -100,7 +101,7 @@ do ' test_expect_success "simultaneous gc ($title)" ' - git gc --prune=12.hours.ago + git gc --no-cruft --prune=12.hours.ago ' test_expect_success "finish writing out commit ($title)" ' @@ -130,7 +131,7 @@ do ' test_expect_success "simultaneous gc ($title)" ' - git gc --prune=12.hours.ago + git gc --no-cruft --prune=12.hours.ago ' # tree should have been refreshed by write-tree @@ -150,8 +151,8 @@ test_expect_success 'do not complain about existing broken links (commit)' ' some message EOF commit=$(git hash-object -t commit -w broken-commit) && - git gc -q 2>stderr && - verbose git cat-file -e $commit && + git gc --no-cruft -q 2>stderr && + git cat-file -e $commit && test_must_be_empty stderr ' @@ -160,7 +161,7 @@ test_expect_success 'do not complain about existing broken links (tree)' ' 100644 blob $(test_oid 003) foo EOF tree=$(git mktree --missing <broken-tree) && - git gc -q 2>stderr && + git gc --no-cruft -q 2>stderr && git cat-file -e $tree && test_must_be_empty stderr ' @@ -175,7 +176,7 @@ test_expect_success 'do not complain about existing broken links (tag)' ' this is a broken tag EOF tag=$(git hash-object -t tag -w broken-tag) && - git gc -q 2>stderr && + git gc --no-cruft -q 2>stderr && git cat-file -e $tag && test_must_be_empty stderr ' diff --git a/t/t6600-test-reach.sh b/t/t6600-test-reach.sh index 338a9c46a2..b330945f49 100755 --- a/t/t6600-test-reach.sh +++ b/t/t6600-test-reach.sh @@ -443,4 +443,173 @@ test_expect_success 'get_reachable_subset:none' ' test_all_modes get_reachable_subset ' +test_expect_success 'for-each-ref ahead-behind:linear' ' + cat >input <<-\EOF && + refs/heads/commit-1-1 + refs/heads/commit-1-3 + refs/heads/commit-1-5 + refs/heads/commit-1-8 + EOF + cat >expect <<-\EOF && + refs/heads/commit-1-1 0 8 + refs/heads/commit-1-3 0 6 + refs/heads/commit-1-5 0 4 + refs/heads/commit-1-8 0 1 + EOF + run_all_modes git for-each-ref \ + --format="%(refname) %(ahead-behind:commit-1-9)" --stdin +' + +test_expect_success 'for-each-ref ahead-behind:all' ' + cat >input <<-\EOF && + refs/heads/commit-1-1 + refs/heads/commit-2-4 + refs/heads/commit-4-2 + refs/heads/commit-4-4 + EOF + cat >expect <<-\EOF && + refs/heads/commit-1-1 0 24 + refs/heads/commit-2-4 0 17 + refs/heads/commit-4-2 0 17 + refs/heads/commit-4-4 0 9 + EOF + run_all_modes git for-each-ref \ + --format="%(refname) %(ahead-behind:commit-5-5)" --stdin +' + +test_expect_success 'for-each-ref ahead-behind:some' ' + cat >input <<-\EOF && + refs/heads/commit-1-1 + refs/heads/commit-5-3 + refs/heads/commit-4-8 + refs/heads/commit-9-9 + EOF + cat >expect <<-\EOF && + refs/heads/commit-1-1 0 53 + refs/heads/commit-4-8 8 30 + refs/heads/commit-5-3 0 39 + refs/heads/commit-9-9 27 0 + EOF + run_all_modes git for-each-ref \ + --format="%(refname) %(ahead-behind:commit-9-6)" --stdin +' + +test_expect_success 'for-each-ref ahead-behind:some, multibase' ' + cat >input <<-\EOF && + refs/heads/commit-1-1 + refs/heads/commit-5-3 + refs/heads/commit-7-8 + refs/heads/commit-4-8 + refs/heads/commit-9-9 + EOF + cat >expect <<-\EOF && + refs/heads/commit-1-1 0 53 0 53 + refs/heads/commit-4-8 8 30 0 22 + refs/heads/commit-5-3 0 39 0 39 + refs/heads/commit-7-8 14 12 8 6 + refs/heads/commit-9-9 27 0 27 0 + EOF + run_all_modes git for-each-ref \ + --format="%(refname) %(ahead-behind:commit-9-6) %(ahead-behind:commit-6-9)" \ + --stdin +' + +test_expect_success 'for-each-ref ahead-behind:none' ' + cat >input <<-\EOF && + refs/heads/commit-7-5 + refs/heads/commit-4-8 + refs/heads/commit-9-9 + EOF + cat >expect <<-\EOF && + refs/heads/commit-4-8 16 16 + refs/heads/commit-7-5 7 4 + refs/heads/commit-9-9 49 0 + EOF + run_all_modes git for-each-ref \ + --format="%(refname) %(ahead-behind:commit-8-4)" --stdin +' + +test_expect_success 'for-each-ref merged:linear' ' + cat >input <<-\EOF && + refs/heads/commit-1-1 + refs/heads/commit-1-3 + refs/heads/commit-1-5 + refs/heads/commit-1-8 + refs/heads/commit-2-1 + refs/heads/commit-5-1 + refs/heads/commit-9-1 + EOF + cat >expect <<-\EOF && + refs/heads/commit-1-1 + refs/heads/commit-1-3 + refs/heads/commit-1-5 + refs/heads/commit-1-8 + EOF + run_all_modes git for-each-ref --merged=commit-1-9 \ + --format="%(refname)" --stdin +' + +test_expect_success 'for-each-ref merged:all' ' + cat >input <<-\EOF && + refs/heads/commit-1-1 + refs/heads/commit-2-4 + refs/heads/commit-4-2 + refs/heads/commit-4-4 + EOF + cat >expect <<-\EOF && + refs/heads/commit-1-1 + refs/heads/commit-2-4 + refs/heads/commit-4-2 + refs/heads/commit-4-4 + EOF + run_all_modes git for-each-ref --merged=commit-5-5 \ + --format="%(refname)" --stdin +' + +test_expect_success 'for-each-ref ahead-behind:some' ' + cat >input <<-\EOF && + refs/heads/commit-1-1 + refs/heads/commit-5-3 + refs/heads/commit-4-8 + refs/heads/commit-9-9 + EOF + cat >expect <<-\EOF && + refs/heads/commit-1-1 + refs/heads/commit-5-3 + EOF + run_all_modes git for-each-ref --merged=commit-9-6 \ + --format="%(refname)" --stdin +' + +test_expect_success 'for-each-ref merged:some, multibase' ' + cat >input <<-\EOF && + refs/heads/commit-1-1 + refs/heads/commit-5-3 + refs/heads/commit-7-8 + refs/heads/commit-4-8 + refs/heads/commit-9-9 + EOF + cat >expect <<-\EOF && + refs/heads/commit-1-1 + refs/heads/commit-4-8 + refs/heads/commit-5-3 + EOF + run_all_modes git for-each-ref \ + --merged=commit-5-8 \ + --merged=commit-8-5 \ + --format="%(refname)" \ + --stdin +' + +test_expect_success 'for-each-ref merged:none' ' + cat >input <<-\EOF && + refs/heads/commit-7-5 + refs/heads/commit-4-8 + refs/heads/commit-9-9 + EOF + >expect && + run_all_modes git for-each-ref --merged=commit-8-4 \ + --format="%(refname)" --stdin +' + test_done diff --git a/t/t6700-tree-depth.sh b/t/t6700-tree-depth.sh new file mode 100755 index 0000000000..e410c41234 --- /dev/null +++ b/t/t6700-tree-depth.sh @@ -0,0 +1,93 @@ +#!/bin/sh + +test_description='handling of deep trees in various commands' +. ./test-lib.sh + +# We'll test against two depths here: a small one that will let us check the +# behavior of the config setting easily, and a large one that should be +# forbidden by default. Testing the default depth will let us know whether our +# default is enough to prevent segfaults on systems that run the tests. +small_depth=50 +big_depth=4100 + +small_ok="-c core.maxtreedepth=$small_depth" +small_no="-c core.maxtreedepth=$((small_depth-1))" + +# usage: mkdeep <name> <depth> +# Create a tag <name> containing a file whose path has depth <depth>. +# +# We'll use fast-import here for two reasons: +# +# 1. It's faster than creating $big_depth tree objects. +# +# 2. As we tighten tree limits, it's more likely to allow large sizes +# than trying to stuff a deep path into the index. +mkdeep () { + { + echo "commit refs/tags/$1" && + echo "committer foo <foo@example.com> 1234 -0000" && + echo "data <<EOF" && + echo "the commit message" && + echo "EOF" && + + printf 'M 100644 inline ' && + i=0 && + while test $i -lt $2 + do + printf 'a/' + i=$((i+1)) + done && + echo "file" && + + echo "data <<EOF" && + echo "the file contents" && + echo "EOF" && + echo + } | git fast-import +} + +test_expect_success 'create small tree' ' + mkdeep small $small_depth +' + +test_expect_success 'create big tree' ' + mkdeep big $big_depth +' + +test_expect_success 'limit recursion of git-archive' ' + git $small_ok archive small >/dev/null && + test_must_fail git $small_no archive small >/dev/null +' + +test_expect_success 'default limit for git-archive fails gracefully' ' + test_must_fail git archive big >/dev/null +' + +test_expect_success 'limit recursion of ls-tree -r' ' + git $small_ok ls-tree -r small && + test_must_fail git $small_no ls-tree -r small +' + +test_expect_success 'default limit for ls-tree fails gracefully' ' + test_must_fail git ls-tree -r big >/dev/null +' + +test_expect_success 'limit recursion of rev-list --objects' ' + git $small_ok rev-list --objects small >/dev/null && + test_must_fail git $small_no rev-list --objects small >/dev/null +' + +test_expect_success 'default limit for rev-list fails gracefully' ' + test_must_fail git rev-list --objects big >/dev/null +' + +test_expect_success 'limit recursion of diff-tree -r' ' + git $small_ok diff-tree -r $EMPTY_TREE small && + test_must_fail git $small_no diff-tree -r $EMPTY_TREE small +' + +test_expect_success 'default limit for diff-tree fails gracefully' ' + test_must_fail git diff-tree -r $EMPTY_TREE big +' + +test_done diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh index 8c37bceb33..f136ea76f7 100755 --- a/t/t7001-mv.sh +++ b/t/t7001-mv.sh @@ -4,6 +4,10 @@ test_description='git mv in subdirs' . ./test-lib.sh . "$TEST_DIRECTORY"/lib-diff-data.sh +index_at_path () { + git ls-files --format='%(objectmode) %(objectname) %(stage)' "$@" +} + test_expect_success 'mv -f refreshes updated index entry' ' echo test >bar && git add bar && @@ -60,8 +64,8 @@ test_expect_success 'checking the commit' ' test_expect_success 'mv --dry-run does not move file' ' git mv -n path0/COPYING MOVED && - test -f path0/COPYING && - test ! -f MOVED + test_path_is_file path0/COPYING && + test_path_is_missing MOVED ' test_expect_success 'checking -k on non-existing file' ' @@ -71,25 +75,25 @@ test_expect_success 'checking -k on non-existing file' ' test_expect_success 'checking -k on untracked file' ' >untracked1 && git mv -k untracked1 path0 && - test -f untracked1 && - test ! -f path0/untracked1 + test_path_is_file untracked1 && + test_path_is_missing path0/untracked1 ' test_expect_success 'checking -k on multiple untracked files' ' >untracked2 && git mv -k untracked1 untracked2 path0 && - test -f untracked1 && - test -f untracked2 && - test ! -f path0/untracked1 && - test ! -f path0/untracked2 + test_path_is_file untracked1 && + test_path_is_file untracked2 && + test_path_is_missing path0/untracked1 && + test_path_is_missing path0/untracked2 ' test_expect_success 'checking -f on untracked file with existing target' ' >path0/untracked1 && test_must_fail git mv -f untracked1 path0 && - test ! -f .git/index.lock && - test -f untracked1 && - test -f path0/untracked1 + test_path_is_missing .git/index.lock && + test_path_is_file untracked1 && + test_path_is_file path0/untracked1 ' # clean up the mess in case bad things happen @@ -170,6 +174,13 @@ test_expect_success 'do not move directory over existing directory' ' test_must_fail git mv path2 path0 ' +test_expect_success 'rename directory to non-existing directory' ' + mkdir dir-a && + >dir-a/f && + git add dir-a && + git mv dir-a non-existing-dir +' + test_expect_success 'move into "."' ' git mv path1/path2/ . ' @@ -187,7 +198,8 @@ test_expect_success "Michael Cassar's test case" ' git mv papers/unsorted/Thesis.pdf papers/all-papers/moo-blah.pdf && T=$(git write-tree) && - git ls-tree -r $T | verbose grep partA/outline.txt + git ls-tree -r $T >out && + grep partA/outline.txt out ' rm -fr papers partA path? @@ -215,8 +227,8 @@ test_expect_success 'absolute pathname' ' git add sub/file && git mv sub "$(pwd)/in" && - ! test -d sub && - test -d in && + test_path_is_missing sub && + test_path_is_dir in && git ls-files --error-unmatch in/file ) ' @@ -234,8 +246,8 @@ test_expect_success 'absolute pathname outside should fail' ' git add sub/file && test_must_fail git mv sub "$out/out" && - test -d sub && - ! test -d ../in && + test_path_is_dir sub && + test_path_is_missing ../in && git ls-files --error-unmatch sub/file ) ' @@ -260,12 +272,12 @@ test_expect_success 'git mv should not change sha1 of moved cache entry' ' git init && echo 1 >dirty && git add dirty && - entry="$(git ls-files --stage dirty | cut -f 1)" && + entry="$(index_at_path dirty)" && git mv dirty dirty2 && - test "$entry" = "$(git ls-files --stage dirty2 | cut -f 1)" && + test "$entry" = "$(index_at_path dirty2)" && echo 2 >dirty2 && git mv dirty2 dirty && - test "$entry" = "$(git ls-files --stage dirty | cut -f 1)" + test "$entry" = "$(index_at_path dirty)" ' rm -f dirty dirty2 @@ -295,8 +307,8 @@ test_expect_success 'git mv should overwrite symlink to a file' ' git add moved && test_must_fail git mv moved symlink && git mv -f moved symlink && - ! test -e moved && - test -f symlink && + test_path_is_missing moved && + test_path_is_file symlink && test "$(cat symlink)" = 1 && git update-index --refresh && git diff-files --quiet @@ -312,13 +324,13 @@ test_expect_success 'git mv should overwrite file with a symlink' ' git add moved && test_must_fail git mv symlink moved && git mv -f symlink moved && - ! test -e symlink && + test_path_is_missing symlink && git update-index --refresh && git diff-files --quiet ' test_expect_success SYMLINKS 'check moved symlink' ' - test -h moved + test_path_is_symlink moved ' rm -f moved symlink @@ -342,7 +354,7 @@ test_expect_success 'git mv cannot move a submodule in a file' ' ' test_expect_success 'git mv moves a submodule with a .git directory and no .gitmodules' ' - entry="$(git ls-files --stage sub | cut -f 1)" && + entry="$(index_at_path sub)" && git rm .gitmodules && ( cd sub && @@ -352,8 +364,8 @@ test_expect_success 'git mv moves a submodule with a .git directory and no .gitm ) && mkdir mod && git mv sub mod/sub && - ! test -e sub && - test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" && + test_path_is_missing sub && + test "$entry" = "$(index_at_path mod/sub)" && git -C mod/sub status && git update-index --refresh && git diff-files --quiet @@ -363,7 +375,7 @@ test_expect_success 'git mv moves a submodule with a .git directory and .gitmodu rm -rf mod && git reset --hard && git submodule update && - entry="$(git ls-files --stage sub | cut -f 1)" && + entry="$(index_at_path sub)" && ( cd sub && rm -f .git && @@ -372,8 +384,8 @@ test_expect_success 'git mv moves a submodule with a .git directory and .gitmodu ) && mkdir mod && git mv sub mod/sub && - ! test -e sub && - test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" && + test_path_is_missing sub && + test "$entry" = "$(index_at_path mod/sub)" && git -C mod/sub status && echo mod/sub >expected && git config -f .gitmodules submodule.sub.path >actual && @@ -386,11 +398,11 @@ test_expect_success 'git mv moves a submodule with gitfile' ' rm -rf mod && git reset --hard && git submodule update && - entry="$(git ls-files --stage sub | cut -f 1)" && + entry="$(index_at_path sub)" && mkdir mod && git -C mod mv ../sub/ . && - ! test -e sub && - test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" && + test_path_is_missing sub && + test "$entry" = "$(index_at_path mod/sub)" && git -C mod/sub status && echo mod/sub >expected && git config -f .gitmodules submodule.sub.path >actual && @@ -404,12 +416,12 @@ test_expect_success 'mv does not complain when no .gitmodules file is found' ' git reset --hard && git submodule update && git rm .gitmodules && - entry="$(git ls-files --stage sub | cut -f 1)" && + entry="$(index_at_path sub)" && mkdir mod && git mv sub mod/sub 2>actual.err && test_must_be_empty actual.err && - ! test -e sub && - test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" && + test_path_is_missing sub && + test "$entry" = "$(index_at_path mod/sub)" && git -C mod/sub status && git update-index --refresh && git diff-files --quiet @@ -420,17 +432,17 @@ test_expect_success 'mv will error out on a modified .gitmodules file unless sta git reset --hard && git submodule update && git config -f .gitmodules foo.bar true && - entry="$(git ls-files --stage sub | cut -f 1)" && + entry="$(index_at_path sub)" && mkdir mod && test_must_fail git mv sub mod/sub 2>actual.err && - test -s actual.err && - test -e sub && + test_file_not_empty actual.err && + test_path_exists sub && git diff-files --quiet -- sub && git add .gitmodules && git mv sub mod/sub 2>actual.err && test_must_be_empty actual.err && - ! test -e sub && - test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" && + test_path_is_missing sub && + test "$entry" = "$(index_at_path mod/sub)" && git -C mod/sub status && git update-index --refresh && git diff-files --quiet @@ -442,13 +454,13 @@ test_expect_success 'mv issues a warning when section is not found in .gitmodule git submodule update && git config -f .gitmodules --remove-section submodule.sub && git add .gitmodules && - entry="$(git ls-files --stage sub | cut -f 1)" && + entry="$(index_at_path sub)" && echo "warning: Could not find section in .gitmodules where path=sub" >expect.err && mkdir mod && git mv sub mod/sub 2>actual.err && test_cmp expect.err actual.err && - ! test -e sub && - test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" && + test_path_is_missing sub && + test "$entry" = "$(index_at_path mod/sub)" && git -C mod/sub status && git update-index --refresh && git diff-files --quiet @@ -460,7 +472,7 @@ test_expect_success 'mv --dry-run does not touch the submodule or .gitmodules' ' git submodule update && mkdir mod && git mv -n sub mod/sub 2>actual.err && - test -f sub/.git && + test_path_is_file sub/.git && git diff-index --exit-code HEAD && git update-index --refresh && git diff-files --quiet -- sub .gitmodules @@ -474,10 +486,10 @@ test_expect_success 'checking out a commit before submodule moved needs manual u git status -s sub2 >actual && echo "?? sub2/" >expected && test_cmp expected actual && - ! test -f sub/.git && - test -f sub2/.git && + test_path_is_missing sub/.git && + test_path_is_file sub2/.git && git submodule update && - test -f sub/.git && + test_path_is_file sub/.git && rm -rf sub2 && git diff-index --exit-code HEAD && git update-index --refresh && diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh index e18a218952..f6aebe92ff 100755 --- a/t/t7003-filter-branch.sh +++ b/t/t7003-filter-branch.sh @@ -49,7 +49,7 @@ test_expect_success 'result is really identical' ' test_expect_success 'rewrite bare repository identically' ' (git config core.bare true && cd .git && git filter-branch branch > filter-output 2>&1 && - ! fgrep fatal filter-output) + ! grep fatal filter-output) ' git config core.bare false test_expect_success 'result is really identical' ' @@ -506,7 +506,7 @@ test_expect_success 'rewrite repository including refs that point at non-commit git tag -a -m "tag to a tree" treetag $new_tree && git reset --hard HEAD && git filter-branch -f -- --all >filter-output 2>&1 && - ! fgrep fatal filter-output + ! grep fatal filter-output ' test_expect_success 'filter-branch handles ref deletion' ' diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 9aa1660651..e689db4292 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -792,6 +792,34 @@ test_expect_success 'annotations for blobs are empty' ' test_cmp expect actual ' +# Run this before doing any signing, so the test has the same results +# regardless of the GPG prereq. +test_expect_success 'git tag --format with ahead-behind' ' + test_when_finished git reset --hard tag-one-line && + git commit --allow-empty -m "left" && + git tag -a -m left tag-left && + git reset --hard HEAD~1 && + git commit --allow-empty -m "right" && + git tag -a -m left tag-right && + + # Use " !" at the end to demonstrate whitespace + # around empty ahead-behind token for tag-blob. + cat >expect <<-EOF && + refs/tags/tag-blob ! + refs/tags/tag-left 1 1 ! + refs/tags/tag-lines 0 1 ! + refs/tags/tag-one-line 0 1 ! + refs/tags/tag-right 0 0 ! + refs/tags/tag-zero-lines 0 1 ! + EOF + git tag -l --format="%(refname) %(ahead-behind:HEAD) !" >actual 2>err && + grep "refs/tags/tag" actual >actual.focus && + test_cmp expect actual.focus && + + # Error reported for tags that point to non-commits. + grep "error: object [0-9a-f]* is a blob, not a commit" err +' + # trying to verify annotated non-signed tags: test_expect_success GPG \ @@ -1843,6 +1871,23 @@ test_expect_success 'invalid sort parameter in configuratoin' ' test_must_fail git tag -l "foo*" ' +test_expect_success 'version sort handles empty value for versionsort.{prereleaseSuffix,suffix}' ' + cp .git/config .git/config.orig && + test_when_finished mv .git/config.orig .git/config && + + cat >>.git/config <<-\EOF && + [versionsort] + prereleaseSuffix + suffix + EOF + cat >expect <<-\EOF && + error: missing value for '\''versionsort.suffix'\'' + error: missing value for '\''versionsort.prereleasesuffix'\'' + EOF + git tag -l --sort=version:refname 2>actual && + test_cmp expect actual +' + test_expect_success 'version sort with prerelease reordering' ' test_config versionsort.prereleaseSuffix -rc && git tag foo1.6-rc1 && @@ -2001,6 +2046,22 @@ test_expect_success '--format should list tags as per format given' ' test_cmp expect actual ' +test_expect_success '--format --omit-empty works' ' + cat >expect <<-\EOF && + refname : refs/tags/v1.0 + + refname : refs/tags/v1.1.3 + EOF + git tag -l --format="%(if:notequals=refs/tags/v1.0.1)%(refname)%(then)refname : %(refname)%(end)" "v1*" >actual && + test_cmp expect actual && + cat >expect <<-\EOF && + refname : refs/tags/v1.0 + refname : refs/tags/v1.1.3 + EOF + git tag -l --omit-empty --format="%(if:notequals=refs/tags/v1.0.1)%(refname)%(then)refname : %(refname)%(end)" "v1*" >actual && + test_cmp expect actual +' + test_expect_success 'git tag -l with --format="%(rest)" must fail' ' test_must_fail git tag -l --format="%(rest)" "v1*" ' @@ -2127,4 +2188,23 @@ test_expect_success 'Does --[no-]contains stop at commits? Yes!' ' test_cmp expected actual ' +test_expect_success 'If tag is created then tag message file is unlinked' ' + test_when_finished "git tag -d foo" && + write_script fakeeditor <<-\EOF && + echo Message >.git/TAG_EDITMSG + EOF + GIT_EDITOR=./fakeeditor git tag -a foo && + test_path_is_missing .git/TAG_EDITMSG +' + +test_expect_success 'If tag cannot be created then tag message file is not unlinked' ' + test_when_finished "git tag -d foo/bar && rm .git/TAG_EDITMSG" && + write_script fakeeditor <<-\EOF && + echo Message >.git/TAG_EDITMSG + EOF + git tag foo/bar && + test_must_fail env GIT_EDITOR=./fakeeditor git tag -a foo && + test_path_exists .git/TAG_EDITMSG +' + test_done diff --git a/t/t7030-verify-tag.sh b/t/t7030-verify-tag.sh index 10faa64515..6f526c37c2 100755 --- a/t/t7030-verify-tag.sh +++ b/t/t7030-verify-tag.sh @@ -115,7 +115,7 @@ test_expect_success GPGSM 'verify and show signatures x509 with high minTrustLev test_expect_success GPG 'detect fudged signature' ' git cat-file tag seventh-signed >raw && - sed -e "/^tag / s/seventh/7th forged/" raw >forged1 && + sed -e "/^tag / s/seventh/7th-forged/" raw >forged1 && git hash-object -w -t tag forged1 >forged1.tag && test_must_fail git verify-tag $(cat forged1.tag) 2>actual1 && grep "BAD signature from" actual1 && diff --git a/t/t7031-verify-tag-signed-ssh.sh b/t/t7031-verify-tag-signed-ssh.sh index 1cb36b9ab8..20913b3713 100755 --- a/t/t7031-verify-tag-signed-ssh.sh +++ b/t/t7031-verify-tag-signed-ssh.sh @@ -125,7 +125,7 @@ test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'verify-tag failes with tag date ou test_expect_success GPGSSH 'detect fudged ssh signature' ' test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && git cat-file tag seventh-signed >raw && - sed -e "/^tag / s/seventh/7th forged/" raw >forged1 && + sed -e "/^tag / s/seventh/7th-forged/" raw >forged1 && git hash-object -w -t tag forged1 >forged1.tag && test_must_fail git verify-tag $(cat forged1.tag) 2>actual1 && grep "${GPGSSH_BAD_SIGNATURE}" actual1 && @@ -200,4 +200,14 @@ test_expect_success GPGSSH 'verifying a forged tag with --format should fail sil test_must_be_empty actual-forged ' +test_expect_success GPGSSH 'rev-list --format=%G' ' + test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && + git rev-list -1 --format="%G? %H" sixth-signed >actual && + cat >expect <<-EOF && + commit $(git rev-parse sixth-signed^0) + G $(git rev-parse sixth-signed^0) + EOF + test_cmp expect actual +' + test_done diff --git a/t/t7101-reset-empty-subdirs.sh b/t/t7101-reset-empty-subdirs.sh index 638bb04e21..89cf98b30c 100755 --- a/t/t7101-reset-empty-subdirs.sh +++ b/t/t7101-reset-empty-subdirs.sh @@ -10,57 +10,57 @@ TEST_PASSES_SANITIZE_LEAK=true . "$TEST_DIRECTORY"/lib-diff-data.sh test_expect_success 'creating initial files' ' - mkdir path0 && - COPYING_test_data >path0/COPYING && - git add path0/COPYING && - git commit -m add -a + mkdir path0 && + COPYING_test_data >path0/COPYING && + git add path0/COPYING && + git commit -m add -a ' test_expect_success 'creating second files' ' - mkdir path1 && - mkdir path1/path2 && - COPYING_test_data >path1/path2/COPYING && - COPYING_test_data >path1/COPYING && - COPYING_test_data >COPYING && - COPYING_test_data >path0/COPYING-TOO && - git add path1/path2/COPYING && - git add path1/COPYING && - git add COPYING && - git add path0/COPYING-TOO && - git commit -m change -a + mkdir path1 && + mkdir path1/path2 && + COPYING_test_data >path1/path2/COPYING && + COPYING_test_data >path1/COPYING && + COPYING_test_data >COPYING && + COPYING_test_data >path0/COPYING-TOO && + git add path1/path2/COPYING && + git add path1/COPYING && + git add COPYING && + git add path0/COPYING-TOO && + git commit -m change -a ' test_expect_success 'resetting tree HEAD^' ' - git reset --hard HEAD^ + git reset --hard HEAD^ ' test_expect_success 'checking initial files exist after rewind' ' - test -d path0 && - test -f path0/COPYING + test -d path0 && + test -f path0/COPYING ' test_expect_success 'checking lack of path1/path2/COPYING' ' - ! test -f path1/path2/COPYING + ! test -f path1/path2/COPYING ' test_expect_success 'checking lack of path1/COPYING' ' - ! test -f path1/COPYING + ! test -f path1/COPYING ' test_expect_success 'checking lack of COPYING' ' - ! test -f COPYING + ! test -f COPYING ' test_expect_success 'checking checking lack of path1/COPYING-TOO' ' - ! test -f path0/COPYING-TOO + ! test -f path0/COPYING-TOO ' test_expect_success 'checking lack of path1/path2' ' - ! test -d path1/path2 + ! test -d path1/path2 ' test_expect_success 'checking lack of path1' ' - ! test -d path1 + ! test -d path1 ' test_done diff --git a/t/t7102-reset.sh b/t/t7102-reset.sh index 22477f3a31..4287863ae6 100755 --- a/t/t7102-reset.sh +++ b/t/t7102-reset.sh @@ -71,6 +71,16 @@ check_changes () { done | test_cmp .cat_expect - } +# no negated form for various type of resets +for opt in soft mixed hard merge keep +do + test_expect_success "no 'git reset --no-$opt'" ' + test_when_finished "rm -f err" && + test_must_fail git reset --no-$opt 2>err && + grep "error: unknown option .no-$opt." err + ' +done + test_expect_success 'reset --hard message' ' hex=$(git log -1 --format="%h") && git reset --hard >.actual && diff --git a/t/t7103-reset-bare.sh b/t/t7103-reset-bare.sh index a60153f9f3..18bbd9975e 100755 --- a/t/t7103-reset-bare.sh +++ b/t/t7103-reset-bare.sh @@ -63,7 +63,7 @@ test_expect_success '"mixed" reset is not allowed in bare' ' test_must_fail git reset --mixed HEAD^ ' -test_expect_success !SANITIZE_LEAK '"soft" reset is allowed in bare' ' +test_expect_success '"soft" reset is allowed in bare' ' git reset --soft HEAD^ && git show --pretty=format:%s >out && echo one >expect && diff --git a/t/t7105-reset-patch.sh b/t/t7105-reset-patch.sh index fc2a6cf5c7..9b46da7aaa 100755 --- a/t/t7105-reset-patch.sh +++ b/t/t7105-reset-patch.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='git reset --patch' + +TEST_PASSES_SANITIZE_LEAK=true . ./lib-patch-mode.sh test_expect_success PERL 'setup' ' diff --git a/t/t7106-reset-unborn-branch.sh b/t/t7106-reset-unborn-branch.sh index ecb85c3b82..a0b67a0b84 100755 --- a/t/t7106-reset-unborn-branch.sh +++ b/t/t7106-reset-unborn-branch.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='git reset should work on unborn branch' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t7107-reset-pathspec-file.sh b/t/t7107-reset-pathspec-file.sh index 523efbecde..af5ea406db 100755 --- a/t/t7107-reset-pathspec-file.sh +++ b/t/t7107-reset-pathspec-file.sh @@ -2,6 +2,7 @@ test_description='reset --pathspec-from-file' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_tick diff --git a/t/t7110-reset-merge.sh b/t/t7110-reset-merge.sh index eb881be95b..772480a345 100755 --- a/t/t7110-reset-merge.sh +++ b/t/t7110-reset-merge.sh @@ -9,17 +9,17 @@ TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' - printf "line %d\n" 1 2 3 >file1 && - cat file1 >file2 && - git add file1 file2 && - test_tick && - git commit -m "Initial commit" && - git tag initial && - echo line 4 >>file1 && - cat file1 >file2 && - test_tick && - git commit -m "add line 4 to file1" file1 && - git tag second + printf "line %d\n" 1 2 3 >file1 && + cat file1 >file2 && + git add file1 file2 && + test_tick && + git commit -m "Initial commit" && + git tag initial && + echo line 4 >>file1 && + cat file1 >file2 && + test_tick && + git commit -m "add line 4 to file1" file1 && + git tag second ' # The next test will test the following: @@ -29,19 +29,19 @@ test_expect_success setup ' # file1: C C C D --merge D D D # file2: C D D D --merge C D D test_expect_success 'reset --merge is ok with changes in file it does not touch' ' - git reset --merge HEAD^ && - ! grep 4 file1 && - grep 4 file2 && - test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" && - test -z "$(git diff --cached)" + git reset --merge HEAD^ && + ! grep 4 file1 && + grep 4 file2 && + test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" && + test -z "$(git diff --cached)" ' test_expect_success 'reset --merge is ok when switching back' ' - git reset --merge second && - grep 4 file1 && - grep 4 file2 && - test "$(git rev-parse HEAD)" = "$(git rev-parse second)" && - test -z "$(git diff --cached)" + git reset --merge second && + grep 4 file1 && + grep 4 file2 && + test "$(git rev-parse HEAD)" = "$(git rev-parse second)" && + test -z "$(git diff --cached)" ' # The next test will test the following: @@ -51,21 +51,21 @@ test_expect_success 'reset --merge is ok when switching back' ' # file1: C C C D --keep D D D # file2: C D D D --keep C D D test_expect_success 'reset --keep is ok with changes in file it does not touch' ' - git reset --hard second && - cat file1 >file2 && - git reset --keep HEAD^ && - ! grep 4 file1 && - grep 4 file2 && - test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" && - test -z "$(git diff --cached)" + git reset --hard second && + cat file1 >file2 && + git reset --keep HEAD^ && + ! grep 4 file1 && + grep 4 file2 && + test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" && + test -z "$(git diff --cached)" ' test_expect_success 'reset --keep is ok when switching back' ' - git reset --keep second && - grep 4 file1 && - grep 4 file2 && - test "$(git rev-parse HEAD)" = "$(git rev-parse second)" && - test -z "$(git diff --cached)" + git reset --keep second && + grep 4 file1 && + grep 4 file2 && + test "$(git rev-parse HEAD)" = "$(git rev-parse second)" && + test -z "$(git diff --cached)" ' # The next test will test the following: @@ -75,28 +75,28 @@ test_expect_success 'reset --keep is ok when switching back' ' # file1: B B C D --merge D D D # file2: C D D D --merge C D D test_expect_success 'reset --merge discards changes added to index (1)' ' - git reset --hard second && - cat file1 >file2 && - echo "line 5" >> file1 && - git add file1 && - git reset --merge HEAD^ && - ! grep 4 file1 && - ! grep 5 file1 && - grep 4 file2 && - test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" && - test -z "$(git diff --cached)" + git reset --hard second && + cat file1 >file2 && + echo "line 5" >> file1 && + git add file1 && + git reset --merge HEAD^ && + ! grep 4 file1 && + ! grep 5 file1 && + grep 4 file2 && + test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" && + test -z "$(git diff --cached)" ' test_expect_success 'reset --merge is ok again when switching back (1)' ' - git reset --hard initial && - echo "line 5" >> file2 && - git add file2 && - git reset --merge second && - ! grep 4 file2 && - ! grep 5 file1 && - grep 4 file1 && - test "$(git rev-parse HEAD)" = "$(git rev-parse second)" && - test -z "$(git diff --cached)" + git reset --hard initial && + echo "line 5" >> file2 && + git add file2 && + git reset --merge second && + ! grep 4 file2 && + ! grep 5 file1 && + grep 4 file1 && + test "$(git rev-parse HEAD)" = "$(git rev-parse second)" && + test -z "$(git diff --cached)" ' # The next test will test the following: @@ -105,10 +105,10 @@ test_expect_success 'reset --merge is ok again when switching back (1)' ' # ---------------------------------------------------- # file1: B B C D --keep (disallowed) test_expect_success 'reset --keep fails with changes in index in files it touches' ' - git reset --hard second && - echo "line 5" >> file1 && - git add file1 && - test_must_fail git reset --keep HEAD^ + git reset --hard second && + echo "line 5" >> file1 && + git add file1 && + test_must_fail git reset --keep HEAD^ ' # The next test will test the following: @@ -118,23 +118,23 @@ test_expect_success 'reset --keep fails with changes in index in files it touche # file1: C C C D --merge D D D # file2: C C D D --merge D D D test_expect_success 'reset --merge discards changes added to index (2)' ' - git reset --hard second && - echo "line 4" >> file2 && - git add file2 && - git reset --merge HEAD^ && - ! grep 4 file2 && - test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" && - test -z "$(git diff)" && - test -z "$(git diff --cached)" + git reset --hard second && + echo "line 4" >> file2 && + git add file2 && + git reset --merge HEAD^ && + ! grep 4 file2 && + test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" && + test -z "$(git diff)" && + test -z "$(git diff --cached)" ' test_expect_success 'reset --merge is ok again when switching back (2)' ' - git reset --hard initial && - git reset --merge second && - ! grep 4 file2 && - grep 4 file1 && - test "$(git rev-parse HEAD)" = "$(git rev-parse second)" && - test -z "$(git diff --cached)" + git reset --hard initial && + git reset --merge second && + ! grep 4 file2 && + grep 4 file1 && + test "$(git rev-parse HEAD)" = "$(git rev-parse second)" && + test -z "$(git diff --cached)" ' # The next test will test the following: @@ -144,21 +144,21 @@ test_expect_success 'reset --merge is ok again when switching back (2)' ' # file1: C C C D --keep D D D # file2: C C D D --keep C D D test_expect_success 'reset --keep keeps changes it does not touch' ' - git reset --hard second && - echo "line 4" >> file2 && - git add file2 && - git reset --keep HEAD^ && - grep 4 file2 && - test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" && - test -z "$(git diff --cached)" + git reset --hard second && + echo "line 4" >> file2 && + git add file2 && + git reset --keep HEAD^ && + grep 4 file2 && + test "$(git rev-parse HEAD)" = "$(git rev-parse initial)" && + test -z "$(git diff --cached)" ' test_expect_success 'reset --keep keeps changes when switching back' ' - git reset --keep second && - grep 4 file2 && - grep 4 file1 && - test "$(git rev-parse HEAD)" = "$(git rev-parse second)" && - test -z "$(git diff --cached)" + git reset --keep second && + grep 4 file2 && + grep 4 file1 && + test "$(git rev-parse HEAD)" = "$(git rev-parse second)" && + test -z "$(git diff --cached)" ' # The next test will test the following: @@ -167,14 +167,14 @@ test_expect_success 'reset --keep keeps changes when switching back' ' # ---------------------------------------------------- # file1: A B B C --merge (disallowed) test_expect_success 'reset --merge fails with changes in file it touches' ' - git reset --hard second && - echo "line 5" >> file1 && - test_tick && - git commit -m "add line 5" file1 && - sed -e "s/line 1/changed line 1/" <file1 >file3 && - mv file3 file1 && - test_must_fail git reset --merge HEAD^ 2>err.log && - grep file1 err.log | grep "not uptodate" + git reset --hard second && + echo "line 5" >> file1 && + test_tick && + git commit -m "add line 5" file1 && + sed -e "s/line 1/changed line 1/" <file1 >file3 && + mv file3 file1 && + test_must_fail git reset --merge HEAD^ 2>err.log && + grep file1 err.log | grep "not uptodate" ' # The next test will test the following: @@ -183,36 +183,36 @@ test_expect_success 'reset --merge fails with changes in file it touches' ' # ---------------------------------------------------- # file1: A B B C --keep (disallowed) test_expect_success 'reset --keep fails with changes in file it touches' ' - git reset --hard second && - echo "line 5" >> file1 && - test_tick && - git commit -m "add line 5" file1 && - sed -e "s/line 1/changed line 1/" <file1 >file3 && - mv file3 file1 && - test_must_fail git reset --keep HEAD^ 2>err.log && - grep file1 err.log | grep "not uptodate" + git reset --hard second && + echo "line 5" >> file1 && + test_tick && + git commit -m "add line 5" file1 && + sed -e "s/line 1/changed line 1/" <file1 >file3 && + mv file3 file1 && + test_must_fail git reset --keep HEAD^ 2>err.log && + grep file1 err.log | grep "not uptodate" ' test_expect_success 'setup 3 different branches' ' - git reset --hard second && - git branch branch1 && - git branch branch2 && - git branch branch3 && - git checkout branch1 && - echo "line 5 in branch1" >> file1 && - test_tick && - git commit -a -m "change in branch1" && - git checkout branch2 && - echo "line 5 in branch2" >> file1 && - test_tick && - git commit -a -m "change in branch2" && - git tag third && - git checkout branch3 && - echo a new file >file3 && - rm -f file1 && - git add file3 && - test_tick && - git commit -a -m "change in branch3" + git reset --hard second && + git branch branch1 && + git branch branch2 && + git branch branch3 && + git checkout branch1 && + echo "line 5 in branch1" >> file1 && + test_tick && + git commit -a -m "change in branch1" && + git checkout branch2 && + echo "line 5 in branch2" >> file1 && + test_tick && + git commit -a -m "change in branch2" && + git tag third && + git checkout branch3 && + echo a new file >file3 && + rm -f file1 && + git add file3 && + test_tick && + git commit -a -m "change in branch3" ' # The next test will test the following: @@ -221,12 +221,12 @@ test_expect_success 'setup 3 different branches' ' # ---------------------------------------------------- # file1: X U B C --merge C C C test_expect_success '"reset --merge HEAD^" is ok with pending merge' ' - git checkout third && - test_must_fail git merge branch1 && - git reset --merge HEAD^ && - test "$(git rev-parse HEAD)" = "$(git rev-parse second)" && - test -z "$(git diff --cached)" && - test -z "$(git diff)" + git checkout third && + test_must_fail git merge branch1 && + git reset --merge HEAD^ && + test "$(git rev-parse HEAD)" = "$(git rev-parse second)" && + test -z "$(git diff --cached)" && + test -z "$(git diff)" ' # The next test will test the following: @@ -235,10 +235,10 @@ test_expect_success '"reset --merge HEAD^" is ok with pending merge' ' # ---------------------------------------------------- # file1: X U B C --keep (disallowed) test_expect_success '"reset --keep HEAD^" fails with pending merge' ' - git reset --hard third && - test_must_fail git merge branch1 && - test_must_fail git reset --keep HEAD^ 2>err.log && - test_i18ngrep "middle of a merge" err.log + git reset --hard third && + test_must_fail git merge branch1 && + test_must_fail git reset --keep HEAD^ 2>err.log && + test_i18ngrep "middle of a merge" err.log ' # The next test will test the following: @@ -247,12 +247,12 @@ test_expect_success '"reset --keep HEAD^" fails with pending merge' ' # ---------------------------------------------------- # file1: X U B B --merge B B B test_expect_success '"reset --merge HEAD" is ok with pending merge' ' - git reset --hard third && - test_must_fail git merge branch1 && - git reset --merge HEAD && - test "$(git rev-parse HEAD)" = "$(git rev-parse third)" && - test -z "$(git diff --cached)" && - test -z "$(git diff)" + git reset --hard third && + test_must_fail git merge branch1 && + git reset --merge HEAD && + test "$(git rev-parse HEAD)" = "$(git rev-parse third)" && + test -z "$(git diff --cached)" && + test -z "$(git diff)" ' # The next test will test the following: @@ -261,36 +261,36 @@ test_expect_success '"reset --merge HEAD" is ok with pending merge' ' # ---------------------------------------------------- # file1: X U B B --keep (disallowed) test_expect_success '"reset --keep HEAD" fails with pending merge' ' - git reset --hard third && - test_must_fail git merge branch1 && - test_must_fail git reset --keep HEAD 2>err.log && - test_i18ngrep "middle of a merge" err.log + git reset --hard third && + test_must_fail git merge branch1 && + test_must_fail git reset --keep HEAD 2>err.log && + test_i18ngrep "middle of a merge" err.log ' test_expect_success '--merge is ok with added/deleted merge' ' - git reset --hard third && - rm -f file2 && - test_must_fail git merge branch3 && - ! test -f file2 && - test -f file3 && - git diff --exit-code file3 && - git diff --exit-code branch3 file3 && - git reset --merge HEAD && - ! test -f file3 && - ! test -f file2 && - git diff --exit-code --cached + git reset --hard third && + rm -f file2 && + test_must_fail git merge branch3 && + ! test -f file2 && + test -f file3 && + git diff --exit-code file3 && + git diff --exit-code branch3 file3 && + git reset --merge HEAD && + ! test -f file3 && + ! test -f file2 && + git diff --exit-code --cached ' test_expect_success '--keep fails with added/deleted merge' ' - git reset --hard third && - rm -f file2 && - test_must_fail git merge branch3 && - ! test -f file2 && - test -f file3 && - git diff --exit-code file3 && - git diff --exit-code branch3 file3 && - test_must_fail git reset --keep HEAD 2>err.log && - test_i18ngrep "middle of a merge" err.log + git reset --hard third && + rm -f file2 && + test_must_fail git merge branch3 && + ! test -f file2 && + test -f file3 && + git diff --exit-code file3 && + git diff --exit-code branch3 file3 && + test_must_fail git reset --keep HEAD 2>err.log && + test_i18ngrep "middle of a merge" err.log ' test_done diff --git a/t/t7111-reset-table.sh b/t/t7111-reset-table.sh index 78f25c1c7e..01b7c3503c 100755 --- a/t/t7111-reset-table.sh +++ b/t/t7111-reset-table.sh @@ -10,9 +10,9 @@ TEST_PASSES_SANITIZE_LEAK=true test_expect_success 'creating initial commits' ' - test_commit E file1 && - test_commit D file1 && - test_commit C file1 + test_commit E file1 && + test_commit D file1 && + test_commit C file1 ' while read W1 I1 H1 T opt W2 I2 H2 @@ -74,13 +74,13 @@ B C C C keep B C C EOF test_expect_success 'setting up branches to test with unmerged entries' ' - git reset --hard C && - git branch branch1 && - git branch branch2 && - git checkout branch1 && - test_commit B1 file1 && - git checkout branch2 && - test_commit B file1 + git reset --hard C && + git branch branch1 && + git branch branch2 && + git checkout branch1 && + test_commit B1 file1 && + git checkout branch2 && + test_commit B file1 ' while read W1 I1 H1 T opt W2 I2 H2 diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 61ad47b0c1..35b9e6ed6b 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -372,75 +372,75 @@ test_expect_success 'checkout specific path while in subdirectory' ' ' test_expect_success 'checkout w/--track sets up tracking' ' - git config branch.autosetupmerge false && - git checkout main && - git checkout --track -b track1 && - test "$(git config branch.track1.remote)" && - test "$(git config branch.track1.merge)" + git config branch.autosetupmerge false && + git checkout main && + git checkout --track -b track1 && + test "$(git config branch.track1.remote)" && + test "$(git config branch.track1.merge)" ' test_expect_success 'checkout w/autosetupmerge=always sets up tracking' ' - test_when_finished git config branch.autosetupmerge false && - git config branch.autosetupmerge always && - git checkout main && - git checkout -b track2 && - test "$(git config branch.track2.remote)" && - test "$(git config branch.track2.merge)" + test_when_finished git config branch.autosetupmerge false && + git config branch.autosetupmerge always && + git checkout main && + git checkout -b track2 && + test "$(git config branch.track2.remote)" && + test "$(git config branch.track2.merge)" ' test_expect_success 'checkout w/--track from non-branch HEAD fails' ' - git checkout main^0 && - test_must_fail git symbolic-ref HEAD && - test_must_fail git checkout --track -b track && - test_must_fail git rev-parse --verify track && - test_must_fail git symbolic-ref HEAD && - test "z$(git rev-parse main^0)" = "z$(git rev-parse HEAD)" + git checkout main^0 && + test_must_fail git symbolic-ref HEAD && + test_must_fail git checkout --track -b track && + test_must_fail git rev-parse --verify track && + test_must_fail git symbolic-ref HEAD && + test "z$(git rev-parse main^0)" = "z$(git rev-parse HEAD)" ' test_expect_success 'checkout w/--track from tag fails' ' - git checkout main^0 && - test_must_fail git symbolic-ref HEAD && - test_must_fail git checkout --track -b track frotz && - test_must_fail git rev-parse --verify track && - test_must_fail git symbolic-ref HEAD && - test "z$(git rev-parse main^0)" = "z$(git rev-parse HEAD)" + git checkout main^0 && + test_must_fail git symbolic-ref HEAD && + test_must_fail git checkout --track -b track frotz && + test_must_fail git rev-parse --verify track && + test_must_fail git symbolic-ref HEAD && + test "z$(git rev-parse main^0)" = "z$(git rev-parse HEAD)" ' test_expect_success 'detach a symbolic link HEAD' ' - git checkout main && - git config --bool core.prefersymlinkrefs yes && - git checkout side && - git checkout main && - it=$(git symbolic-ref HEAD) && - test "z$it" = zrefs/heads/main && - here=$(git rev-parse --verify refs/heads/main) && - git checkout side^ && - test "z$(git rev-parse --verify refs/heads/main)" = "z$here" + git checkout main && + git config --bool core.prefersymlinkrefs yes && + git checkout side && + git checkout main && + it=$(git symbolic-ref HEAD) && + test "z$it" = zrefs/heads/main && + here=$(git rev-parse --verify refs/heads/main) && + git checkout side^ && + test "z$(git rev-parse --verify refs/heads/main)" = "z$here" ' test_expect_success 'checkout with --track fakes a sensible -b <name>' ' - git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" && - git update-ref refs/remotes/origin/koala/bear renamer && + git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" && + git update-ref refs/remotes/origin/koala/bear renamer && - git checkout --track origin/koala/bear && - test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" && - test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" && + git checkout --track origin/koala/bear && + test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" && + test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" && - git checkout main && git branch -D koala/bear && + git checkout main && git branch -D koala/bear && - git checkout --track refs/remotes/origin/koala/bear && - test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" && - test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" && + git checkout --track refs/remotes/origin/koala/bear && + test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" && + test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" && - git checkout main && git branch -D koala/bear && + git checkout main && git branch -D koala/bear && - git checkout --track remotes/origin/koala/bear && - test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" && - test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" + git checkout --track remotes/origin/koala/bear && + test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" && + test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" ' test_expect_success 'checkout with --track, but without -b, fails with too short tracked name' ' - test_must_fail git checkout --track renamer + test_must_fail git checkout --track renamer ' setup_conflicting_index () { diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh index c975eb54d2..0ef7b78457 100755 --- a/t/t7300-clean.sh +++ b/t/t7300-clean.sh @@ -120,7 +120,7 @@ test_expect_success 'git clean with relative prefix' ' grep part3 | sed -n -e "s|^Would remove ||p" ) && - verbose test "$would_clean" = ../src/part3.c + test "$would_clean" = ../src/part3.c ' test_expect_success 'git clean with absolute path' ' @@ -133,7 +133,7 @@ test_expect_success 'git clean with absolute path' ' grep part3 | sed -n -e "s|^Would remove ||p" ) && - verbose test "$would_clean" = ../src/part3.c + test "$would_clean" = ../src/part3.c ' test_expect_success 'git clean with out of work tree relative path' ' diff --git a/t/t7301-clean-interactive.sh b/t/t7301-clean-interactive.sh index a07e8b86de..d82a3210a1 100755 --- a/t/t7301-clean-interactive.sh +++ b/t/t7301-clean-interactive.sh @@ -2,6 +2,7 @@ test_description='git clean -i basic tests' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-terminal.sh diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index a989aafaf5..d9fbabb2b9 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 @@ -1341,6 +1351,22 @@ test_expect_success 'clone active submodule without submodule url set' ' ) ' +test_expect_success 'update submodules without url set in .gitconfig' ' + test_when_finished "rm -rf multisuper_clone" && + git clone file://"$pwd"/multisuper multisuper_clone && + + git -C multisuper_clone submodule init && + for s in sub0 sub1 sub2 sub3 + do + key=submodule.$s.url && + git -C multisuper_clone config --local --unset $key && + git -C multisuper_clone config --file .gitmodules --unset $key || return 1 + done && + + test_must_fail git -C multisuper_clone submodule update 2>err && + grep "cannot clone submodule .sub[0-3]. without a URL" err +' + test_expect_success 'clone --recurse-submodules with a pathspec works' ' test_when_finished "rm -rf multisuper_clone" && cat >expected <<-\EOF && diff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh index ebeca12a71..2b3c363078 100755 --- a/t/t7402-submodule-rebase.sh +++ b/t/t7402-submodule-rebase.sh @@ -5,6 +5,7 @@ test_description='Test rebasing, stashing, etc. with submodules' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' @@ -55,12 +56,15 @@ chmod a+x fake-editor.sh test_expect_success 'interactive rebase with a dirty submodule' ' - test submodule = $(git diff --name-only) && + echo submodule >expect && + git diff --name-only >actual && + test_cmp expect actual && HEAD=$(git rev-parse HEAD) && GIT_EDITOR="\"$(pwd)/fake-editor.sh\"" EDITOR_TEXT="pick $HEAD" \ git rebase -i HEAD^ && - test submodule = $(git diff --name-only) - + echo submodule >expect && + git diff --name-only >actual && + test_cmp expect actual ' test_expect_success 'rebase with dirty file and submodule fails' ' @@ -82,11 +86,19 @@ test_expect_success 'stash with a dirty submodule' ' CURRENT=$(cd submodule && git rev-parse HEAD) && git stash && test new != $(cat file) && - test submodule = $(git diff --name-only) && - test $CURRENT = $(cd submodule && git rev-parse HEAD) && + echo submodule >expect && + git diff --name-only >actual && + test_cmp expect actual && + + echo "$CURRENT" >expect && + git -C submodule rev-parse HEAD >actual && + test_cmp expect actual && + git stash apply && test new = $(cat file) && - test $CURRENT = $(cd submodule && git rev-parse HEAD) + echo "$CURRENT" >expect && + git -C submodule rev-parse HEAD >actual && + test_cmp expect actual ' diff --git a/t/t7403-submodule-sync.sh b/t/t7403-submodule-sync.sh index ea92ef52a5..ff09443a0a 100755 --- a/t/t7403-submodule-sync.sh +++ b/t/t7403-submodule-sync.sh @@ -11,6 +11,7 @@ These tests exercise the "git submodule sync" subcommand. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh index f094e3d7f3..00651c25cb 100755 --- a/t/t7406-submodule-update.sh +++ b/t/t7406-submodule-update.sh @@ -1179,4 +1179,27 @@ test_expect_success 'submodule update --recursive skip submodules with strategy= test_cmp expect.err actual.err ' +add_submodule_commit_and_validate () { + HASH=$(git rev-parse HEAD) && + git update-index --add --cacheinfo 160000,$HASH,sub && + git commit -m "create submodule" && + echo "160000 commit $HASH sub" >expect && + git ls-tree HEAD -- sub >actual && + test_cmp expect actual +} + +test_expect_success 'commit with staged submodule change' ' + add_submodule_commit_and_validate +' + +test_expect_success 'commit with staged submodule change with ignoreSubmodules dirty' ' + test_config diff.ignoreSubmodules dirty && + add_submodule_commit_and_validate +' + +test_expect_success 'commit with staged submodule change with ignoreSubmodules all' ' + test_config diff.ignoreSubmodules all && + add_submodule_commit_and_validate +' + test_done 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/t7409-submodule-detached-work-tree.sh b/t/t7409-submodule-detached-work-tree.sh index 374ed481e9..574a6fc526 100755 --- a/t/t7409-submodule-detached-work-tree.sh +++ b/t/t7409-submodule-detached-work-tree.sh @@ -13,6 +13,7 @@ TEST_NO_CREATE_REPO=1 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' 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/t7412-submodule-absorbgitdirs.sh b/t/t7412-submodule-absorbgitdirs.sh index 2859695c6d..f778321857 100755 --- a/t/t7412-submodule-absorbgitdirs.sh +++ b/t/t7412-submodule-absorbgitdirs.sh @@ -10,6 +10,7 @@ TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup a real submodule' ' + cwd="$(pwd)" && git init sub1 && test_commit -C sub1 first && git submodule add ./sub1 && @@ -18,13 +19,21 @@ test_expect_success 'setup a real submodule' ' ' test_expect_success 'absorb the git dir' ' + >expect && + >actual && >expect.1 && >expect.2 && >actual.1 && >actual.2 && git status >expect.1 && git -C sub1 rev-parse HEAD >expect.2 && - git submodule absorbgitdirs && + cat >expect <<-EOF && + Migrating git directory of '\''sub1'\'' from + '\''$cwd/sub1/.git'\'' to + '\''$cwd/.git/modules/sub1'\'' + EOF + git submodule absorbgitdirs 2>actual && + test_cmp expect actual && git fsck && test -f sub1/.git && test -d .git/modules/sub1 && @@ -37,7 +46,8 @@ test_expect_success 'absorb the git dir' ' test_expect_success 'absorbing does not fail for deinitialized submodules' ' test_when_finished "git submodule update --init" && git submodule deinit --all && - git submodule absorbgitdirs && + git submodule absorbgitdirs 2>err && + test_must_be_empty err && test -d .git/modules/sub1 && test -d sub1 && ! test -e sub1/.git @@ -56,7 +66,13 @@ test_expect_success 'setup nested submodule' ' test_expect_success 'absorb the git dir in a nested submodule' ' git status >expect.1 && git -C sub1/nested rev-parse HEAD >expect.2 && - git submodule absorbgitdirs && + cat >expect <<-EOF && + Migrating git directory of '\''sub1/nested'\'' from + '\''$cwd/sub1/nested/.git'\'' to + '\''$cwd/.git/modules/sub1/modules/nested'\'' + EOF + git submodule absorbgitdirs 2>actual && + test_cmp expect actual && test -f sub1/nested/.git && test -d .git/modules/sub1/modules/nested && git status >actual.1 && @@ -87,7 +103,13 @@ test_expect_success 're-setup nested submodule' ' test_expect_success 'absorb the git dir in a nested submodule' ' git status >expect.1 && git -C sub1/nested rev-parse HEAD >expect.2 && - git submodule absorbgitdirs && + cat >expect <<-EOF && + Migrating git directory of '\''sub1'\'' from + '\''$cwd/sub1/.git'\'' to + '\''$cwd/.git/modules/sub1'\'' + EOF + git submodule absorbgitdirs 2>actual && + test_cmp expect actual && test -f sub1/.git && test -f sub1/nested/.git && test -d .git/modules/sub1/modules/nested && @@ -97,6 +119,27 @@ test_expect_success 'absorb the git dir in a nested submodule' ' test_cmp expect.2 actual.2 ' +test_expect_success 'absorb the git dir outside of primary worktree' ' + test_when_finished "rm -rf repo-bare.git" && + git clone --bare . repo-bare.git && + test_when_finished "rm -rf repo-wt" && + git -C repo-bare.git worktree add ../repo-wt && + + test_when_finished "rm -f .gitconfig" && + test_config_global protocol.file.allow always && + git -C repo-wt submodule update --init && + git init repo-wt/sub2 && + test_commit -C repo-wt/sub2 A && + git -C repo-wt submodule add ./sub2 sub2 && + cat >expect <<-EOF && + Migrating git directory of '\''sub2'\'' from + '\''$cwd/repo-wt/sub2/.git'\'' to + '\''$cwd/repo-bare.git/worktrees/repo-wt/modules/sub2'\'' + EOF + git -C repo-wt submodule absorbgitdirs 2>actual && + test_cmp expect actual +' + test_expect_success 'setup a gitlink with missing .gitmodules entry' ' git init sub2 && test_commit -C sub2 first && @@ -107,7 +150,11 @@ test_expect_success 'setup a gitlink with missing .gitmodules entry' ' test_expect_success 'absorbing the git dir fails for incomplete submodules' ' git status >expect.1 && git -C sub2 rev-parse HEAD >expect.2 && - test_must_fail git submodule absorbgitdirs && + cat >expect <<-\EOF && + fatal: could not lookup name for submodule '\''sub2'\'' + EOF + test_must_fail git submodule absorbgitdirs 2>actual && + test_cmp expect actual && git -C sub2 fsck && test -d sub2/.git && git status >actual && @@ -127,8 +174,11 @@ test_expect_success 'setup a submodule with multiple worktrees' ' ' test_expect_success 'absorbing fails for a submodule with multiple worktrees' ' - test_must_fail git submodule absorbgitdirs sub3 2>error && - test_i18ngrep "not supported" error + cat >expect <<-\EOF && + fatal: could not lookup name for submodule '\''sub2'\'' + EOF + test_must_fail git submodule absorbgitdirs 2>actual && + test_cmp expect actual ' test_done diff --git a/t/t7413-submodule-is-active.sh b/t/t7413-submodule-is-active.sh index 7cdc263764..887d181b72 100755 --- a/t/t7413-submodule-is-active.sh +++ b/t/t7413-submodule-is-active.sh @@ -51,6 +51,22 @@ test_expect_success 'is-active works with submodule.<name>.active config' ' test-tool -C super submodule is-active sub1 ' +test_expect_success 'is-active handles submodule.active config missing a value' ' + cp super/.git/config super/.git/config.orig && + test_when_finished mv super/.git/config.orig super/.git/config && + + cat >>super/.git/config <<-\EOF && + [submodule] + active + EOF + + cat >expect <<-\EOF && + error: missing value for '\''submodule.active'\'' + EOF + test-tool -C super submodule is-active sub1 2>actual && + test_cmp expect actual +' + test_expect_success 'is-active works with basic submodule.active config' ' test_when_finished "git -C super config submodule.sub1.URL ../sub" && test_when_finished "git -C super config --unset-all submodule.active" && diff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh index 3ebd985981..7cf72b9a07 100755 --- a/t/t7416-submodule-dash-url.sh +++ b/t/t7416-submodule-dash-url.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='check handling of disallowed .gitmodule urls' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' 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/t7450-bad-git-dotfiles.sh b/t/t7450-bad-git-dotfiles.sh index ba1f569bcb..0d0c3f2c68 100755 --- a/t/t7450-bad-git-dotfiles.sh +++ b/t/t7450-bad-git-dotfiles.sh @@ -12,6 +12,8 @@ Such as: - symlinked .gitmodules, etc ' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-pack.sh diff --git a/t/t7502-commit-porcelain.sh b/t/t7502-commit-porcelain.sh index 38a532d81c..b5bf7de7cd 100755 --- a/t/t7502-commit-porcelain.sh +++ b/t/t7502-commit-porcelain.sh @@ -466,6 +466,25 @@ test_expect_success 'commit --trailer with -c and command' ' test_cmp expected actual ' +test_expect_success 'commit --trailer not confused by --- separator' ' + cat >msg <<-\EOF && + subject + + body with dashes + --- + in it + EOF + git commit --allow-empty --trailer="my-trailer: value" -F msg && + { + cat msg && + echo && + echo "my-trailer: value" + } >expected && + git cat-file commit HEAD >commit.msg && + sed -e "1,/^\$/d" commit.msg >actual && + test_cmp expected actual +' + test_expect_success 'multiple -m' ' >negative && diff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh index a39de8c112..d1255228d5 100755 --- a/t/t7504-commit-msg-hook.sh +++ b/t/t7504-commit-msg-hook.sh @@ -5,6 +5,7 @@ test_description='commit-msg hook' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'with no hook' ' @@ -101,7 +102,9 @@ test_expect_success 'setup: commit-msg hook that always fails' ' ' commit_msg_is () { - test "$(git log --pretty=format:%s%b -1)" = "$1" + printf "%s" "$1" >expect && + git log --pretty=format:%s%b -1 >actual && + test_cmp expect actual } test_expect_success 'with failing hook' ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index 2b7ef6c41a..6928fd89f5 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -5,6 +5,7 @@ test_description='git status' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-terminal.sh @@ -91,7 +92,7 @@ test_expect_success 'status --column' ' # On branch main # Your branch and '\''upstream'\'' have diverged, # and have 1 and 2 different commits each, respectively. -# (use "git pull" to merge the remote branch into yours) +# (use "git pull" if you want to integrate the remote branch with yours) # # Changes to be committed: # (use "git restore --staged <file>..." to unstage) @@ -122,7 +123,7 @@ cat >expect <<\EOF # On branch main # Your branch and 'upstream' have diverged, # and have 1 and 2 different commits each, respectively. -# (use "git pull" to merge the remote branch into yours) +# (use "git pull" if you want to integrate the remote branch with yours) # # Changes to be committed: # (use "git restore --staged <file>..." to unstage) @@ -269,7 +270,7 @@ test_expect_success 'status with gitignore' ' On branch main Your branch and '\''upstream'\'' have diverged, and have 1 and 2 different commits each, respectively. - (use "git pull" to merge the remote branch into yours) + (use "git pull" if you want to integrate the remote branch with yours) Changes to be committed: (use "git restore --staged <file>..." to unstage) @@ -334,7 +335,7 @@ test_expect_success 'status with gitignore (nothing untracked)' ' On branch main Your branch and '\''upstream'\'' have diverged, and have 1 and 2 different commits each, respectively. - (use "git pull" to merge the remote branch into yours) + (use "git pull" if you want to integrate the remote branch with yours) Changes to be committed: (use "git restore --staged <file>..." to unstage) @@ -404,7 +405,7 @@ test_expect_success 'status -uno' ' On branch main Your branch and '\''upstream'\'' have diverged, and have 1 and 2 different commits each, respectively. - (use "git pull" to merge the remote branch into yours) + (use "git pull" if you want to integrate the remote branch with yours) Changes to be committed: (use "git restore --staged <file>..." to unstage) @@ -466,7 +467,7 @@ test_expect_success 'status -unormal' ' On branch main Your branch and '\''upstream'\'' have diverged, and have 1 and 2 different commits each, respectively. - (use "git pull" to merge the remote branch into yours) + (use "git pull" if you want to integrate the remote branch with yours) Changes to be committed: (use "git restore --staged <file>..." to unstage) @@ -521,7 +522,7 @@ test_expect_success 'status -uall' ' On branch main Your branch and '\''upstream'\'' have diverged, and have 1 and 2 different commits each, respectively. - (use "git pull" to merge the remote branch into yours) + (use "git pull" if you want to integrate the remote branch with yours) Changes to be committed: (use "git restore --staged <file>..." to unstage) @@ -581,7 +582,7 @@ test_expect_success 'status with relative paths' ' On branch main Your branch and '\''upstream'\'' have diverged, and have 1 and 2 different commits each, respectively. - (use "git pull" to merge the remote branch into yours) + (use "git pull" if you want to integrate the remote branch with yours) Changes to be committed: (use "git restore --staged <file>..." to unstage) @@ -649,7 +650,7 @@ test_expect_success TTY 'status with color.ui' ' On branch <GREEN>main<RESET> Your branch and '\''upstream'\'' have diverged, and have 1 and 2 different commits each, respectively. - (use "git pull" to merge the remote branch into yours) + (use "git pull" if you want to integrate the remote branch with yours) Changes to be committed: (use "git restore --staged <file>..." to unstage) @@ -772,7 +773,7 @@ test_expect_success 'status without relative paths' ' On branch main Your branch and '\''upstream'\'' have diverged, and have 1 and 2 different commits each, respectively. - (use "git pull" to merge the remote branch into yours) + (use "git pull" if you want to integrate the remote branch with yours) Changes to be committed: (use "git restore --staged <file>..." to unstage) @@ -846,7 +847,6 @@ test_expect_success 'dry-run of partial commit excluding new file in index' ' On branch main Your branch and '\''upstream'\'' have diverged, and have 1 and 2 different commits each, respectively. - (use "git pull" to merge the remote branch into yours) Changes to be committed: (use "git restore --staged <file>..." to unstage) @@ -900,7 +900,7 @@ test_expect_success 'status submodule summary is disabled by default' ' On branch main Your branch and '\''upstream'\'' have diverged, and have 1 and 2 different commits each, respectively. - (use "git pull" to merge the remote branch into yours) + (use "git pull" if you want to integrate the remote branch with yours) Changes to be committed: (use "git restore --staged <file>..." to unstage) @@ -957,7 +957,7 @@ test_expect_success 'status submodule summary' ' On branch main Your branch and '\''upstream'\'' have diverged, and have 1 and 2 different commits each, respectively. - (use "git pull" to merge the remote branch into yours) + (use "git pull" if you want to integrate the remote branch with yours) Changes to be committed: (use "git restore --staged <file>..." to unstage) @@ -1012,11 +1012,11 @@ test_expect_success 'status -s submodule summary' ' ' test_expect_success 'status submodule summary (clean submodule): commit' ' - cat >expect <<EOF && + cat >expect-status <<EOF && On branch main Your branch and '\''upstream'\'' have diverged, and have 2 and 2 different commits each, respectively. - (use "git pull" to merge the remote branch into yours) + (use "git pull" if you want to integrate the remote branch with yours) Changes not staged for commit: (use "git add <file>..." to update what will be committed) @@ -1032,12 +1032,13 @@ Untracked files: no changes added to commit (use "git add" and/or "git commit -a") EOF + sed "/git pull/d" expect-status > expect-commit && git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && - test_cmp expect output && + test_cmp expect-commit output && git status >output && - test_cmp expect output + test_cmp expect-status output ' cat >expect <<EOF @@ -1064,7 +1065,6 @@ test_expect_success 'commit --dry-run submodule summary (--amend)' ' On branch main Your branch and '\''upstream'\'' have diverged, and have 2 and 2 different commits each, respectively. - (use "git pull" to merge the remote branch into yours) Changes to be committed: (use "git restore --source=HEAD^1 --staged <file>..." to unstage) @@ -1116,7 +1116,7 @@ test_expect_success '--ignore-submodules=untracked suppresses submodules with un On branch main Your branch and '\''upstream'\'' have diverged, and have 2 and 2 different commits each, respectively. - (use "git pull" to merge the remote branch into yours) + (use "git pull" if you want to integrate the remote branch with yours) Changes to be committed: (use "git restore --staged <file>..." to unstage) @@ -1225,7 +1225,7 @@ test_expect_success "--ignore-submodules=untracked doesn't suppress submodules w On branch main Your branch and '\''upstream'\'' have diverged, and have 2 and 2 different commits each, respectively. - (use "git pull" to merge the remote branch into yours) + (use "git pull" if you want to integrate the remote branch with yours) Changes to be committed: (use "git restore --staged <file>..." to unstage) @@ -1282,7 +1282,7 @@ test_expect_success "--ignore-submodules=untracked doesn't suppress submodule su On branch main Your branch and '\''upstream'\'' have diverged, and have 2 and 2 different commits each, respectively. - (use "git pull" to merge the remote branch into yours) + (use "git pull" if you want to integrate the remote branch with yours) Changes to be committed: (use "git restore --staged <file>..." to unstage) @@ -1363,7 +1363,7 @@ cat > expect << EOF ; On branch main ; Your branch and 'upstream' have diverged, ; and have 2 and 2 different commits each, respectively. -; (use "git pull" to merge the remote branch into yours) +; (use "git pull" if you want to integrate the remote branch with yours) ; ; Changes to be committed: ; (use "git restore --staged <file>..." to unstage) @@ -1411,7 +1411,7 @@ test_expect_success "--ignore-submodules=all suppresses submodule summary" ' On branch main Your branch and '\''upstream'\'' have diverged, and have 2 and 2 different commits each, respectively. - (use "git pull" to merge the remote branch into yours) + (use "git pull" if you want to integrate the remote branch with yours) Changes not staged for commit: (use "git add <file>..." to update what will be committed) @@ -1437,7 +1437,7 @@ test_expect_success '.gitmodules ignore=all suppresses unstaged submodule summar On branch main Your branch and '\''upstream'\'' have diverged, and have 2 and 2 different commits each, respectively. - (use "git pull" to merge the remote branch into yours) + (use "git pull" if you want to integrate the remote branch with yours) Changes to be committed: (use "git restore --staged <file>..." to unstage) @@ -1519,8 +1519,8 @@ test_expect_success '"status.branch=true" weaker than "--no-branch"' ' ' test_expect_success '"status.branch=true" weaker than "--porcelain"' ' - git -c status.branch=true status --porcelain >actual && - test_cmp expected_nobranch actual + git -c status.branch=true status --porcelain >actual && + test_cmp expected_nobranch actual ' test_expect_success '"status.branch=false" same as "--no-branch"' ' @@ -1557,7 +1557,6 @@ test_expect_success 'git commit --dry-run will show a staged but ignored submodu On branch main Your branch and '\''upstream'\'' have diverged, and have 2 and 2 different commits each, respectively. - (use "git pull" to merge the remote branch into yours) Changes to be committed: (use "git restore --staged <file>..." to unstage) @@ -1676,4 +1675,74 @@ test_expect_success 'racy timestamps will be fixed for dirty worktree' ' ! test_is_magic_mtime .git/index ' +test_expect_success 'setup slow status advice' ' + GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main git init slowstatus && + ( + cd slowstatus && + cat >.gitignore <<-\EOF && + /actual + /expected + /out + EOF + git add .gitignore && + git commit -m "Add .gitignore" && + git config advice.statusuoption true + ) +' + +test_expect_success 'slow status advice when core.untrackedCache and fsmonitor are unset' ' + ( + cd slowstatus && + git config core.untrackedCache false && + git config core.fsmonitor false && + GIT_TEST_UF_DELAY_WARNING=1 git status >actual && + cat >expected <<-\EOF && + On branch main + + It took 3.25 seconds to enumerate untracked files. + See '\''git help status'\'' for information on how to improve this. + + nothing to commit, working tree clean + EOF + test_cmp expected actual + ) +' + +test_expect_success 'slow status advice when core.untrackedCache true, but not fsmonitor' ' + ( + cd slowstatus && + git config core.untrackedCache true && + git config core.fsmonitor false && + GIT_TEST_UF_DELAY_WARNING=1 git status >actual && + cat >expected <<-\EOF && + On branch main + + It took 3.25 seconds to enumerate untracked files. + See '\''git help status'\'' for information on how to improve this. + + nothing to commit, working tree clean + EOF + test_cmp expected actual + ) +' + +test_expect_success 'slow status advice when core.untrackedCache true, and fsmonitor' ' + ( + cd slowstatus && + git config core.untrackedCache true && + git config core.fsmonitor true && + GIT_TEST_UF_DELAY_WARNING=1 git status >actual && + cat >expected <<-\EOF && + On branch main + + It took 3.25 seconds to enumerate untracked files, + but the results were cached, and subsequent runs may be faster. + See '\''git help status'\'' for information on how to improve this. + + nothing to commit, working tree clean + EOF + test_cmp expected actual + ) +' + test_done diff --git a/t/t7509-commit-authorship.sh b/t/t7509-commit-authorship.sh index 21c668f75e..5d890949f7 100755 --- a/t/t7509-commit-authorship.sh +++ b/t/t7509-commit-authorship.sh @@ -105,7 +105,7 @@ test_expect_success '--amend option with empty author' ' test_expect_success '--amend option with missing author' ' git cat-file commit Initial >tmp && sed "s/author [^<]* </author </" tmp >malformed && - sha=$(git hash-object -t commit -w malformed) && + sha=$(git hash-object --literally -t commit -w malformed) && test_when_finished "remove_object $sha" && git checkout $sha && test_when_finished "git checkout Initial" && diff --git a/t/t7510-signed-commit.sh b/t/t7510-signed-commit.sh index 8593b7e3cb..0d2dd29fe6 100755 --- a/t/t7510-signed-commit.sh +++ b/t/t7510-signed-commit.sh @@ -202,7 +202,7 @@ test_expect_success GPG 'detect fudged signature with NUL' ' git cat-file commit seventh-signed >raw && cat raw >forged2 && echo Qwik | tr "Q" "\000" >>forged2 && - git hash-object -w -t commit forged2 >forged2.commit && + git hash-object --literally -w -t commit forged2 >forged2.commit && test_must_fail git verify-commit $(cat forged2.commit) && git show --pretty=short --show-signature $(cat forged2.commit) >actual2 && grep "BAD signature from" actual2 && @@ -218,87 +218,101 @@ test_expect_success GPG 'amending already signed commit' ' ! grep "BAD signature from" actual ' +test_expect_success GPG2 'bare signature' ' + git verify-commit fifth-signed 2>expect && + echo >>expect && + git log -1 --format="%GG" fifth-signed >actual && + test_cmp expect actual +' + test_expect_success GPG 'show good signature with custom format' ' cat >expect <<-\EOF && G + ultimate 13B6F51ECDDE430D C O Mitter <committer@example.com> 73D758744BE721698EC54E8713B6F51ECDDE430D 73D758744BE721698EC54E8713B6F51ECDDE430D EOF - git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" sixth-signed >actual && + git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" sixth-signed >actual && test_cmp expect actual ' test_expect_success GPG 'show bad signature with custom format' ' cat >expect <<-\EOF && B + undefined 13B6F51ECDDE430D C O Mitter <committer@example.com> EOF - git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" $(cat forged1.commit) >actual && + git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" $(cat forged1.commit) >actual && test_cmp expect actual ' test_expect_success GPG 'show untrusted signature with custom format' ' cat >expect <<-\EOF && U + undefined 65A0EEA02E30CAD7 Eris Discordia <discord@example.net> F8364A59E07FFE9F4D63005A65A0EEA02E30CAD7 D4BE22311AD3131E5EDA29A461092E85B7227189 EOF - git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual && + git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual && test_cmp expect actual ' test_expect_success GPG 'show untrusted signature with undefined trust level' ' cat >expect <<-\EOF && + U undefined 65A0EEA02E30CAD7 Eris Discordia <discord@example.net> F8364A59E07FFE9F4D63005A65A0EEA02E30CAD7 D4BE22311AD3131E5EDA29A461092E85B7227189 EOF - git log -1 --format="%GT%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual && + git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual && test_cmp expect actual ' test_expect_success GPG 'show untrusted signature with ultimate trust level' ' cat >expect <<-\EOF && + G ultimate 13B6F51ECDDE430D C O Mitter <committer@example.com> 73D758744BE721698EC54E8713B6F51ECDDE430D 73D758744BE721698EC54E8713B6F51ECDDE430D EOF - git log -1 --format="%GT%n%GK%n%GS%n%GF%n%GP" sixth-signed >actual && + git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" sixth-signed >actual && test_cmp expect actual ' test_expect_success GPG 'show unknown signature with custom format' ' cat >expect <<-\EOF && E + undefined 65A0EEA02E30CAD7 EOF - GNUPGHOME="$GNUPGHOME_NOT_USED" git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual && + GNUPGHOME="$GNUPGHOME_NOT_USED" git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual && test_cmp expect actual ' test_expect_success GPG 'show lack of signature with custom format' ' cat >expect <<-\EOF && N + undefined EOF - git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" seventh-unsigned >actual && + git log -1 --format="%G?%n%GT%n%GK%n%GS%n%GF%n%GP" seventh-unsigned >actual && test_cmp expect actual ' @@ -387,4 +401,48 @@ test_expect_success GPG 'verify-commit verifies multiply signed commits' ' ! grep "BAD signature from" actual ' +test_expect_success 'custom `gpg.program`' ' + write_script fake-gpg <<-\EOF && + args="$*" + + # skip uninteresting options + while case "$1" in + --status-fd=*|--keyid-format=*) ;; # skip + *) break;; + esac; do shift; done + + case "$1" in + -bsau) + test -z "$LET_GPG_PROGRAM_FAIL" || { + echo "zOMG signing failed!" >&2 + exit 1 + } + cat >sign.file + echo "[GNUPG:] SIG_CREATED $args" >&2 + echo "-----BEGIN PGP MESSAGE-----" + echo "$args" + echo "-----END PGP MESSAGE-----" + ;; + --verify) + cat "$2" >verify.file + exit 0 + ;; + *) + echo "Unhandled args: $*" >&2 + exit 1 + ;; + esac + EOF + + test_config gpg.program "$(pwd)/fake-gpg" && + git commit -S --allow-empty -m signed-commit && + test_path_exists sign.file && + git show --show-signature && + test_path_exists verify.file && + + test_must_fail env LET_GPG_PROGRAM_FAIL=1 \ + git commit -S --allow-empty -m must-fail 2>err && + grep zOMG err +' + test_done diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh index 2f16d5787e..c2ab8a444a 100755 --- a/t/t7512-status-help.sh +++ b/t/t7512-status-help.sh @@ -774,6 +774,28 @@ EOF test_cmp expected actual ' +test_expect_success 'status when cherry-picking multiple commits' ' + git reset --hard cherry_branch && + test_when_finished "git cherry-pick --abort" && + test_must_fail git cherry-pick cherry_branch_second one_cherry && + TO_CHERRY_PICK=$(git rev-parse --short CHERRY_PICK_HEAD) && + cat >expected <<EOF && +On branch cherry_branch +You are currently cherry-picking commit $TO_CHERRY_PICK. + (fix conflicts and run "git cherry-pick --continue") + (use "git cherry-pick --skip" to skip this patch) + (use "git cherry-pick --abort" to cancel the cherry-pick operation) + +Unmerged paths: + (use "git add <file>..." to mark resolution) + both modified: main.txt + +no changes added to commit (use "git add" and/or "git commit -a") +EOF + git status --untracked-files=no >actual && + test_cmp expected actual +' + test_expect_success 'status when cherry-picking after committing conflict resolution' ' git reset --hard cherry_branch && test_when_finished "git cherry-pick --abort" && diff --git a/t/t7516-commit-races.sh b/t/t7516-commit-races.sh index f2ce14e907..bb95f09810 100755 --- a/t/t7516-commit-races.sh +++ b/t/t7516-commit-races.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='git commit races' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'race to create orphan commit' ' @@ -10,7 +12,8 @@ test_expect_success 'race to create orphan commit' ' test_must_fail env EDITOR=./hare-editor git commit --allow-empty -m tortoise -e && git show -s --pretty=format:%s >subject && grep hare subject && - test -z "$(git show -s --pretty=format:%P)" + git show -s --pretty=format:%P >out && + test_must_be_empty out ' test_expect_success 'race to create non-orphan commit' ' diff --git a/t/t7517-per-repo-email.sh b/t/t7517-per-repo-email.sh index 163ae80468..efc6496e2b 100755 --- a/t/t7517-per-repo-email.sh +++ b/t/t7517-per-repo-email.sh @@ -9,6 +9,7 @@ test_description='per-repo forced setting of email address' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup a likely user.useConfigOnly use case' ' diff --git a/t/t7518-ident-corner-cases.sh b/t/t7518-ident-corner-cases.sh index fffdb6ff2e..9ab2ae2f3b 100755 --- a/t/t7518-ident-corner-cases.sh +++ b/t/t7518-ident-corner-cases.sh @@ -20,10 +20,19 @@ test_expect_success 'empty name and missing email' ' ' test_expect_success 'commit rejects all-crud name' ' - test_must_fail env GIT_AUTHOR_NAME=" .;<>" \ + test_must_fail env GIT_AUTHOR_NAME=" ,;<>" \ git commit --allow-empty -m foo ' +test_expect_success 'commit does not strip trailing dot' ' + author_name="Pat Doe Jr." && + env GIT_AUTHOR_NAME="$author_name" \ + git commit --allow-empty -m foo && + git log -1 --format=%an >actual && + echo "$author_name" >expected && + test_cmp actual expected +' + # We must test the actual error message here, as an unwanted # auto-detection could fail for other reasons. test_expect_success 'empty configured name does not auto-detect' ' diff --git a/t/t7520-ignored-hook-warning.sh b/t/t7520-ignored-hook-warning.sh index dc57526e6f..184b258989 100755 --- a/t/t7520-ignored-hook-warning.sh +++ b/t/t7520-ignored-hook-warning.sh @@ -2,6 +2,7 @@ test_description='ignored hook warning' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh index d419085379..78503158fd 100755 --- a/t/t7527-builtin-fsmonitor.sh +++ b/t/t7527-builtin-fsmonitor.sh @@ -809,6 +809,11 @@ my_match_and_clean () { status --porcelain=v2 >actual.without && test_cmp actual.with actual.without && + git -C super --no-optional-locks diff-index --name-status HEAD >actual.with && + git -C super --no-optional-locks -c core.fsmonitor=false \ + diff-index --name-status HEAD >actual.without && + test_cmp actual.with actual.without && + git -C super/dir_1/dir_2/sub reset --hard && git -C super/dir_1/dir_2/sub clean -d -f } @@ -866,27 +871,9 @@ test_expect_success 'submodule always visited' ' # the submodule, and someone does a `git submodule absorbgitdirs` # in the super, Git will recursively invoke `git submodule--helper` # to do the work and this may try to read the index. This will -# try to start the daemon in the submodule *and* pass (either -# directly or via inheritance) the `--super-prefix` arg to the -# `git fsmonitor--daemon start` command inside the submodule. -# This causes a warning because fsmonitor--daemon does take that -# global arg (see the table in git.c) -# -# This causes a warning when trying to start the daemon that is -# somewhat confusing. It does not seem to hurt anything because -# the fsmonitor code maps the query failure into a trivial response -# and does the work anyway. -# -# It would be nice to silence the warning, however. +# try to start the daemon in the submodule. -have_t2_error_event () { - log=$1 - msg="fsmonitor--daemon doesnQt support --super-prefix" && - - tr '\047' Q <$1 | grep -e "$msg" -} - -test_expect_success "stray submodule super-prefix warning" ' +test_expect_success "submodule absorbgitdirs implicitly starts daemon" ' test_when_finished "rm -rf super; \ rm -rf sub; \ rm super-sub.trace" && @@ -904,21 +891,31 @@ test_expect_success "stray submodule super-prefix warning" ' test_path_is_dir super/dir_1/dir_2/sub/.git && + cwd="$(cd super && pwd)" && + cat >expect <<-EOF && + Migrating git directory of '\''dir_1/dir_2/sub'\'' from + '\''$cwd/dir_1/dir_2/sub/.git'\'' to + '\''$cwd/.git/modules/dir_1/dir_2/sub'\'' + EOF GIT_TRACE2_EVENT="$PWD/super-sub.trace" \ - git -C super submodule absorbgitdirs && + git -C super submodule absorbgitdirs >out 2>actual && + test_cmp expect actual && + test_must_be_empty out && - ! have_t2_error_event super-sub.trace + # Confirm that the trace2 log contains a record of the + # daemon starting. + test_subcommand git fsmonitor--daemon start <super-sub.trace ' # On a case-insensitive file system, confirm that the daemon # notices when the .git directory is moved/renamed/deleted -# regardless of how it is spelled in the the FS event. +# regardless of how it is spelled in the FS event. # That is, does the FS event receive the spelling of the # operation or does it receive the spelling preserved with # the file/directory. # test_expect_success CASE_INSENSITIVE_FS 'case insensitive+preserving' ' -# test_when_finished "stop_daemon_delete_repo test_insensitive" && + test_when_finished "stop_daemon_delete_repo test_insensitive" && git init test_insensitive && @@ -930,8 +927,8 @@ test_expect_success CASE_INSENSITIVE_FS 'case insensitive+preserving' ' test_path_is_dir test_insensitive/.git && test_path_is_dir test_insensitive/.GIT && - # Rename .git using an alternate spelling to verify that that - # daemon detects it and automatically shuts down. + # Rename .git using an alternate spelling to verify that + # the daemon detects it and automatically shuts down. mv test_insensitive/.GIT test_insensitive/.FOO && # See [1] above. @@ -943,9 +940,9 @@ test_expect_success CASE_INSENSITIVE_FS 'case insensitive+preserving' ' # directories and files that we touched. We may or may not get a # trailing slash on modified directories. # - egrep "^event: abc/?$" ./insensitive.trace && - egrep "^event: abc/def/?$" ./insensitive.trace && - egrep "^event: abc/def/xyz$" ./insensitive.trace + grep -E "^event: abc/?$" ./insensitive.trace && + grep -E "^event: abc/def/?$" ./insensitive.trace && + grep -E "^event: abc/def/xyz$" ./insensitive.trace ' # The variable "unicode_debug" is defined in the following library @@ -987,20 +984,57 @@ test_expect_success !UNICODE_COMPOSITION_SENSITIVE 'Unicode nfc/nfd' ' then # We should have seen NFC event from OS. # We should not have synthesized an NFD event. - egrep "^event: nfc/c_${utf8_nfc}/?$" ./unicode.trace && - egrep -v "^event: nfc/c_${utf8_nfd}/?$" ./unicode.trace + grep -E "^event: nfc/c_${utf8_nfc}/?$" ./unicode.trace && + grep -E -v "^event: nfc/c_${utf8_nfd}/?$" ./unicode.trace else # We should have seen NFD event from OS. # We should have synthesized an NFC event. - egrep "^event: nfc/c_${utf8_nfd}/?$" ./unicode.trace && - egrep "^event: nfc/c_${utf8_nfc}/?$" ./unicode.trace + grep -E "^event: nfc/c_${utf8_nfd}/?$" ./unicode.trace && + grep -E "^event: nfc/c_${utf8_nfc}/?$" ./unicode.trace fi && # We assume UNICODE_NFD_PRESERVED. # We should have seen explicit NFD from OS. # We should have synthesized an NFC event. - egrep "^event: nfd/d_${utf8_nfd}/?$" ./unicode.trace && - egrep "^event: nfd/d_${utf8_nfc}/?$" ./unicode.trace + grep -E "^event: nfd/d_${utf8_nfd}/?$" ./unicode.trace && + grep -E "^event: nfd/d_${utf8_nfc}/?$" ./unicode.trace +' + +test_expect_success 'split-index and FSMonitor work well together' ' + git init split-index && + test_when_finished "git -C \"$PWD/split-index\" \ + fsmonitor--daemon stop" && + ( + cd split-index && + git config core.splitIndex true && + # force split-index in most cases + git config splitIndex.maxPercentChange 99 && + git config core.fsmonitor true && + + # Create the following commit topology: + # + # * merge three + # |\ + # | * three + # * | merge two + # |\| + # | * two + # * | one + # |/ + # * 5a5efd7 initial + + test_commit initial && + test_commit two && + test_commit three && + git reset --hard initial && + test_commit one && + test_tick && + git merge two && + test_tick && + git merge three && + + git rebase --force-rebase -r one + ) ' test_done diff --git a/t/t7528-signed-commit-ssh.sh b/t/t7528-signed-commit-ssh.sh index f47e995179..065f780636 100755 --- a/t/t7528-signed-commit-ssh.sh +++ b/t/t7528-signed-commit-ssh.sh @@ -270,7 +270,7 @@ test_expect_success GPGSSH 'detect fudged signature with NUL' ' git cat-file commit seventh-signed >raw && cat raw >forged2 && echo Qwik | tr "Q" "\000" >>forged2 && - git hash-object -w -t commit forged2 >forged2.commit && + git hash-object --literally -w -t commit forged2 >forged2.commit && test_must_fail git verify-commit $(cat forged2.commit) && git show --pretty=short --show-signature $(cat forged2.commit) >actual2 && grep "${GPGSSH_BAD_SIGNATURE}" actual2 && diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh index 7c3f6ed994..fdc607277c 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 } @@ -639,41 +639,41 @@ test_expect_success 'merge log message' ' test_debug 'git log --graph --decorate --oneline --all' test_expect_success 'merge c1 with c0, c2, c0, and c1' ' - git reset --hard c1 && - test_tick && - git merge c0 c2 c0 c1 && - verify_merge file result.1-5 && - verify_parents $c1 $c2 + git reset --hard c1 && + test_tick && + git merge c0 c2 c0 c1 && + verify_merge file result.1-5 && + verify_parents $c1 $c2 ' test_debug 'git log --graph --decorate --oneline --all' test_expect_success 'merge c1 with c0, c2, c0, and c1' ' - git reset --hard c1 && - test_tick && - git merge c0 c2 c0 c1 && - verify_merge file result.1-5 && - verify_parents $c1 $c2 + git reset --hard c1 && + test_tick && + git merge c0 c2 c0 c1 && + verify_merge file result.1-5 && + verify_parents $c1 $c2 ' test_debug 'git log --graph --decorate --oneline --all' test_expect_success 'merge c1 with c1 and c2' ' - git reset --hard c1 && - test_tick && - git merge c1 c2 && - verify_merge file result.1-5 && - verify_parents $c1 $c2 + git reset --hard c1 && + test_tick && + git merge c1 c2 && + verify_merge file result.1-5 && + verify_parents $c1 $c2 ' test_debug 'git log --graph --decorate --oneline --all' test_expect_success 'merge fast-forward in a dirty tree' ' - git reset --hard c0 && - mv file file1 && - cat file1 >file && - rm -f file1 && - git merge c2 + git reset --hard c0 && + mv file file1 && + cat file1 >file && + rm -f file1 && + git merge c2 ' test_debug 'git log --graph --decorate --oneline --all' diff --git a/t/t7605-merge-resolve.sh b/t/t7605-merge-resolve.sh index 5d56c38546..62d935d31c 100755 --- a/t/t7605-merge-resolve.sh +++ b/t/t7605-merge-resolve.sh @@ -4,6 +4,7 @@ test_description='git merge Testing the resolve strategy.' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh index 8cc64729ad..22b3a85b3e 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" && @@ -860,4 +860,42 @@ test_expect_success 'mergetool hideResolved' ' git commit -m "test resolved with mergetool" ' +test_expect_success 'mergetool with guiDefault' ' + test_config merge.guitool myguitool && + test_config mergetool.myguitool.cmd "(printf \"gui \" && cat \"\$REMOTE\") >\"\$MERGED\"" && + test_config mergetool.myguitool.trustExitCode true && + test_when_finished "git reset --hard" && + git checkout -b test$test_count branch1 && + git submodule update -N && + test_must_fail git merge main && + + test_config mergetool.guiDefault auto && + DISPLAY=SOMETHING && export DISPLAY && + yes "" | git mergetool both && + yes "" | git mergetool file1 file1 && + + DISPLAY= && export DISPLAY && + yes "" | git mergetool file2 "spaced name" && + + test_config mergetool.guiDefault true && + yes "" | git mergetool subdir/file3 && + + yes "d" | git mergetool file11 && + yes "d" | git mergetool file12 && + yes "l" | git mergetool submod && + + echo "gui main updated" >expect && + test_cmp expect file1 && + + echo "main new" >expect && + test_cmp expect file2 && + + echo "gui main new sub" >expect && + test_cmp expect subdir/file3 && + + echo "branch1 submodule" >expect && + test_cmp expect submod/bar && + git commit -m "branch1 resolved with mergetool" +' + test_done diff --git a/t/t7612-merge-verify-signatures.sh b/t/t7612-merge-verify-signatures.sh index 61330f71b1..f5c90cc22a 100755 --- a/t/t7612-merge-verify-signatures.sh +++ b/t/t7612-merge-verify-signatures.sh @@ -4,6 +4,7 @@ test_description='merge signature verification tests' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY/lib-gpg.sh" diff --git a/t/t7614-merge-signoff.sh b/t/t7614-merge-signoff.sh index fee258d4f0..cf96a35e8e 100755 --- a/t/t7614-merge-signoff.sh +++ b/t/t7614-merge-signoff.sh @@ -8,6 +8,7 @@ This test runs git merge --signoff and makes sure that it works. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Setup test files diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh index ca45c4cd2c..27b66807cd 100755 --- a/t/t7700-repack.sh +++ b/t/t7700-repack.sh @@ -10,6 +10,10 @@ test_description='git repack works correctly' commit_and_pack () { test_commit "$@" 1>&2 && incrpackid=$(git pack-objects --all --unpacked --incremental .git/objects/pack/pack </dev/null) && + # Remove any loose object(s) created by test_commit, since they have + # already been packed. Leaving these around can create subtly different + # packs with `pack-objects`'s `--unpacked` option. + git prune-packed 1>&2 && echo pack-${incrpackid}.pack } @@ -90,6 +94,39 @@ 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 '--local disables writing bitmaps when connected to alternate ODB' ' + test_when_finished "rm -rf shared member" && + + git init shared && + git clone --shared shared member && + ( + cd member && + test_commit "object" && + GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adl --write-bitmap-index 2>err && + cat >expect <<-EOF && + warning: disabling bitmap writing, as some objects are not being packed + EOF + test_cmp expect err && + test_path_is_missing .git/objects/pack-*.bitmap + ) +' + 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 && @@ -176,6 +213,8 @@ test_expect_success 'repack --keep-pack' ' test_create_repo keep-pack && ( cd keep-pack && + # avoid producing different packs due to delta/base choices + git config pack.window 0 && P1=$(commit_and_pack 1) && P2=$(commit_and_pack 2) && P3=$(commit_and_pack 3) && @@ -187,10 +226,61 @@ test_expect_success 'repack --keep-pack' ' grep -q $P1 new-counts && grep -q $P4 new-counts && test_line_count = 3 new-counts && + git fsck && + + P5=$(commit_and_pack --no-tag 5) && + git reset --hard HEAD^ && + git reflog expire --all --expire=all && + rm -f ".git/objects/pack/${P5%.pack}.idx" && + rm -f ".git/objects/info/commit-graph" && + for from in $(find .git/objects/pack -type f -name "${P5%.pack}.*") + do + to="$(dirname "$from")/.tmp-1234-$(basename "$from")" && + mv "$from" "$to" || return 1 + done && + + # A .idx file without a .pack should not stop us from + # repacking what we can. + touch .git/objects/pack/pack-does-not-exist.idx && + + git repack --cruft -d --keep-pack $P1 --keep-pack $P4 && + + ls .git/objects/pack/*.pack >newer-counts && + test_cmp new-counts newer-counts && git fsck ) ' +test_expect_success 'repacking fails when missing .pack actually means missing objects' ' + test_create_repo idx-without-pack && + ( + cd idx-without-pack && + + # Avoid producing different packs due to delta/base choices + git config pack.window 0 && + P1=$(commit_and_pack 1) && + P2=$(commit_and_pack 2) && + P3=$(commit_and_pack 3) && + P4=$(commit_and_pack 4) && + ls .git/objects/pack/*.pack >old-counts && + test_line_count = 4 old-counts && + + # Remove one .pack file + rm .git/objects/pack/$P2 && + + ls .git/objects/pack/*.pack >before-pack-dir && + + test_must_fail git fsck && + test_must_fail git repack --cruft -d 2>err && + grep "bad object" err && + + # Before failing, the repack did not modify the + # pack directory. + ls .git/objects/pack/*.pack >after-pack-dir && + test_cmp before-pack-dir after-pack-dir + ) +' + test_expect_success 'bitmaps are created by default in bare repos' ' git clone --bare .git bare.git && rm -f bare.git/objects/pack/*.bitmap && @@ -426,12 +516,73 @@ test_expect_success '--write-midx -b packs non-kept objects' ' ) ' +test_expect_success '--write-midx removes stale pack-based bitmaps' ' + rm -fr repo && + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + test_commit base && + GIT_TEST_MULTI_PACK_INDEX=0 git repack -Ab && + + pack_bitmap=$(ls $objdir/pack/pack-*.bitmap) && + test_path_is_file "$pack_bitmap" && + + test_commit tip && + GIT_TEST_MULTI_PACK_INDEX=0 git repack -bm && + + test_path_is_file $midx && + test_path_is_file $midx-$(midx_checksum $objdir).bitmap && + test_path_is_missing $pack_bitmap + ) +' + +test_expect_success '--write-midx with --pack-kept-objects' ' + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + + test_commit one && + test_commit two && + + one="$(echo "one" | git pack-objects --revs $objdir/pack/pack)" && + two="$(echo "one..two" | git pack-objects --revs $objdir/pack/pack)" && + + keep="$objdir/pack/pack-$one.keep" && + touch "$keep" && + + git repack --write-midx --write-bitmap-index --geometric=2 -d \ + --pack-kept-objects && + + test_path_is_file $keep && + test_path_is_file $midx && + test_path_is_file $midx-$(midx_checksum $objdir).bitmap + ) +' + test_expect_success TTY '--quiet disables progress' ' test_terminal env GIT_PROGRESS_DELAY=0 \ git -C midx repack -ad --quiet --write-midx 2>stderr && test_must_be_empty stderr ' +test_expect_success 'clean up .tmp-* packs on error' ' + test_must_fail ok=sigpipe git \ + -c repack.cruftwindow=bogus \ + repack -ad --cruft && + find $objdir/pack -name '.tmp-*' >tmpfiles && + test_must_be_empty tmpfiles +' + +test_expect_success 'repack -ad cleans up old .tmp-* packs' ' + git rev-parse HEAD >input && + git pack-objects $objdir/pack/.tmp-1234 <input && + git repack -ad && + find $objdir/pack -name '.tmp-*' >tmpfiles && + test_must_be_empty tmpfiles +' + test_expect_success 'setup for update-server-info' ' git init update-server-info && test_commit -C update-server-info message @@ -482,4 +633,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/t7701-repack-unpack-unreachable.sh b/t/t7701-repack-unpack-unreachable.sh index 937f89ee8c..fe6c3e77a3 100755 --- a/t/t7701-repack-unpack-unreachable.sh +++ b/t/t7701-repack-unpack-unreachable.sh @@ -5,6 +5,7 @@ test_description='git repack works correctly' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh fsha1= @@ -35,7 +36,7 @@ test_expect_success '-A with -d option leaves unreachable objects unpacked' ' git repack -A -d -l && # verify objects are packed in repository test 3 = $(git verify-pack -v -- .git/objects/pack/*.idx | - egrep "^($fsha1|$csha1|$tsha1) " | + grep -E "^($fsha1|$csha1|$tsha1) " | sort | uniq | wc -l) && git show $fsha1 && git show $csha1 && @@ -49,7 +50,7 @@ test_expect_success '-A with -d option leaves unreachable objects unpacked' ' git repack -A -d -l && # verify objects are retained unpacked test 0 = $(git verify-pack -v -- .git/objects/pack/*.idx | - egrep "^($fsha1|$csha1|$tsha1) " | + grep -E "^($fsha1|$csha1|$tsha1) " | sort | uniq | wc -l) && git show $fsha1 && git show $csha1 && @@ -112,6 +113,48 @@ test_expect_success 'do not bother loosening old objects' ' test_must_fail git cat-file -p $obj2 ' +test_expect_success 'gc.recentObjectsHook' ' + obj1=$(echo one | git hash-object -w --stdin) && + obj2=$(echo two | git hash-object -w --stdin) && + obj3=$(echo three | git hash-object -w --stdin) && + pack1=$(echo $obj1 | git pack-objects .git/objects/pack/pack) && + pack2=$(echo $obj2 | git pack-objects .git/objects/pack/pack) && + pack3=$(echo $obj3 | git pack-objects .git/objects/pack/pack) && + git prune-packed && + + git cat-file -p $obj1 && + git cat-file -p $obj2 && + git cat-file -p $obj3 && + + # make an unreachable annotated tag object to ensure we rescue objects + # which are reachable from non-pruned unreachable objects + obj2_tag="$(git mktag <<-EOF + object $obj2 + type blob + tag obj2-tag + tagger T A Gger <tagger@example.com> 1234567890 -0000 + EOF + )" && + + obj2_tag_pack="$(echo $obj2_tag | git pack-objects .git/objects/pack/pack)" && + git prune-packed && + + write_script precious-objects <<-EOF && + echo $obj2_tag + EOF + git config gc.recentObjectsHook ./precious-objects && + + test-tool chmtime =-86400 .git/objects/pack/pack-$pack2.pack && + test-tool chmtime =-86400 .git/objects/pack/pack-$pack3.pack && + test-tool chmtime =-86400 .git/objects/pack/pack-$obj2_tag_pack.pack && + git repack -A -d --unpack-unreachable=1.hour.ago && + + git cat-file -p $obj1 && + git cat-file -p $obj2 && + git cat-file -p $obj2_tag && + test_must_fail git cat-file -p $obj3 +' + test_expect_success 'keep packed objects found only in index' ' echo my-unique-content >file && git add file && diff --git a/t/t7703-repack-geometric.sh b/t/t7703-repack-geometric.sh index da87f8b2d8..00f28fb558 100755 --- a/t/t7703-repack-geometric.sh +++ b/t/t7703-repack-geometric.sh @@ -10,6 +10,12 @@ objdir=.git/objects packdir=$objdir/pack midx=$objdir/pack/multi-pack-index +packed_objects () { + git show-index <"$1" >tmp-object-list && + cut -d' ' -f2 tmp-object-list | sort && + rm tmp-object-list + } + test_expect_success '--geometric with no packs' ' git init geometric && test_when_finished "rm -fr geometric" && @@ -176,8 +182,12 @@ test_expect_success '--geometric ignores kept packs' ' # be repacked, too. git repack --geometric 2 -d --pack-kept-objects && + # After repacking, two packs remain: one new one (containing the + # objects in both the .keep and non-kept pack), and the .keep + # pack (since `--pack-kept-objects -d` does not actually delete + # the kept pack). find $objdir/pack -name "*.pack" >after && - test_line_count = 1 after + test_line_count = 2 after ) ' @@ -277,4 +287,162 @@ test_expect_success '--geometric with pack.packSizeLimit' ' ) ' +test_expect_success '--geometric --write-midx with packfiles in main and alternate ODB' ' + test_when_finished "rm -fr shared member" && + + # Create a shared repository that will serve as the alternate object + # database for the member linked to it. It has got some objects on its + # own that are packed into a single packfile. + git init shared && + test_commit -C shared common-object && + git -C shared repack -ad && + + # We create member so that its alternates file points to the shared + # repository. We then create a commit in it so that git-repack(1) has + # something to repack. + # of the shared object database. + git clone --shared shared member && + test_commit -C member unique-object && + git -C member repack --geometric=2 --write-midx 2>err && + test_must_be_empty err && + + # We should see that a new packfile was generated. + find shared/.git/objects/pack -type f -name "*.pack" >packs && + test_line_count = 1 packs && + + # We should also see a multi-pack-index. This multi-pack-index should + # never refer to any packfiles in the alternate object database. + test_path_is_file member/.git/objects/pack/multi-pack-index && + test-tool read-midx member/.git/objects >packs.midx && + grep "^pack-.*\.idx$" packs.midx | sort >actual && + basename member/.git/objects/pack/pack-*.idx >expect && + test_cmp expect actual +' + +test_expect_success '--geometric --with-midx with no local objects' ' + test_when_finished "rm -fr shared member" && + + # Create a repository with a single packfile that acts as alternate + # object database. + git init shared && + test_commit -C shared "shared-objects" && + git -C shared repack -ad && + + # Create a second repository linked to the first one and perform a + # geometric repack on it. + git clone --shared shared member && + git -C member repack --geometric 2 --write-midx 2>err && + test_must_be_empty err && + + # Assert that we wrote neither a new packfile nor a multi-pack-index. + # We should not have a packfile because the single packfile in the + # alternate object database does not invalidate the geometric sequence. + # And we should not have a multi-pack-index because these only index + # local packfiles, and there are none. + test_dir_is_empty member/$packdir +' + +test_expect_success '--geometric with same pack in main and alternate ODB' ' + test_when_finished "rm -fr shared member" && + + # Create a repository with a single packfile that acts as alternate + # object database. + git init shared && + test_commit -C shared "shared-objects" && + git -C shared repack -ad && + + # We create the member repository as an exact copy so that it has the + # same packfile. + cp -r shared member && + test-tool path-utils real_path shared/.git/objects >member/.git/objects/info/alternates && + find shared/.git/objects -type f >expected-files && + + # Verify that we can repack objects as expected without observing any + # error. Having the same packfile in both ODBs used to cause an error + # in git-pack-objects(1). + git -C member repack --geometric 2 2>err && + test_must_be_empty err && + # Nothing should have changed. + find shared/.git/objects -type f >actual-files && + test_cmp expected-files actual-files +' + +test_expect_success '--geometric -l with non-intact geometric sequence across ODBs' ' + test_when_finished "rm -fr shared member" && + + git init shared && + test_commit_bulk -C shared --start=1 1 && + + git clone --shared shared member && + test_commit_bulk -C member --start=2 1 && + + # Verify that our assumptions actually hold: both generated packfiles + # should have three objects and should be non-equal. + packed_objects shared/.git/objects/pack/pack-*.idx >shared-objects && + packed_objects member/.git/objects/pack/pack-*.idx >member-objects && + test_line_count = 3 shared-objects && + test_line_count = 3 member-objects && + ! test_cmp shared-objects member-objects && + + # Perform the geometric repack. With `-l`, we should only see the local + # packfile and thus arrive at the conclusion that the geometric + # sequence is intact. We thus expect no changes. + # + # Note that we are tweaking mtimes of the packfiles so that we can + # verify they did not change. This is done in order to detect the case + # where we do repack objects, but the resulting packfile is the same. + test-tool chmtime --verbose =0 member/.git/objects/pack/* >expected-member-packs && + git -C member repack --geometric=2 -l -d && + test-tool chmtime --verbose member/.git/objects/pack/* >actual-member-packs && + test_cmp expected-member-packs actual-member-packs && + + { + packed_objects shared/.git/objects/pack/pack-*.idx && + packed_objects member/.git/objects/pack/pack-*.idx + } | sort >expected-objects && + + # On the other hand, when doing a non-local geometric repack we should + # see both packfiles and thus repack them. We expect that the shared + # object database was not changed. + test-tool chmtime --verbose =0 shared/.git/objects/pack/* >expected-shared-packs && + git -C member repack --geometric=2 -d && + test-tool chmtime --verbose shared/.git/objects/pack/* >actual-shared-packs && + test_cmp expected-shared-packs actual-shared-packs && + + # Furthermore, we expect that the member repository now has a single + # packfile that contains the combined shared and non-shared objects. + ls member/.git/objects/pack/pack-*.idx >actual && + test_line_count = 1 actual && + packed_objects member/.git/objects/pack/pack-*.idx >actual-objects && + test_line_count = 6 actual-objects && + test_cmp expected-objects actual-objects +' + +test_expect_success '--geometric -l disables writing bitmaps with non-local packfiles' ' + test_when_finished "rm -fr shared member" && + + git init shared && + test_commit_bulk -C shared --start=1 1 && + + git clone --shared shared member && + test_commit_bulk -C member --start=2 1 && + + # When performing a geometric repack with `-l` while connected to an + # alternate object database that has a packfile we do not have full + # coverage of objects. As a result, we expect that writing the bitmap + # will be disabled. + git -C member repack -l --geometric=2 --write-midx --write-bitmap-index 2>err && + cat >expect <<-EOF && + warning: disabling bitmap writing, as some objects are not being packed + EOF + test_cmp expect err && + test_path_is_missing member/.git/objects/pack/multi-pack-index-*.bitmap && + + # On the other hand, when we repack without `-l`, we should see that + # the bitmap gets created. + git -C member repack --geometric=2 --write-midx --write-bitmap-index 2>err && + test_must_be_empty err && + test_path_is_file member/.git/objects/pack/multi-pack-index-*.bitmap +' + test_done diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh index 24297e26ca..59d3847bf8 100755 --- a/t/t7800-difftool.sh +++ b/t/t7800-difftool.sh @@ -155,6 +155,58 @@ test_expect_success 'difftool honors --gui' ' test_cmp expect actual ' +test_expect_success 'difftool with guiDefault auto selects gui tool when there is DISPLAY' ' + difftool_test_setup && + test_config merge.tool bogus-tool && + test_config diff.tool bogus-tool && + test_config diff.guitool test-tool && + test_config difftool.guiDefault auto && + DISPLAY=SOMETHING && export DISPLAY && + + echo branch >expect && + git difftool --no-prompt branch >actual && + test_cmp expect actual +' +test_expect_success 'difftool with guiDefault auto selects regular tool when no DISPLAY' ' + difftool_test_setup && + test_config diff.guitool bogus-tool && + test_config diff.tool test-tool && + test_config difftool.guiDefault Auto && + DISPLAY= && export DISPLAY && + + echo branch >expect && + git difftool --no-prompt branch >actual && + test_cmp expect actual +' + +test_expect_success 'difftool with guiDefault true selects gui tool' ' + difftool_test_setup && + test_config diff.tool bogus-tool && + test_config diff.guitool test-tool && + test_config difftool.guiDefault true && + + DISPLAY= && export DISPLAY && + echo branch >expect && + git difftool --no-prompt branch >actual && + test_cmp expect actual && + + DISPLAY=Something && export DISPLAY && + echo branch >expect && + git difftool --no-prompt branch >actual && + test_cmp expect actual +' + +test_expect_success 'difftool --no-gui trumps config guiDefault' ' + difftool_test_setup && + test_config diff.guitool bogus-tool && + test_config diff.tool test-tool && + test_config difftool.guiDefault true && + + echo branch >expect && + git difftool --no-prompt --no-gui branch >actual && + test_cmp expect actual +' + test_expect_success 'difftool --gui last setting wins' ' difftool_test_setup && : >expect && diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index 0f937990a0..39d6d713ec 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -18,6 +18,9 @@ test_invalid_grep_expression() { ' } +LC_ALL=en_US.UTF-8 test-tool regex '^.$' '¿' && + test_set_prereq MB_REGEX + cat >hello.c <<EOF #include <assert.h> #include <stdio.h> @@ -88,6 +91,10 @@ test_expect_success setup ' echo unusual >"\"unusual\" pathname" && echo unusual >"t/nested \"unusual\" pathname" fi && + if test_have_prereq MB_REGEX + then + echo "¿" >reverse-question-mark + fi && git add . && test_tick && git commit -m initial @@ -569,6 +576,14 @@ do ' done +test_expect_success MB_REGEX 'grep exactly one char in single-char multibyte file' ' + LC_ALL=en_US.UTF-8 git grep "^.$" reverse-question-mark +' + +test_expect_success MB_REGEX 'grep two chars in single-char multibyte file' ' + LC_ALL=en_US.UTF-8 test_expect_code 1 git grep ".." reverse-question-mark +' + cat >expected <<EOF file EOF @@ -986,7 +1001,9 @@ test_expect_success 'log --committer does not search in timestamp' ' test_expect_success 'grep with CE_VALID file' ' git update-index --assume-unchanged t/t && rm t/t && - test "$(git grep test)" = "t/t:test" && + echo "t/t:test" >expect && + git grep test >actual && + test_cmp expect actual && git update-index --no-assume-unchanged t/t && git checkout t/t ' diff --git a/t/t7814-grep-recurse-submodules.sh b/t/t7814-grep-recurse-submodules.sh index 8143817b19..d37c83b464 100755 --- a/t/t7814-grep-recurse-submodules.sh +++ b/t/t7814-grep-recurse-submodules.sh @@ -594,4 +594,44 @@ test_expect_success 'grep partially-cloned submodule' ' ) ' +test_expect_success 'check scope of core.useReplaceRefs' ' + git init base && + git init base/sub && + + echo A >base/a && + echo B >base/b && + echo C >base/sub/c && + echo D >base/sub/d && + + git -C base/sub add c d && + git -C base/sub commit -m "Add files" && + + git -C base submodule add ./sub && + git -C base add a b sub && + git -C base commit -m "Add files and submodule" && + + A=$(git -C base rev-parse HEAD:a) && + B=$(git -C base rev-parse HEAD:b) && + C=$(git -C base/sub rev-parse HEAD:c) && + D=$(git -C base/sub rev-parse HEAD:d) && + + git -C base replace $A $B && + git -C base/sub replace $C $D && + + test_must_fail git -C base grep --cached --recurse-submodules A && + test_must_fail git -C base grep --cached --recurse-submodules C && + + git -C base config core.useReplaceRefs false && + git -C base grep --recurse-submodules A && + test_must_fail git -C base grep --cached --recurse-submodules C && + + git -C base/sub config core.useReplaceRefs false && + git -C base grep --cached --recurse-submodules A && + git -C base grep --cached --recurse-submodules C && + + git -C base config --unset core.useReplaceRefs && + test_must_fail git -C base grep --cached --recurse-submodules A && + git -C base grep --cached --recurse-submodules C +' + test_done diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh index 2724a44fe3..e56f5980dc 100755 --- a/t/t7900-maintenance.sh +++ b/t/t7900-maintenance.sh @@ -480,6 +480,11 @@ test_expect_success 'maintenance.strategy inheritance' ' test_expect_success 'register and unregister' ' test_when_finished git config --global --unset-all maintenance.repo && + + test_must_fail git maintenance unregister 2>err && + grep "is not registered" err && + git maintenance unregister --force && + git config --global --add maintenance.repo /existing1 && git config --global --add maintenance.repo /existing2 && git config --global --get-all maintenance.repo >before && @@ -493,7 +498,68 @@ test_expect_success 'register and unregister' ' git maintenance unregister && git config --global --get-all maintenance.repo >actual && - test_cmp before 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 && + + 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 'register with no value for maintenance.repo' ' + cp .git/config .git/config.orig && + test_when_finished mv .git/config.orig .git/config && + + cat >>.git/config <<-\EOF && + [maintenance] + repo + EOF + cat >expect <<-\EOF && + error: missing value for '\''maintenance.repo'\'' + EOF + git maintenance register 2>actual && + test_cmp expect actual && + git config maintenance.repo +' + +test_expect_success 'unregister with no value for maintenance.repo' ' + cp .git/config .git/config.orig && + test_when_finished mv .git/config.orig .git/config && + + cat >>.git/config <<-\EOF && + [maintenance] + repo + EOF + cat >expect <<-\EOF && + error: missing value for '\''maintenance.repo'\'' + EOF + test_expect_code 128 git maintenance unregister 2>actual.raw && + grep ^error actual.raw >actual && + test_cmp expect actual && + git config maintenance.repo && + + git maintenance unregister --force 2>actual.raw && + grep ^error actual.raw >actual && + test_cmp expect actual && + git config maintenance.repo ' test_expect_success !MINGW 'register and unregister with regex metacharacters' ' @@ -678,7 +744,15 @@ test_expect_success 'start and stop Linux/systemd maintenance' ' # start registers the repo git config --get --global --fixed-value maintenance.repo "$(pwd)" && - test_systemd_analyze_verify "systemd/user/git-maintenance@.service" && + for schedule in hourly daily weekly + do + test_path_is_file "systemd/user/git-maintenance@$schedule.timer" || return 1 + done && + test_path_is_file "systemd/user/git-maintenance@.service" && + + test_systemd_analyze_verify "systemd/user/git-maintenance@hourly.service" && + test_systemd_analyze_verify "systemd/user/git-maintenance@daily.service" && + test_systemd_analyze_verify "systemd/user/git-maintenance@weekly.service" && printf -- "--user enable --now git-maintenance@%s.timer\n" hourly daily weekly >expect && test_cmp expect args && @@ -689,7 +763,10 @@ test_expect_success 'start and stop Linux/systemd maintenance' ' # stop does not unregister the repo git config --get --global --fixed-value maintenance.repo "$(pwd)" && - test_path_is_missing "systemd/user/git-maintenance@.timer" && + for schedule in hourly daily weekly + do + test_path_is_missing "systemd/user/git-maintenance@$schedule.timer" || return 1 + done && test_path_is_missing "systemd/user/git-maintenance@.service" && printf -- "--user disable --now git-maintenance@%s.timer\n" hourly daily weekly >expect && @@ -772,4 +849,17 @@ test_expect_success 'register and unregister bare repo' ' ) ' +test_expect_success 'failed schedule prevents config change' ' + git init --bare failcase && + + for scheduler in crontab launchctl schtasks systemctl + do + GIT_TEST_MAINT_SCHEDULER="$scheduler:false" && + export GIT_TEST_MAINT_SCHEDULER && + test_must_fail \ + git -C failcase maintenance start && + test_must_fail git -C failcase config maintenance.auto || return 1 + done +' + test_done diff --git a/t/t8003-blame-corner-cases.sh b/t/t8003-blame-corner-cases.sh index d751d48b7d..8bcd39e81b 100755 --- a/t/t8003-blame-corner-cases.sh +++ b/t/t8003-blame-corner-cases.sh @@ -201,7 +201,7 @@ committer David Reiss <dreiss@facebook.com> 1234567890 +0000 some message EOF - COMMIT=$(git hash-object -t commit -w badcommit) && + COMMIT=$(git hash-object --literally -t commit -w badcommit) && git --no-pager blame $COMMIT -- uno >/dev/null ' diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 01c74b8b07..263db3ad17 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -12,7 +12,7 @@ PREREQ="PERL" replace_variable_fields () { sed -e "s/^\(Date:\).*/\1 DATE-STRING/" \ - -e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \ + -e "s/^\(Message-ID:\).*/\1 MESSAGE-ID-STRING/" \ -e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/" } @@ -47,7 +47,7 @@ clean_fake_sendmail () { test_expect_success $PREREQ 'Extract patches' ' patches=$(git format-patch -s --cc="One <one@example.com>" --cc=two@example.com -n HEAD^1) && - threaded_patches=$(git format-patch -o threaded -s --in-reply-to="format" HEAD^1) + threaded_patches=$(git format-patch -o threaded --thread=shallow -s --in-reply-to="format" HEAD^1) ' # Test no confirm early to ensure remaining tests will not hang @@ -61,8 +61,8 @@ test_no_confirm () { --smtp-server="$(pwd)/fake.sendmail" \ $@ \ $patches >stdout && - ! grep "Send this email" stdout && - >no_confirm_okay + ! grep "Send this email" stdout && + >no_confirm_okay } # Exit immediately to prevent hang if a no-confirm test fails @@ -225,7 +225,7 @@ Cc: cc@example.com, two@example.com Subject: [PATCH 1/1] Second. Date: DATE-STRING -Message-Id: MESSAGE-ID-STRING +Message-ID: MESSAGE-ID-STRING X-Mailer: X-MAILER-STRING In-Reply-To: <unique-message-id@example.com> References: <unique-message-id@example.com> @@ -337,13 +337,14 @@ test_expect_success $PREREQ 'Show all headers' ' test_expect_success $PREREQ 'Prompting works' ' clean_fake_sendmail && (echo "to@example.com" && - echo "" + echo "my-message-id@example.com" ) | GIT_SEND_EMAIL_NOTTY=1 git send-email \ --smtp-server="$(pwd)/fake.sendmail" \ $patches \ 2>errors && grep "^From: A U Thor <author@example.com>\$" msgtxt1 && - grep "^To: to@example.com\$" msgtxt1 + grep "^To: to@example.com\$" msgtxt1 && + grep "^In-Reply-To: <my-message-id@example.com>" msgtxt1 ' test_expect_success $PREREQ,AUTOIDENT 'implicit ident is allowed' ' @@ -374,13 +375,16 @@ test_expect_success $PREREQ,!AUTOIDENT 'broken implicit ident aborts send-email' ) ' -test_expect_success $PREREQ 'setup tocmd and cccmd scripts' ' +test_expect_success $PREREQ 'setup cmd scripts' ' write_script tocmd-sed <<-\EOF && sed -n -e "s/^tocmd--//p" "$1" EOF - write_script cccmd-sed <<-\EOF + write_script cccmd-sed <<-\EOF && sed -n -e "s/^cccmd--//p" "$1" EOF + write_script headercmd-sed <<-\EOF + sed -n -e "s/^headercmd--//p" "$1" + EOF ' test_expect_success $PREREQ 'tocmd works' ' @@ -410,6 +414,70 @@ test_expect_success $PREREQ 'cccmd works' ' grep "^ cccmd@example.com" msgtxt1 ' +test_expect_success $PREREQ 'headercmd works' ' + clean_fake_sendmail && + cp $patches headercmd.patch && + echo "headercmd--X-Debbugs-CC: dummy@example.com" >>headercmd.patch && + git send-email \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --header-cmd=./headercmd-sed \ + --smtp-server="$(pwd)/fake.sendmail" \ + headercmd.patch \ + && + grep "^X-Debbugs-CC: dummy@example.com" msgtxt1 +' + +test_expect_success $PREREQ '--no-header-cmd works' ' + clean_fake_sendmail && + cp $patches headercmd.patch && + echo "headercmd--X-Debbugs-CC: dummy@example.com" >>headercmd.patch && + git send-email \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --header-cmd=./headercmd-sed \ + --no-header-cmd \ + --smtp-server="$(pwd)/fake.sendmail" \ + headercmd.patch \ + && + ! grep "^X-Debbugs-CC: dummy@example.com" msgtxt1 +' + +test_expect_success $PREREQ 'multiline fields are correctly unfolded' ' + clean_fake_sendmail && + cp $patches headercmd.patch && + write_script headercmd-multiline <<-\EOF && + echo "X-Debbugs-CC: someone@example.com +FoldedField: This is a tale + best told using + multiple lines." + EOF + git send-email \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --header-cmd=./headercmd-multiline \ + --smtp-server="$(pwd)/fake.sendmail" \ + headercmd.patch && + grep "^FoldedField: This is a tale best told using multiple lines.$" msgtxt1 +' + +# Blank lines in the middle of the output of a command are invalid. +test_expect_success $PREREQ 'malform output reported on blank lines in command output' ' + clean_fake_sendmail && + cp $patches headercmd.patch && + write_script headercmd-malformed-output <<-\EOF && + echo "X-Debbugs-CC: someone@example.com + +SomeOtherField: someone-else@example.com" + EOF + ! git send-email \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --header-cmd=./headercmd-malformed-output \ + --smtp-server="$(pwd)/fake.sendmail" \ + headercmd.patch +' + test_expect_success $PREREQ 'reject long lines' ' z8=zzzzzzzz && z64=$z8$z8$z8$z8$z8$z8$z8$z8 && @@ -540,7 +608,7 @@ test_expect_success $PREREQ "--validate respects relative core.hooksPath path" ' test_path_is_file my-hooks.ran && cat >expect <<-EOF && fatal: longline.patch: rejected by sendemail-validate hook - fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch>'"'"' died with exit code 1 + fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch> <header>'"'"' died with exit code 1 warning: no patches were sent EOF test_cmp expect actual @@ -559,12 +627,49 @@ test_expect_success $PREREQ "--validate respects absolute core.hooksPath path" ' test_path_is_file my-hooks.ran && cat >expect <<-EOF && fatal: longline.patch: rejected by sendemail-validate hook - fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch>'"'"' died with exit code 1 + fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch> <header>'"'"' died with exit code 1 warning: no patches were sent EOF test_cmp expect actual ' +test_expect_success $PREREQ "--validate hook supports header argument" ' + write_script my-hooks/sendemail-validate <<-\EOF && + if test "$#" -ge 2 + then + grep "X-test-header: v1.0" "$2" + else + echo "No header arg passed" + exit 1 + fi + EOF + test_config core.hooksPath "my-hooks" && + rm -fr outdir && + git format-patch \ + --add-header="X-test-header: v1.0" \ + -n HEAD^1 -o outdir && + git send-email \ + --dry-run \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + --validate \ + outdir/000?-*.patch +' + +test_expect_success $PREREQ 'clear message-id before parsing a new message' ' + clean_fake_sendmail && + echo true | write_script my-hooks/sendemail-validate && + test_config core.hooksPath my-hooks && + git send-email --validate --to=recipient@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches $threaded_patches && + id0=$(grep "^Message-ID: " $threaded_patches) && + id1=$(grep "^Message-ID: " msgtxt1) && + id2=$(grep "^Message-ID: " msgtxt2) && + test "z$id0" = "z$id2" && + test "z$id1" != "z$id2" +' + for enc in 7bit 8bit quoted-printable base64 do test_expect_success $PREREQ "--transfer-encoding=$enc produces correct header" ' @@ -617,7 +722,7 @@ test_expect_success $PREREQ 'In-Reply-To without --chain-reply-to' ' sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt1 >actual && test_cmp expect actual && # Second and subsequent messages are replies to the first one - sed -n -e "s/^Message-Id: *\(.*\)/\1/p" msgtxt1 >expect && + sed -n -e "s/^Message-ID: *\(.*\)/\1/p" msgtxt1 >expect && sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt2 >actual && test_cmp expect actual && sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt3 >actual && @@ -637,10 +742,10 @@ test_expect_success $PREREQ 'In-Reply-To with --chain-reply-to' ' 2>errors && sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt1 >actual && test_cmp expect actual && - sed -n -e "s/^Message-Id: *\(.*\)/\1/p" msgtxt1 >expect && + sed -n -e "s/^Message-ID: *\(.*\)/\1/p" msgtxt1 >expect && sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt2 >actual && test_cmp expect actual && - sed -n -e "s/^Message-Id: *\(.*\)/\1/p" msgtxt2 >expect && + sed -n -e "s/^Message-ID: *\(.*\)/\1/p" msgtxt2 >expect && sed -n -e "s/^In-Reply-To: *\(.*\)/\1/p" msgtxt3 >actual && test_cmp expect actual ' @@ -713,7 +818,7 @@ Cc: cc@example.com, two@example.com Subject: [PATCH 1/1] Second. Date: DATE-STRING -Message-Id: MESSAGE-ID-STRING +Message-ID: MESSAGE-ID-STRING X-Mailer: X-MAILER-STRING MIME-Version: 1.0 Content-Transfer-Encoding: 8bit @@ -759,7 +864,7 @@ Cc: A <author@example.com>, two@example.com Subject: [PATCH 1/1] Second. Date: DATE-STRING -Message-Id: MESSAGE-ID-STRING +Message-ID: MESSAGE-ID-STRING X-Mailer: X-MAILER-STRING MIME-Version: 1.0 Content-Transfer-Encoding: 8bit @@ -796,7 +901,7 @@ Cc: A <author@example.com>, C O Mitter <committer@example.com> Subject: [PATCH 1/1] Second. Date: DATE-STRING -Message-Id: MESSAGE-ID-STRING +Message-ID: MESSAGE-ID-STRING X-Mailer: X-MAILER-STRING MIME-Version: 1.0 Content-Transfer-Encoding: 8bit @@ -824,7 +929,7 @@ From: Example <from@example.com> To: to@example.com Subject: [PATCH 1/1] Second. Date: DATE-STRING -Message-Id: MESSAGE-ID-STRING +Message-ID: MESSAGE-ID-STRING X-Mailer: X-MAILER-STRING MIME-Version: 1.0 Content-Transfer-Encoding: 8bit @@ -860,7 +965,7 @@ Cc: A <author@example.com>, cc-cmd@example.com Subject: [PATCH 1/1] Second. Date: DATE-STRING -Message-Id: MESSAGE-ID-STRING +Message-ID: MESSAGE-ID-STRING X-Mailer: X-MAILER-STRING MIME-Version: 1.0 Content-Transfer-Encoding: 8bit @@ -893,7 +998,7 @@ Cc: A <author@example.com>, two@example.com Subject: [PATCH 1/1] Second. Date: DATE-STRING -Message-Id: MESSAGE-ID-STRING +Message-ID: MESSAGE-ID-STRING X-Mailer: X-MAILER-STRING MIME-Version: 1.0 Content-Transfer-Encoding: 8bit @@ -926,7 +1031,7 @@ Cc: A <author@example.com>, two@example.com Subject: [PATCH 1/1] Second. Date: DATE-STRING -Message-Id: MESSAGE-ID-STRING +Message-ID: MESSAGE-ID-STRING X-Mailer: X-MAILER-STRING MIME-Version: 1.0 Content-Transfer-Encoding: 8bit @@ -963,7 +1068,7 @@ Cc: A <author@example.com>, C O Mitter <committer@example.com> Subject: [PATCH 1/1] Second. Date: DATE-STRING -Message-Id: MESSAGE-ID-STRING +Message-ID: MESSAGE-ID-STRING X-Mailer: X-MAILER-STRING MIME-Version: 1.0 Content-Transfer-Encoding: 8bit @@ -993,7 +1098,7 @@ Cc: A <author@example.com>, C O Mitter <committer@example.com> Subject: [PATCH 1/1] Second. Date: DATE-STRING -Message-Id: MESSAGE-ID-STRING +Message-ID: MESSAGE-ID-STRING X-Mailer: X-MAILER-STRING MIME-Version: 1.0 Content-Transfer-Encoding: 8bit @@ -1478,7 +1583,7 @@ test_expect_success $PREREQ 'To headers from files reset each patch' ' test_expect_success $PREREQ 'setup expect' ' cat >email-using-8bit <<\EOF From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001 -Message-Id: <bogus-message-id@example.com> +Message-ID: <bogus-message-id@example.com> From: author@example.com Date: Sat, 12 Jun 2010 15:53:58 +0200 Subject: subject goes here @@ -1519,7 +1624,7 @@ test_expect_success $PREREQ 'asks about and fixes 8bit encodings' ' grep "do not declare a Content-Transfer-Encoding" stdout && grep email-using-8bit stdout && grep "Which 8bit encoding" stdout && - egrep "Content|MIME" msgtxt1 >actual && + grep -E "Content|MIME" msgtxt1 >actual && test_cmp content-type-decl actual ' @@ -1530,7 +1635,7 @@ test_expect_success $PREREQ 'sendemail.8bitEncoding works' ' git send-email --from=author@example.com --to=nobody@example.com \ --smtp-server="$(pwd)/fake.sendmail" \ email-using-8bit >stdout && - egrep "Content|MIME" msgtxt1 >actual && + grep -E "Content|MIME" msgtxt1 >actual && test_cmp content-type-decl actual ' @@ -1545,7 +1650,7 @@ test_expect_success $PREREQ 'sendemail.8bitEncoding in .git/config overrides --g git send-email --from=author@example.com --to=nobody@example.com \ --smtp-server="$(pwd)/fake.sendmail" \ email-using-8bit >stdout && - egrep "Content|MIME" msgtxt1 >actual && + grep -E "Content|MIME" msgtxt1 >actual && test_cmp content-type-decl actual ' @@ -1557,14 +1662,14 @@ test_expect_success $PREREQ '--8bit-encoding overrides sendemail.8bitEncoding' ' --smtp-server="$(pwd)/fake.sendmail" \ --8bit-encoding=UTF-8 \ email-using-8bit >stdout && - egrep "Content|MIME" msgtxt1 >actual && + grep -E "Content|MIME" msgtxt1 >actual && test_cmp content-type-decl actual ' test_expect_success $PREREQ 'setup expect' ' cat >email-using-8bit <<-\EOF From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001 - Message-Id: <bogus-message-id@example.com> + Message-ID: <bogus-message-id@example.com> From: author@example.com Date: Sat, 12 Jun 2010 15:53:58 +0200 Subject: Dieser Betreff enthält auch einen Umlaut! @@ -1593,7 +1698,7 @@ test_expect_success $PREREQ '--8bit-encoding also treats subject' ' test_expect_success $PREREQ 'setup expect' ' cat >email-using-8bit <<-\EOF From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001 - Message-Id: <bogus-message-id@example.com> + Message-ID: <bogus-message-id@example.com> From: A U Thor <author@example.com> Date: Sat, 12 Jun 2010 15:53:58 +0200 Content-Type: text/plain; charset=UTF-8 @@ -1674,7 +1779,7 @@ test_expect_success $PREREQ '8-bit and sendemail.transferencoding=base64' ' test_expect_success $PREREQ 'setup expect' ' cat >email-using-qp <<-\EOF From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001 - Message-Id: <bogus-message-id@example.com> + Message-ID: <bogus-message-id@example.com> From: A U Thor <author@example.com> Date: Sat, 12 Jun 2010 15:53:58 +0200 MIME-Version: 1.0 @@ -1700,7 +1805,7 @@ test_expect_success $PREREQ 'convert from quoted-printable to base64' ' test_expect_success $PREREQ 'setup expect' " tr -d '\\015' | tr '%' '\\015' >email-using-crlf <<EOF From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001 -Message-Id: <bogus-message-id@example.com> +Message-ID: <bogus-message-id@example.com> From: A U Thor <author@example.com> Date: Sat, 12 Jun 2010 15:53:58 +0200 Content-Type: text/plain; charset=UTF-8 @@ -2326,6 +2431,37 @@ test_expect_success $PREREQ 'invoke hook' ' ) ' +expected_file_counter_output () { + total=$1 + count=0 + while test $count -ne $total + do + count=$((count + 1)) && + echo "$count/$total" || return + done +} + +test_expect_success $PREREQ '--validate hook allows counting of messages' ' + test_when_finished "rm -rf my-hooks.log" && + test_config core.hooksPath "my-hooks" && + mkdir -p my-hooks && + + write_script my-hooks/sendemail-validate <<-\EOF && + num=$GIT_SENDEMAIL_FILE_COUNTER && + tot=$GIT_SENDEMAIL_FILE_TOTAL && + echo "$num/$tot" >>my-hooks.log || exit 1 + EOF + + >my-hooks.log && + expected_file_counter_output 4 >expect && + git send-email \ + --from="Example <from@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + --validate -3 --cover-letter --force && + test_cmp expect my-hooks.log +' + test_expect_success $PREREQ 'test that send-email works outside a repo' ' nongit git send-email \ --from="Example <nobody@example.com>" \ @@ -2334,6 +2470,12 @@ test_expect_success $PREREQ 'test that send-email works outside a repo' ' "$(pwd)/0001-add-main.patch" ' +test_expect_success $PREREQ 'send-email relays -v 3 to format-patch' ' + test_when_finished "rm -f out" && + git send-email --dry-run -v 3 -1 >out && + grep "PATCH v3" out +' + test_expect_success $PREREQ 'test that sendmail config is rejected' ' test_config sendmail.program sendmail && test_must_fail git send-email \ diff --git a/t/t9003-help-autocorrect.sh b/t/t9003-help-autocorrect.sh index f00deaf381..14a704d0a8 100755 --- a/t/t9003-help-autocorrect.sh +++ b/t/t9003-help-autocorrect.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='help.autocorrect finding a match' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' @@ -60,4 +62,10 @@ test_expect_success 'autocorrect can be declined altogether' ' test_line_count = 1 actual ' +test_expect_success 'autocorrect works in work tree created from bare repo' ' + git clone --bare . bare.git && + git -C bare.git worktree add ../worktree && + git -C worktree -c help.autocorrect=immediate stauts +' + test_done diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh index fea41b3c36..af28b01fef 100755 --- a/t/t9100-git-svn-basic.sh +++ b/t/t9100-git-svn-basic.sh @@ -21,7 +21,7 @@ test_expect_success 'git svn help works anywhere' ' ' test_expect_success \ - 'initialize git svn' ' + 'initialize git svn' ' mkdir import && ( cd import && @@ -38,9 +38,9 @@ test_expect_success \ rm -rf import && git svn init "$svnrepo"' -test_expect_success \ - 'import an SVN revision into git' \ - 'git svn fetch' +test_expect_success 'import an SVN revision into git' ' + git svn fetch +' test_expect_success "checkout from svn" 'svn co "$svnrepo" "$SVN_TREE"' @@ -233,27 +233,26 @@ test_expect_success POSIXPERM,SYMLINKS "$name" ' ' test_expect_success 'exit if remote refs are ambigious' ' - git config --add svn-remote.svn.fetch \ + git config --add svn-remote.svn.fetch \ bar:refs/remotes/git-svn && test_must_fail git svn migrate ' test_expect_success 'exit if init-ing a would clobber a URL' ' - svnadmin create "${PWD}/svnrepo2" && - svn mkdir -m "mkdir bar" "${svnrepo}2/bar" && - git config --unset svn-remote.svn.fetch \ + svnadmin create "${PWD}/svnrepo2" && + svn mkdir -m "mkdir bar" "${svnrepo}2/bar" && + git config --unset svn-remote.svn.fetch \ "^bar:refs/remotes/git-svn$" && test_must_fail git svn init "${svnrepo}2/bar" ' -test_expect_success \ - 'init allows us to connect to another directory in the same repo' ' - git svn init --minimize-url -i bar "$svnrepo/bar" && - git config --get svn-remote.svn.fetch \ - "^bar:refs/remotes/bar$" && - git config --get svn-remote.svn.fetch \ - "^:refs/remotes/git-svn$" - ' +test_expect_success 'init allows us to connect to another directory in the same repo' ' + git svn init --minimize-url -i bar "$svnrepo/bar" && + git config --get svn-remote.svn.fetch \ + "^bar:refs/remotes/bar$" && + git config --get svn-remote.svn.fetch \ + "^:refs/remotes/git-svn$" +' test_expect_success 'dcommit $rev does not clobber current branch' ' git svn fetch -i bar && diff --git a/t/t9104-git-svn-follow-parent.sh b/t/t9104-git-svn-follow-parent.sh index 85d735861f..b5845e28fe 100755 --- a/t/t9104-git-svn-follow-parent.sh +++ b/t/t9104-git-svn-follow-parent.sh @@ -41,51 +41,51 @@ test_expect_success 'init and fetch a moved directory' ' ' test_expect_success 'init and fetch from one svn-remote' ' - git config svn-remote.svn.url "$svnrepo" && - git config --add svn-remote.svn.fetch \ - trunk:refs/remotes/svn/trunk && - git config --add svn-remote.svn.fetch \ - thunk:refs/remotes/svn/thunk && - git svn fetch -i svn/thunk && + git config svn-remote.svn.url "$svnrepo" && + git config --add svn-remote.svn.fetch \ + trunk:refs/remotes/svn/trunk && + git config --add svn-remote.svn.fetch \ + thunk:refs/remotes/svn/thunk && + git svn fetch -i svn/thunk && test "$(git rev-parse --verify refs/remotes/svn/trunk)" \ - = "$(git rev-parse --verify refs/remotes/svn/thunk~1)" && + = "$(git rev-parse --verify refs/remotes/svn/thunk~1)" && git cat-file blob refs/remotes/svn/thunk:readme >actual && test "$(sed -n -e "3p" actual)" = goodbye - ' +' test_expect_success 'follow deleted parent' ' - (svn_cmd cp -m "resurrecting trunk as junk" \ - "$svnrepo"/trunk@2 "$svnrepo"/junk || - svn cp -m "resurrecting trunk as junk" \ - -r2 "$svnrepo"/trunk "$svnrepo"/junk) && - git config --add svn-remote.svn.fetch \ - junk:refs/remotes/svn/junk && - git svn fetch -i svn/thunk && - git svn fetch -i svn/junk && + (svn_cmd cp -m "resurrecting trunk as junk" \ + "$svnrepo"/trunk@2 "$svnrepo"/junk || + svn cp -m "resurrecting trunk as junk" \ + -r2 "$svnrepo"/trunk "$svnrepo"/junk) && + git config --add svn-remote.svn.fetch \ + junk:refs/remotes/svn/junk && + git svn fetch -i svn/thunk && + git svn fetch -i svn/junk && test -z "$(git diff svn/junk svn/trunk)" && test "$(git merge-base svn/junk svn/trunk)" \ - = "$(git rev-parse svn/trunk)" - ' + = "$(git rev-parse svn/trunk)" +' test_expect_success 'follow larger parent' ' - mkdir -p import/trunk/thunk/bump/thud && - echo hi > import/trunk/thunk/bump/thud/file && - svn import -m "import a larger parent" import "$svnrepo"/larger-parent && - svn cp -m "hi" "$svnrepo"/larger-parent "$svnrepo"/another-larger && - git svn init --minimize-url -i larger \ - "$svnrepo"/larger-parent/trunk/thunk/bump/thud && - git svn fetch -i larger && + mkdir -p import/trunk/thunk/bump/thud && + echo hi > import/trunk/thunk/bump/thud/file && + svn import -m "import a larger parent" import "$svnrepo"/larger-parent && + svn cp -m "hi" "$svnrepo"/larger-parent "$svnrepo"/another-larger && + git svn init --minimize-url -i larger \ + "$svnrepo"/larger-parent/trunk/thunk/bump/thud && + git svn fetch -i larger && git svn init --minimize-url -i larger-parent \ - "$svnrepo"/another-larger/trunk/thunk/bump/thud && + "$svnrepo"/another-larger/trunk/thunk/bump/thud && git svn fetch -i larger-parent && - git rev-parse --verify refs/remotes/larger && - git rev-parse --verify \ - refs/remotes/larger-parent && + git rev-parse --verify refs/remotes/larger && + git rev-parse --verify \ + refs/remotes/larger-parent && test "$(git merge-base \ refs/remotes/larger-parent \ refs/remotes/larger)" = \ - "$(git rev-parse refs/remotes/larger)" - ' + "$(git rev-parse refs/remotes/larger)" +' test_expect_success 'follow higher-level parent' ' svn mkdir -m "follow higher-level parent" "$svnrepo"/blob && diff --git a/t/t9106-git-svn-commit-diff-clobber.sh b/t/t9106-git-svn-commit-diff-clobber.sh index 3cab0b9720..bca496c40e 100755 --- a/t/t9106-git-svn-commit-diff-clobber.sh +++ b/t/t9106-git-svn-commit-diff-clobber.sh @@ -3,7 +3,6 @@ # Copyright (c) 2006 Eric Wong test_description='git svn commit-diff clobber' -TEST_FAILS_SANITIZE_LEAK=true . ./lib-git-svn.sh test_expect_success 'initialize repo' ' diff --git a/t/t9115-git-svn-dcommit-funky-renames.sh b/t/t9115-git-svn-dcommit-funky-renames.sh index 419f055721..743fbe1fe4 100755 --- a/t/t9115-git-svn-dcommit-funky-renames.sh +++ b/t/t9115-git-svn-dcommit-funky-renames.sh @@ -5,7 +5,6 @@ test_description='git svn dcommit can commit renames of files with ugly names' -TEST_FAILS_SANITIZE_LEAK=true . ./lib-git-svn.sh test_expect_success 'load repository with strange names' ' diff --git a/t/t9119-git-svn-info.sh b/t/t9119-git-svn-info.sh index 8201c3e808..088d1c57a8 100755 --- a/t/t9119-git-svn-info.sh +++ b/t/t9119-git-svn-info.sh @@ -28,7 +28,7 @@ test_cmp_info () { rm -f tmp.expect tmp.actual } -quoted_svnrepo="$(echo $svnrepo | sed 's/ /%20/')" +quoted_svnrepo="$(echo $svnrepo | test_uri_escape)" test_expect_success 'setup repository and import' ' mkdir info && diff --git a/t/t9133-git-svn-nested-git-repo.sh b/t/t9133-git-svn-nested-git-repo.sh index f894860867..d8d536269c 100755 --- a/t/t9133-git-svn-nested-git-repo.sh +++ b/t/t9133-git-svn-nested-git-repo.sh @@ -35,7 +35,7 @@ test_expect_success 'SVN-side change outside of .git' ' echo b >> a && svn_cmd commit -m "SVN-side change outside of .git" && svn_cmd up && - svn_cmd log -v | fgrep "SVN-side change outside of .git" + svn_cmd log -v | grep -F "SVN-side change outside of .git" ) ' @@ -59,7 +59,7 @@ test_expect_success 'SVN-side change inside of .git' ' svn_cmd add --force .git && svn_cmd commit -m "SVN-side change inside of .git" && svn_cmd up && - svn_cmd log -v | fgrep "SVN-side change inside of .git" + svn_cmd log -v | grep -F "SVN-side change inside of .git" ) ' @@ -82,7 +82,7 @@ test_expect_success 'SVN-side change in and out of .git' ' git commit -m "add a inside an SVN repo" && svn_cmd commit -m "SVN-side change in and out of .git" && svn_cmd up && - svn_cmd log -v | fgrep "SVN-side change in and out of .git" + svn_cmd log -v | grep -F "SVN-side change in and out of .git" ) ' diff --git a/t/t9134-git-svn-ignore-paths.sh b/t/t9134-git-svn-ignore-paths.sh index 4a77eb9f60..3188400226 100755 --- a/t/t9134-git-svn-ignore-paths.sh +++ b/t/t9134-git-svn-ignore-paths.sh @@ -43,7 +43,7 @@ test_expect_success 'init+fetch an SVN repository with ignored www directory' ' test_expect_success 'verify ignore-paths config saved by clone' ' ( cd g && - git config --get svn-remote.svn.ignore-paths | fgrep "www" + git config --get svn-remote.svn.ignore-paths | grep www ) ' @@ -53,7 +53,7 @@ test_expect_success 'SVN-side change outside of www' ' echo b >> qqq/test_qqq.txt && svn_cmd commit -m "SVN-side change outside of www" && svn_cmd up && - svn_cmd log -v | fgrep "SVN-side change outside of www" + svn_cmd log -v | grep "SVN-side change outside of www" ) ' @@ -85,7 +85,7 @@ test_expect_success 'SVN-side change inside of ignored www' ' echo zaq >> www/test_www.txt && svn_cmd commit -m "SVN-side change inside of www/test_www.txt" && svn_cmd up && - svn_cmd log -v | fgrep "SVN-side change inside of www/test_www.txt" + svn_cmd log -v | grep -F "SVN-side change inside of www/test_www.txt" ) ' @@ -118,7 +118,7 @@ test_expect_success 'SVN-side change in and out of ignored www' ' echo ygg >> qqq/test_qqq.txt && svn_cmd commit -m "SVN-side change in and out of ignored www" && svn_cmd up && - svn_cmd log -v | fgrep "SVN-side change in and out of ignored www" + svn_cmd log -v | grep "SVN-side change in and out of ignored www" ) ' diff --git a/t/t9140-git-svn-reset.sh b/t/t9140-git-svn-reset.sh index e855904629..a420b2a87a 100755 --- a/t/t9140-git-svn-reset.sh +++ b/t/t9140-git-svn-reset.sh @@ -43,7 +43,7 @@ test_expect_success 'fetch fails on modified hidden file' ' git svn find-rev refs/remotes/git-svn > ../expect && test_must_fail git svn fetch 2> ../errors && git svn find-rev refs/remotes/git-svn > ../expect2 ) && - fgrep "not found in commit" errors && + grep "not found in commit" errors && test_cmp expect expect2 ' @@ -59,7 +59,7 @@ test_expect_success 'refetch succeeds not ignoring any files' ' ( cd g && git svn fetch && git svn rebase && - fgrep "mod hidden" hid/hid.txt + grep "mod hidden" hid/hid.txt ) ' diff --git a/t/t9146-git-svn-empty-dirs.sh b/t/t9146-git-svn-empty-dirs.sh index 79c26ed69c..09606f1b3c 100755 --- a/t/t9146-git-svn-empty-dirs.sh +++ b/t/t9146-git-svn-empty-dirs.sh @@ -4,7 +4,6 @@ test_description='git svn creates empty directories' -TEST_FAILS_SANITIZE_LEAK=true . ./lib-git-svn.sh test_expect_success 'initialize repo' ' diff --git a/t/t9147-git-svn-include-paths.sh b/t/t9147-git-svn-include-paths.sh index 257fc8f2f8..63fa0b6732 100755 --- a/t/t9147-git-svn-include-paths.sh +++ b/t/t9147-git-svn-include-paths.sh @@ -45,7 +45,7 @@ test_expect_success 'init+fetch an SVN repository with included qqq directory' ' test_expect_success 'verify include-paths config saved by clone' ' ( cd g && - git config --get svn-remote.svn.include-paths | fgrep "qqq" + git config --get svn-remote.svn.include-paths | grep qqq ) ' @@ -55,7 +55,7 @@ test_expect_success 'SVN-side change outside of www' ' echo b >> qqq/test_qqq.txt && svn_cmd commit -m "SVN-side change outside of www" && svn_cmd up && - svn_cmd log -v | fgrep "SVN-side change outside of www" + svn_cmd log -v | grep "SVN-side change outside of www" ) ' @@ -87,7 +87,7 @@ test_expect_success 'SVN-side change inside of ignored www' ' echo zaq >> www/test_www.txt && svn_cmd commit -m "SVN-side change inside of www/test_www.txt" && svn_cmd up && - svn_cmd log -v | fgrep "SVN-side change inside of www/test_www.txt" + svn_cmd log -v | grep "SVN-side change inside of www/test_www.txt" ) ' @@ -120,7 +120,7 @@ test_expect_success 'SVN-side change in and out of included qqq' ' echo ygg >> qqq/test_qqq.txt && svn_cmd commit -m "SVN-side change in and out of ignored www" && svn_cmd up && - svn_cmd log -v | fgrep "SVN-side change in and out of ignored www" + svn_cmd log -v | grep "SVN-side change in and out of ignored www" ) ' diff --git a/t/t9148-git-svn-propset.sh b/t/t9148-git-svn-propset.sh index 6cc76a07b3..aebb28995e 100755 --- a/t/t9148-git-svn-propset.sh +++ b/t/t9148-git-svn-propset.sh @@ -5,7 +5,6 @@ test_description='git svn propset tests' -TEST_FAILS_SANITIZE_LEAK=true . ./lib-git-svn.sh test_expect_success 'setup propset via import' ' diff --git a/t/t9160-git-svn-preserve-empty-dirs.sh b/t/t9160-git-svn-preserve-empty-dirs.sh index 9cf7a1427a..36c6b1a12f 100755 --- a/t/t9160-git-svn-preserve-empty-dirs.sh +++ b/t/t9160-git-svn-preserve-empty-dirs.sh @@ -9,7 +9,6 @@ This test uses git to clone a Subversion repository that contains empty directories, and checks that corresponding directories are created in the local Git repository with placeholder files.' -TEST_FAILS_SANITIZE_LEAK=true . ./lib-git-svn.sh GIT_REPO=git-svn-repo diff --git a/t/t9164-git-svn-dcommit-concurrent.sh b/t/t9164-git-svn-dcommit-concurrent.sh index 1465156072..c8e6c0733f 100755 --- a/t/t9164-git-svn-dcommit-concurrent.sh +++ b/t/t9164-git-svn-dcommit-concurrent.sh @@ -5,7 +5,6 @@ test_description='concurrent git svn dcommit' -TEST_FAILS_SANITIZE_LEAK=true . ./lib-git-svn.sh diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index c5946cb0b8..a44eabf0d8 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -50,56 +50,56 @@ check_entries () { fi } -test_expect_success \ - 'New file' \ - 'mkdir A B C D E F && - echo hello1 >A/newfile1.txt && - echo hello2 >B/newfile2.txt && - cp "$TEST_DIRECTORY"/test-binary-1.png C/newfile3.png && - cp "$TEST_DIRECTORY"/test-binary-1.png D/newfile4.png && - git add A/newfile1.txt && - git add B/newfile2.txt && - git add C/newfile3.png && - git add D/newfile4.png && - git commit -a -m "Test: New file" && - id=$(git rev-list --max-count=1 HEAD) && - (cd "$CVSWORK" && - git cvsexportcommit -c $id && - check_entries A "newfile1.txt/1.1/" && - check_entries B "newfile2.txt/1.1/" && - check_entries C "newfile3.png/1.1/-kb" && - check_entries D "newfile4.png/1.1/-kb" && - test_cmp A/newfile1.txt ../A/newfile1.txt && - test_cmp B/newfile2.txt ../B/newfile2.txt && - test_cmp C/newfile3.png ../C/newfile3.png && - test_cmp D/newfile4.png ../D/newfile4.png - )' +test_expect_success 'New file' ' + mkdir A B C D E F && + echo hello1 >A/newfile1.txt && + echo hello2 >B/newfile2.txt && + cp "$TEST_DIRECTORY"/test-binary-1.png C/newfile3.png && + cp "$TEST_DIRECTORY"/test-binary-1.png D/newfile4.png && + git add A/newfile1.txt && + git add B/newfile2.txt && + git add C/newfile3.png && + git add D/newfile4.png && + git commit -a -m "Test: New file" && + id=$(git rev-list --max-count=1 HEAD) && + (cd "$CVSWORK" && + git cvsexportcommit -c $id && + check_entries A "newfile1.txt/1.1/" && + check_entries B "newfile2.txt/1.1/" && + check_entries C "newfile3.png/1.1/-kb" && + check_entries D "newfile4.png/1.1/-kb" && + test_cmp A/newfile1.txt ../A/newfile1.txt && + test_cmp B/newfile2.txt ../B/newfile2.txt && + test_cmp C/newfile3.png ../C/newfile3.png && + test_cmp D/newfile4.png ../D/newfile4.png + ) +' -test_expect_success \ - 'Remove two files, add two and update two' \ - 'echo Hello1 >>A/newfile1.txt && - rm -f B/newfile2.txt && - rm -f C/newfile3.png && - echo Hello5 >E/newfile5.txt && - cp "$TEST_DIRECTORY"/test-binary-2.png D/newfile4.png && - cp "$TEST_DIRECTORY"/test-binary-1.png F/newfile6.png && - git add E/newfile5.txt && - git add F/newfile6.png && - git commit -a -m "Test: Remove, add and update" && - id=$(git rev-list --max-count=1 HEAD) && - (cd "$CVSWORK" && - git cvsexportcommit -c $id && - check_entries A "newfile1.txt/1.2/" && - check_entries B "" && - check_entries C "" && - check_entries D "newfile4.png/1.2/-kb" && - check_entries E "newfile5.txt/1.1/" && - check_entries F "newfile6.png/1.1/-kb" && - test_cmp A/newfile1.txt ../A/newfile1.txt && - test_cmp D/newfile4.png ../D/newfile4.png && - test_cmp E/newfile5.txt ../E/newfile5.txt && - test_cmp F/newfile6.png ../F/newfile6.png - )' +test_expect_success 'Remove two files, add two and update two' ' + echo Hello1 >>A/newfile1.txt && + rm -f B/newfile2.txt && + rm -f C/newfile3.png && + echo Hello5 >E/newfile5.txt && + cp "$TEST_DIRECTORY"/test-binary-2.png D/newfile4.png && + cp "$TEST_DIRECTORY"/test-binary-1.png F/newfile6.png && + git add E/newfile5.txt && + git add F/newfile6.png && + git commit -a -m "Test: Remove, add and update" && + id=$(git rev-list --max-count=1 HEAD) && + (cd "$CVSWORK" && + git cvsexportcommit -c $id && + check_entries A "newfile1.txt/1.2/" && + check_entries B "" && + check_entries C "" && + check_entries D "newfile4.png/1.2/-kb" && + check_entries E "newfile5.txt/1.1/" && + check_entries F "newfile6.png/1.1/-kb" && + test_cmp A/newfile1.txt ../A/newfile1.txt && + test_cmp D/newfile4.png ../D/newfile4.png && + test_cmp E/newfile5.txt ../E/newfile5.txt && + test_cmp F/newfile6.png ../F/newfile6.png + ) +' # Should fail (but only on the git cvsexportcommit stage) test_expect_success \ @@ -129,67 +129,67 @@ test_expect_success \ # This test is here because a patch for only binary files will # fail with gnu patch, so cvsexportcommit must handle that. -test_expect_success \ - 'Remove only binary files' \ - 'git reset --hard HEAD^^ && - rm -f D/newfile4.png && - git commit -a -m "test: remove only a binary file" && - id=$(git rev-list --max-count=1 HEAD) && - (cd "$CVSWORK" && - git cvsexportcommit -c $id && - check_entries A "newfile1.txt/1.2/" && - check_entries B "" && - check_entries C "" && - check_entries D "" && - check_entries E "newfile5.txt/1.1/" && - check_entries F "newfile6.png/1.1/-kb" && - test_cmp A/newfile1.txt ../A/newfile1.txt && - test_cmp E/newfile5.txt ../E/newfile5.txt && - test_cmp F/newfile6.png ../F/newfile6.png - )' +test_expect_success 'Remove only binary files' ' + git reset --hard HEAD^^ && + rm -f D/newfile4.png && + git commit -a -m "test: remove only a binary file" && + id=$(git rev-list --max-count=1 HEAD) && + (cd "$CVSWORK" && + git cvsexportcommit -c $id && + check_entries A "newfile1.txt/1.2/" && + check_entries B "" && + check_entries C "" && + check_entries D "" && + check_entries E "newfile5.txt/1.1/" && + check_entries F "newfile6.png/1.1/-kb" && + test_cmp A/newfile1.txt ../A/newfile1.txt && + test_cmp E/newfile5.txt ../E/newfile5.txt && + test_cmp F/newfile6.png ../F/newfile6.png + ) +' -test_expect_success \ - 'Remove only a text file' \ - 'rm -f A/newfile1.txt && - git commit -a -m "test: remove only a binary file" && - id=$(git rev-list --max-count=1 HEAD) && - (cd "$CVSWORK" && - git cvsexportcommit -c $id && - check_entries A "" && - check_entries B "" && - check_entries C "" && - check_entries D "" && - check_entries E "newfile5.txt/1.1/" && - check_entries F "newfile6.png/1.1/-kb" && - test_cmp E/newfile5.txt ../E/newfile5.txt && - test_cmp F/newfile6.png ../F/newfile6.png - )' +test_expect_success 'Remove only a text file' ' + rm -f A/newfile1.txt && + git commit -a -m "test: remove only a binary file" && + id=$(git rev-list --max-count=1 HEAD) && + (cd "$CVSWORK" && + git cvsexportcommit -c $id && + check_entries A "" && + check_entries B "" && + check_entries C "" && + check_entries D "" && + check_entries E "newfile5.txt/1.1/" && + check_entries F "newfile6.png/1.1/-kb" && + test_cmp E/newfile5.txt ../E/newfile5.txt && + test_cmp F/newfile6.png ../F/newfile6.png + ) +' -test_expect_success \ - 'New file with spaces in file name' \ - 'mkdir "G g" && - echo ok then >"G g/with spaces.txt" && - git add "G g/with spaces.txt" && \ - cp "$TEST_DIRECTORY"/test-binary-1.png "G g/with spaces.png" && \ - git add "G g/with spaces.png" && - git commit -a -m "With spaces" && - id=$(git rev-list --max-count=1 HEAD) && - (cd "$CVSWORK" && - git cvsexportcommit -c $id && - check_entries "G g" "with spaces.png/1.1/-kb|with spaces.txt/1.1/" - )' +test_expect_success 'New file with spaces in file name' ' + mkdir "G g" && + echo ok then >"G g/with spaces.txt" && + git add "G g/with spaces.txt" && \ + cp "$TEST_DIRECTORY"/test-binary-1.png "G g/with spaces.png" && \ + git add "G g/with spaces.png" && + git commit -a -m "With spaces" && + id=$(git rev-list --max-count=1 HEAD) && + (cd "$CVSWORK" && + git cvsexportcommit -c $id && + check_entries "G g" "with spaces.png/1.1/-kb|with spaces.txt/1.1/" + ) +' -test_expect_success \ - 'Update file with spaces in file name' \ - 'echo Ok then >>"G g/with spaces.txt" && - cat "$TEST_DIRECTORY"/test-binary-1.png >>"G g/with spaces.png" && \ - git add "G g/with spaces.png" && - git commit -a -m "Update with spaces" && - id=$(git rev-list --max-count=1 HEAD) && - (cd "$CVSWORK" && - git cvsexportcommit -c $id && - check_entries "G g" "with spaces.png/1.2/-kb|with spaces.txt/1.2/" - )' +test_expect_success 'Update file with spaces in file name' ' + echo Ok then >>"G g/with spaces.txt" && + cat "$TEST_DIRECTORY"/test-binary-1.png >>"G g/with spaces.png" && \ + git add "G g/with spaces.png" && + git commit -a -m "Update with spaces" && + id=$(git rev-list --max-count=1 HEAD) && + (cd "$CVSWORK" && + git cvsexportcommit -c $id && + check_entries "G g" "with spaces.png/1.2/-kb|with spaces.txt/1.2/" + ) +' # Some filesystems mangle pathnames with UTF-8 characters -- # check and skip @@ -202,68 +202,68 @@ if p="Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö" && then # This test contains UTF-8 characters -test_expect_success !MINGW \ - 'File with non-ascii file name' \ - 'mkdir -p Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö && - echo Foo >Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.txt && - git add Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.txt && - cp "$TEST_DIRECTORY"/test-binary-1.png Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.png && - git add Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.png && - git commit -a -m "Går det så går det" && \ - id=$(git rev-list --max-count=1 HEAD) && - (cd "$CVSWORK" && - git cvsexportcommit -v -c $id && - check_entries \ - "Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö" \ - "gårdetsågårdet.png/1.1/-kb|gårdetsågårdet.txt/1.1/" - )' +test_expect_success !MINGW 'File with non-ascii file name' ' + mkdir -p Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö && + echo Foo >Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.txt && + git add Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.txt && + cp "$TEST_DIRECTORY"/test-binary-1.png Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.png && + git add Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.png && + git commit -a -m "Går det så går det" && \ + id=$(git rev-list --max-count=1 HEAD) && + (cd "$CVSWORK" && + git cvsexportcommit -v -c $id && + check_entries \ + "Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö" \ + "gårdetsågårdet.png/1.1/-kb|gårdetsågårdet.txt/1.1/" + ) +' fi rm -fr tst -test_expect_success \ - 'Mismatching patch should fail' \ - 'date >>"E/newfile5.txt" && - git add "E/newfile5.txt" && - git commit -a -m "Update one" && - date >>"E/newfile5.txt" && - git add "E/newfile5.txt" && - git commit -a -m "Update two" && - id=$(git rev-list --max-count=1 HEAD) && - (cd "$CVSWORK" && - test_must_fail git cvsexportcommit -c $id - )' - -test_expect_success FILEMODE \ - 'Retain execute bit' \ - 'mkdir G && - echo executeon >G/on && - chmod +x G/on && - echo executeoff >G/off && - git add G/on && - git add G/off && - git commit -a -m "Execute test" && - (cd "$CVSWORK" && - git cvsexportcommit -c HEAD && - test -x G/on && - ! test -x G/off - )' +test_expect_success 'Mismatching patch should fail' ' + date >>"E/newfile5.txt" && + git add "E/newfile5.txt" && + git commit -a -m "Update one" && + date >>"E/newfile5.txt" && + git add "E/newfile5.txt" && + git commit -a -m "Update two" && + id=$(git rev-list --max-count=1 HEAD) && + (cd "$CVSWORK" && + test_must_fail git cvsexportcommit -c $id + ) +' + +test_expect_success FILEMODE 'Retain execute bit' ' + mkdir G && + echo executeon >G/on && + chmod +x G/on && + echo executeoff >G/off && + git add G/on && + git add G/off && + git commit -a -m "Execute test" && + (cd "$CVSWORK" && + git cvsexportcommit -c HEAD && + test -x G/on && + ! test -x G/off + ) +' test_expect_success '-w option should work with relative GIT_DIR' ' - mkdir W && - echo foobar >W/file1.txt && - echo bazzle >W/file2.txt && - git add W/file1.txt && - git add W/file2.txt && - git commit -m "More updates" && - id=$(git rev-list --max-count=1 HEAD) && - (cd "$GIT_DIR" && - GIT_DIR=. git cvsexportcommit -w "$CVSWORK" -c $id && - check_entries "$CVSWORK/W" "file1.txt/1.1/|file2.txt/1.1/" && - test_cmp "$CVSWORK/W/file1.txt" ../W/file1.txt && - test_cmp "$CVSWORK/W/file2.txt" ../W/file2.txt - ) + mkdir W && + echo foobar >W/file1.txt && + echo bazzle >W/file2.txt && + git add W/file1.txt && + git add W/file2.txt && + git commit -m "More updates" && + id=$(git rev-list --max-count=1 HEAD) && + (cd "$GIT_DIR" && + GIT_DIR=. git cvsexportcommit -w "$CVSWORK" -c $id && + check_entries "$CVSWORK/W" "file1.txt/1.1/|file2.txt/1.1/" && + test_cmp "$CVSWORK/W/file1.txt" ../W/file1.txt && + test_cmp "$CVSWORK/W/file2.txt" ../W/file2.txt + ) ' test_expect_success 'check files before directories' ' @@ -290,21 +290,20 @@ test_expect_success 'check files before directories' ' ' test_expect_success 're-commit a removed filename which remains in CVS attic' ' - - (cd "$CVSWORK" && - echo >attic_gremlin && - cvs -Q add attic_gremlin && - cvs -Q ci -m "added attic_gremlin" && - rm attic_gremlin && - cvs -Q rm attic_gremlin && - cvs -Q ci -m "removed attic_gremlin") && - - echo > attic_gremlin && - git add attic_gremlin && - git commit -m "Added attic_gremlin" && + (cd "$CVSWORK" && + echo >attic_gremlin && + cvs -Q add attic_gremlin && + cvs -Q ci -m "added attic_gremlin" && + rm attic_gremlin && + cvs -Q rm attic_gremlin && + cvs -Q ci -m "removed attic_gremlin") && + + echo > attic_gremlin && + git add attic_gremlin && + git commit -m "Added attic_gremlin" && git cvsexportcommit -w "$CVSWORK" -c HEAD && - (cd "$CVSWORK" && cvs -Q update -d) && - test -f "$CVSWORK/attic_gremlin" + (cd "$CVSWORK" && cvs -Q update -d) && + test -f "$CVSWORK/attic_gremlin" ' # the state of the CVS sandbox may be indeterminate for ' space' diff --git a/t/t9210-scalar.sh b/t/t9210-scalar.sh index 14ca575a21..4432a30d10 100755 --- a/t/t9210-scalar.sh +++ b/t/t9210-scalar.sh @@ -104,6 +104,13 @@ test_expect_success FSMONITOR_DAEMON 'scalar register starts fsmon daemon' ' test_cmp_config -C test/src true core.fsmonitor ' +test_expect_success 'scalar register warns when background maintenance fails' ' + git init register-repo && + GIT_TEST_MAINT_SCHEDULER="crontab:false,launchctl:false,schtasks:false" \ + scalar register register-repo 2>err && + grep "could not turn on maintenance" err +' + test_expect_success 'scalar unregister' ' git init vanish/src && scalar register vanish/src && @@ -116,7 +123,10 @@ test_expect_success 'scalar unregister' ' test_must_fail git config --get --global --fixed-value \ maintenance.repo "$(pwd)/vanish/src" && scalar list >scalar.repos && - ! grep -F "$(pwd)/vanish/src" scalar.repos + ! grep -F "$(pwd)/vanish/src" scalar.repos && + + # scalar unregister should be idempotent + scalar unregister vanish ' test_expect_success 'set up repository to clone' ' @@ -163,6 +173,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 ' diff --git a/t/t9211-scalar-clone.sh b/t/t9211-scalar-clone.sh index dd33d87e9b..7869f45ee6 100755 --- a/t/t9211-scalar-clone.sh +++ b/t/t9211-scalar-clone.sh @@ -3,6 +3,7 @@ test_description='test the `scalar clone` subcommand' . ./test-lib.sh +. "${TEST_DIRECTORY}/lib-terminal.sh" GIT_TEST_MAINT_SCHEDULER="crontab:test-tool crontab cron.txt,launchctl:true,schtasks:true" export GIT_TEST_MAINT_SCHEDULER @@ -148,4 +149,47 @@ test_expect_success '--no-single-branch clones all branches' ' cleanup_clone $enlistment ' +test_expect_success TTY 'progress with tty' ' + enlistment=progress1 && + + test_config -C to-clone uploadpack.allowfilter true && + test_config -C to-clone uploadpack.allowanysha1inwant true && + + test_terminal env GIT_PROGRESS_DELAY=0 \ + scalar clone "file://$(pwd)/to-clone" "$enlistment" 2>stderr && + grep "Enumerating objects" stderr >actual && + test_line_count = 2 actual && + cleanup_clone $enlistment +' + +test_expect_success 'progress without tty' ' + enlistment=progress2 && + + test_config -C to-clone uploadpack.allowfilter true && + test_config -C to-clone uploadpack.allowanysha1inwant true && + + GIT_PROGRESS_DELAY=0 scalar clone "file://$(pwd)/to-clone" "$enlistment" 2>stderr && + ! grep "Enumerating objects" stderr && + ! grep "Updating files" stderr && + cleanup_clone $enlistment +' + +test_expect_success 'scalar clone warns when background maintenance fails' ' + GIT_TEST_MAINT_SCHEDULER="crontab:false,launchctl:false,schtasks:false" \ + scalar clone "file://$(pwd)/to-clone" maint-fail 2>err && + grep "could not turn on maintenance" err +' + +test_expect_success '`scalar clone --no-src`' ' + scalar clone --src "file://$(pwd)/to-clone" with-src && + scalar clone --no-src "file://$(pwd)/to-clone" without-src && + + test_path_is_dir with-src/src && + test_path_is_missing without-src/src && + + (cd with-src/src && ls ?*) >with && + (cd without-src && ls ?*) >without && + test_cmp with without +' + test_done diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index aa55b41b9a..ac237a1f90 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -388,9 +388,7 @@ test_expect_success 'B: accept branch name "TEMP_TAG"' ' INPUT_END - test_when_finished "rm -f .git/TEMP_TAG - git gc - git prune" && + test_when_finished "rm -f .git/TEMP_TAG && git gc --prune=now" && git fast-import <input && test $(test-tool ref-store main resolve-ref TEMP_TAG 0 | cut -f1 -d " " ) != "$ZERO_OID" && test $(git rev-parse main) = $(git rev-parse TEMP_TAG^) @@ -406,8 +404,7 @@ test_expect_success 'B: accept empty committer' ' INPUT_END test_when_finished "git update-ref -d refs/heads/empty-committer-1 - git gc - git prune" && + git gc --prune=now" && git fast-import <input && out=$(git fsck) && echo "$out" && @@ -452,8 +449,7 @@ test_expect_success 'B: accept and fixup committer with no name' ' INPUT_END test_when_finished "git update-ref -d refs/heads/empty-committer-2 - git gc - git prune" && + git gc --prune=now" && git fast-import <input && out=$(git fsck) && echo "$out" && @@ -1778,8 +1774,7 @@ test_expect_success 'P: verbatim SHA gitlinks' ' INPUT_END git branch -D sub && - git gc && - git prune && + git gc --prune=now && git fast-import <input && test $(git rev-parse --verify subuse2) = $(git rev-parse --verify subuse1) ' diff --git a/t/t9304-fast-import-marks.sh b/t/t9304-fast-import-marks.sh index a98ef032d9..410a871c52 100755 --- a/t/t9304-fast-import-marks.sh +++ b/t/t9304-fast-import-marks.sh @@ -49,4 +49,33 @@ test_expect_success 'import with submodule mapping' ' test_cmp expect actual ' +test_expect_success 'paths adjusted for relative subdir' ' + git init deep-dst && + mkdir deep-dst/subdir && + >deep-dst/subdir/empty-marks && + git -C deep-dst/subdir fast-import \ + --rewrite-submodules-from=sub:../../from \ + --rewrite-submodules-to=sub:../../to \ + --import-marks=empty-marks \ + --export-marks=exported-marks \ + --export-pack-edges=exported-edges \ + <dump && + # we do not bother checking resulting repo; we just care that nothing + # complained about failing to open files for reading, and that files + # for writing were created in the expected spot + test_path_is_file deep-dst/subdir/exported-marks && + test_path_is_file deep-dst/subdir/exported-edges +' + +test_expect_success 'relative marks are not affected by subdir' ' + git init deep-relative && + mkdir deep-relative/subdir && + git -C deep-relative/subdir fast-import \ + --relative-marks \ + --export-marks=exported-marks \ + <dump && + test_path_is_missing deep-relative/subdir/exported-marks && + test_path_is_file deep-relative/.git/info/fast-import/exported-marks +' + test_done diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh index ff21a12ee6..26c25c0eb2 100755 --- a/t/t9350-fast-export.sh +++ b/t/t9350-fast-export.sh @@ -373,7 +373,7 @@ EOF test_expect_success 'cope with tagger-less tags' ' - TAG=$(git hash-object -t tag -w tag-content) && + TAG=$(git hash-object --literally -t tag -w tag-content) && git update-ref refs/tags/sonnenschein $TAG && git fast-export -C -C --signed-tags=strip --all > output && test $(grep -c "^tag " output) = 4 && diff --git a/t/t9351-fast-export-anonymize.sh b/t/t9351-fast-export-anonymize.sh index 77047e250d..156a647484 100755 --- a/t/t9351-fast-export-anonymize.sh +++ b/t/t9351-fast-export-anonymize.sh @@ -25,6 +25,7 @@ test_expect_success 'setup simple repo' ' test_expect_success 'export anonymized stream' ' git fast-export --anonymize --all \ --anonymize-map=retain-me \ + --anonymize-map=xyzzy:should-not-appear \ --anonymize-map=xyzzy:custom-name \ --anonymize-map=other \ >stream @@ -41,6 +42,7 @@ test_expect_success 'stream omits path names' ' test_expect_success 'stream contains user-specified names' ' grep retain-me stream && + ! grep should-not-appear stream && grep custom-name stream ' diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh index 379b19f2f8..003c0b61d0 100755 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@ -66,10 +66,11 @@ test_expect_success 'setup' ' # note that cvs doesn't accept absolute pathnames # as argument to co -d -test_expect_success 'basic checkout' \ - 'GIT_CONFIG="$git_config" cvs -Q co -d cvswork main && - test "$(echo $(grep -v ^D cvswork/CVS/Entries|cut -d/ -f2,3,5 | head -n 1))" = "empty/1.1/" && - test "$(echo $(grep -v ^D cvswork/CVS/Entries|cut -d/ -f2,3,5 | sed -ne \$p))" = "secondrootfile/1.1/"' +test_expect_success 'basic checkout' ' + GIT_CONFIG="$git_config" cvs -Q co -d cvswork main && + test "$(echo $(grep -v ^D cvswork/CVS/Entries|cut -d/ -f2,3,5 | head -n 1))" = "empty/1.1/" && + test "$(echo $(grep -v ^D cvswork/CVS/Entries|cut -d/ -f2,3,5 | sed -ne \$p))" = "secondrootfile/1.1/" +' #------------------------ # PSERVER AUTHENTICATION @@ -115,35 +116,40 @@ Ah<Z:yZZ30 e END VERIFICATION REQUEST EOF -test_expect_success 'pserver authentication' \ - 'cat request-anonymous | git-cvsserver pserver >log 2>&1 && - sed -ne \$p log | grep "^I LOVE YOU\$"' +test_expect_success 'pserver authentication' ' + cat request-anonymous | git-cvsserver pserver >log 2>&1 && + sed -ne \$p log | grep "^I LOVE YOU\$" +' -test_expect_success 'pserver authentication failure (non-anonymous user)' \ - 'if cat request-git | git-cvsserver pserver >log 2>&1 - then - false - else - true - fi && - sed -ne \$p log | grep "^I HATE YOU\$"' +test_expect_success 'pserver authentication failure (non-anonymous user)' ' + if cat request-git | git-cvsserver pserver >log 2>&1 + then + false + else + true + fi && + sed -ne \$p log | grep "^I HATE YOU\$" +' -test_expect_success 'pserver authentication success (non-anonymous user with password)' \ - 'cat login-git-ok | git-cvsserver pserver >log 2>&1 && - sed -ne \$p log | grep "^I LOVE YOU\$"' +test_expect_success 'pserver authentication success (non-anonymous user with password)' ' + cat login-git-ok | git-cvsserver pserver >log 2>&1 && + sed -ne \$p log | grep "^I LOVE YOU\$" +' -test_expect_success 'pserver authentication (login)' \ - 'cat login-anonymous | git-cvsserver pserver >log 2>&1 && - sed -ne \$p log | grep "^I LOVE YOU\$"' +test_expect_success 'pserver authentication (login)' ' + cat login-anonymous | git-cvsserver pserver >log 2>&1 && + sed -ne \$p log | grep "^I LOVE YOU\$" +' -test_expect_success 'pserver authentication failure (login/non-anonymous user)' \ - 'if cat login-git | git-cvsserver pserver >log 2>&1 - then - false - else - true - fi && - sed -ne \$p log | grep "^I HATE YOU\$"' +test_expect_success 'pserver authentication failure (login/non-anonymous user)' ' + if cat login-git | git-cvsserver pserver >log 2>&1 + then + false + else + true + fi && + sed -ne \$p log | grep "^I HATE YOU\$" +' # misuse pserver authentication for testing of req_Root @@ -165,36 +171,40 @@ END AUTH REQUEST Root $WORKDIR EOF -test_expect_success 'req_Root failure (relative pathname)' \ - 'if cat request-relative | git-cvsserver pserver >log 2>&1 - then - echo unexpected success - false - else - true - fi && - tail log | grep "^error 1 Root must be an absolute pathname$"' +test_expect_success 'req_Root failure (relative pathname)' ' + if cat request-relative | git-cvsserver pserver >log 2>&1 + then + echo unexpected success + false + else + true + fi && + tail log | grep "^error 1 Root must be an absolute pathname$" +' -test_expect_success 'req_Root failure (conflicting roots)' \ - 'cat request-conflict | git-cvsserver pserver >log 2>&1 && - tail log | grep "^error 1 Conflicting roots specified$"' +test_expect_success 'req_Root failure (conflicting roots)' ' + cat request-conflict | git-cvsserver pserver >log 2>&1 && + tail log | grep "^error 1 Conflicting roots specified$" +' -test_expect_success 'req_Root (strict paths)' \ - 'cat request-anonymous | git-cvsserver --strict-paths pserver "$SERVERDIR" >log 2>&1 && - sed -ne \$p log | grep "^I LOVE YOU\$"' +test_expect_success 'req_Root (strict paths)' ' + cat request-anonymous | git-cvsserver --strict-paths pserver "$SERVERDIR" >log 2>&1 && + sed -ne \$p log | grep "^I LOVE YOU\$" +' test_expect_success 'req_Root failure (strict-paths)' ' - ! cat request-anonymous | - git-cvsserver --strict-paths pserver "$WORKDIR" >log 2>&1 + ! cat request-anonymous | + git-cvsserver --strict-paths pserver "$WORKDIR" >log 2>&1 ' -test_expect_success 'req_Root (w/o strict-paths)' \ - 'cat request-anonymous | git-cvsserver pserver "$WORKDIR/" >log 2>&1 && - sed -ne \$p log | grep "^I LOVE YOU\$"' +test_expect_success 'req_Root (w/o strict-paths)' ' + cat request-anonymous | git-cvsserver pserver "$WORKDIR/" >log 2>&1 && + sed -ne \$p log | grep "^I LOVE YOU\$" +' test_expect_success 'req_Root failure (w/o strict-paths)' ' - ! cat request-anonymous | - git-cvsserver pserver "$WORKDIR/gitcvs" >log 2>&1 + ! cat request-anonymous | + git-cvsserver pserver "$WORKDIR/gitcvs" >log 2>&1 ' cat >request-base <<EOF @@ -206,27 +216,30 @@ END AUTH REQUEST Root /gitcvs.git EOF -test_expect_success 'req_Root (base-path)' \ - 'cat request-base | git-cvsserver --strict-paths --base-path "$WORKDIR/" pserver "$SERVERDIR" >log 2>&1 && - sed -ne \$p log | grep "^I LOVE YOU\$"' +test_expect_success 'req_Root (base-path)' ' + cat request-base | git-cvsserver --strict-paths --base-path "$WORKDIR/" pserver "$SERVERDIR" >log 2>&1 && + sed -ne \$p log | grep "^I LOVE YOU\$" +' test_expect_success 'req_Root failure (base-path)' ' - ! cat request-anonymous | - git-cvsserver --strict-paths --base-path "$WORKDIR" pserver "$SERVERDIR" >log 2>&1 + ! cat request-anonymous | + git-cvsserver --strict-paths --base-path "$WORKDIR" pserver "$SERVERDIR" >log 2>&1 ' GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled false || exit 1 -test_expect_success 'req_Root (export-all)' \ - 'cat request-anonymous | git-cvsserver --export-all pserver "$WORKDIR" >log 2>&1 && - sed -ne \$p log | grep "^I LOVE YOU\$"' +test_expect_success 'req_Root (export-all)' ' + cat request-anonymous | git-cvsserver --export-all pserver "$WORKDIR" >log 2>&1 && + sed -ne \$p log | grep "^I LOVE YOU\$" +' -test_expect_success 'req_Root failure (export-all w/o directory list)' \ - '! (cat request-anonymous | git-cvsserver --export-all pserver >log 2>&1 || false)' +test_expect_success 'req_Root failure (export-all w/o directory list)' ' + ! (cat request-anonymous | git-cvsserver --export-all pserver >log 2>&1 || false)' -test_expect_success 'req_Root (everything together)' \ - 'cat request-base | git-cvsserver --export-all --strict-paths --base-path "$WORKDIR/" pserver "$SERVERDIR" >log 2>&1 && - sed -ne \$p log | grep "^I LOVE YOU\$"' +test_expect_success 'req_Root (everything together)' ' + cat request-base | git-cvsserver --export-all --strict-paths --base-path "$WORKDIR/" pserver "$SERVERDIR" >log 2>&1 && + sed -ne \$p log | grep "^I LOVE YOU\$" +' GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true || exit 1 @@ -247,45 +260,49 @@ test_expect_success 'gitcvs.enabled = false' \ test ! -d cvswork2' rm -fr cvswork2 -test_expect_success 'gitcvs.ext.enabled = true' \ - 'GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled true && - GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled false && - GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 main >cvs.log 2>&1 && - test_cmp cvswork cvswork2' +test_expect_success 'gitcvs.ext.enabled = true' ' + GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled true && + GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled false && + GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 main >cvs.log 2>&1 && + test_cmp cvswork cvswork2 +' rm -fr cvswork2 -test_expect_success 'gitcvs.ext.enabled = false' \ - 'GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled false && - GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true && - if GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 main >cvs.log 2>&1 - then - echo unexpected cvs success - false - else - true - fi && - grep "GITCVS emulation disabled" cvs.log && - test ! -d cvswork2' +test_expect_success 'gitcvs.ext.enabled = false' ' + GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled false && + GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true && + if GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 main >cvs.log 2>&1 + then + echo unexpected cvs success + false + else + true + fi && + grep "GITCVS emulation disabled" cvs.log && + test ! -d cvswork2 +' rm -fr cvswork2 -test_expect_success 'gitcvs.dbname' \ - 'GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled true && - GIT_DIR="$SERVERDIR" git config gitcvs.dbname %Ggitcvs.%a.%m.sqlite && - GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 main >cvs.log 2>&1 && - test_cmp cvswork cvswork2 && - test -f "$SERVERDIR/gitcvs.ext.main.sqlite" && - cmp "$SERVERDIR/gitcvs.main.sqlite" "$SERVERDIR/gitcvs.ext.main.sqlite"' +test_expect_success 'gitcvs.dbname' ' + GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled true && + GIT_DIR="$SERVERDIR" git config gitcvs.dbname %Ggitcvs.%a.%m.sqlite && + GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 main >cvs.log 2>&1 && + test_cmp cvswork cvswork2 && + test -f "$SERVERDIR/gitcvs.ext.main.sqlite" && + cmp "$SERVERDIR/gitcvs.main.sqlite" "$SERVERDIR/gitcvs.ext.main.sqlite" +' rm -fr cvswork2 -test_expect_success 'gitcvs.ext.dbname' \ - 'GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled true && - GIT_DIR="$SERVERDIR" git config gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite && - GIT_DIR="$SERVERDIR" git config gitcvs.dbname %Ggitcvs2.%a.%m.sqlite && - GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 main >cvs.log 2>&1 && - test_cmp cvswork cvswork2 && - test -f "$SERVERDIR/gitcvs1.ext.main.sqlite" && - test ! -f "$SERVERDIR/gitcvs2.ext.main.sqlite" && - cmp "$SERVERDIR/gitcvs.main.sqlite" "$SERVERDIR/gitcvs1.ext.main.sqlite"' +test_expect_success 'gitcvs.ext.dbname' ' + GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled true && + GIT_DIR="$SERVERDIR" git config gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite && + GIT_DIR="$SERVERDIR" git config gitcvs.dbname %Ggitcvs2.%a.%m.sqlite && + GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 main >cvs.log 2>&1 && + test_cmp cvswork cvswork2 && + test -f "$SERVERDIR/gitcvs1.ext.main.sqlite" && + test ! -f "$SERVERDIR/gitcvs2.ext.main.sqlite" && + cmp "$SERVERDIR/gitcvs.main.sqlite" "$SERVERDIR/gitcvs1.ext.main.sqlite" +' #------------ @@ -299,109 +316,115 @@ GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true && GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log" || exit 1 -test_expect_success 'cvs update (create new file)' \ - 'echo testfile1 >testfile1 && - git add testfile1 && - git commit -q -m "Add testfile1" && - git push gitcvs.git >/dev/null && - cd cvswork && - GIT_CONFIG="$git_config" cvs -Q update && - test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.1/" && - test_cmp testfile1 ../testfile1' +test_expect_success 'cvs update (create new file)' ' + echo testfile1 >testfile1 && + git add testfile1 && + git commit -q -m "Add testfile1" && + git push gitcvs.git >/dev/null && + cd cvswork && + GIT_CONFIG="$git_config" cvs -Q update && + test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.1/" && + test_cmp testfile1 ../testfile1 +' cd "$WORKDIR" -test_expect_success 'cvs update (update existing file)' \ - 'echo line 2 >>testfile1 && - git add testfile1 && - git commit -q -m "Append to testfile1" && - git push gitcvs.git >/dev/null && - cd cvswork && - GIT_CONFIG="$git_config" cvs -Q update && - test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.2/" && - test_cmp testfile1 ../testfile1' +test_expect_success 'cvs update (update existing file)' ' + echo line 2 >>testfile1 && + git add testfile1 && + git commit -q -m "Append to testfile1" && + git push gitcvs.git >/dev/null && + cd cvswork && + GIT_CONFIG="$git_config" cvs -Q update && + test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.2/" && + test_cmp testfile1 ../testfile1 +' cd "$WORKDIR" #TODO: cvsserver doesn't support update w/o -d test_expect_failure "cvs update w/o -d doesn't create subdir (TODO)" ' - mkdir test && - echo >test/empty && - git add test && - git commit -q -m "Single Subdirectory" && - git push gitcvs.git >/dev/null && - cd cvswork && - GIT_CONFIG="$git_config" cvs -Q update && - test ! -d test + mkdir test && + echo >test/empty && + git add test && + git commit -q -m "Single Subdirectory" && + git push gitcvs.git >/dev/null && + cd cvswork && + GIT_CONFIG="$git_config" cvs -Q update && + test ! -d test ' cd "$WORKDIR" -test_expect_success 'cvs update (subdirectories)' \ - '(for dir in A A/B A/B/C A/D E; do - mkdir $dir && - echo "test file in $dir" >"$dir/file_in_$(echo $dir|sed -e "s#/# #g")" && - git add $dir || exit 1 - done) && - git commit -q -m "deep sub directory structure" && - git push gitcvs.git >/dev/null && - cd cvswork && - GIT_CONFIG="$git_config" cvs -Q update -d && - (for dir in A A/B A/B/C A/D E; do - filename="file_in_$(echo $dir|sed -e "s#/# #g")" && - if test "$(echo $(grep -v ^D $dir/CVS/Entries|cut -d/ -f2,3,5))" = "$filename/1.1/" && - test_cmp "$dir/$filename" "../$dir/$filename"; then - : - else - exit 1 - fi - done)' +test_expect_success 'cvs update (subdirectories)' ' + (for dir in A A/B A/B/C A/D E; do + mkdir $dir && + echo "test file in $dir" >"$dir/file_in_$(echo $dir|sed -e "s#/# #g")" && + git add $dir || exit 1 + done) && + git commit -q -m "deep sub directory structure" && + git push gitcvs.git >/dev/null && + cd cvswork && + GIT_CONFIG="$git_config" cvs -Q update -d && + (for dir in A A/B A/B/C A/D E; do + filename="file_in_$(echo $dir|sed -e "s#/# #g")" && + if test "$(echo $(grep -v ^D $dir/CVS/Entries|cut -d/ -f2,3,5))" = "$filename/1.1/" && + test_cmp "$dir/$filename" "../$dir/$filename"; then + : + else + exit 1 + fi + done) +' cd "$WORKDIR" -test_expect_success 'cvs update (delete file)' \ - 'git rm testfile1 && - git commit -q -m "Remove testfile1" && - git push gitcvs.git >/dev/null && - cd cvswork && - GIT_CONFIG="$git_config" cvs -Q update && - test -z "$(grep testfile1 CVS/Entries)" && - test ! -f testfile1' +test_expect_success 'cvs update (delete file)' ' + git rm testfile1 && + git commit -q -m "Remove testfile1" && + git push gitcvs.git >/dev/null && + cd cvswork && + GIT_CONFIG="$git_config" cvs -Q update && + test -z "$(grep testfile1 CVS/Entries)" && + test ! -f testfile1 +' cd "$WORKDIR" -test_expect_success 'cvs update (re-add deleted file)' \ - 'echo readded testfile >testfile1 && - git add testfile1 && - git commit -q -m "Re-Add testfile1" && - git push gitcvs.git >/dev/null && - cd cvswork && - GIT_CONFIG="$git_config" cvs -Q update && - test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.4/" && - test_cmp testfile1 ../testfile1' +test_expect_success 'cvs update (re-add deleted file)' ' + echo readded testfile >testfile1 && + git add testfile1 && + git commit -q -m "Re-Add testfile1" && + git push gitcvs.git >/dev/null && + cd cvswork && + GIT_CONFIG="$git_config" cvs -Q update && + test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.4/" && + test_cmp testfile1 ../testfile1 +' cd "$WORKDIR" -test_expect_success 'cvs update (merge)' \ - 'echo Line 0 >expected && - for i in 1 2 3 4 5 6 7 - do - echo Line $i >>merge && - echo Line $i >>expected || return 1 - done && - echo Line 8 >>expected && - git add merge && - git commit -q -m "Merge test (pre-merge)" && - git push gitcvs.git >/dev/null && - cd cvswork && - GIT_CONFIG="$git_config" cvs -Q update && - test "$(echo $(grep merge CVS/Entries|cut -d/ -f2,3,5))" = "merge/1.1/" && - test_cmp merge ../merge && - ( echo Line 0 && cat merge ) >merge.tmp && - mv merge.tmp merge && - cd "$WORKDIR" && - echo Line 8 >>merge && - git add merge && - git commit -q -m "Merge test (merge)" && - git push gitcvs.git >/dev/null && - cd cvswork && - sleep 1 && touch merge && - GIT_CONFIG="$git_config" cvs -Q update && - test_cmp merge ../expected' +test_expect_success 'cvs update (merge)' ' + echo Line 0 >expected && + for i in 1 2 3 4 5 6 7 + do + echo Line $i >>merge && + echo Line $i >>expected || return 1 + done && + echo Line 8 >>expected && + git add merge && + git commit -q -m "Merge test (pre-merge)" && + git push gitcvs.git >/dev/null && + cd cvswork && + GIT_CONFIG="$git_config" cvs -Q update && + test "$(echo $(grep merge CVS/Entries|cut -d/ -f2,3,5))" = "merge/1.1/" && + test_cmp merge ../merge && + ( echo Line 0 && cat merge ) >merge.tmp && + mv merge.tmp merge && + cd "$WORKDIR" && + echo Line 8 >>merge && + git add merge && + git commit -q -m "Merge test (merge)" && + git push gitcvs.git >/dev/null && + cd cvswork && + sleep 1 && touch merge && + GIT_CONFIG="$git_config" cvs -Q update && + test_cmp merge ../expected +' cd "$WORKDIR" @@ -418,55 +441,58 @@ do echo Line $i >>expected.C done -test_expect_success 'cvs update (conflict merge)' \ - '( echo LINE 0 && cat merge ) >merge.tmp && - mv merge.tmp merge && - git add merge && - git commit -q -m "Merge test (conflict)" && - git push gitcvs.git >/dev/null && - cd cvswork && - GIT_CONFIG="$git_config" cvs -Q update && - test_cmp merge ../expected.C' +test_expect_success 'cvs update (conflict merge)' ' + ( echo LINE 0 && cat merge ) >merge.tmp && + mv merge.tmp merge && + git add merge && + git commit -q -m "Merge test (conflict)" && + git push gitcvs.git >/dev/null && + cd cvswork && + GIT_CONFIG="$git_config" cvs -Q update && + test_cmp merge ../expected.C +' cd "$WORKDIR" -test_expect_success 'cvs update (-C)' \ - 'cd cvswork && - GIT_CONFIG="$git_config" cvs -Q update -C && - test_cmp merge ../merge' +test_expect_success 'cvs update (-C)' ' + cd cvswork && + GIT_CONFIG="$git_config" cvs -Q update -C && + test_cmp merge ../merge +' cd "$WORKDIR" -test_expect_success 'cvs update (merge no-op)' \ - 'echo Line 9 >>merge && - cp merge cvswork/merge && - git add merge && - git commit -q -m "Merge test (no-op)" && - git push gitcvs.git >/dev/null && - cd cvswork && - sleep 1 && touch merge && - GIT_CONFIG="$git_config" cvs -Q update && - test_cmp merge ../merge' +test_expect_success 'cvs update (merge no-op)' ' + echo Line 9 >>merge && + cp merge cvswork/merge && + git add merge && + git commit -q -m "Merge test (no-op)" && + git push gitcvs.git >/dev/null && + cd cvswork && + sleep 1 && touch merge && + GIT_CONFIG="$git_config" cvs -Q update && + test_cmp merge ../merge +' cd "$WORKDIR" test_expect_success 'cvs update (-p)' ' - touch really-empty && - echo Line 1 > no-lf && - printf "Line 2" >> no-lf && - git add really-empty no-lf && - git commit -q -m "Update -p test" && - git push gitcvs.git >/dev/null && - cd cvswork && - GIT_CONFIG="$git_config" cvs update && - for i in merge no-lf empty really-empty; do - GIT_CONFIG="$git_config" cvs update -p "$i" >$i.out && - test_cmp $i.out ../$i || return 1 - done + touch really-empty && + echo Line 1 > no-lf && + printf "Line 2" >> no-lf && + git add really-empty no-lf && + git commit -q -m "Update -p test" && + git push gitcvs.git >/dev/null && + cd cvswork && + GIT_CONFIG="$git_config" cvs update && + for i in merge no-lf empty really-empty; do + GIT_CONFIG="$git_config" cvs update -p "$i" >$i.out && + test_cmp $i.out ../$i || return 1 + done ' cd "$WORKDIR" test_expect_success 'cvs update (module list supports packed refs)' ' - GIT_DIR="$SERVERDIR" git pack-refs --all && - GIT_CONFIG="$git_config" cvs -n up -d 2> out && - grep "cvs update: New directory \`main'\''" < out + GIT_DIR="$SERVERDIR" git pack-refs --all && + GIT_CONFIG="$git_config" cvs -n up -d 2> out && + grep "cvs update: New directory \`main'\''" < out ' #------------ @@ -475,30 +501,30 @@ test_expect_success 'cvs update (module list supports packed refs)' ' cd "$WORKDIR" test_expect_success 'cvs status' ' - mkdir status.dir && - echo Line > status.dir/status.file && - echo Line > status.file && - git add status.dir status.file && - git commit -q -m "Status test" && - git push gitcvs.git >/dev/null && - cd cvswork && - GIT_CONFIG="$git_config" cvs update && - GIT_CONFIG="$git_config" cvs status | grep "^File: status.file" >../out && - test_line_count = 2 ../out + mkdir status.dir && + echo Line > status.dir/status.file && + echo Line > status.file && + git add status.dir status.file && + git commit -q -m "Status test" && + git push gitcvs.git >/dev/null && + cd cvswork && + GIT_CONFIG="$git_config" cvs update && + GIT_CONFIG="$git_config" cvs status | grep "^File: status.file" >../out && + test_line_count = 2 ../out ' cd "$WORKDIR" test_expect_success 'cvs status (nonrecursive)' ' - cd cvswork && - GIT_CONFIG="$git_config" cvs status -l | grep "^File: status.file" >../out && - test_line_count = 1 ../out + cd cvswork && + GIT_CONFIG="$git_config" cvs status -l | grep "^File: status.file" >../out && + test_line_count = 1 ../out ' cd "$WORKDIR" test_expect_success 'cvs status (no subdirs in header)' ' - cd cvswork && - GIT_CONFIG="$git_config" cvs status | grep ^File: >../out && - ! grep / <../out + cd cvswork && + GIT_CONFIG="$git_config" cvs status | grep ^File: >../out && + ! grep / <../out ' #------------ @@ -507,9 +533,9 @@ test_expect_success 'cvs status (no subdirs in header)' ' cd "$WORKDIR" test_expect_success 'cvs co -c (shows module database)' ' - GIT_CONFIG="$git_config" cvs co -c > out && - grep "^main[ ][ ]*main$" <out && - ! grep -v "^main[ ][ ]*main$" <out + GIT_CONFIG="$git_config" cvs co -c > out && + grep "^main[ ][ ]*main$" <out && + ! grep -v "^main[ ][ ]*main$" <out ' #------------ @@ -575,11 +601,11 @@ expectStat="$?" cd "$WORKDIR" test_expect_success 'cvs log' ' - cd cvswork && - test x"$expectStat" = x"0" && - GIT_CONFIG="$git_config" cvs log merge >../out && - sed -e "s%2[0-9][0-9][0-9]/[01][0-9]/[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]%__DATE__%" ../out > ../actual && - test_cmp ../expect ../actual + cd cvswork && + test x"$expectStat" = x"0" && + GIT_CONFIG="$git_config" cvs log merge >../out && +sed -e "s%2[0-9][0-9][0-9]/[01][0-9]/[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]%__DATE__%" ../out > ../actual && + test_cmp ../expect ../actual ' #------------ @@ -588,11 +614,11 @@ test_expect_success 'cvs log' ' cd "$WORKDIR" test_expect_success 'cvs annotate' ' - cd cvswork && - GIT_CONFIG="$git_config" cvs annotate merge >../out && - sed -e "s/ .*//" ../out >../actual && - printf "1.%d\n" 3 1 1 1 1 1 1 1 2 4 >../expect && - test_cmp ../expect ../actual + cd cvswork && + GIT_CONFIG="$git_config" cvs annotate merge >../out && + sed -e "s/ .*//" ../out >../actual && + printf "1.%d\n" 3 1 1 1 1 1 1 1 2 4 >../expect && + test_cmp ../expect ../actual ' #------------ diff --git a/t/t9700-perl-git.sh b/t/t9700-perl-git.sh index 4aa5d90d32..ccc8212d73 100755 --- a/t/t9700-perl-git.sh +++ b/t/t9700-perl-git.sh @@ -13,37 +13,40 @@ skip_all_if_no_Test_More # set up test repository -test_expect_success \ - 'set up test repository' \ - 'echo "test file 1" > file1 && - echo "test file 2" > file2 && - mkdir directory1 && - echo "in directory1" >> directory1/file && - mkdir directory2 && - echo "in directory2" >> directory2/file && - git add . && - git commit -m "first commit" && - - echo "new file in subdir 2" > directory2/file2 && - git add . && - git commit -m "commit in directory2" && - - echo "changed file 1" > file1 && - git commit -a -m "second commit" && - - git config --add color.test.slot1 green && - git config --add test.string value && - git config --add test.dupstring value1 && - git config --add test.dupstring value2 && - git config --add test.booltrue true && - git config --add test.boolfalse no && - git config --add test.boolother other && - git config --add test.int 2k && - git config --add test.path "~/foo" && - git config --add test.pathexpanded "$HOME/foo" && - git config --add test.pathmulti foo && - git config --add test.pathmulti bar - ' +test_expect_success 'set up test repository' ' + echo "test file 1" >file1 && + echo "test file 2" >file2 && + mkdir directory1 && + echo "in directory1" >>directory1/file && + mkdir directory2 && + echo "in directory2" >>directory2/file && + git add . && + git commit -m "first commit" && + + echo "new file in subdir 2" >directory2/file2 && + git add . && + git commit -m "commit in directory2" && + + echo "changed file 1" >file1 && + git commit -a -m "second commit" && + + git config --add color.test.slot1 green && + git config --add test.string value && + git config --add test.dupstring value1 && + git config --add test.dupstring value2 && + git config --add test.booltrue true && + git config --add test.boolfalse no && + git config --add test.boolother other && + git config --add test.int 2k && + git config --add test.path "~/foo" && + git config --add test.pathexpanded "$HOME/foo" && + git config --add test.pathmulti foo && + git config --add test.pathmulti bar +' + +test_expect_success 'set up bare repository' ' + git init --bare bare.git +' test_expect_success 'use t9700/test.pl to test Git.pm' ' "$PERL_PATH" "$TEST_DIRECTORY"/t9700/test.pl 2>stderr && diff --git a/t/t9700/test.pl b/t/t9700/test.pl index e046f7db76..6d753708d2 100755 --- a/t/t9700/test.pl +++ b/t/t9700/test.pl @@ -30,6 +30,18 @@ BEGIN { use_ok('Git') } # set up our $abs_repo_dir = cwd(); ok(our $r = Git->repository(Directory => "."), "open repository"); +{ + local $ENV{GIT_TEST_ASSUME_DIFFERENT_OWNER} = 1; + my $failed; + + $failed = eval { Git->repository(Directory => $abs_repo_dir) }; + ok(!$failed, "reject unsafe non-bare repository"); + like($@, qr/not a git repository/i, "unsafe error message"); + + $failed = eval { Git->repository(Directory => "$abs_repo_dir/bare.git") }; + ok(!$failed, "reject unsafe bare repository"); + like($@, qr/not a git repository/i, "unsafe error message"); +} # config is($r->config("test.string"), "value", "config scalar: string"); diff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh index dc88d0e064..a4b3cb9492 100755 --- a/t/t9800-git-p4-basic.sh +++ b/t/t9800-git-p4-basic.sh @@ -330,7 +330,7 @@ test_expect_success 'initial import time from top change time' ' test_when_finished cleanup_git && ( cd "$git" && - gittime=$(git show -s --raw --pretty=format:%at HEAD) && + gittime=$(git show -s --pretty=format:%at HEAD) && echo $p4time $gittime && test $p4time = $gittime ) diff --git a/t/t9814-git-p4-rename.sh b/t/t9814-git-p4-rename.sh index 468767cbf4..2a9838f37f 100755 --- a/t/t9814-git-p4-rename.sh +++ b/t/t9814-git-p4-rename.sh @@ -216,7 +216,7 @@ test_expect_success 'detect copies' ' # variable exists, which allows admins to disable the "p4 move" command. test_lazy_prereq P4D_HAVE_CONFIGURABLE_RUN_MOVE_ALLOW ' p4 configure show run.move.allow >out && - egrep ^run.move.allow: out + grep -E ^run.move.allow: out ' # If move can be disabled, turn it off and test p4 move handling diff --git a/t/t9815-git-p4-submit-fail.sh b/t/t9815-git-p4-submit-fail.sh index 9779dc0d11..0ca9937de6 100755 --- a/t/t9815-git-p4-submit-fail.sh +++ b/t/t9815-git-p4-submit-fail.sh @@ -417,8 +417,8 @@ test_expect_success 'cleanup chmod after submit cancel' ' ! p4 fstat -T action text && test_path_is_file text+x && ! p4 fstat -T action text+x && - ls -l text | egrep ^-r-- && - ls -l text+x | egrep ^-r-x + ls -l text | grep -E ^-r-- && + ls -l text+x | grep -E ^-r-x ) ' diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 43de868b80..47e20fb8b1 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -405,40 +405,40 @@ test_expect_success '__gitdir - remote as argument' ' test_expect_success '__git_dequote - plain unquoted word' ' __git_dequote unquoted-word && - verbose test unquoted-word = "$dequoted_word" + test unquoted-word = "$dequoted_word" ' # input: b\a\c\k\'\\\"s\l\a\s\h\es # expected: back'\"slashes test_expect_success '__git_dequote - backslash escaped' ' __git_dequote "b\a\c\k\\'\''\\\\\\\"s\l\a\s\h\es" && - verbose test "back'\''\\\"slashes" = "$dequoted_word" + test "back'\''\\\"slashes" = "$dequoted_word" ' # input: sin'gle\' '"quo'ted # expected: single\ "quoted test_expect_success '__git_dequote - single quoted' ' __git_dequote "'"sin'gle\\\\' '\\\"quo'ted"'" && - verbose test '\''single\ "quoted'\'' = "$dequoted_word" + test '\''single\ "quoted'\'' = "$dequoted_word" ' # input: dou"ble\\" "\"\quot"ed # expected: double\ "\quoted test_expect_success '__git_dequote - double quoted' ' __git_dequote '\''dou"ble\\" "\"\quot"ed'\'' && - verbose test '\''double\ "\quoted'\'' = "$dequoted_word" + test '\''double\ "\quoted'\'' = "$dequoted_word" ' # input: 'open single quote test_expect_success '__git_dequote - open single quote' ' __git_dequote "'\''open single quote" && - verbose test "open single quote" = "$dequoted_word" + test "open single quote" = "$dequoted_word" ' # input: "open double quote test_expect_success '__git_dequote - open double quote' ' __git_dequote "\"open double quote" && - verbose test "open double quote" = "$dequoted_word" + test "open double quote" = "$dequoted_word" ' @@ -616,7 +616,7 @@ test_expect_success '__git_is_configured_remote' ' test_when_finished "git remote remove remote_2" && git remote add remote_2 git://remote_2 && ( - verbose __git_is_configured_remote remote_2 && + __git_is_configured_remote remote_2 && test_must_fail __git_is_configured_remote non-existent ) ' @@ -1622,14 +1622,22 @@ test_expect_success 'git checkout - with -d, complete only references' ' ' test_expect_success 'git switch - with --track, complete only remote branches' ' - test_completion "git switch --track " <<-\EOF + test_completion "git switch --track " <<-\EOF && + other/branch-in-other Z + other/main-in-other Z + EOF + test_completion "git switch -t " <<-\EOF other/branch-in-other Z other/main-in-other Z EOF ' test_expect_success 'git checkout - with --track, complete only remote branches' ' - test_completion "git checkout --track " <<-\EOF + test_completion "git checkout --track " <<-\EOF && + other/branch-in-other Z + other/main-in-other Z + EOF + test_completion "git checkout -t " <<-\EOF other/branch-in-other Z other/main-in-other Z EOF @@ -2255,6 +2263,36 @@ test_expect_success 'checkout completes ref names' ' EOF ' +test_expect_success 'checkout does not match ref names of a different case' ' + test_completion "git checkout M" "" +' + +test_expect_success 'checkout matches case insensitively with GIT_COMPLETION_IGNORE_CASE' ' + ( + GIT_COMPLETION_IGNORE_CASE=1 && + test_completion "git checkout M" <<-\EOF + main Z + mybranch Z + mytag Z + EOF + ) +' + +test_expect_success 'checkout completes pseudo refs' ' + test_completion "git checkout H" <<-\EOF + HEAD Z + EOF +' + +test_expect_success 'checkout completes pseudo refs case insensitively with GIT_COMPLETION_IGNORE_CASE' ' + ( + GIT_COMPLETION_IGNORE_CASE=1 && + test_completion "git checkout h" <<-\EOF + HEAD Z + EOF + ) +' + test_expect_success 'git -C <path> checkout uses the right repo' ' test_completion "git -C subdir -C subsubdir -C .. -C ../otherrepo checkout b" <<-\EOF branch-in-other Z @@ -2566,30 +2604,30 @@ test_expect_success 'options with value' ' test_expect_success 'sourcing the completion script clears cached commands' ' ( __git_compute_all_commands && - verbose test -n "$__git_all_commands" && + test -n "$__git_all_commands" && . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" && - verbose test -z "$__git_all_commands" + test -z "$__git_all_commands" ) ' test_expect_success 'sourcing the completion script clears cached merge strategies' ' ( __git_compute_merge_strategies && - verbose test -n "$__git_merge_strategies" && + test -n "$__git_merge_strategies" && . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" && - verbose test -z "$__git_merge_strategies" + test -z "$__git_merge_strategies" ) ' test_expect_success 'sourcing the completion script clears cached --options' ' ( __gitcomp_builtin checkout && - verbose test -n "$__gitcomp_builtin_checkout" && + test -n "$__gitcomp_builtin_checkout" && __gitcomp_builtin notes_edit && - verbose test -n "$__gitcomp_builtin_notes_edit" && + test -n "$__gitcomp_builtin_notes_edit" && . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" && - verbose test -z "$__gitcomp_builtin_checkout" && - verbose test -z "$__gitcomp_builtin_notes_edit" + test -z "$__gitcomp_builtin_checkout" && + test -z "$__gitcomp_builtin_notes_edit" ) ' diff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh index d459fae655..d667dda654 100755 --- a/t/t9903-bash-prompt.sh +++ b/t/t9903-bash-prompt.sh @@ -13,10 +13,10 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . "$GIT_BUILD_DIR/contrib/completion/git-prompt.sh" actual="$TRASH_DIRECTORY/actual" -c_red='\\[\\e[31m\\]' -c_green='\\[\\e[32m\\]' -c_lblue='\\[\\e[1;34m\\]' -c_clear='\\[\\e[0m\\]' +c_red='\001\e[31m\002' +c_green='\001\e[32m\002' +c_lblue='\001\e[1;34m\002' +c_clear='\001\e[0m\002' test_expect_success 'setup for prompt tests' ' git init otherrepo && diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index c6479f24eb..2f8868caa1 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -32,6 +32,14 @@ test_set_editor () { export EDITOR } +# Like test_set_editor but sets GIT_SEQUENCE_EDITOR instead of EDITOR +test_set_sequence_editor () { + FAKE_SEQUENCE_EDITOR="$1" + export FAKE_SEQUENCE_EDITOR + GIT_SEQUENCE_EDITOR='"$FAKE_SEQUENCE_EDITOR"' + export GIT_SEQUENCE_EDITOR +} + test_decode_color () { awk ' function name(n) { @@ -273,13 +281,13 @@ debug () { # <file>, <contents>, and <tag> all default to <message>. test_commit () { - notick= && - echo=echo && - append= && - author= && - signoff= && - indir= && - tag=light && + local notick= && + local echo=echo && + local append= && + local author= && + local signoff= && + local indir= && + local tag=light && while test $# != 0 do case "$1" in @@ -322,7 +330,7 @@ test_commit () { shift done && indir=${indir:+"$indir"/} && - file=${2:-"$1.t"} && + local file=${2:-"$1.t"} && if test -n "$append" then $echo "${3-$1}" >>"$indir$file" @@ -534,8 +542,17 @@ test_config () { config_dir=$1 shift fi - test_when_finished "test_unconfig ${config_dir:+-C '$config_dir'} '$1'" && - git ${config_dir:+-C "$config_dir"} config "$@" + + # If --worktree is provided, use it to configure/unconfigure + is_worktree= + if test "$1" = --worktree + then + is_worktree=1 + shift + fi + + test_when_finished "test_unconfig ${config_dir:+-C '$config_dir'} ${is_worktree:+--worktree} '$1'" && + git ${config_dir:+-C "$config_dir"} config ${is_worktree:+--worktree} "$@" } test_config_global () { @@ -893,11 +910,20 @@ test_path_is_symlink () { fi } +test_path_is_executable () { + test "$#" -ne 1 && BUG "1 param" + if ! test -x "$1" + then + echo "$1 is not executable" + false + fi +} + # Check if the directory exists and is empty as expected, barf otherwise. test_dir_is_empty () { test "$#" -ne 1 && BUG "1 param" test_path_is_dir "$1" && - if test -n "$(ls -a1 "$1" | egrep -v '^\.\.?$')" + if test -n "$(ls -a1 "$1" | grep -E -v '^\.\.?$')" then echo "Directory '$1' is not empty, it contains:" ls -la "$1" @@ -921,10 +947,6 @@ test_path_is_missing () { then echo "Path exists:" ls -ld "$1" - if test $# -ge 1 - then - echo "$*" - fi false fi } @@ -1020,7 +1042,7 @@ test_must_fail_acceptable () { fi case "$1" in - git|__git*|test-tool|test_terminal) + git|__git*|scalar|test-tool|test_terminal) return 0 ;; *) @@ -1223,15 +1245,6 @@ test_i18ngrep () { return 1 } -# Call any command "$@" but be more verbose about its -# failure. This is handy for commands like "test" which do -# not output anything when they fail. -verbose () { - "$@" && return 0 - echo >&4 "command failed: $(git rev-parse --sq-quote "$@")" - return 1 -} - # Check if the file expected to be empty is indeed empty, and barfs # otherwise. @@ -1278,6 +1291,39 @@ test_cmp_rev () { fi } +# Tests that a commit message matches the expected text +# +# Usage: test_commit_message <rev> [-m <msg> | <file>] +# +# When using "-m" <msg> will have a line feed appended. If the second +# argument is omitted then the expected message is read from stdin. + +test_commit_message () { + local msg_file=expect.msg + + case $# in + 3) + if test "$2" = "-m" + then + printf "%s\n" "$3" >"$msg_file" + else + BUG "Usage: test_commit_message <rev> [-m <message> | <file>]" + fi + ;; + 2) + msg_file="$2" + ;; + 1) + cat >"$msg_file" + ;; + *) + BUG "Usage: test_commit_message <rev> [-m <message> | <file>]" + ;; + esac + git show --no-patch --pretty=format:%B "$1" -- >actual.msg && + test_cmp "$msg_file" actual.msg +} + # Compare paths respecting core.ignoreCase test_cmp_fspath () { if test "x$1" = "x$2" @@ -1426,7 +1472,7 @@ test_bool_env () { BUG "test_bool_env requires two parameters (variable name and default value)" fi - git env--helper --type=bool --default="$2" --exit-code "$1" + test-tool env-helper --type=bool --default="$2" --exit-code "$1" ret=$? case $ret in 0|1) # unset or valid bool value @@ -1454,72 +1500,6 @@ test_skip_or_die () { error "$2" } -# The following mingw_* functions obey POSIX shell syntax, but are actually -# bash scripts, and are meant to be used only with bash on Windows. - -# A test_cmp function that treats LF and CRLF equal and avoids to fork -# diff when possible. -mingw_test_cmp () { - # Read text into shell variables and compare them. If the results - # are different, use regular diff to report the difference. - local test_cmp_a= test_cmp_b= - - # When text came from stdin (one argument is '-') we must feed it - # to diff. - local stdin_for_diff= - - # Since it is difficult to detect the difference between an - # empty input file and a failure to read the files, we go straight - # to diff if one of the inputs is empty. - if test -s "$1" && test -s "$2" - then - # regular case: both files non-empty - mingw_read_file_strip_cr_ test_cmp_a <"$1" - mingw_read_file_strip_cr_ test_cmp_b <"$2" - elif test -s "$1" && test "$2" = - - then - # read 2nd file from stdin - mingw_read_file_strip_cr_ test_cmp_a <"$1" - mingw_read_file_strip_cr_ test_cmp_b - stdin_for_diff='<<<"$test_cmp_b"' - elif test "$1" = - && test -s "$2" - then - # read 1st file from stdin - mingw_read_file_strip_cr_ test_cmp_a - mingw_read_file_strip_cr_ test_cmp_b <"$2" - stdin_for_diff='<<<"$test_cmp_a"' - fi - test -n "$test_cmp_a" && - test -n "$test_cmp_b" && - test "$test_cmp_a" = "$test_cmp_b" || - eval "diff -u \"\$@\" $stdin_for_diff" -} - -# $1 is the name of the shell variable to fill in -mingw_read_file_strip_cr_ () { - # Read line-wise using LF as the line separator - # and use IFS to strip CR. - local line - while : - do - if IFS=$'\r' read -r -d $'\n' line - then - # good - line=$line$'\n' - else - # we get here at EOF, but also if the last line - # was not terminated by LF; in the latter case, - # some text was read - if test -z "$line" - then - # EOF, really - break - fi - fi - eval "$1=\$$1\$line" - done -} - # Like "env FOO=BAR some-program", but run inside a subshell, which means # it also works for shell functions (though those functions cannot impact # the environment outside of the test_env invocation). @@ -1686,7 +1666,7 @@ test_oid () { then BUG "undefined key '$1'" fi && - eval "printf '%s' \"\${$var}\"" + eval "printf '%s\n' \"\${$var}\"" } # Insert a slash into an object ID so it can be used to reference a location @@ -1755,6 +1735,13 @@ test_path_is_hidden () { return 1 } +# Poor man's URI escaping. Good enough for the test suite whose trash +# directory has a space in it. See 93c3fcbe4d4 (git-svn: attempt to +# mimic SVN 1.7 URL canonicalization, 2012-07-28) for prior art. +test_uri_escape() { + sed 's/ /%20/g' +} + # Check that the given command was invoked as part of the # trace2-format trace on stdin. # @@ -1830,6 +1817,14 @@ test_region () { return 0 } +# Given a GIT_TRACE2_EVENT log over stdin, writes to stdout a list of URLs +# sent to git-remote-https child processes. +test_remote_https_urls() { + grep -e '"event":"child_start".*"argv":\["git-remote-https",".*"\]' | + sed -e 's/{"event":"child_start".*"argv":\["git-remote-https","//g' \ + -e 's/"\]}//g' +} + # Print the destination of symlink(s) provided as arguments. Basically # the same as the readlink command, but it's not available everywhere. test_readlink () { @@ -1868,3 +1863,22 @@ test_is_magic_mtime () { rm -f .git/test-mtime-actual return $ret } + +# Given two filenames, parse both using 'git config --list --file' +# and compare the sorted output of those commands. Useful when +# wanting to ignore whitespace differences and sorting concerns. +test_cmp_config_output () { + git config --list --file="$1" >config-expect && + git config --list --file="$2" >config-actual && + sort config-expect >sorted-expect && + sort config-actual >sorted-actual && + test_cmp sorted-expect sorted-actual +} + +# Given a filename, extract its trailing hash as a hex string +test_trailing_hash () { + local file="$1" && + tail -c $(test_oid rawsz) "$file" | + test-tool hexdump | + sed "s/ //g" +} diff --git a/t/test-lib.sh b/t/test-lib.sh index 6ca68311eb..5ea5d1d62a 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -47,6 +47,16 @@ then echo "PANIC: Running in a $TEST_DIRECTORY that doesn't end in '/t'?" >&2 exit 1 fi +if test -f "$GIT_BUILD_DIR/GIT-BUILD-DIR" +then + GIT_BUILD_DIR="$(cat "$GIT_BUILD_DIR/GIT-BUILD-DIR")" || exit 1 + # On Windows, we must convert Windows paths lest they contain a colon + case "$(uname -s)" in + *MINGW*) + GIT_BUILD_DIR="$(cygpath -au "$GIT_BUILD_DIR")" + ;; + esac +fi # Prepend a string to a VAR using an arbitrary ":" delimiter, not # adding the delimiter if VAR or VALUE is empty. I.e. a generalized: @@ -324,6 +334,7 @@ nr_san_dir_leaks_ () { find "$TEST_RESULTS_SAN_DIR" \ -type f \ -name "$TEST_RESULTS_SAN_FILE_PFX.*" 2>/dev/null | + xargs grep -lv "Unable to get registers from thread" | wc -l } @@ -635,12 +646,6 @@ u200c=$(printf '\342\200\214') export _x05 _x35 LF u200c EMPTY_TREE EMPTY_BLOB ZERO_OID OID_REGEX -# Each test should start with something like this, after copyright notices: -# -# test_description='Description of this test... -# This test checks if command xyzzy does the right thing... -# ' -# . ./test-lib.sh test "x$TERM" != "xdumb" && ( test -t 1 && tput bold >/dev/null 2>&1 && @@ -1037,10 +1042,7 @@ want_trace () { # (and we want to make sure we run any cleanup like # "set +x"). test_eval_inner_ () { - # Do not add anything extra (including LF) after '$*' - eval " - want_trace && trace_level_=$(($trace_level_+1)) && set -x - $*" + eval "$*" } test_eval_ () { @@ -1065,7 +1067,10 @@ test_eval_ () { # be _inside_ the block to avoid polluting the "set -x" output # - test_eval_inner_ "$@" </dev/null >&3 2>&4 + # Do not add anything extra (including LF) after '$*' + test_eval_inner_ </dev/null >&3 2>&4 " + want_trace && trace_level_=$(($trace_level_+1)) && set -x + $*" { test_eval_ret_=$? if want_trace @@ -1082,22 +1087,22 @@ test_eval_ () { return $test_eval_ret_ } +fail_117 () { + return 117 +} + test_run_ () { test_cleanup=: expecting_failure=$2 if test "${GIT_TEST_CHAIN_LINT:-1}" != 0; then - # turn off tracing for this test-eval, as it simply creates - # confusing noise in the "-x" output - trace_tmp=$trace - trace= # 117 is magic because it is unlikely to match the exit # code of other programs - if test "OK-117" != "$(test_eval_ "(exit 117) && $1${LF}${LF}echo OK-\$?" 3>&1)" + test_eval_inner_ "fail_117 && $1" </dev/null >&3 2>&4 + if test $? != 117 then - BUG "broken &&-chain or run-away HERE-DOC: $1" + BUG "broken &&-chain: $1" fi - trace=$trace_tmp fi setup_malloc_check @@ -1532,8 +1537,8 @@ then # Normalize with test_bool_env passes_sanitize_leak= - # We need to see TEST_PASSES_SANITIZE_LEAK in "git - # env--helper" (via test_bool_env) + # We need to see TEST_PASSES_SANITIZE_LEAK in "test-tool + # env-helper" (via test_bool_env) export TEST_PASSES_SANITIZE_LEAK if test_bool_env TEST_PASSES_SANITIZE_LEAK false then @@ -1589,7 +1594,8 @@ then BAIL_OUT_ENV_NEEDS_SANITIZE_LEAK "GIT_TEST_SANITIZE_LEAK_LOG=true" fi -if test "${GIT_TEST_CHAIN_LINT:-1}" != 0 +if test "${GIT_TEST_CHAIN_LINT:-1}" != 0 && + test "${GIT_TEST_EXT_CHAIN_LINT:-1}" != 0 then "$PERL_PATH" "$TEST_DIRECTORY/chainlint.pl" "$0" || BUG "lint error (see '?!...!? annotations above)" @@ -1672,7 +1678,7 @@ yes () { # The GIT_TEST_FAIL_PREREQS code hooks into test_set_prereq(), and # thus needs to be set up really early, and set an internal variable # for convenience so the hot test_set_prereq() codepath doesn't need -# to call "git env--helper" (via test_bool_env). Only do that work +# to call "test-tool env-helper" (via test_bool_env). Only do that work # if needed by seeing if GIT_TEST_FAIL_PREREQS is set at all. GIT_TEST_FAIL_PREREQS_INTERNAL= if test -n "$GIT_TEST_FAIL_PREREQS" @@ -1711,7 +1717,7 @@ case $uname_s in test_set_prereq SED_STRIPS_CR test_set_prereq GREP_STRIPS_CR test_set_prereq WINDOWS - GIT_TEST_CMP=mingw_test_cmp + GIT_TEST_CMP="GIT_DIR=/dev/null git diff --no-index --ignore-cr-at-eol --" ;; *CYGWIN*) test_set_prereq POSIXPERM @@ -1927,10 +1933,6 @@ test_lazy_prereq SHA1 ' esac ' -test_lazy_prereq ADD_I_USE_BUILTIN ' - test_bool_env GIT_TEST_ADD_I_USE_BUILTIN true -' - # Ensure that no test accidentally triggers a Git command # that runs the actual maintenance scheduler, affecting a user's # system permanently. |
