diff options
Diffstat (limited to 't')
267 files changed, 13292 insertions, 2648 deletions
diff --git a/t/Git-SVN/00compile.t b/t/Git-SVN/00compile.t new file mode 100644 index 0000000000..c92fee453f --- /dev/null +++ b/t/Git-SVN/00compile.t @@ -0,0 +1,14 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use Test::More tests => 7; + +require_ok 'Git::SVN'; +require_ok 'Git::SVN::Utils'; +require_ok 'Git::SVN::Ra'; +require_ok 'Git::SVN::Log'; +require_ok 'Git::SVN::Migration'; +require_ok 'Git::IndexInfo'; +require_ok 'Git::SVN::GlobSpec'; diff --git a/t/Git-SVN/Utils/add_path_to_url.t b/t/Git-SVN/Utils/add_path_to_url.t new file mode 100644 index 0000000000..bfbd87845f --- /dev/null +++ b/t/Git-SVN/Utils/add_path_to_url.t @@ -0,0 +1,27 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use Test::More 'no_plan'; + +use Git::SVN::Utils qw( + add_path_to_url +); + +# A reference cannot be a hash key, so we use an array. +my @tests = ( + ["http://x.com", "bar"] => 'http://x.com/bar', + ["http://x.com", ""] => 'http://x.com', + ["http://x.com/foo/", undef] => 'http://x.com/foo/', + ["http://x.com/foo/", "/bar/baz/"] => 'http://x.com/foo/bar/baz/', + ["http://x.com", 'per%cent'] => 'http://x.com/per%25cent', +); + +while(@tests) { + my($have, $want) = splice @tests, 0, 2; + + my $args = join ", ", map { qq['$_'] } map { defined($_) ? $_ : 'undef' } @$have; + my $name = "add_path_to_url($args) eq $want"; + is add_path_to_url(@$have), $want, $name; +} diff --git a/t/Git-SVN/Utils/can_compress.t b/t/Git-SVN/Utils/can_compress.t new file mode 100644 index 0000000000..d7b49b8d54 --- /dev/null +++ b/t/Git-SVN/Utils/can_compress.t @@ -0,0 +1,11 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Test::More 'no_plan'; + +use Git::SVN::Utils qw(can_compress); + +# !! is the "convert this to boolean" operator. +is !!can_compress(), !!eval { require Compress::Zlib }; diff --git a/t/Git-SVN/Utils/canonicalize_url.t b/t/Git-SVN/Utils/canonicalize_url.t new file mode 100644 index 0000000000..05795ab636 --- /dev/null +++ b/t/Git-SVN/Utils/canonicalize_url.t @@ -0,0 +1,26 @@ +#!/usr/bin/env perl + +# Test our own home rolled URL canonicalizer. Test the private one +# directly because we can't predict what the SVN API is doing to do. + +use strict; +use warnings; + +use Test::More 'no_plan'; + +use Git::SVN::Utils; +my $canonicalize_url = \&Git::SVN::Utils::_canonicalize_url_ourselves; + +my %tests = ( + "http://x.com" => "http://x.com", + "http://x.com/" => "http://x.com", + "http://x.com/foo/bar" => "http://x.com/foo/bar", + "http://x.com//foo//bar//" => "http://x.com/foo/bar", + "http://x.com/ /%/" => "http://x.com/%20%20/%25", +); + +for my $arg (keys %tests) { + my $want = $tests{$arg}; + + is $canonicalize_url->($arg), $want, "canonicalize_url('$arg') => $want"; +} diff --git a/t/Git-SVN/Utils/collapse_dotdot.t b/t/Git-SVN/Utils/collapse_dotdot.t new file mode 100644 index 0000000000..1da1cce156 --- /dev/null +++ b/t/Git-SVN/Utils/collapse_dotdot.t @@ -0,0 +1,23 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use Test::More 'no_plan'; + +use Git::SVN::Utils; +my $collapse_dotdot = \&Git::SVN::Utils::_collapse_dotdot; + +my %tests = ( + "foo/bar/baz" => "foo/bar/baz", + ".." => "..", + "foo/.." => "", + "/foo/bar/../../baz" => "/baz", + "deeply/.././deeply/nested" => "./deeply/nested", +); + +for my $arg (keys %tests) { + my $want = $tests{$arg}; + + is $collapse_dotdot->($arg), $want, "_collapse_dotdot('$arg') => $want"; +} diff --git a/t/Git-SVN/Utils/fatal.t b/t/Git-SVN/Utils/fatal.t new file mode 100644 index 0000000000..49e1438295 --- /dev/null +++ b/t/Git-SVN/Utils/fatal.t @@ -0,0 +1,34 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Test::More 'no_plan'; + +BEGIN { + # Override exit at BEGIN time before Git::SVN::Utils is loaded + # so it will see our local exit later. + *CORE::GLOBAL::exit = sub(;$) { + return @_ ? CORE::exit($_[0]) : CORE::exit(); + }; +} + +use Git::SVN::Utils qw(fatal); + +# fatal() +{ + # Capture the exit code and prevent exit. + my $exit_status; + no warnings 'redefine'; + local *CORE::GLOBAL::exit = sub { $exit_status = $_[0] || 0 }; + + # Trap fatal's message to STDERR + my $stderr; + close STDERR; + ok open STDERR, ">", \$stderr; + + fatal "Some", "Stuff", "Happened"; + + is $stderr, "Some Stuff Happened\n"; + is $exit_status, 1; +} diff --git a/t/Git-SVN/Utils/join_paths.t b/t/Git-SVN/Utils/join_paths.t new file mode 100644 index 0000000000..d4488e7162 --- /dev/null +++ b/t/Git-SVN/Utils/join_paths.t @@ -0,0 +1,32 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use Test::More 'no_plan'; + +use Git::SVN::Utils qw( + join_paths +); + +# A reference cannot be a hash key, so we use an array. +my @tests = ( + [] => '', + ["/x.com", "bar"] => '/x.com/bar', + ["x.com", ""] => 'x.com', + ["/x.com/foo/", undef, "bar"] => '/x.com/foo/bar', + ["x.com/foo/", "/bar/baz/"] => 'x.com/foo/bar/baz/', + ["foo", "bar"] => 'foo/bar', + ["/foo/bar", "baz", "/biff"] => '/foo/bar/baz/biff', + ["", undef, "."] => '.', + [] => '', + +); + +while(@tests) { + my($have, $want) = splice @tests, 0, 2; + + my $args = join ", ", map { qq['$_'] } map { defined($_) ? $_ : 'undef' } @$have; + my $name = "join_paths($args) eq '$want'"; + is join_paths(@$have), $want, $name; +} diff --git a/t/Makefile b/t/Makefile index b5048ab77b..88e289fc8b 100644 --- a/t/Makefile +++ b/t/Makefile @@ -28,7 +28,7 @@ test: pre-clean $(TEST_LINT) prove: pre-clean $(TEST_LINT) @echo "*** prove ***"; GIT_CONFIG=.git/config $(PROVE) --exec '$(SHELL_PATH_SQ)' $(GIT_PROVE_OPTS) $(T) :: $(GIT_TEST_OPTS) - $(MAKE) clean + $(MAKE) clean-except-prove-cache $(T): @echo "*** $@ ***"; GIT_CONFIG=.git/config '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS) @@ -36,9 +36,11 @@ $(T): pre-clean: $(RM) -r test-results -clean: +clean-except-prove-cache: $(RM) -r 'trash directory'.* test-results $(RM) -r valgrind/bin + +clean: clean-except-prove-cache $(RM) .prove test-lint: test-lint-duplicates test-lint-executable @@ -73,4 +75,45 @@ gitweb-test: valgrind: $(MAKE) GIT_TEST_OPTS="$(GIT_TEST_OPTS) --valgrind" -.PHONY: pre-clean $(T) aggregate-results clean valgrind +perf: + $(MAKE) -C perf/ all + +# Smoke testing targets +-include ../GIT-VERSION-FILE +uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo unknown') +uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo unknown') + +test-results: + mkdir -p test-results + +test-results/git-smoke.tar.gz: test-results + $(PERL_PATH) ./harness \ + --archive="test-results/git-smoke.tar.gz" \ + $(T) + +smoke: test-results/git-smoke.tar.gz + +SMOKE_UPLOAD_FLAGS = +ifdef SMOKE_USERNAME + SMOKE_UPLOAD_FLAGS += -F username="$(SMOKE_USERNAME)" -F password="$(SMOKE_PASSWORD)" +endif +ifdef SMOKE_COMMENT + SMOKE_UPLOAD_FLAGS += -F comments="$(SMOKE_COMMENT)" +endif +ifdef SMOKE_TAGS + SMOKE_UPLOAD_FLAGS += -F tags="$(SMOKE_TAGS)" +endif + +smoke_report: smoke + curl \ + -H "Expect: " \ + -F project=Git \ + -F architecture="$(uname_M)" \ + -F platform="$(uname_S)" \ + -F revision="$(GIT_VERSION)" \ + -F report_file=@test-results/git-smoke.tar.gz \ + $(SMOKE_UPLOAD_FLAGS) \ + http://smoke.git.nix.is/app/projects/process_add_report/1 \ + | grep -v ^Redirecting + +.PHONY: pre-clean $(T) aggregate-results clean valgrind perf @@ -307,6 +307,25 @@ Don't: Use test_done instead if you need to stop the tests early (see "Skipping tests" below). + - use '! git cmd' when you want to make sure the git command exits + with failure in a controlled way by calling "die()". Instead, + use 'test_must_fail git cmd'. This will signal a failure if git + dies in an unexpected way (e.g. segfault). + + - use perl without spelling it as "$PERL_PATH". This is to help our + friends on Windows where the platform Perl often adds CR before + the end of line, and they bundle Git with a version of Perl that + does not do so, whose path is specified with $PERL_PATH. + + - use sh without spelling it as "$SHELL_PATH", when the script can + be misinterpreted by broken platform shell (e.g. Solaris). + + - chdir around in tests. It is not sufficient to chdir to + somewhere and then chdir back to the original location later in + the test, as any intermediate step can fail and abort the test, + causing the next test to start in an unexpected directory. Do so + inside a subshell if necessary. + - Break the TAP output The raw output from your test may be interpreted by a TAP harness. TAP @@ -342,9 +361,9 @@ If you need to skip tests you should do so by using the three-arg form of the test_* functions (see the "Test harness library" section below), e.g.: - test_expect_success PERL 'I need Perl' " - '$PERL_PATH' -e 'hlagh() if unf_unf()' - " + test_expect_success PERL 'I need Perl' ' + "$PERL_PATH" -e "hlagh() if unf_unf()" + ' The advantage of skipping tests like this is that platforms that don't have the PERL and other optional dependencies get an indication of how @@ -548,6 +567,19 @@ library for your script to use. ... ' + - test_pause + + This command is useful for writing and debugging tests and must be + removed before submitting. It halts the execution of the test and + spawns a shell in the trash directory. Exit the shell to continue + the test. Example: + + test_expect_success 'test' ' + git do-something >actual && + test_pause && + test_cmp expected actual + ' + Prerequisites ------------- @@ -593,6 +625,15 @@ use these, and "test_set_prereq" for how to define your own. Git was compiled with USE_LIBPCRE=YesPlease. Wrap any tests that use git-grep --perl-regexp or git-grep -P in these. + - CASE_INSENSITIVE_FS + + Test is run on a case insensitive file system. + + - UTF8_NFD_TO_NFC + + Test is run on a filesystem which converts decomposed utf-8 (nfd) + to precomposed utf-8 (nfc). + Tips for Writing Tests ---------------------- diff --git a/t/gitweb-lib.sh b/t/gitweb-lib.sh index 21d11d6c2d..ae2dc4604f 100644 --- a/t/gitweb-lib.sh +++ b/t/gitweb-lib.sh @@ -69,7 +69,7 @@ gitweb_run () { # written to web server logs, so we are not interested in that: # we are interested only in properly formatted errors/warnings rm -f gitweb.log && - perl -- "$SCRIPT_NAME" \ + "$PERL_PATH" -- "$SCRIPT_NAME" \ >gitweb.output 2>gitweb.log && perl -w -e ' open O, ">gitweb.headers"; diff --git a/t/lib-bash.sh b/t/lib-bash.sh new file mode 100644 index 0000000000..11397f747b --- /dev/null +++ b/t/lib-bash.sh @@ -0,0 +1,18 @@ +#!/bin/sh +# +# Ensures that tests are run under Bash; primarily intended for running tests +# of the completion script. + +if test -n "$BASH" && test -z "$POSIXLY_CORRECT"; then + # we are in full-on bash mode + true +elif type bash >/dev/null 2>&1; then + # execute in full-on bash mode + unset POSIXLY_CORRECT + exec bash "$0" "$@" +else + echo '1..0 #SKIP skipping bash completion tests; bash not available' + exit 0 +fi + +. ./test-lib.sh diff --git a/t/lib-credential.sh b/t/lib-credential.sh index 4a37cd79e5..957ae936e8 100755 --- a/t/lib-credential.sh +++ b/t/lib-credential.sh @@ -4,10 +4,20 @@ # stdout and stderr should be provided on stdin, # separated by "--". check() { + credential_opts= + credential_cmd=$1 + shift + for arg in "$@"; do + credential_opts="$credential_opts -c credential.helper='$arg'" + done read_chunk >stdin && read_chunk >expect-stdout && read_chunk >expect-stderr && - test-credential "$@" <stdin >stdout 2>stderr && + if ! eval "git $credential_opts credential $credential_cmd <stdin >stdout 2>stderr"; then + echo "git credential failed with code $?" && + cat stderr && + false + fi && test_cmp expect-stdout stdout && test_cmp expect-stderr stderr } @@ -41,7 +51,7 @@ reject() { echo protocol=$2 echo host=$3 echo username=$4 - ) | test-credential reject $1 + ) | git -c credential.helper=$1 credential reject } helper_test() { @@ -52,6 +62,8 @@ helper_test() { protocol=https host=example.com -- + protocol=https + host=example.com username=askpass-username password=askpass-password -- @@ -74,6 +86,8 @@ helper_test() { protocol=https host=example.com -- + protocol=https + host=example.com username=store-user password=store-pass -- @@ -85,6 +99,8 @@ helper_test() { protocol=http host=example.com -- + protocol=http + host=example.com username=askpass-username password=askpass-password -- @@ -98,6 +114,8 @@ helper_test() { protocol=https host=other.tld -- + protocol=https + host=other.tld username=askpass-username password=askpass-password -- @@ -112,6 +130,8 @@ helper_test() { host=example.com username=other -- + protocol=https + host=example.com username=other password=askpass-password -- @@ -133,6 +153,9 @@ helper_test() { host=path.tld path=bar.git -- + protocol=http + host=path.tld + path=bar.git username=askpass-username password=askpass-password -- @@ -150,6 +173,8 @@ helper_test() { protocol=https host=example.com -- + protocol=https + host=example.com username=askpass-username password=askpass-password -- @@ -176,6 +201,8 @@ helper_test() { host=example.com username=user1 -- + protocol=https + host=example.com username=user1 password=pass1 EOF @@ -184,6 +211,8 @@ helper_test() { host=example.com username=user2 -- + protocol=https + host=example.com username=user2 password=pass2 EOF @@ -200,6 +229,8 @@ helper_test() { host=example.com username=user1 -- + protocol=https + host=example.com username=user1 password=askpass-password -- @@ -213,6 +244,8 @@ helper_test() { host=example.com username=user2 -- + protocol=https + host=example.com username=user2 password=pass2 EOF @@ -234,6 +267,8 @@ helper_test_timeout() { protocol=https host=timeout.tld -- + protocol=https + host=timeout.tld username=askpass-username password=askpass-password -- diff --git a/t/lib-git-daemon.sh b/t/lib-git-daemon.sh new file mode 100644 index 0000000000..87f0ad8f41 --- /dev/null +++ b/t/lib-git-daemon.sh @@ -0,0 +1,69 @@ +#!/bin/sh + +if test -z "$GIT_TEST_GIT_DAEMON" +then + skip_all="git-daemon testing disabled (define GIT_TEST_GIT_DAEMON to enable)" + test_done +fi + +LIB_GIT_DAEMON_PORT=${LIB_GIT_DAEMON_PORT-'8121'} + +GIT_DAEMON_PID= +GIT_DAEMON_DOCUMENT_ROOT_PATH="$PWD"/repo +GIT_DAEMON_URL=git://127.0.0.1:$LIB_GIT_DAEMON_PORT + +start_git_daemon() { + if test -n "$GIT_DAEMON_PID" + then + error "start_git_daemon already called" + fi + + mkdir -p "$GIT_DAEMON_DOCUMENT_ROOT_PATH" + + trap 'code=$?; stop_git_daemon; (exit $code); die' EXIT + + say >&3 "Starting git daemon ..." + mkfifo git_daemon_output + git daemon --listen=127.0.0.1 --port="$LIB_GIT_DAEMON_PORT" \ + --reuseaddr --verbose \ + --base-path="$GIT_DAEMON_DOCUMENT_ROOT_PATH" \ + "$@" "$GIT_DAEMON_DOCUMENT_ROOT_PATH" \ + >&3 2>git_daemon_output & + GIT_DAEMON_PID=$! + { + read line <&7 + echo >&4 "$line" + cat <&7 >&4 & + } 7<git_daemon_output && + + # Check expected output + if test x"$(expr "$line" : "\[[0-9]*\] \(.*\)")" != x"Ready to rumble" + then + kill "$GIT_DAEMON_PID" + wait "$GIT_DAEMON_PID" + trap 'die' EXIT + error "git daemon failed to start" + fi +} + +stop_git_daemon() { + if test -z "$GIT_DAEMON_PID" + then + return + fi + + trap 'die' EXIT + + # kill git-daemon child of git + say >&3 "Stopping git daemon ..." + kill "$GIT_DAEMON_PID" + wait "$GIT_DAEMON_PID" >&3 2>&4 + ret=$? + # expect exit with status 143 = 128+15 for signal TERM=15 + if test $ret -ne 143 + then + error "git daemon exited with status: $ret" + fi + GIT_DAEMON_PID= + rm -f git_daemon_output +} diff --git a/t/lib-git-p4.sh b/t/lib-git-p4.sh index a870f9a5d2..2d753ab7e1 100644 --- a/t/lib-git-p4.sh +++ b/t/lib-git-p4.sh @@ -1,20 +1,22 @@ # -# Library code for git-p4 tests +# Library code for git p4 tests # +# p4 tests never use the top-level repo; always build/clone into +# a subdirectory called "$git" +TEST_NO_CREATE_REPO=NoThanks + . ./test-lib.sh if ! test_have_prereq PYTHON; then - skip_all='skipping git-p4 tests; python not available' + skip_all='skipping git p4 tests; python not available' test_done fi ( p4 -h && p4d -h ) >/dev/null 2>&1 || { - skip_all='skipping git-p4 tests; no p4 or p4d' + skip_all='skipping git p4 tests; no p4 or p4d' test_done } -GITP4="$GIT_BUILD_DIR/contrib/fast-import/git-p4" - # Try to pick a unique port: guess a large number, then hope # no more than one of each test is running. # @@ -26,25 +28,51 @@ P4DPORT=$((10669 + ($testid - $git_p4_test_start))) export P4PORT=localhost:$P4DPORT export P4CLIENT=client +export P4EDITOR=: db="$TRASH_DIRECTORY/db" -cli="$TRASH_DIRECTORY/cli" +cli=$(test-path-utils real_path "$TRASH_DIRECTORY/cli") git="$TRASH_DIRECTORY/git" pidfile="$TRASH_DIRECTORY/p4d.pid" start_p4d() { mkdir -p "$db" "$cli" "$git" && + rm -f "$pidfile" && ( p4d -q -r "$db" -p $P4DPORT & echo $! >"$pidfile" ) && - for i in 1 2 3 4 5 ; do - p4 info >/dev/null 2>&1 && break || true && - echo waiting for p4d to start && + + # This gives p4d a long time to start up, as it can be + # quite slow depending on the machine. Set this environment + # variable to something smaller to fail faster in, say, + # an automated test setup. If the p4d process dies, that + # will be caught with the "kill -0" check below. + i=${P4D_START_PATIENCE:-300} + pid=$(cat "$pidfile") + ready= + while test $i -gt 0 + do + # succeed when p4 client commands start to work + if p4 info >/dev/null 2>&1 + then + ready=true + break + fi + # fail if p4d died + kill -0 $pid 2>/dev/null || break + echo waiting for p4d to start sleep 1 - done && - # complain if it never started - p4 info >/dev/null && + i=$(( $i - 1 )) + done + + if test -z "$ready" + then + # p4d failed to start + return 1 + fi + + # build a client ( cd "$cli" && p4 client -i <<-EOF @@ -54,6 +82,7 @@ start_p4d() { View: //depot/... //client/... EOF ) + return 0 } kill_p4d() { @@ -70,5 +99,19 @@ kill_p4d() { } cleanup_git() { - rm -rf "$git" + rm -rf "$git" && + mkdir "$git" +} + +marshal_dump() { + what=$1 && + line=${2:-1} && + cat >"$TRASH_DIRECTORY/marshal-dump.py" <<-EOF && + import marshal + import sys + for i in range($line): + d = marshal.load(sys.stdin) + print d['$what'] + EOF + "$PYTHON_PATH" "$TRASH_DIRECTORY/marshal-dump.py" } diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh index f7dc0781d5..d773542680 100644 --- a/t/lib-httpd.sh +++ b/t/lib-httpd.sh @@ -43,6 +43,10 @@ TEST_PATH="$TEST_DIRECTORY"/lib-httpd HTTPD_ROOT_PATH="$PWD"/httpd HTTPD_DOCUMENT_ROOT_PATH=$HTTPD_ROOT_PATH/www +# hack to suppress apache PassEnv warnings +GIT_VALGRIND=$GIT_VALGRIND; export GIT_VALGRIND +GIT_VALGRIND_OPTIONS=$GIT_VALGRIND_OPTIONS; export GIT_VALGRIND_OPTIONS + if ! test -x "$LIB_HTTPD_PATH" then skip_all="skipping test, no web server found at '$LIB_HTTPD_PATH'" @@ -160,6 +164,6 @@ test_http_push_nonff() { ' test_expect_success 'non-fast-forward push shows help message' ' - test_i18ngrep "To prevent you from losing history, non-fast-forward updates were rejected" output + test_i18ngrep "Updates were rejected because" output ' } diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf index 3c12b05d60..36b1596a10 100644 --- a/t/lib-httpd/apache.conf +++ b/t/lib-httpd/apache.conf @@ -42,6 +42,9 @@ ErrorLog error.log </IfModule> </IfVersion> +PassEnv GIT_VALGRIND +PassEnv GIT_VALGRIND_OPTIONS + Alias /dumb/ www/ Alias /auth/ www/auth/ @@ -52,10 +55,17 @@ Alias /auth/ www/auth/ <Location /smart_noexport/> SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH} </Location> +<Location /smart_custom_env/> + SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH} + SetEnv GIT_HTTP_EXPORT_ALL + SetEnv GIT_COMMITTER_NAME "Custom User" + SetEnv GIT_COMMITTER_EMAIL custom@example.com +</Location> ScriptAlias /smart/ ${GIT_EXEC_PATH}/git-http-backend/ ScriptAlias /smart_noexport/ ${GIT_EXEC_PATH}/git-http-backend/ +ScriptAlias /smart_custom_env/ ${GIT_EXEC_PATH}/git-http-backend/ <Directory ${GIT_EXEC_PATH}> - Options None + Options FollowSymlinks </Directory> <Files ${GIT_EXEC_PATH}/git-http-backend> Options ExecCGI diff --git a/t/perf/.gitignore b/t/perf/.gitignore new file mode 100644 index 0000000000..50f5cc1ed9 --- /dev/null +++ b/t/perf/.gitignore @@ -0,0 +1,2 @@ +build/ +test-results/ diff --git a/t/perf/Makefile b/t/perf/Makefile new file mode 100644 index 0000000000..8c47155a7c --- /dev/null +++ b/t/perf/Makefile @@ -0,0 +1,15 @@ +-include ../../config.mak +export GIT_TEST_OPTIONS + +all: perf + +perf: pre-clean + ./run + +pre-clean: + rm -rf test-results + +clean: + rm -rf build "trash directory".* test-results + +.PHONY: all perf pre-clean clean diff --git a/t/perf/README b/t/perf/README new file mode 100644 index 0000000000..b2dbad4d50 --- /dev/null +++ b/t/perf/README @@ -0,0 +1,146 @@ +Git performance tests +===================== + +This directory holds performance testing scripts for git tools. The +first part of this document describes the various ways in which you +can run them. + +When fixing the tools or adding enhancements, you are strongly +encouraged to add tests in this directory to cover what you are +trying to fix or enhance. The later part of this short document +describes how your test scripts should be organized. + + +Running Tests +------------- + +The easiest way to run tests is to say "make". This runs all +the tests on the current git repository. + + === Running 2 tests in this tree === + [...] + Test this tree + --------------------------------------------------------- + 0001.1: rev-list --all 0.54(0.51+0.02) + 0001.2: rev-list --all --objects 6.14(5.99+0.11) + 7810.1: grep worktree, cheap regex 0.16(0.16+0.35) + 7810.2: grep worktree, expensive regex 7.90(29.75+0.37) + 7810.3: grep --cached, cheap regex 3.07(3.02+0.25) + 7810.4: grep --cached, expensive regex 9.39(30.57+0.24) + +You can compare multiple repositories and even git revisions with the +'run' script: + + $ ./run . origin/next /path/to/git-tree p0001-rev-list.sh + +where . stands for the current git tree. The full invocation is + + ./run [<revision|directory>...] [--] [<test-script>...] + +A '.' argument is implied if you do not pass any other +revisions/directories. + +You can also manually test this or another git build tree, and then +call the aggregation script to summarize the results: + + $ ./p0001-rev-list.sh + [...] + $ GIT_BUILD_DIR=/path/to/other/git ./p0001-rev-list.sh + [...] + $ ./aggregate.perl . /path/to/other/git ./p0001-rev-list.sh + +aggregate.perl has the same invocation as 'run', it just does not run +anything beforehand. + +You can set the following variables (also in your config.mak): + + GIT_PERF_REPEAT_COUNT + Number of times a test should be repeated for best-of-N + measurements. Defaults to 5. + + GIT_PERF_MAKE_OPTS + Options to use when automatically building a git tree for + performance testing. E.g., -j6 would be useful. + + GIT_PERF_REPO + GIT_PERF_LARGE_REPO + Repositories to copy for the performance tests. The normal + repo should be at least git.git size. The large repo should + probably be about linux-2.6.git size for optimal results. + Both default to the git.git you are running from. + +You can also pass the options taken by ordinary git tests; the most +useful one is: + +--root=<directory>:: + Create "trash" directories used to store all temporary data during + testing under <directory>, instead of the t/ directory. + Using this option with a RAM-based filesystem (such as tmpfs) + can massively speed up the test suite. + + +Naming Tests +------------ + +The performance test files are named as: + + pNNNN-commandname-details.sh + +where N is a decimal digit. The same conventions for choosing NNNN as +for normal tests apply. + + +Writing Tests +------------- + +The perf script starts much like a normal test script, except it +sources perf-lib.sh: + + #!/bin/sh + # + # Copyright (c) 2005 Junio C Hamano + # + + test_description='xxx performance test' + . ./perf-lib.sh + +After that you will want to use some of the following: + + test_perf_default_repo # sets up a "normal" repository + test_perf_large_repo # sets up a "large" repository + + test_perf_default_repo sub # ditto, in a subdir "sub" + + test_checkout_worktree # if you need the worktree too + +At least one of the first two is required! + +You can use test_expect_success as usual. For actual performance +tests, use + + test_perf 'descriptive string' ' + command1 && + command2 + ' + +test_perf spawns a subshell, for lack of better options. This means +that + +* you _must_ export all variables that you need in the subshell + +* you _must_ flag all variables that you want to persist from the + subshell with 'test_export': + + test_perf 'descriptive string' ' + foo=$(git rev-parse HEAD) && + test_export foo + ' + + The so-exported variables are automatically marked for export in the + shell executing the perf test. For your convenience, test_export is + the same as export in the main shell. + + This feature relies on a bit of magic using 'set' and 'source'. + While we have tried to make sure that it can cope with embedded + whitespace and other special characters, it will not work with + multi-line data. diff --git a/t/perf/aggregate.perl b/t/perf/aggregate.perl new file mode 100755 index 0000000000..15f7fc1b80 --- /dev/null +++ b/t/perf/aggregate.perl @@ -0,0 +1,166 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Git; + +sub get_times { + my $name = shift; + open my $fh, "<", $name or return undef; + my $line = <$fh>; + return undef if not defined $line; + close $fh or die "cannot close $name: $!"; + $line =~ /^(?:(\d+):)?(\d+):(\d+(?:\.\d+)?) (\d+(?:\.\d+)?) (\d+(?:\.\d+)?)$/ + or die "bad input line: $line"; + my $rt = ((defined $1 ? $1 : 0.0)*60+$2)*60+$3; + return ($rt, $4, $5); +} + +sub format_times { + my ($r, $u, $s, $firstr) = @_; + if (!defined $r) { + return "<missing>"; + } + my $out = sprintf "%.2f(%.2f+%.2f)", $r, $u, $s; + if (defined $firstr) { + if ($firstr > 0) { + $out .= sprintf " %+.1f%%", 100.0*($r-$firstr)/$firstr; + } elsif ($r == 0) { + $out .= " ="; + } else { + $out .= " +inf"; + } + } + return $out; +} + +my (@dirs, %dirnames, %dirabbrevs, %prefixes, @tests); +while (scalar @ARGV) { + my $arg = $ARGV[0]; + my $dir; + last if -f $arg or $arg eq "--"; + if (! -d $arg) { + my $rev = Git::command_oneline(qw(rev-parse --verify), $arg); + $dir = "build/".$rev; + } else { + $arg =~ s{/*$}{}; + $dir = $arg; + $dirabbrevs{$dir} = $dir; + } + push @dirs, $dir; + $dirnames{$dir} = $arg; + my $prefix = $dir; + $prefix =~ tr/^a-zA-Z0-9/_/c; + $prefixes{$dir} = $prefix . '.'; + shift @ARGV; +} + +if (not @dirs) { + @dirs = ('.'); +} +$dirnames{'.'} = $dirabbrevs{'.'} = "this tree"; +$prefixes{'.'} = ''; + +shift @ARGV if scalar @ARGV and $ARGV[0] eq "--"; + +@tests = @ARGV; +if (not @tests) { + @tests = glob "p????-*.sh"; +} + +my @subtests; +my %shorttests; +for my $t (@tests) { + $t =~ s{(?:.*/)?(p(\d+)-[^/]+)\.sh$}{$1} or die "bad test name: $t"; + my $n = $2; + my $fname = "test-results/$t.subtests"; + open my $fp, "<", $fname or die "cannot open $fname: $!"; + for (<$fp>) { + chomp; + /^(\d+)$/ or die "malformed subtest line: $_"; + push @subtests, "$t.$1"; + $shorttests{"$t.$1"} = "$n.$1"; + } + close $fp or die "cannot close $fname: $!"; +} + +sub read_descr { + my $name = shift; + open my $fh, "<", $name or return "<error reading description>"; + my $line = <$fh>; + close $fh or die "cannot close $name"; + chomp $line; + return $line; +} + +my %descrs; +my $descrlen = 4; # "Test" +for my $t (@subtests) { + $descrs{$t} = $shorttests{$t}.": ".read_descr("test-results/$t.descr"); + $descrlen = length $descrs{$t} if length $descrs{$t}>$descrlen; +} + +sub have_duplicate { + my %seen; + for (@_) { + return 1 if exists $seen{$_}; + $seen{$_} = 1; + } + return 0; +} +sub have_slash { + for (@_) { + return 1 if m{/}; + } + return 0; +} + +my %newdirabbrevs = %dirabbrevs; +while (!have_duplicate(values %newdirabbrevs)) { + %dirabbrevs = %newdirabbrevs; + last if !have_slash(values %dirabbrevs); + %newdirabbrevs = %dirabbrevs; + for (values %newdirabbrevs) { + s{^[^/]*/}{}; + } +} + +my %times; +my @colwidth = ((0)x@dirs); +for my $i (0..$#dirs) { + my $d = $dirs[$i]; + my $w = length (exists $dirabbrevs{$d} ? $dirabbrevs{$d} : $dirnames{$d}); + $colwidth[$i] = $w if $w > $colwidth[$i]; +} +for my $t (@subtests) { + my $firstr; + for my $i (0..$#dirs) { + my $d = $dirs[$i]; + $times{$prefixes{$d}.$t} = [get_times("test-results/$prefixes{$d}$t.times")]; + my ($r,$u,$s) = @{$times{$prefixes{$d}.$t}}; + my $w = length format_times($r,$u,$s,$firstr); + $colwidth[$i] = $w if $w > $colwidth[$i]; + $firstr = $r unless defined $firstr; + } +} +my $totalwidth = 3*@dirs+$descrlen; +$totalwidth += $_ for (@colwidth); + +printf "%-${descrlen}s", "Test"; +for my $i (0..$#dirs) { + my $d = $dirs[$i]; + printf " %-$colwidth[$i]s", (exists $dirabbrevs{$d} ? $dirabbrevs{$d} : $dirnames{$d}); +} +print "\n"; +print "-"x$totalwidth, "\n"; +for my $t (@subtests) { + printf "%-${descrlen}s", $descrs{$t}; + my $firstr; + for my $i (0..$#dirs) { + my $d = $dirs[$i]; + my ($r,$u,$s) = @{$times{$prefixes{$d}.$t}}; + printf " %-$colwidth[$i]s", format_times($r,$u,$s,$firstr); + $firstr = $r unless defined $firstr; + } + print "\n"; +} diff --git a/t/perf/min_time.perl b/t/perf/min_time.perl new file mode 100755 index 0000000000..c1a2717e07 --- /dev/null +++ b/t/perf/min_time.perl @@ -0,0 +1,21 @@ +#!/usr/bin/perl + +my $minrt = 1e100; +my $min; + +while (<>) { + # [h:]m:s.xx U.xx S.xx + /^(?:(\d+):)?(\d+):(\d+(?:\.\d+)?) (\d+(?:\.\d+)?) (\d+(?:\.\d+)?)$/ + or die "bad input line: $_"; + my $rt = ((defined $1 ? $1 : 0.0)*60+$2)*60+$3; + if ($rt < $minrt) { + $min = $_; + $minrt = $rt; + } +} + +if (!defined $min) { + die "no input found"; +} + +print $min; diff --git a/t/perf/p0000-perf-lib-sanity.sh b/t/perf/p0000-perf-lib-sanity.sh new file mode 100755 index 0000000000..cf8e1efce7 --- /dev/null +++ b/t/perf/p0000-perf-lib-sanity.sh @@ -0,0 +1,55 @@ +#!/bin/sh + +test_description='Tests whether perf-lib facilities work' +. ./perf-lib.sh + +test_perf_default_repo + +test_perf 'test_perf_default_repo works' ' + foo=$(git rev-parse HEAD) && + test_export foo +' + +test_checkout_worktree + +test_perf 'test_checkout_worktree works' ' + wt=$(find . | wc -l) && + idx=$(git ls-files | wc -l) && + test $wt -gt $idx +' + +baz=baz +test_export baz + +test_expect_success 'test_export works' ' + echo "$foo" && + test "$foo" = "$(git rev-parse HEAD)" && + echo "$baz" && + test "$baz" = baz +' + +test_perf 'export a weird var' ' + bar="weird # variable" && + test_export bar +' + +test_expect_success 'test_export works with weird vars' ' + echo "$bar" && + test "$bar" = "weird # variable" +' + +test_perf 'important variables available in subshells' ' + test -n "$HOME" && + test -n "$TEST_DIRECTORY" && + test -n "$TRASH_DIRECTORY" && + test -n "$GIT_BUILD_DIR" +' + +test_perf 'test-lib-functions correctly loaded in subshells' ' + : >a && + test_path_is_file a && + : >b && + test_cmp a b +' + +test_done diff --git a/t/perf/p0001-rev-list.sh b/t/perf/p0001-rev-list.sh new file mode 100755 index 0000000000..4f71a63b0a --- /dev/null +++ b/t/perf/p0001-rev-list.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +test_description="Tests history walking performance" + +. ./perf-lib.sh + +test_perf_default_repo + +test_perf 'rev-list --all' ' + git rev-list --all >/dev/null +' + +test_perf 'rev-list --all --objects' ' + git rev-list --all --objects >/dev/null +' + +test_done diff --git a/t/perf/p4000-diff-algorithms.sh b/t/perf/p4000-diff-algorithms.sh new file mode 100755 index 0000000000..7e00c9da47 --- /dev/null +++ b/t/perf/p4000-diff-algorithms.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +test_description="Tests diff generation performance" + +. ./perf-lib.sh + +test_perf_default_repo + +test_perf 'log -3000 (baseline)' ' + git log -3000 >/dev/null +' + +test_perf 'log --raw -3000 (tree-only)' ' + git log --raw -3000 >/dev/null +' + +test_perf 'log -p -3000 (Myers)' ' + git log -p -3000 >/dev/null +' + +test_perf 'log -p -3000 --histogram' ' + git log -p -3000 --histogram >/dev/null +' + +test_perf 'log -p -3000 --patience' ' + git log -p -3000 --patience >/dev/null +' + +test_done diff --git a/t/perf/p5302-pack-index.sh b/t/perf/p5302-pack-index.sh new file mode 100755 index 0000000000..6cb5b0d55b --- /dev/null +++ b/t/perf/p5302-pack-index.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +test_description="Tests index-pack performance" + +. ./perf-lib.sh + +test_perf_large_repo + +test_expect_success 'repack' ' + git repack -ad && + PACK=`ls .git/objects/pack/*.pack | head -n1` && + test -f "$PACK" && + export PACK +' + +test_perf 'index-pack 0 threads' ' + GIT_DIR=t1 git index-pack --threads=1 --stdin < $PACK +' + +test_perf 'index-pack 1 thread ' ' + GIT_DIR=t2 GIT_FORCE_THREADS=1 git index-pack --threads=1 --stdin < $PACK +' + +test_perf 'index-pack 2 threads' ' + GIT_DIR=t3 git index-pack --threads=2 --stdin < $PACK +' + +test_perf 'index-pack 4 threads' ' + GIT_DIR=t4 git index-pack --threads=4 --stdin < $PACK +' + +test_perf 'index-pack 8 threads' ' + GIT_DIR=t5 git index-pack --threads=8 --stdin < $PACK +' + +test_perf 'index-pack default number of threads' ' + GIT_DIR=t6 git index-pack --stdin < $PACK +' + +test_done diff --git a/t/perf/p7810-grep.sh b/t/perf/p7810-grep.sh new file mode 100755 index 0000000000..9f4ade639f --- /dev/null +++ b/t/perf/p7810-grep.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +test_description="git-grep performance in various modes" + +. ./perf-lib.sh + +test_perf_large_repo +test_checkout_worktree + +test_perf 'grep worktree, cheap regex' ' + git grep some_nonexistent_string || : +' +test_perf 'grep worktree, expensive regex' ' + git grep "^.* *some_nonexistent_string$" || : +' +test_perf 'grep --cached, cheap regex' ' + git grep --cached some_nonexistent_string || : +' +test_perf 'grep --cached, expensive regex' ' + git grep --cached "^.* *some_nonexistent_string$" || : +' + +test_done diff --git a/t/perf/perf-lib.sh b/t/perf/perf-lib.sh new file mode 100644 index 0000000000..a1361e530c --- /dev/null +++ b/t/perf/perf-lib.sh @@ -0,0 +1,202 @@ +#!/bin/sh +# +# Copyright (c) 2011 Thomas Rast +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see http://www.gnu.org/licenses/ . + +# do the --tee work early; it otherwise confuses our careful +# GIT_BUILD_DIR mangling +case "$GIT_TEST_TEE_STARTED, $* " in +done,*) + # do not redirect again + ;; +*' --tee '*|*' --va'*) + mkdir -p test-results + BASE=test-results/$(basename "$0" .sh) + (GIT_TEST_TEE_STARTED=done ${SHELL-sh} "$0" "$@" 2>&1; + echo $? > $BASE.exit) | tee $BASE.out + test "$(cat $BASE.exit)" = 0 + exit + ;; +esac + +TEST_DIRECTORY=$(pwd)/.. +TEST_OUTPUT_DIRECTORY=$(pwd) +if test -z "$GIT_TEST_INSTALLED"; then + perf_results_prefix= +else + perf_results_prefix=$(printf "%s" "${GIT_TEST_INSTALLED%/bin-wrappers}" | tr -c "[a-zA-Z0-9]" "[_*]")"." + # make the tested dir absolute + GIT_TEST_INSTALLED=$(cd "$GIT_TEST_INSTALLED" && pwd) +fi + +TEST_NO_CREATE_REPO=t + +. ../test-lib.sh + +# Variables from test-lib that are normally internal to the tests; we +# need to export them for test_perf subshells +export TEST_DIRECTORY TRASH_DIRECTORY GIT_BUILD_DIR GIT_TEST_CMP + +perf_results_dir=$TEST_OUTPUT_DIRECTORY/test-results +mkdir -p "$perf_results_dir" +rm -f "$perf_results_dir"/$(basename "$0" .sh).subtests + +if test -z "$GIT_PERF_REPEAT_COUNT"; then + GIT_PERF_REPEAT_COUNT=3 +fi +die_if_build_dir_not_repo () { + if ! ( cd "$TEST_DIRECTORY/.." && + git rev-parse --build-dir >/dev/null 2>&1 ); then + error "No $1 defined, and your build directory is not a repo" + fi +} + +if test -z "$GIT_PERF_REPO"; then + die_if_build_dir_not_repo '$GIT_PERF_REPO' + GIT_PERF_REPO=$TEST_DIRECTORY/.. +fi +if test -z "$GIT_PERF_LARGE_REPO"; then + die_if_build_dir_not_repo '$GIT_PERF_LARGE_REPO' + GIT_PERF_LARGE_REPO=$TEST_DIRECTORY/.. +fi + +test_perf_create_repo_from () { + test "$#" = 2 || + error "bug in the test script: not 2 parameters to test-create-repo" + repo="$1" + source="$2" + source_git=$source/$(cd "$source" && git rev-parse --git-dir) + mkdir -p "$repo/.git" + ( + cd "$repo/.git" && + { cp -Rl "$source_git/objects" . 2>/dev/null || + cp -R "$source_git/objects" .; } && + for stuff in "$source_git"/*; do + case "$stuff" in + */objects|*/hooks|*/config) + ;; + *) + cp -R "$stuff" . || break + ;; + esac + done && + cd .. && + git init -q && + mv .git/hooks .git/hooks-disabled 2>/dev/null + ) || error "failed to copy repository '$source' to '$repo'" +} + +# call at least one of these to establish an appropriately-sized repository +test_perf_default_repo () { + test_perf_create_repo_from "${1:-$TRASH_DIRECTORY}" "$GIT_PERF_REPO" +} +test_perf_large_repo () { + if test "$GIT_PERF_LARGE_REPO" = "$GIT_BUILD_DIR"; then + echo "warning: \$GIT_PERF_LARGE_REPO is \$GIT_BUILD_DIR." >&2 + echo "warning: This will work, but may not be a sufficiently large repo" >&2 + echo "warning: for representative measurements." >&2 + fi + test_perf_create_repo_from "${1:-$TRASH_DIRECTORY}" "$GIT_PERF_LARGE_REPO" +} +test_checkout_worktree () { + git checkout-index -u -a || + error "git checkout-index failed" +} + +# Performance tests should never fail. If they do, stop immediately +immediate=t + +test_run_perf_ () { + test_cleanup=: + test_export_="test_cleanup" + export test_cleanup test_export_ + /usr/bin/time -f "%E %U %S" -o test_time.$i "$SHELL" -c ' +. '"$TEST_DIRECTORY"/test-lib-functions.sh' +test_export () { + [ $# != 0 ] || return 0 + test_export_="$test_export_\\|$1" + shift + test_export "$@" +} +'"$1"' +ret=$? +set | sed -n "s'"/'/'\\\\''/g"';s/^\\($test_export_\\)/export '"'&'"'/p" >test_vars +exit $ret' >&3 2>&4 + eval_ret=$? + + if test $eval_ret = 0 || test -n "$expecting_failure" + then + test_eval_ "$test_cleanup" + . ./test_vars || error "failed to load updated environment" + fi + if test "$verbose" = "t" && test -n "$HARNESS_ACTIVE"; then + echo "" + fi + return "$eval_ret" +} + + +test_perf () { + test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= + test "$#" = 2 || + error "bug in the test script: not 2 or 3 parameters to test-expect-success" + export test_prereq + if ! test_skip "$@" + then + base=$(basename "$0" .sh) + echo "$test_count" >>"$perf_results_dir"/$base.subtests + echo "$1" >"$perf_results_dir"/$base.$test_count.descr + if test -z "$verbose"; then + echo -n "perf $test_count - $1:" + else + echo "perf $test_count - $1:" + fi + for i in $(test_seq 1 $GIT_PERF_REPEAT_COUNT); do + say >&3 "running: $2" + if test_run_perf_ "$2" + then + if test -z "$verbose"; then + echo -n " $i" + else + echo "* timing run $i/$GIT_PERF_REPEAT_COUNT:" + fi + else + test -z "$verbose" && echo + test_failure_ "$@" + break + fi + done + if test -z "$verbose"; then + echo " ok" + else + test_ok_ "$1" + fi + base="$perf_results_dir"/"$perf_results_prefix$(basename "$0" .sh)"."$test_count" + "$TEST_DIRECTORY"/perf/min_time.perl test_time.* >"$base".times + fi + echo >&3 "" +} + +# We extend test_done to print timings at the end (./run disables this +# and does it after running everything) +test_at_end_hook_ () { + if test -z "$GIT_PERF_AGGREGATING_LATER"; then + ( cd "$TEST_DIRECTORY"/perf && ./aggregate.perl $(basename "$0") ) + fi +} + +test_export () { + export "$@" +} diff --git a/t/perf/run b/t/perf/run new file mode 100755 index 0000000000..cfd70129bb --- /dev/null +++ b/t/perf/run @@ -0,0 +1,82 @@ +#!/bin/sh + +case "$1" in + --help) + echo "usage: $0 [other_git_tree...] [--] [test_scripts]" + exit 0 + ;; +esac + +die () { + echo >&2 "error: $*" + exit 1 +} + +run_one_dir () { + if test $# -eq 0; then + set -- p????-*.sh + fi + echo "=== Running $# tests in ${GIT_TEST_INSTALLED:-this tree} ===" + for t in "$@"; do + ./$t $GIT_TEST_OPTS + done +} + +unpack_git_rev () { + rev=$1 + mkdir -p build/$rev + (cd "$(git rev-parse --show-cdup)" && git archive --format=tar $rev) | + (cd build/$rev && tar x) +} +build_git_rev () { + rev=$1 + cp ../../config.mak build/$rev/config.mak + (cd build/$rev && make $GIT_PERF_MAKE_OPTS) || + die "failed to build revision '$mydir'" +} + +run_dirs_helper () { + mydir=${1%/} + shift + while test $# -gt 0 -a "$1" != -- -a ! -f "$1"; do + shift + done + if test $# -gt 0 -a "$1" = --; then + shift + fi + if [ ! -d "$mydir" ]; then + rev=$(git rev-parse --verify "$mydir" 2>/dev/null) || + die "'$mydir' is neither a directory nor a valid revision" + if [ ! -d build/$rev ]; then + unpack_git_rev $rev + fi + build_git_rev $rev + mydir=build/$rev + fi + if test "$mydir" = .; then + unset GIT_TEST_INSTALLED + else + GIT_TEST_INSTALLED="$mydir/bin-wrappers" + export GIT_TEST_INSTALLED + fi + run_one_dir "$@" +} + +run_dirs () { + while test $# -gt 0 -a "$1" != -- -a ! -f "$1"; do + run_dirs_helper "$@" + shift + done +} + +GIT_PERF_AGGREGATING_LATER=t +export GIT_PERF_AGGREGATING_LATER + +cd "$(dirname $0)" +. ../../GIT-BUILD-OPTIONS + +if test $# = 0 -o "$1" = -- -o -f "$1"; then + set -- . "$@" +fi +run_dirs "$@" +./aggregate.perl "$@" diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index f4e8f43bae..ccb5435b2a 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -34,69 +34,69 @@ fi # git init has been done in an empty repository. # make sure it is empty. -find .git/objects -type f -print >should-be-empty -test_expect_success \ - '.git/objects should be empty after git init in an empty repo.' \ - 'cmp -s /dev/null should-be-empty' +test_expect_success '.git/objects should be empty after git init in an empty repo' ' + find .git/objects -type f -print >should-be-empty && + test_line_count = 0 should-be-empty +' # also it should have 2 subdirectories; no fan-out anymore, pack, and info. # 3 is counting "objects" itself -find .git/objects -type d -print >full-of-directories -test_expect_success \ - '.git/objects should have 3 subdirectories.' \ - 'test $(wc -l < full-of-directories) = 3' +test_expect_success '.git/objects should have 3 subdirectories' ' + find .git/objects -type d -print >full-of-directories && + test_line_count = 3 full-of-directories +' ################################################################ # Test harness test_expect_success 'success is reported like this' ' - : + : ' test_expect_failure 'pretend we have a known breakage' ' - false + false ' test_expect_success 'pretend we have fixed a known breakage (run in sub test-lib)' " - mkdir passing-todo && - (cd passing-todo && - cat >passing-todo.sh <<EOF && -#!$SHELL_PATH - -test_description='A passing TODO test - -This is run in a sub test-lib so that we do not get incorrect passing -metrics -' - -# Point to the t/test-lib.sh, which isn't in ../ as usual -TEST_DIRECTORY=\"$TEST_DIRECTORY\" -. \"\$TEST_DIRECTORY\"/test-lib.sh - -test_expect_failure 'pretend we have fixed a known breakage' ' - : -' - -test_done -EOF - chmod +x passing-todo.sh && - ./passing-todo.sh >out 2>err && - ! test -s err && -sed -e 's/^> //' >expect <<EOF && -> ok 1 - pretend we have fixed a known breakage # TODO known breakage -> # fixed 1 known breakage(s) -> # passed all 1 test(s) -> 1..1 -EOF - test_cmp expect out) + mkdir passing-todo && + (cd passing-todo && + cat >passing-todo.sh <<-EOF && + #!$SHELL_PATH + + test_description='A passing TODO test + + This is run in a sub test-lib so that we do not get incorrect + passing metrics + ' + + # Point to the t/test-lib.sh, which isn't in ../ as usual + TEST_DIRECTORY=\"$TEST_DIRECTORY\" + . \"\$TEST_DIRECTORY\"/test-lib.sh + + test_expect_failure 'pretend we have fixed a known breakage' ' + : + ' + + test_done + EOF + chmod +x passing-todo.sh && + ./passing-todo.sh >out 2>err && + ! test -s err && + sed -e 's/^> //' >expect <<-\\EOF && + > ok 1 - pretend we have fixed a known breakage # TODO known breakage + > # fixed 1 known breakage(s) + > # passed all 1 test(s) + > 1..1 + EOF + test_cmp expect out) " test_set_prereq HAVEIT haveit=no test_expect_success HAVEIT 'test runs if prerequisite is satisfied' ' - test_have_prereq HAVEIT && - haveit=yes + test_have_prereq HAVEIT && + haveit=yes ' donthaveit=yes test_expect_success DONTHAVEIT 'unmet prerequisite causes test to be skipped' ' - donthaveit=no + donthaveit=no ' if test $haveit$donthaveit != yesyes then @@ -107,17 +107,17 @@ fi test_set_prereq HAVETHIS haveit=no test_expect_success HAVETHIS,HAVEIT 'test runs if prerequisites are satisfied' ' - test_have_prereq HAVEIT && - test_have_prereq HAVETHIS && - haveit=yes + test_have_prereq HAVEIT && + test_have_prereq HAVETHIS && + haveit=yes ' donthaveit=yes test_expect_success HAVEIT,DONTHAVEIT 'unmet prerequisites causes test to be skipped' ' - donthaveit=no + donthaveit=no ' donthaveiteither=yes test_expect_success DONTHAVEIT,HAVEIT 'unmet prerequisites causes test to be skipped' ' - donthaveiteither=no + donthaveiteither=no ' if test $haveit$donthaveit$donthaveiteither != yesyesyes then @@ -127,7 +127,7 @@ fi clean=no test_expect_success 'tests clean up after themselves' ' - test_when_finished clean=yes + test_when_finished clean=yes ' if test $clean != yes @@ -137,106 +137,100 @@ then fi test_expect_success 'tests clean up even on failures' " - mkdir failing-cleanup && - (cd failing-cleanup && - cat >failing-cleanup.sh <<EOF && -#!$SHELL_PATH - -test_description='Failing tests with cleanup commands' - -# Point to the t/test-lib.sh, which isn't in ../ as usual -TEST_DIRECTORY=\"$TEST_DIRECTORY\" -. \"\$TEST_DIRECTORY\"/test-lib.sh - -test_expect_success 'tests clean up even after a failure' ' - touch clean-after-failure && - test_when_finished rm clean-after-failure && - (exit 1) -' - -test_expect_success 'failure to clean up causes the test to fail' ' - test_when_finished \"(exit 2)\" -' - -test_done -EOF - chmod +x failing-cleanup.sh && - test_must_fail ./failing-cleanup.sh >out 2>err && - ! test -s err && - ! test -f \"trash directory.failing-cleanup/clean-after-failure\" && -sed -e 's/Z$//' -e 's/^> //' >expect <<\EOF && -> not ok - 1 tests clean up even after a failure -> # Z -> # touch clean-after-failure && -> # test_when_finished rm clean-after-failure && -> # (exit 1) -> # Z -> not ok - 2 failure to clean up causes the test to fail -> # Z -> # test_when_finished \"(exit 2)\" -> # Z -> # failed 2 among 2 test(s) -> 1..2 -EOF - test_cmp expect out) + mkdir failing-cleanup && + ( + cd failing-cleanup && + + cat >failing-cleanup.sh <<-EOF && + #!$SHELL_PATH + + test_description='Failing tests with cleanup commands' + + # Point to the t/test-lib.sh, which isn't in ../ as usual + TEST_DIRECTORY=\"$TEST_DIRECTORY\" + . \"\$TEST_DIRECTORY\"/test-lib.sh + + test_expect_success 'tests clean up even after a failure' ' + touch clean-after-failure && + test_when_finished rm clean-after-failure && + (exit 1) + ' + test_expect_success 'failure to clean up causes the test to fail' ' + test_when_finished \"(exit 2)\" + ' + test_done + + EOF + + chmod +x failing-cleanup.sh && + test_must_fail ./failing-cleanup.sh >out 2>err && + ! test -s err && + ! test -f \"trash directory.failing-cleanup/clean-after-failure\" && + sed -e 's/Z$//' -e 's/^> //' >expect <<-\\EOF && + > not ok - 1 tests clean up even after a failure + > # Z + > # touch clean-after-failure && + > # test_when_finished rm clean-after-failure && + > # (exit 1) + > # Z + > not ok - 2 failure to clean up causes the test to fail + > # Z + > # test_when_finished \"(exit 2)\" + > # Z + > # failed 2 among 2 test(s) + > 1..2 + EOF + test_cmp expect out + ) " ################################################################ # Basics of the basics # updating a new file without --add should fail. -test_expect_success 'git update-index without --add should fail adding.' ' - test_must_fail git update-index should-be-empty +test_expect_success 'git update-index without --add should fail adding' ' + test_must_fail git update-index should-be-empty ' # and with --add it should succeed, even if it is empty (it used to fail). -test_expect_success \ - 'git update-index with --add should succeed.' \ - 'git update-index --add should-be-empty' +test_expect_success 'git update-index with --add should succeed' ' + git update-index --add should-be-empty +' -test_expect_success \ - 'writing tree out with git write-tree' \ - 'tree=$(git write-tree)' +test_expect_success 'writing tree out with git write-tree' ' + tree=$(git write-tree) +' # we know the shape and contents of the tree and know the object ID for it. -test_expect_success \ - 'validate object ID of a known tree.' \ - 'test "$tree" = 7bb943559a305bdd6bdee2cef6e5df2413c3d30a' +test_expect_success 'validate object ID of a known tree' ' + test "$tree" = 7bb943559a305bdd6bdee2cef6e5df2413c3d30a + ' # Removing paths. -rm -f should-be-empty full-of-directories -test_expect_success 'git update-index without --remove should fail removing.' ' - test_must_fail git update-index should-be-empty +test_expect_success 'git update-index without --remove should fail removing' ' + rm -f should-be-empty full-of-directories && + test_must_fail git update-index should-be-empty ' -test_expect_success \ - 'git update-index with --remove should be able to remove.' \ - 'git update-index --remove should-be-empty' +test_expect_success 'git update-index with --remove should be able to remove' ' + git update-index --remove should-be-empty +' # Empty tree can be written with recent write-tree. -test_expect_success \ - 'git write-tree should be able to write an empty tree.' \ - 'tree=$(git write-tree)' +test_expect_success 'git write-tree should be able to write an empty tree' ' + tree=$(git write-tree) +' -test_expect_success \ - 'validate object ID of a known tree.' \ - 'test "$tree" = 4b825dc642cb6eb9a060e54bf8d69288fbee4904' +test_expect_success 'validate object ID of a known tree' ' + test "$tree" = 4b825dc642cb6eb9a060e54bf8d69288fbee4904 +' # Various types of objects + # Some filesystems do not support symblic links; on such systems # some expected values are different -mkdir path2 path3 path3/subp3 -paths='path0 path2/file2 path3/file3 path3/subp3/file3' -for p in $paths -do - echo "hello $p" >$p -done if test_have_prereq SYMLINKS then - for p in $paths - do - ln -s "hello $p" ${p}sym - done expectfilter=cat expectedtree=087704a96baf1c2d1c869a8b084481e121c88b5b expectedptree1=21ae8269cacbe57ae09138dcc3a2887f904d02b3 @@ -248,135 +242,154 @@ else expectedptree2=ce580448f0148b985a513b693fdf7d802cacb44f fi -test_expect_success \ - 'adding various types of objects with git update-index --add.' \ - 'find path* ! -type d -print | xargs git update-index --add' + +test_expect_success 'adding various types of objects with git update-index --add' ' + mkdir path2 path3 path3/subp3 && + paths="path0 path2/file2 path3/file3 path3/subp3/file3" && + ( + for p in $paths + do + echo "hello $p" >$p || exit 1 + if test_have_prereq SYMLINKS + then + ln -s "hello $p" ${p}sym || exit 1 + fi + done + ) && + find path* ! -type d -print | xargs git update-index --add +' # Show them and see that matches what we expect. -test_expect_success \ - 'showing stage with git ls-files --stage' \ - 'git ls-files --stage >current' - -$expectfilter >expected <<\EOF -100644 f87290f8eb2cbbea7857214459a0739927eab154 0 path0 -120000 15a98433ae33114b085f3eb3bb03b832b3180a01 0 path0sym -100644 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 0 path2/file2 -120000 d8ce161addc5173867a3c3c730924388daedbc38 0 path2/file2sym -100644 0aa34cae68d0878578ad119c86ca2b5ed5b28376 0 path3/file3 -120000 8599103969b43aff7e430efea79ca4636466794f 0 path3/file3sym -100644 00fb5908cb97c2564a9783c0c64087333b3b464f 0 path3/subp3/file3 -120000 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c 0 path3/subp3/file3sym -EOF -test_expect_success \ - 'validate git ls-files output for a known tree.' \ - 'test_cmp expected current' - -test_expect_success \ - 'writing tree out with git write-tree.' \ - 'tree=$(git write-tree)' -test_expect_success \ - 'validate object ID for a known tree.' \ - 'test "$tree" = "$expectedtree"' - -test_expect_success \ - 'showing tree with git ls-tree' \ - 'git ls-tree $tree >current' -cat >expected <<\EOF -100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0 -120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym -040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe path2 -040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3 path3 -EOF -test_expect_success SYMLINKS \ - 'git ls-tree output for a known tree.' \ - 'test_cmp expected current' +test_expect_success 'showing stage with git ls-files --stage' ' + git ls-files --stage >current +' + +test_expect_success 'validate git ls-files output for a known tree' ' + $expectfilter >expected <<-\EOF && + 100644 f87290f8eb2cbbea7857214459a0739927eab154 0 path0 + 120000 15a98433ae33114b085f3eb3bb03b832b3180a01 0 path0sym + 100644 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 0 path2/file2 + 120000 d8ce161addc5173867a3c3c730924388daedbc38 0 path2/file2sym + 100644 0aa34cae68d0878578ad119c86ca2b5ed5b28376 0 path3/file3 + 120000 8599103969b43aff7e430efea79ca4636466794f 0 path3/file3sym + 100644 00fb5908cb97c2564a9783c0c64087333b3b464f 0 path3/subp3/file3 + 120000 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c 0 path3/subp3/file3sym + EOF + test_cmp expected current +' + +test_expect_success 'writing tree out with git write-tree' ' + tree=$(git write-tree) +' + +test_expect_success 'validate object ID for a known tree' ' + test "$tree" = "$expectedtree" +' + +test_expect_success 'showing tree with git ls-tree' ' + git ls-tree $tree >current +' + +test_expect_success SYMLINKS 'git ls-tree output for a known tree' ' + cat >expected <<-\EOF && + 100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0 + 120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym + 040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe path2 + 040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3 path3 + EOF + test_cmp expected current +' # This changed in ls-tree pathspec change -- recursive does # not show tree nodes anymore. -test_expect_success \ - 'showing tree with git ls-tree -r' \ - 'git ls-tree -r $tree >current' -$expectfilter >expected <<\EOF -100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0 -120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym -100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2 -120000 blob d8ce161addc5173867a3c3c730924388daedbc38 path2/file2sym -100644 blob 0aa34cae68d0878578ad119c86ca2b5ed5b28376 path3/file3 -120000 blob 8599103969b43aff7e430efea79ca4636466794f path3/file3sym -100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f path3/subp3/file3 -120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c path3/subp3/file3sym -EOF -test_expect_success \ - 'git ls-tree -r output for a known tree.' \ - 'test_cmp expected current' +test_expect_success 'showing tree with git ls-tree -r' ' + git ls-tree -r $tree >current +' + +test_expect_success 'git ls-tree -r output for a known tree' ' + $expectfilter >expected <<-\EOF && + 100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0 + 120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym + 100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2 + 120000 blob d8ce161addc5173867a3c3c730924388daedbc38 path2/file2sym + 100644 blob 0aa34cae68d0878578ad119c86ca2b5ed5b28376 path3/file3 + 120000 blob 8599103969b43aff7e430efea79ca4636466794f path3/file3sym + 100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f path3/subp3/file3 + 120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c path3/subp3/file3sym + EOF + test_cmp expected current +' # But with -r -t we can have both. -test_expect_success \ - 'showing tree with git ls-tree -r -t' \ - 'git ls-tree -r -t $tree >current' -cat >expected <<\EOF -100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0 -120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym -040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe path2 -100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2 -120000 blob d8ce161addc5173867a3c3c730924388daedbc38 path2/file2sym -040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3 path3 -100644 blob 0aa34cae68d0878578ad119c86ca2b5ed5b28376 path3/file3 -120000 blob 8599103969b43aff7e430efea79ca4636466794f path3/file3sym -040000 tree 3c5e5399f3a333eddecce7a9b9465b63f65f51e2 path3/subp3 -100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f path3/subp3/file3 -120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c path3/subp3/file3sym -EOF -test_expect_success SYMLINKS \ - 'git ls-tree -r output for a known tree.' \ - 'test_cmp expected current' - -test_expect_success \ - 'writing partial tree out with git write-tree --prefix.' \ - 'ptree=$(git write-tree --prefix=path3)' -test_expect_success \ - 'validate object ID for a known tree.' \ - 'test "$ptree" = "$expectedptree1"' - -test_expect_success \ - 'writing partial tree out with git write-tree --prefix.' \ - 'ptree=$(git write-tree --prefix=path3/subp3)' -test_expect_success \ - 'validate object ID for a known tree.' \ - 'test "$ptree" = "$expectedptree2"' - -cat >badobjects <<EOF -100644 blob 1000000000000000000000000000000000000000 dir/file1 -100644 blob 2000000000000000000000000000000000000000 dir/file2 -100644 blob 3000000000000000000000000000000000000000 dir/file3 -100644 blob 4000000000000000000000000000000000000000 dir/file4 -100644 blob 5000000000000000000000000000000000000000 dir/file5 -EOF +test_expect_success 'showing tree with git ls-tree -r -t' ' + git ls-tree -r -t $tree >current +' -rm .git/index -test_expect_success \ - 'put invalid objects into the index.' \ - 'git update-index --index-info < badobjects' +test_expect_success SYMLINKS 'git ls-tree -r output for a known tree' ' + cat >expected <<-\EOF && + 100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0 + 120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym + 040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe path2 + 100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2 + 120000 blob d8ce161addc5173867a3c3c730924388daedbc38 path2/file2sym + 040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3 path3 + 100644 blob 0aa34cae68d0878578ad119c86ca2b5ed5b28376 path3/file3 + 120000 blob 8599103969b43aff7e430efea79ca4636466794f path3/file3sym + 040000 tree 3c5e5399f3a333eddecce7a9b9465b63f65f51e2 path3/subp3 + 100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f path3/subp3/file3 + 120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c path3/subp3/file3sym + EOF + test_cmp expected current +' -test_expect_success 'writing this tree without --missing-ok.' ' - test_must_fail git write-tree +test_expect_success 'writing partial tree out with git write-tree --prefix' ' + ptree=$(git write-tree --prefix=path3) ' -test_expect_success \ - 'writing this tree with --missing-ok.' \ - 'git write-tree --missing-ok' +test_expect_success 'validate object ID for a known tree' ' + test "$ptree" = "$expectedptree1" +' + +test_expect_success 'writing partial tree out with git write-tree --prefix' ' + ptree=$(git write-tree --prefix=path3/subp3) +' + +test_expect_success 'validate object ID for a known tree' ' + test "$ptree" = "$expectedptree2" +' + +test_expect_success 'put invalid objects into the index' ' + rm -f .git/index && + cat >badobjects <<-\EOF && + 100644 blob 1000000000000000000000000000000000000000 dir/file1 + 100644 blob 2000000000000000000000000000000000000000 dir/file2 + 100644 blob 3000000000000000000000000000000000000000 dir/file3 + 100644 blob 4000000000000000000000000000000000000000 dir/file4 + 100644 blob 5000000000000000000000000000000000000000 dir/file5 + EOF + git update-index --index-info <badobjects +' + +test_expect_success 'writing this tree without --missing-ok' ' + test_must_fail git write-tree +' + +test_expect_success 'writing this tree with --missing-ok' ' + git write-tree --missing-ok +' ################################################################ -rm .git/index -test_expect_success \ - 'git read-tree followed by write-tree should be idempotent.' \ - 'git read-tree $tree && - test -f .git/index && - newtree=$(git write-tree) && - test "$newtree" = "$tree"' - -$expectfilter >expected <<\EOF +test_expect_success 'git read-tree followed by write-tree should be idempotent' ' + rm -f .git/index + git read-tree $tree && + test -f .git/index && + newtree=$(git write-tree) && + test "$newtree" = "$tree" +' + +test_expect_success 'validate git diff-files output for a know cache/work tree state' ' + $expectfilter >expected <<\EOF && :100644 100644 f87290f8eb2cbbea7857214459a0739927eab154 0000000000000000000000000000000000000000 M path0 :120000 120000 15a98433ae33114b085f3eb3bb03b832b3180a01 0000000000000000000000000000000000000000 M path0sym :100644 100644 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 0000000000000000000000000000000000000000 M path2/file2 @@ -386,45 +399,47 @@ $expectfilter >expected <<\EOF :100644 100644 00fb5908cb97c2564a9783c0c64087333b3b464f 0000000000000000000000000000000000000000 M path3/subp3/file3 :120000 120000 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c 0000000000000000000000000000000000000000 M path3/subp3/file3sym EOF -test_expect_success \ - 'validate git diff-files output for a know cache/work tree state.' \ - 'git diff-files >current && test_cmp current expected >/dev/null' + git diff-files >current && + test_cmp current expected +' -test_expect_success \ - 'git update-index --refresh should succeed.' \ - 'git update-index --refresh' +test_expect_success 'git update-index --refresh should succeed' ' + git update-index --refresh +' -test_expect_success \ - 'no diff after checkout and git update-index --refresh.' \ - 'git diff-files >current && cmp -s current /dev/null' +test_expect_success 'no diff after checkout and git update-index --refresh' ' + git diff-files >current && + cmp -s current /dev/null +' ################################################################ P=$expectedtree -test_expect_success \ - 'git commit-tree records the correct tree in a commit.' \ - 'commit0=$(echo NO | git commit-tree $P) && - tree=$(git show --pretty=raw $commit0 | - sed -n -e "s/^tree //p" -e "/^author /q") && - test "z$tree" = "z$P"' - -test_expect_success \ - 'git commit-tree records the correct parent in a commit.' \ - 'commit1=$(echo NO | git commit-tree $P -p $commit0) && - parent=$(git show --pretty=raw $commit1 | - sed -n -e "s/^parent //p" -e "/^author /q") && - test "z$commit0" = "z$parent"' - -test_expect_success \ - 'git commit-tree omits duplicated parent in a commit.' \ - 'commit2=$(echo NO | git commit-tree $P -p $commit0 -p $commit0) && - parent=$(git show --pretty=raw $commit2 | - sed -n -e "s/^parent //p" -e "/^author /q" | - sort -u) && - test "z$commit0" = "z$parent" && - numparent=$(git show --pretty=raw $commit2 | - sed -n -e "s/^parent //p" -e "/^author /q" | - wc -l) && - test $numparent = 1' + +test_expect_success 'git commit-tree records the correct tree in a commit' ' + commit0=$(echo NO | git commit-tree $P) && + tree=$(git show --pretty=raw $commit0 | + sed -n -e "s/^tree //p" -e "/^author /q") && + test "z$tree" = "z$P" +' + +test_expect_success 'git commit-tree records the correct parent in a commit' ' + commit1=$(echo NO | git commit-tree $P -p $commit0) && + parent=$(git show --pretty=raw $commit1 | + sed -n -e "s/^parent //p" -e "/^author /q") && + test "z$commit0" = "z$parent" +' + +test_expect_success 'git commit-tree omits duplicated parent in a commit' ' + commit2=$(echo NO | git commit-tree $P -p $commit0 -p $commit0) && + parent=$(git show --pretty=raw $commit2 | + sed -n -e "s/^parent //p" -e "/^author /q" | + sort -u) && + test "z$commit0" = "z$parent" && + numparent=$(git show --pretty=raw $commit2 | + sed -n -e "s/^parent //p" -e "/^author /q" | + wc -l) && + test $numparent = 1 +' test_expect_success 'update-index D/F conflict' ' mv path0 tmp && diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh index 51f3045ba4..febc45c9cc 100755 --- a/t/t0003-attributes.sh +++ b/t/t0003-attributes.sh @@ -123,16 +123,6 @@ test_expect_success 'attribute matching is case insensitive when core.ignorecase ' -test_expect_success 'check whether FS is case-insensitive' ' - mkdir junk && - echo good >junk/CamelCase && - echo bad >junk/camelcase && - if test "$(cat junk/CamelCase)" != good - then - test_set_prereq CASE_INSENSITIVE_FS - fi -' - test_expect_success CASE_INSENSITIVE_FS 'additional case insensitivity tests' ' test_must_fail attr_check a/B/D/g "a/b/d/*" "-c core.ignorecase=0" && test_must_fail attr_check A/B/D/NO "a/b/d/*" "-c core.ignorecase=0" && diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh index f19e6510d0..e50f0f742f 100755 --- a/t/t0021-conversion.sh +++ b/t/t0021-conversion.sh @@ -153,4 +153,41 @@ test_expect_success 'filter shell-escaped filenames' ' : ' +test_expect_success 'required filter success' ' + git config filter.required.smudge cat && + git config filter.required.clean cat && + git config filter.required.required true && + + echo "*.r filter=required" >.gitattributes && + + echo test >test.r && + git add test.r && + rm -f test.r && + git checkout -- test.r +' + +test_expect_success 'required filter smudge failure' ' + git config filter.failsmudge.smudge false && + git config filter.failsmudge.clean cat && + git config filter.failsmudge.required true && + + echo "*.fs filter=failsmudge" >.gitattributes && + + echo test >test.fs && + git add test.fs && + rm -f test.fs && + test_must_fail git checkout -- test.fs +' + +test_expect_success 'required filter clean failure' ' + git config filter.failclean.smudge cat && + git config filter.failclean.clean false && + git config filter.failclean.required true && + + echo "*.fc filter=failclean" >.gitattributes && + + echo test >test.fc && + test_must_fail git add test.fc +' + test_done diff --git a/t/t0023-crlf-am.sh b/t/t0023-crlf-am.sh index aaed725402..f9bbb91f64 100755 --- a/t/t0023-crlf-am.sh +++ b/t/t0023-crlf-am.sh @@ -11,7 +11,7 @@ Date: Thu, 23 Aug 2007 13:00:00 +0200 Subject: test1 --- - foo | 1 + + foo | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 foo diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index a1e4616feb..e3f354a45e 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -10,7 +10,10 @@ test_description='our own option parser' cat > expect << EOF usage: test-parse-options <options> - -b, --boolean get a boolean + --yes get a boolean + -D, --no-doubt begins with 'no-' + -B, --no-fear be brave + -b, --boolean increment by one -4, --or4 bitwise-or boolean with ...0100 --neg-or4 same as --no-or4 @@ -53,6 +56,59 @@ test_expect_success 'test help' ' mv expect expect.err +cat >expect.template <<EOF +boolean: 0 +integer: 0 +timestamp: 0 +string: (not set) +abbrev: 7 +verbose: 0 +quiet: no +dry run: no +file: (not set) +EOF + +check() { + what="$1" && + shift && + expect="$1" && + shift && + sed "s/^$what .*/$what $expect/" <expect.template >expect && + test-parse-options $* >output 2>output.err && + test ! -s output.err && + test_cmp expect output +} + +check_unknown() { + case "$1" in + --*) + echo error: unknown option \`${1#--}\' >expect ;; + -*) + echo error: unknown switch \`${1#-}\' >expect ;; + esac && + cat expect.err >>expect && + test_must_fail test-parse-options $* >output 2>output.err && + test ! -s output && + test_cmp expect output.err +} + +test_expect_success 'OPT_BOOL() #1' 'check boolean: 1 --yes' +test_expect_success 'OPT_BOOL() #2' 'check boolean: 1 --no-doubt' +test_expect_success 'OPT_BOOL() #3' 'check boolean: 1 -D' +test_expect_success 'OPT_BOOL() #4' 'check boolean: 1 --no-fear' +test_expect_success 'OPT_BOOL() #5' 'check boolean: 1 -B' + +test_expect_success 'OPT_BOOL() is idempotent #1' 'check boolean: 1 --yes --yes' +test_expect_success 'OPT_BOOL() is idempotent #2' 'check boolean: 1 -DB' + +test_expect_success 'OPT_BOOL() negation #1' 'check boolean: 0 -D --no-yes' +test_expect_success 'OPT_BOOL() negation #2' 'check boolean: 0 -D --no-no-doubt' + +test_expect_success 'OPT_BOOL() no negation #1' 'check_unknown --fear' +test_expect_success 'OPT_BOOL() no negation #2' 'check_unknown --no-no-fear' + +test_expect_success 'OPT_BOOL() positivation' 'check boolean: 0 -D --doubt' + cat > expect << EOF boolean: 2 integer: 1729 @@ -180,6 +236,16 @@ test_expect_success 'detect possible typos' ' test_cmp typo.err output.err ' +cat > typo.err << EOF +error: did you mean \`--ambiguous\` (with two dashes ?) +EOF + +test_expect_success 'detect possible typos' ' + test_must_fail test-parse-options -ambiguous > output 2> output.err && + test ! -s output && + test_cmp typo.err output.err +' + cat > expect <<EOF boolean: 0 integer: 0 @@ -296,7 +362,7 @@ test_expect_success 'OPT_NEGBIT() works' ' test_cmp expect output ' -test_expect_success 'OPT_BOOLEAN() with PARSE_OPT_NODASH works' ' +test_expect_success 'OPT_COUNTUP() with PARSE_OPT_NODASH works' ' test-parse-options + + + + + + > output 2> output.err && test ! -s output.err && test_cmp expect output diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh index 1542cf6a13..78816d9d93 100755 --- a/t/t0050-filesystem.sh +++ b/t/t0050-filesystem.sh @@ -7,48 +7,26 @@ test_description='Various filesystem issues' auml=$(printf '\303\244') aumlcdiar=$(printf '\141\314\210') -case_insensitive= -unibad= -no_symlinks= -test_expect_success 'see what we expect' ' - - test_case=test_expect_success && - test_unicode=test_expect_success && - mkdir junk && - echo good >junk/CamelCase && - echo bad >junk/camelcase && - if test "$(cat junk/CamelCase)" != good - then - test_case=test_expect_failure && - case_insensitive=t - fi && - rm -fr junk && - mkdir junk && - >junk/"$auml" && - case "$(cd junk && echo *)" in - "$aumlcdiar") - test_unicode=test_expect_failure && - unibad=t - ;; - *) ;; - esac && - rm -fr junk && - { - ln -s x y 2> /dev/null && - test -h y 2> /dev/null || - no_symlinks=1 && - rm -f y - } -' - -test "$case_insensitive" && +if test_have_prereq CASE_INSENSITIVE_FS +then say "will test on a case insensitive filesystem" -test "$unibad" && + test_case=test_expect_failure +else + test_case=test_expect_success +fi + +if test_have_prereq UTF8_NFD_TO_NFC +then say "will test on a unicode corrupting filesystem" -test "$no_symlinks" && + test_unicode=test_expect_failure +else + test_unicode=test_expect_success +fi + +test_have_prereq SYMLINKS || say "will test on a filesystem lacking symbolic links" -if test "$case_insensitive" +if test_have_prereq CASE_INSENSITIVE_FS then test_expect_success "detection of case insensitive filesystem during repo init" ' @@ -62,18 +40,18 @@ test_expect_success "detection of case insensitive filesystem during repo init" ' fi -if test "$no_symlinks" +if test_have_prereq SYMLINKS then test_expect_success "detection of filesystem w/o symlink support during repo init" ' - v=$(git config --bool core.symlinks) && - test "$v" = false + test_must_fail git config --bool core.symlinks || + test "$(git config --bool core.symlinks)" = true ' else test_expect_success "detection of filesystem w/o symlink support during repo init" ' - test_must_fail git config --bool core.symlinks || - test "$(git config --bool core.symlinks)" = true + v=$(git config --bool core.symlinks) && + test "$v" = false ' fi diff --git a/t/t0061-run-command.sh b/t/t0061-run-command.sh index 8d4938f019..17e969df60 100755 --- a/t/t0061-run-command.sh +++ b/t/t0061-run-command.sh @@ -34,4 +34,17 @@ test_expect_success POSIXPERM 'run_command reports EACCES' ' grep "fatal: cannot exec.*hello.sh" err ' +test_expect_success POSIXPERM 'unreadable directory in PATH' ' + mkdir local-command && + test_when_finished "chmod u+rwx local-command && rm -fr local-command" && + git config alias.nitfol "!echo frotz" && + chmod a-rx local-command && + ( + PATH=./local-command:$PATH && + git nitfol >actual + ) && + echo frotz >expect && + test_cmp expect actual +' + test_done diff --git a/t/t0062-revision-walking.sh b/t/t0062-revision-walking.sh new file mode 100755 index 0000000000..3d98eb847f --- /dev/null +++ b/t/t0062-revision-walking.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# +# Copyright (c) 2012 Heiko Voigt +# + +test_description='Test revision walking api' + +. ./test-lib.sh + +cat >run_twice_expected <<-EOF +1st + > add b + > add a +2nd + > add b + > add a +EOF + +test_expect_success 'setup' ' + echo a > a && + git add a && + git commit -m "add a" && + echo b > b && + git add b && + git commit -m "add b" +' + +test_expect_success 'revision walking can be done twice' ' + test-revision-walking run-twice > run_twice_actual + test_cmp run_twice_expected run_twice_actual +' + +test_done diff --git a/t/t0080-vcs-svn.sh b/t/t0080-vcs-svn.sh deleted file mode 100755 index 99a314b080..0000000000 --- a/t/t0080-vcs-svn.sh +++ /dev/null @@ -1,117 +0,0 @@ -#!/bin/sh - -test_description='check infrastructure for svn importer' - -. ./test-lib.sh -uint32_max=4294967295 - -test_expect_success 'obj pool: store data' ' - cat <<-\EOF >expected && - 0 - 1 - EOF - - test-obj-pool <<-\EOF >actual && - alloc one 16 - set one 13 - test one 13 - reset one - EOF - test_cmp expected actual -' - -test_expect_success 'obj pool: NULL is offset ~0' ' - echo "$uint32_max" >expected && - echo null one | test-obj-pool >actual && - test_cmp expected actual -' - -test_expect_success 'obj pool: out-of-bounds access' ' - cat <<-EOF >expected && - 0 - 0 - $uint32_max - $uint32_max - 16 - 20 - $uint32_max - EOF - - test-obj-pool <<-\EOF >actual && - alloc one 16 - alloc two 16 - offset one 20 - offset two 20 - alloc one 5 - offset one 20 - free one 1 - offset one 20 - reset one - reset two - EOF - test_cmp expected actual -' - -test_expect_success 'obj pool: high-water mark' ' - cat <<-\EOF >expected && - 0 - 0 - 10 - 20 - 20 - 20 - EOF - - test-obj-pool <<-\EOF >actual && - alloc one 10 - committed one - alloc one 10 - commit one - committed one - alloc one 10 - free one 20 - committed one - reset one - EOF - test_cmp expected actual -' - -test_expect_success 'string pool' ' - echo a does not equal b >expected.differ && - echo a equals a >expected.match && - echo equals equals equals >expected.matchmore && - - test-string-pool "a,--b" >actual.differ && - test-string-pool "a,a" >actual.match && - test-string-pool "equals-equals" >actual.matchmore && - test_must_fail test-string-pool a,a,a && - test_must_fail test-string-pool a && - - test_cmp expected.differ actual.differ && - test_cmp expected.match actual.match && - test_cmp expected.matchmore actual.matchmore -' - -test_expect_success 'treap sort' ' - cat <<-\EOF >unsorted && - 68 - 12 - 13 - 13 - 68 - 13 - 13 - 21 - 10 - 11 - 12 - 13 - 13 - EOF - sort unsorted >expected && - - test-treap <unsorted >actual && - test_cmp expected actual -' - -test_done diff --git a/t/t0201-gettext-fallbacks.sh b/t/t0201-gettext-fallbacks.sh index 52b1c27c2c..5d80a985fb 100755 --- a/t/t0201-gettext-fallbacks.sh +++ b/t/t0201-gettext-fallbacks.sh @@ -51,16 +51,16 @@ test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate v test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables with spaces' ' cmdline="git am" && export cmdline; - printf "When you have resolved this problem run git am --resolved." >expect && - eval_gettext "When you have resolved this problem run \$cmdline --resolved." >actual + printf "When you have resolved this problem, run git am --resolved." >expect && + eval_gettext "When you have resolved this problem, run \$cmdline --resolved." >actual test_i18ncmp expect actual ' test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables with spaces and quotes' ' cmdline="git am" && export cmdline; - printf "When you have resolved this problem run \"git am --resolved\"." >expect && - eval_gettext "When you have resolved this problem run \"\$cmdline --resolved\"." >actual + printf "When you have resolved this problem, run \"git am --resolved\"." >expect && + eval_gettext "When you have resolved this problem, run \"\$cmdline --resolved\"." >actual test_i18ncmp expect actual ' diff --git a/t/t0204-gettext-reencode-sanity.sh b/t/t0204-gettext-reencode-sanity.sh index 189af90c02..8437e51eb5 100755 --- a/t/t0204-gettext-reencode-sanity.sh +++ b/t/t0204-gettext-reencode-sanity.sh @@ -7,6 +7,10 @@ test_description="Gettext reencoding of our *.po/*.mo files works" . ./lib-gettext.sh +# The constants used in a tricky observation for undefined behaviour +RUNES="TILRAUN: ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ" +PUNTS="TILRAUN: ?? ???? ??? ?? ???? ?? ??? ????? ??????????? ??? ?? ????" +MSGKEY="TEST: Old English Runes" test_expect_success GETTEXT_LOCALE 'gettext: Emitting UTF-8 from our UTF-8 *.mo files / Icelandic' ' printf "TILRAUN: Halló Heimur!" >expect && @@ -15,8 +19,8 @@ test_expect_success GETTEXT_LOCALE 'gettext: Emitting UTF-8 from our UTF-8 *.mo ' test_expect_success GETTEXT_LOCALE 'gettext: Emitting UTF-8 from our UTF-8 *.mo files / Runes' ' - printf "TILRAUN: ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ" >expect && - LANGUAGE=is LC_ALL="$is_IS_locale" gettext "TEST: Old English Runes" >actual && + printf "%s" "$RUNES" >expect && + LANGUAGE=is LC_ALL="$is_IS_locale" gettext "$MSGKEY" >actual && test_cmp expect actual ' @@ -26,18 +30,23 @@ test_expect_success GETTEXT_ISO_LOCALE 'gettext: Emitting ISO-8859-1 from our UT test_cmp expect actual ' -test_expect_success GETTEXT_ISO_LOCALE 'gettext: Emitting ISO-8859-1 from our UTF-8 *.mo files / Runes' ' - LANGUAGE=is LC_ALL="$is_IS_iso_locale" gettext "TEST: Old English Runes" >runes && - - if grep "^TEST: Old English Runes$" runes - then - say "Your system can not handle this complexity and returns the string as-is" - else - # Both Solaris and GNU libintl will return this stream of - # question marks, so it is s probably portable enough - printf "TILRAUN: ?? ???? ??? ?? ???? ?? ??? ????? ??????????? ??? ?? ????" >runes-expect && - test_cmp runes-expect runes - fi +test_expect_success GETTEXT_ISO_LOCALE 'gettext: impossible ISO-8859-1 output' ' + LANGUAGE=is LC_ALL="$is_IS_iso_locale" gettext "$MSGKEY" >runes && + case "$(cat runes)" in + "$MSGKEY") + say "Your system gives back the key to message catalog" + ;; + "$PUNTS") + say "Your system replaces an impossible character with ?" + ;; + "$RUNES") + say "Your system gives back the raw message for an impossible request" + ;; + *) + say "We never saw the error behaviour your system exhibits" + false + ;; + esac ' test_expect_success GETTEXT_LOCALE 'gettext: Fetching a UTF-8 msgid -> UTF-8' ' diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh index c1c8108148..538ea5fb1c 100755 --- a/t/t0300-credentials.sh +++ b/t/t0300-credentials.sh @@ -17,22 +17,18 @@ test_expect_success 'setup helper scripts' ' IFS=$OIFS EOF - cat >git-credential-useless <<-\EOF && - #!/bin/sh + write_script git-credential-useless <<-\EOF && . ./dump exit 0 EOF - chmod +x git-credential-useless && - cat >git-credential-verbatim <<-\EOF && - #!/bin/sh + write_script git-credential-verbatim <<-\EOF && user=$1; shift pass=$1; shift . ./dump test -z "$user" || echo username=$user test -z "$pass" || echo password=$pass EOF - chmod +x git-credential-verbatim && PATH="$PWD:$PATH" ' @@ -86,6 +82,9 @@ test_expect_success 'credential_fill passes along metadata' ' host=example.com path=foo.git -- + protocol=ftp + host=example.com + path=foo.git username=one password=two -- @@ -217,6 +216,8 @@ test_expect_success 'match configured credential' ' host=example.com path=repo.git -- + protocol=https + host=example.com username=foo password=bar -- @@ -229,6 +230,8 @@ test_expect_success 'do not match configured credential' ' protocol=https host=bar -- + protocol=https + host=bar username=askpass-username password=askpass-password -- @@ -243,6 +246,8 @@ test_expect_success 'pull username from config' ' protocol=https host=example.com -- + protocol=https + host=example.com username=foo password=askpass-password -- @@ -256,6 +261,8 @@ test_expect_success 'http paths can be part of context' ' host=example.com path=foo.git -- + protocol=https + host=example.com username=foo password=bar -- @@ -269,6 +276,9 @@ test_expect_success 'http paths can be part of context' ' host=example.com path=foo.git -- + protocol=https + host=example.com + path=foo.git username=foo password=bar -- diff --git a/t/t0303-credential-external.sh b/t/t0303-credential-external.sh index 267f4c8ba3..f028fd1418 100755 --- a/t/t0303-credential-external.sh +++ b/t/t0303-credential-external.sh @@ -1,39 +1,60 @@ #!/bin/sh -test_description='external credential helper tests' -. ./test-lib.sh -. "$TEST_DIRECTORY"/lib-credential.sh +test_description='external credential helper tests -pre_test() { - test -z "$GIT_TEST_CREDENTIAL_HELPER_SETUP" || - eval "$GIT_TEST_CREDENTIAL_HELPER_SETUP" +This is a tool for authors of external helper tools to sanity-check +their helpers. If you have written the "git-credential-foo" helper, +you check it with: + + make GIT_TEST_CREDENTIAL_HELPER=foo t0303-credential-external.sh + +This assumes that your helper is capable of both storing and +retrieving credentials (some helpers may be read-only, and they will +fail these tests). + +Please note that the individual tests do not verify all of the +preconditions themselves, but rather build on each other. A failing +test means that tests later in the sequence can return false "OK" +results. + +If your helper supports time-based expiration with a configurable +timeout, you can test that feature with: + + make GIT_TEST_CREDENTIAL_HELPER=foo \ + GIT_TEST_CREDENTIAL_HELPER_TIMEOUT="foo --timeout=1" \ + t0303-credential-external.sh - # clean before the test in case there is cruft left - # over from a previous run that would impact results - helper_test_clean "$GIT_TEST_CREDENTIAL_HELPER" -} +If your helper requires additional setup before the tests are started, +you can set GIT_TEST_CREDENTIAL_HELPER_SETUP to a sequence of shell +commands. +' -post_test() { - # clean afterwards so that we are good citizens - # and don't leave cruft in the helper's storage, which - # might be long-term system storage - helper_test_clean "$GIT_TEST_CREDENTIAL_HELPER" -} +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-credential.sh if test -z "$GIT_TEST_CREDENTIAL_HELPER"; then - say "# skipping external helper tests (set GIT_TEST_CREDENTIAL_HELPER)" -else - pre_test - helper_test "$GIT_TEST_CREDENTIAL_HELPER" - post_test + skip_all="used to test external credential helpers" + test_done fi +test -z "$GIT_TEST_CREDENTIAL_HELPER_SETUP" || + eval "$GIT_TEST_CREDENTIAL_HELPER_SETUP" + +# clean before the test in case there is cruft left +# over from a previous run that would impact results +helper_test_clean "$GIT_TEST_CREDENTIAL_HELPER" + +helper_test "$GIT_TEST_CREDENTIAL_HELPER" + if test -z "$GIT_TEST_CREDENTIAL_HELPER_TIMEOUT"; then - say "# skipping external helper timeout tests" + say "# skipping timeout tests (GIT_TEST_CREDENTIAL_HELPER_TIMEOUT not set)" else - pre_test helper_test_timeout "$GIT_TEST_CREDENTIAL_HELPER_TIMEOUT" - post_test fi +# clean afterwards so that we are good citizens +# and don't leave cruft in the helper's storage, which +# might be long-term system storage +helper_test_clean "$GIT_TEST_CREDENTIAL_HELPER" + test_done diff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh index b946f87686..df573c4978 100755 --- a/t/t1010-mktree.sh +++ b/t/t1010-mktree.sh @@ -42,13 +42,13 @@ test_expect_success 'ls-tree piped to mktree (2)' ' ' test_expect_success 'ls-tree output in wrong order given to mktree (1)' ' - perl -e "print reverse <>" <top | + "$PERL_PATH" -e "print reverse <>" <top | git mktree >actual && test_cmp tree actual ' test_expect_success 'ls-tree output in wrong order given to mktree (2)' ' - perl -e "print reverse <>" <top.withsub | + "$PERL_PATH" -e "print reverse <>" <top.withsub | git mktree >actual && test_cmp tree.withsub actual ' diff --git a/t/t1050-large.sh b/t/t1050-large.sh index 29d6024b7f..fd10528009 100755 --- a/t/t1050-large.sh +++ b/t/t1050-large.sh @@ -6,11 +6,15 @@ test_description='adding and checking out large blobs' . ./test-lib.sh test_expect_success setup ' - git config core.bigfilethreshold 200k && + # clone does not allow us to pass core.bigfilethreshold to + # new repos, so set core.bigfilethreshold globally + git config --global core.bigfilethreshold 200k && echo X | dd of=large1 bs=1k seek=2000 && echo X | dd of=large2 bs=1k seek=2000 && echo X | dd of=large3 bs=1k seek=2000 && - echo Y | dd of=huge bs=1k seek=2500 + echo Y | dd of=huge bs=1k seek=2500 && + GIT_ALLOC_LIMIT=1500 && + export GIT_ALLOC_LIMIT ' test_expect_success 'add a large file or two' ' @@ -100,4 +104,63 @@ test_expect_success 'packsize limit' ' ) ' +test_expect_success 'diff --raw' ' + git commit -q -m initial && + echo modified >>large1 && + git add large1 && + git commit -q -m modified && + git diff --raw HEAD^ +' + +test_expect_success 'hash-object' ' + git hash-object large1 +' + +test_expect_success 'cat-file a large file' ' + git cat-file blob :large1 >/dev/null +' + +test_expect_success 'cat-file a large file from a tag' ' + git tag -m largefile largefiletag :large1 && + git cat-file blob largefiletag >/dev/null +' + +test_expect_success 'git-show a large file' ' + git show :large1 >/dev/null + +' + +test_expect_success 'index-pack' ' + git clone file://"`pwd`"/.git foo && + GIT_DIR=non-existent git index-pack --strict --verify foo/.git/objects/pack/*.pack +' + +test_expect_success 'repack' ' + git repack -ad +' + +test_expect_success 'pack-objects with large loose object' ' + SHA1=`git hash-object huge` && + test_create_repo loose && + echo $SHA1 | git pack-objects --stdout | + GIT_ALLOC_LIMIT=0 GIT_DIR=loose/.git git unpack-objects && + echo $SHA1 | GIT_DIR=loose/.git git pack-objects pack && + test_create_repo packed && + mv pack-* packed/.git/objects/pack && + GIT_DIR=packed/.git git cat-file blob $SHA1 >actual && + cmp huge actual +' + +test_expect_success 'tar achiving' ' + git archive --format=tar HEAD >/dev/null +' + +test_expect_success 'zip achiving, store only' ' + git archive --format=zip -0 HEAD >/dev/null +' + +test_expect_success 'zip achiving, deflate' ' + git archive --format=zip HEAD >/dev/null +' + test_done diff --git a/t/t1100-commit-tree-options.sh b/t/t1100-commit-tree-options.sh index c4414ff576..f8457f9d14 100755 --- a/t/t1100-commit-tree-options.sh +++ b/t/t1100-commit-tree-options.sh @@ -7,6 +7,9 @@ test_description='git commit-tree options test This test checks that git commit-tree can create a specific commit object by defining all environment variables that it understands. + +Also make sure that command line parser understands the normal +"flags first and then non flag arguments" command line. ' . ./test-lib.sh @@ -42,4 +45,19 @@ test_expect_success \ 'compare commit' \ 'test_cmp expected commit' + +test_expect_success 'flags and then non flags' ' + test_tick && + echo comment text | + git commit-tree $(cat treeid) >commitid && + echo comment text | + git commit-tree $(cat treeid) -p $(cat commitid) >childid-1 && + echo comment text | + git commit-tree -p $(cat commitid) $(cat treeid) >childid-2 && + test_cmp childid-1 childid-2 && + git commit-tree $(cat treeid) -m foo >childid-3 && + git commit-tree -m foo $(cat treeid) >childid-4 && + test_cmp childid-3 childid-4 +' + test_done diff --git a/t/t1200-tutorial.sh b/t/t1200-tutorial.sh index 9356beaf4b..397ccb6909 100755 --- a/t/t1200-tutorial.sh +++ b/t/t1200-tutorial.sh @@ -154,8 +154,8 @@ test_expect_success 'git show-branch' ' cat > resolve.expect << EOF Updating VARIABLE..VARIABLE FASTFORWARD (no commit created; -m option ignored) - example | 1 + - hello | 1 + + example | 1 + + hello | 1 + 2 files changed, 2 insertions(+) EOF diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 728a965669..a477453e2e 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -451,13 +451,21 @@ test_expect_success 'refer config from subdirectory' ' mkdir x && ( cd x && - echo strasse >expect + echo strasse >expect && git config --get --file ../other-config ein.bahn >actual && test_cmp expect actual ) ' +test_expect_success 'refer config from subdirectory via GIT_CONFIG' ' + ( + cd x && + GIT_CONFIG=../other-config git config --get ein.bahn >actual && + test_cmp expect actual + ) +' + cat > expect << EOF [ein] bahn = strasse @@ -542,6 +550,14 @@ EOF test_expect_success "rename succeeded" "test_cmp expect .git/config" +test_expect_success 'renaming empty section name is rejected' ' + test_must_fail git config --rename-section branch.zwei "" +' + +test_expect_success 'renaming to bogus section is rejected' ' + test_must_fail git config --rename-section branch.zwei "bogus name" +' + cat >> .git/config << EOF [branch "zwei"] a = 1 [branch "vier"] EOF @@ -960,6 +976,23 @@ test_expect_success 'git -c complains about empty key and value' ' test_must_fail git -c "" rev-parse ' +test_expect_success 'git config --edit works' ' + git config -f tmp test.value no && + echo test.value=yes >expect && + GIT_EDITOR="echo [test]value=yes >" git config -f tmp --edit && + git config -f tmp --list >actual && + test_cmp expect actual +' + +test_expect_success 'git config --edit respects core.editor' ' + git config -f tmp test.value no && + echo test.value=yes >expect && + test_config core.editor "echo [test]value=yes >" && + git config -f tmp --edit && + git config -f tmp --list >actual && + test_cmp expect actual +' + # malformed configuration files test_expect_success 'barf on syntax error' ' cat >.git/config <<-\EOF && diff --git a/t/t1304-default-acl.sh b/t/t1304-default-acl.sh index 2b962cfda7..79045abb51 100755 --- a/t/t1304-default-acl.sh +++ b/t/t1304-default-acl.sh @@ -14,16 +14,15 @@ umask 077 # We need an arbitrary other user give permission to using ACLs. root # is a good candidate: exists on all unices, and it has permission # anyway, so we don't create a security hole running the testsuite. - -setfacl_out="$(setfacl -m u:root:rwx . 2>&1)" -setfacl_ret=$? - -if test $setfacl_ret != 0 -then - say "Unable to use setfacl (output: '$setfacl_out'; return code: '$setfacl_ret')" -else - test_set_prereq SETFACL -fi +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-" + then + test_set_prereq SETFACL + fi +' if test -z "$LOGNAME" then diff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh new file mode 100755 index 0000000000..a70707620f --- /dev/null +++ b/t/t1305-config-include.sh @@ -0,0 +1,142 @@ +#!/bin/sh + +test_description='test config file include directives' +. ./test-lib.sh + +test_expect_success 'include file by absolute path' ' + echo "[test]one = 1" >one && + echo "[include]path = \"$(pwd)/one\"" >.gitconfig && + echo 1 >expect && + git config test.one >actual && + test_cmp expect actual +' + +test_expect_success 'include file by relative path' ' + echo "[test]one = 1" >one && + echo "[include]path = one" >.gitconfig && + echo 1 >expect && + git config test.one >actual && + test_cmp expect actual +' + +test_expect_success 'chained relative paths' ' + mkdir subdir && + echo "[test]three = 3" >subdir/three && + echo "[include]path = three" >subdir/two && + echo "[include]path = subdir/two" >.gitconfig && + echo 3 >expect && + git config test.three >actual && + test_cmp expect actual +' + +test_expect_success 'include paths get tilde-expansion' ' + echo "[test]one = 1" >one && + echo "[include]path = ~/one" >.gitconfig && + echo 1 >expect && + git config test.one >actual && + test_cmp expect actual +' + +test_expect_success 'include options can still be examined' ' + echo "[test]one = 1" >one && + echo "[include]path = one" >.gitconfig && + echo one >expect && + git config include.path >actual && + test_cmp expect actual +' + +test_expect_success 'listing includes option and expansion' ' + echo "[test]one = 1" >one && + echo "[include]path = one" >.gitconfig && + cat >expect <<-\EOF && + include.path=one + test.one=1 + EOF + git config --list >actual.full && + grep -v ^core actual.full >actual && + test_cmp expect actual +' + +test_expect_success 'single file lookup does not expand includes by default' ' + echo "[test]one = 1" >one && + echo "[include]path = one" >.gitconfig && + test_must_fail git config -f .gitconfig test.one && + test_must_fail git config --global test.one && + echo 1 >expect && + git config --includes -f .gitconfig test.one >actual && + test_cmp expect actual +' + +test_expect_success 'single file list does not expand includes by default' ' + echo "[test]one = 1" >one && + echo "[include]path = one" >.gitconfig && + echo "include.path=one" >expect && + git config -f .gitconfig --list >actual && + test_cmp expect actual +' + +test_expect_success 'writing config file does not expand includes' ' + echo "[test]one = 1" >one && + echo "[include]path = one" >.gitconfig && + git config test.two 2 && + echo 2 >expect && + git config --no-includes test.two >actual && + test_cmp expect actual && + test_must_fail git config --no-includes test.one +' + +test_expect_success 'config modification does not affect includes' ' + echo "[test]one = 1" >one && + echo "[include]path = one" >.gitconfig && + git config test.one 2 && + echo 1 >expect && + git config -f one test.one >actual && + test_cmp expect actual && + cat >expect <<-\EOF && + 1 + 2 + EOF + git config --get-all test.one >actual && + test_cmp expect actual +' + +test_expect_success 'missing include files are ignored' ' + cat >.gitconfig <<-\EOF && + [include]path = foo + [test]value = yes + EOF + echo yes >expect && + git config test.value >actual && + test_cmp expect actual +' + +test_expect_success 'absolute includes from command line work' ' + echo "[test]one = 1" >one && + echo 1 >expect && + git -c include.path="$PWD/one" config test.one >actual && + test_cmp expect actual +' + +test_expect_success 'relative includes from command line fail' ' + echo "[test]one = 1" >one && + test_must_fail git -c include.path=one config test.one +' + +test_expect_success 'include cycles are detected' ' + cat >.gitconfig <<-\EOF && + [test]value = gitconfig + [include]path = cycle + EOF + cat >cycle <<-\EOF && + [test]value = cycle + [include]path = .gitconfig + EOF + cat >expect <<-\EOF && + gitconfig + cycle + EOF + test_must_fail git config --get-all test.value 2>stderr && + grep "exceeded maximum include depth" stderr +' + +test_done diff --git a/t/t1306-xdg-files.sh b/t/t1306-xdg-files.sh new file mode 100755 index 0000000000..8b14ab187c --- /dev/null +++ b/t/t1306-xdg-files.sh @@ -0,0 +1,197 @@ +#!/bin/sh +# +# Copyright (c) 2012 Valentin Duperray, Lucien Kong, Franck Jonas, +# Thomas Nguy, Khoi Nguyen +# Grenoble INP Ensimag +# + +test_description='Compatibility with $XDG_CONFIG_HOME/git/ files' + +. ./test-lib.sh + +test_expect_success 'read config: xdg file exists and ~/.gitconfig doesn'\''t' ' + mkdir -p .config/git && + echo "[alias]" >.config/git/config && + echo " myalias = !echo in_config" >>.config/git/config && + echo in_config >expected && + git myalias >actual && + test_cmp expected actual +' + + +test_expect_success 'read config: xdg file exists and ~/.gitconfig exists' ' + >.gitconfig && + echo "[alias]" >.gitconfig && + echo " myalias = !echo in_gitconfig" >>.gitconfig && + echo in_gitconfig >expected && + git myalias >actual && + test_cmp expected actual +' + + +test_expect_success 'read with --get: xdg file exists and ~/.gitconfig doesn'\''t' ' + rm .gitconfig && + echo "[user]" >.config/git/config && + echo " name = read_config" >>.config/git/config && + echo read_config >expected && + git config --get user.name >actual && + test_cmp expected actual +' + +test_expect_success '"$XDG_CONFIG_HOME overrides $HOME/.config/git' ' + mkdir -p "$HOME"/xdg/git && + echo "[user]name = in_xdg" >"$HOME"/xdg/git/config && + echo in_xdg >expected && + XDG_CONFIG_HOME="$HOME"/xdg git config --get-all user.name >actual && + test_cmp expected actual +' + +test_expect_success 'read with --get: xdg file exists and ~/.gitconfig exists' ' + >.gitconfig && + echo "[user]" >.gitconfig && + echo " name = read_gitconfig" >>.gitconfig && + echo read_gitconfig >expected && + git config --get user.name >actual && + test_cmp expected actual +' + + +test_expect_success 'read with --list: xdg file exists and ~/.gitconfig doesn'\''t' ' + rm .gitconfig && + echo user.name=read_config >expected && + git config --global --list >actual && + test_cmp expected actual +' + + +test_expect_success 'read with --list: xdg file exists and ~/.gitconfig exists' ' + >.gitconfig && + echo "[user]" >.gitconfig && + echo " name = read_gitconfig" >>.gitconfig && + echo user.name=read_gitconfig >expected && + git config --global --list >actual && + test_cmp expected actual +' + + +test_expect_success 'Setup' ' + git init git && + cd git && + echo foo >to_be_excluded +' + + +test_expect_success 'Exclusion of a file in the XDG ignore file' ' + mkdir -p "$HOME"/.config/git/ && + echo to_be_excluded >"$HOME"/.config/git/ignore && + test_must_fail git add to_be_excluded +' + +test_expect_success '$XDG_CONFIG_HOME overrides $HOME/.config/git/ignore' ' + mkdir -p "$HOME"/xdg/git && + echo content >excluded_by_xdg_only && + echo excluded_by_xdg_only >"$HOME"/xdg/git/ignore && + test_when_finished "git read-tree --empty" && + (XDG_CONFIG_HOME="$HOME/xdg" && + export XDG_CONFIG_HOME && + git add to_be_excluded && + test_must_fail git add excluded_by_xdg_only + ) +' + +test_expect_success 'Exclusion in both XDG and local ignore files' ' + echo to_be_excluded >.gitignore && + test_must_fail git add to_be_excluded +' + + +test_expect_success 'Exclusion in a non-XDG global ignore file' ' + rm .gitignore && + echo >"$HOME"/.config/git/ignore && + echo to_be_excluded >"$HOME"/my_gitignore && + git config core.excludesfile "$HOME"/my_gitignore && + test_must_fail git add to_be_excluded +' + +test_expect_success 'Checking XDG ignore file when HOME is unset' ' + >expected && + (sane_unset HOME && + git config --unset core.excludesfile && + git ls-files --exclude-standard --ignored >actual) && + test_cmp expected actual +' + +test_expect_success 'Checking attributes in the XDG attributes file' ' + echo foo >f && + git check-attr -a f >actual && + test_line_count -eq 0 actual && + echo "f attr_f" >"$HOME"/.config/git/attributes && + echo "f: attr_f: set" >expected && + git check-attr -a f >actual && + test_cmp expected actual +' + +test_expect_success 'Checking XDG attributes when HOME is unset' ' + >expected && + (sane_unset HOME && + git check-attr -a f >actual) && + test_cmp expected actual +' + +test_expect_success '$XDG_CONFIG_HOME overrides $HOME/.config/git/attributes' ' + mkdir -p "$HOME"/xdg/git && + echo "f attr_f=xdg" >"$HOME"/xdg/git/attributes && + echo "f: attr_f: xdg" >expected && + XDG_CONFIG_HOME="$HOME/xdg" git check-attr -a f >actual && + test_cmp expected actual +' + +test_expect_success 'Checking attributes in both XDG and local attributes files' ' + echo "f -attr_f" >.gitattributes && + echo "f: attr_f: unset" >expected && + git check-attr -a f >actual && + test_cmp expected actual +' + + +test_expect_success 'Checking attributes in a non-XDG global attributes file' ' + test_might_fail rm .gitattributes && + echo "f attr_f=test" >"$HOME"/my_gitattributes && + git config core.attributesfile "$HOME"/my_gitattributes && + echo "f: attr_f: test" >expected && + git check-attr -a f >actual && + test_cmp expected actual +' + + +test_expect_success 'write: xdg file exists and ~/.gitconfig doesn'\''t' ' + mkdir -p "$HOME"/.config/git && + >"$HOME"/.config/git/config && + test_might_fail rm "$HOME"/.gitconfig && + git config --global user.name "write_config" && + echo "[user]" >expected && + echo " name = write_config" >>expected && + test_cmp expected "$HOME"/.config/git/config +' + + +test_expect_success 'write: xdg file exists and ~/.gitconfig exists' ' + >"$HOME"/.gitconfig && + git config --global user.name "write_gitconfig" && + echo "[user]" >expected && + echo " name = write_gitconfig" >>expected && + test_cmp expected "$HOME"/.gitconfig +' + + +test_expect_success 'write: ~/.config/git/ exists and config file doesn'\''t' ' + test_might_fail rm "$HOME"/.gitconfig && + test_might_fail rm "$HOME"/.config/git/config && + git config --global user.name "write_gitconfig" && + echo "[user]" >expected && + echo " name = write_gitconfig" >>expected && + test_cmp expected "$HOME"/.gitconfig +' + + +test_done diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh index 252fc82837..236b13a3ab 100755 --- a/t/t1410-reflog.sh +++ b/t/t1410-reflog.sh @@ -100,8 +100,7 @@ test_expect_success setup ' check_fsck && - loglen=$(wc -l <.git/logs/refs/heads/master) && - test $loglen = 4 + test_line_count = 4 .git/logs/refs/heads/master ' test_expect_success rewind ' @@ -117,8 +116,7 @@ test_expect_success rewind ' check_have A B C D E F G H I J K L && - loglen=$(wc -l <.git/logs/refs/heads/master) && - test $loglen = 5 + test_line_count = 5 .git/logs/refs/heads/master ' test_expect_success 'corrupt and check' ' @@ -136,8 +134,7 @@ test_expect_success 'reflog expire --dry-run should not touch reflog' ' --stale-fix \ --all && - loglen=$(wc -l <.git/logs/refs/heads/master) && - test $loglen = 5 && + test_line_count = 5 .git/logs/refs/heads/master && check_fsck "missing blob $F" ' @@ -150,8 +147,7 @@ test_expect_success 'reflog expire' ' --stale-fix \ --all && - loglen=$(wc -l <.git/logs/refs/heads/master) && - test $loglen = 2 && + test_line_count = 2 .git/logs/refs/heads/master && check_fsck "dangling commit $K" ' @@ -217,9 +213,7 @@ test_expect_success 'delete' ' test_expect_success 'rewind2' ' test_tick && git reset --hard HEAD~2 && - loglen=$(wc -l <.git/logs/refs/heads/master) && - test $loglen = 4 - + test_line_count = 4 .git/logs/refs/heads/master ' test_expect_success '--expire=never' ' @@ -228,9 +222,7 @@ test_expect_success '--expire=never' ' --expire=never \ --expire-unreachable=never \ --all && - loglen=$(wc -l <.git/logs/refs/heads/master) && - test $loglen = 4 - + test_line_count = 4 .git/logs/refs/heads/master ' test_expect_success 'gc.reflogexpire=never' ' @@ -238,8 +230,7 @@ test_expect_success 'gc.reflogexpire=never' ' git config gc.reflogexpire never && git config gc.reflogexpireunreachable never && git reflog expire --verbose --all && - loglen=$(wc -l <.git/logs/refs/heads/master) && - test $loglen = 4 + test_line_count = 4 .git/logs/refs/heads/master ' test_expect_success 'gc.reflogexpire=false' ' @@ -247,8 +238,7 @@ test_expect_success 'gc.reflogexpire=false' ' git config gc.reflogexpire false && git config gc.reflogexpireunreachable false && git reflog expire --verbose --all && - loglen=$(wc -l <.git/logs/refs/heads/master) && - test $loglen = 4 && + test_line_count = 4 .git/logs/refs/heads/master && git config --unset gc.reflogexpire && git config --unset gc.reflogexpireunreachable diff --git a/t/t1411-reflog-show.sh b/t/t1411-reflog-show.sh index caa687b5b4..9a105fe21f 100755 --- a/t/t1411-reflog-show.sh +++ b/t/t1411-reflog-show.sh @@ -65,20 +65,73 @@ test_expect_success 'using @{now} syntax shows reflog date (oneline)' ' ' cat >expect <<'EOF' -Reflog: HEAD@{1112911993 -0700} (C O Mitter <committer@example.com>) +HEAD@{Thu Apr 7 15:13:13 2005 -0700} +EOF +test_expect_success 'using @{now} syntax shows reflog date (format=%gd)' ' + git log -g -1 --format=%gd HEAD@{now} >actual && + test_cmp expect actual +' + +cat >expect <<'EOF' +Reflog: HEAD@{Thu Apr 7 15:13:13 2005 -0700} (C O Mitter <committer@example.com>) Reflog message: commit (initial): one EOF test_expect_success 'using --date= shows reflog date (multiline)' ' - git log -g -1 --date=raw >tmp && + git log -g -1 --date=default >tmp && grep ^Reflog <tmp >actual && test_cmp expect actual ' cat >expect <<'EOF' -e46513e HEAD@{1112911993 -0700}: commit (initial): one +e46513e HEAD@{Thu Apr 7 15:13:13 2005 -0700}: commit (initial): one EOF test_expect_success 'using --date= shows reflog date (oneline)' ' - git log -g -1 --oneline --date=raw >actual && + git log -g -1 --oneline --date=default >actual && + test_cmp expect actual +' + +cat >expect <<'EOF' +HEAD@{1112911993 -0700} +EOF +test_expect_success 'using --date= shows reflog date (format=%gd)' ' + git log -g -1 --format=%gd --date=raw >actual && + test_cmp expect actual +' + +cat >expect <<'EOF' +Reflog: HEAD@{0} (C O Mitter <committer@example.com>) +Reflog message: commit (initial): one +EOF +test_expect_success 'log.date does not invoke "--date" magic (multiline)' ' + test_config log.date raw && + git log -g -1 >tmp && + grep ^Reflog <tmp >actual && + test_cmp expect actual +' + +cat >expect <<'EOF' +e46513e HEAD@{0}: commit (initial): one +EOF +test_expect_success 'log.date does not invoke "--date" magic (oneline)' ' + test_config log.date raw && + git log -g -1 --oneline >actual && + test_cmp expect actual +' + +cat >expect <<'EOF' +HEAD@{0} +EOF +test_expect_success 'log.date does not invoke "--date" magic (format=%gd)' ' + test_config log.date raw && + git log -g -1 --format=%gd >actual && + test_cmp expect actual +' + +cat >expect <<'EOF' +HEAD@{0} +EOF +test_expect_success '--date magic does not override explicit @{0} syntax' ' + git log -g -1 --format=%gd --date=raw HEAD@{0} >actual && test_cmp expect actual ' diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh index 5b8ebd8053..bf7a2cd6fb 100755 --- a/t/t1450-fsck.sh +++ b/t/t1450-fsck.sh @@ -27,12 +27,8 @@ test_expect_success 'loose objects borrowed from alternate are not missing' ' git init && echo ../../../.git/objects >.git/objects/info/alternates && test_commit C fileC one && - git fsck >../out 2>&1 + git fsck --no-dangling >../actual 2>&1 ) && - { - grep -v dangling out >actual || - : - } && test_cmp empty actual ' @@ -217,4 +213,30 @@ test_expect_success 'rev-list --verify-objects with bad sha1' ' grep -q "error: sha1 mismatch 63ffffffffffffffffffffffffffffffffffffff" out ' +_bz='\0' +_bz5="$_bz$_bz$_bz$_bz$_bz" +_bz20="$_bz5$_bz5$_bz5$_bz5" + +test_expect_success 'fsck notices blob entry pointing to null sha1' ' + (git init null-blob && + cd null-blob && + sha=$(printf "100644 file$_bz$_bz20" | + git hash-object -w --stdin -t tree) && + git fsck 2>out && + cat out && + grep "warning.*null sha1" out + ) +' + +test_expect_success 'fsck notices submodule entry pointing to null sha1' ' + (git init null-commit && + cd null-commit && + sha=$(printf "160000 submodule$_bz$_bz20" | + git hash-object -w --stdin -t tree) && + git fsck 2>out && + cat out && + grep "warning.*null sha1" out + ) +' + test_done diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh index e661147c57..8f36aa9fc4 100755 --- a/t/t1501-worktree.sh +++ b/t/t1501-worktree.sh @@ -68,7 +68,7 @@ test_expect_success 'inside work tree' ' ) ' -test_expect_failure 'empty prefix is actually written out' ' +test_expect_success 'empty prefix is actually written out' ' echo >expected && ( cd work && diff --git a/t/t1506-rev-parse-diagnosis.sh b/t/t1506-rev-parse-diagnosis.sh index 0843a1c13b..c5cb77a0e1 100755 --- a/t/t1506-rev-parse-diagnosis.sh +++ b/t/t1506-rev-parse-diagnosis.sh @@ -171,4 +171,15 @@ test_expect_success 'relative path when startup_info is NULL' ' grep "BUG: startup_info struct is not initialized." error ' +test_expect_success '<commit>:file correctly diagnosed after a pathname' ' + test_must_fail git rev-parse file.txt HEAD:file.txt 1>actual 2>error && + test_i18ngrep ! "exists on disk" error && + test_i18ngrep "no such path in the working tree" error && + cat >expect <<-\EOF && + file.txt + HEAD:file.txt + EOF + test_cmp expect actual +' + test_done diff --git a/t/t1507-rev-parse-upstream.sh b/t/t1507-rev-parse-upstream.sh index a4555510c3..d6e576192f 100755 --- a/t/t1507-rev-parse-upstream.sh +++ b/t/t1507-rev-parse-upstream.sh @@ -15,10 +15,18 @@ test_expect_success 'setup' ' test_commit 3 && (cd clone && test_commit 4 && - git branch --track my-side origin/side) - + git branch --track my-side origin/side && + git branch --track local-master master && + git remote add -t master master-only .. && + git fetch master-only && + git branch bad-upstream && + git config branch.bad-upstream.remote master-only && + git config branch.bad-upstream.merge refs/heads/side + ) ' +sq="'" + full_name () { (cd clone && git rev-parse --symbolic-full-name "$@") @@ -29,6 +37,11 @@ commit_subject () { git show -s --pretty=format:%s "$@") } +error_message () { + (cd clone && + test_must_fail git rev-parse --verify "$@") +} + test_expect_success '@{upstream} resolves to correct full name' ' test refs/remotes/origin/master = "$(full_name @{upstream})" ' @@ -78,7 +91,6 @@ test_expect_success 'checkout -b new my-side@{u} forks from the same' ' test_expect_success 'merge my-side@{u} records the correct name' ' ( - sq="'\''" && cd clone || exit git checkout master || exit git branch -D new ;# can fail but is ok @@ -107,6 +119,69 @@ test_expect_success 'checkout other@{u}' ' test_cmp expect actual ' +test_expect_success 'branch@{u} works when tracking a local branch' ' + test refs/heads/master = "$(full_name local-master@{u})" +' + +test_expect_success 'branch@{u} error message when no upstream' ' + cat >expect <<-EOF && + error: No upstream configured for branch ${sq}non-tracking${sq} + fatal: Needed a single revision + EOF + error_message non-tracking@{u} 2>actual && + test_i18ncmp expect actual +' + +test_expect_success '@{u} error message when no upstream' ' + cat >expect <<-EOF && + error: No upstream configured for branch ${sq}master${sq} + fatal: Needed a single revision + EOF + test_must_fail git rev-parse --verify @{u} 2>actual && + test_i18ncmp expect actual +' + +test_expect_success 'branch@{u} error message with misspelt branch' ' + cat >expect <<-EOF && + error: No such branch: ${sq}no-such-branch${sq} + fatal: Needed a single revision + EOF + error_message no-such-branch@{u} 2>actual && + test_i18ncmp expect actual +' + +test_expect_success '@{u} error message when not on a branch' ' + cat >expect <<-EOF && + error: HEAD does not point to a branch + fatal: Needed a single revision + EOF + git checkout HEAD^0 && + test_must_fail git rev-parse --verify @{u} 2>actual && + test_i18ncmp expect actual +' + +test_expect_success 'branch@{u} error message if upstream branch not fetched' ' + cat >expect <<-EOF && + error: Upstream branch ${sq}refs/heads/side${sq} not stored as a remote-tracking branch + fatal: Needed a single revision + EOF + error_message bad-upstream@{u} 2>actual && + test_i18ncmp expect actual +' + +test_expect_success 'pull works when tracking a local branch' ' +( + cd clone && + git checkout local-master && + git pull +) +' + +# makes sense if the previous one succeeded +test_expect_success '@{u} works when tracking a local branch' ' + test refs/heads/master = "$(full_name @{u})" +' + cat >expect <<EOF commit 8f489d01d0cc65c3b0f09504ec50b5ed02a70bd5 Reflog: master@{0} (C O Mitter <committer@example.com>) diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh new file mode 100755 index 0000000000..6b3d797cea --- /dev/null +++ b/t/t1512-rev-parse-disambiguation.sh @@ -0,0 +1,264 @@ +#!/bin/sh + +test_description='object name disambiguation + +Create blobs, trees, commits and a tag that all share the same +prefix, and make sure "git rev-parse" can take advantage of +type information to disambiguate short object names that are +not necessarily unique. + +The final history used in the test has five commits, with the bottom +one tagged as v1.0.0. They all have one regular file each. + + +-------------------------------------------+ + | | + | .-------b3wettvi---- ad2uee | + | / / | + | a2onsxbvj---czy8f73t--ioiley5o | + | | + +-------------------------------------------+ + +' + +. ./test-lib.sh + +test_expect_success 'blob and tree' ' + test_tick && + ( + for i in 0 1 2 3 4 5 6 7 8 9 + do + echo $i + done + echo + echo b1rwzyc3 + ) >a0blgqsjc && + + # create one blob 0000000000b36 + git add a0blgqsjc && + + # create one tree 0000000000cdc + git write-tree +' + +test_expect_success 'warn ambiguity when no candidate matches type hint' ' + test_must_fail git rev-parse --verify 000000000^{commit} 2>actual && + grep "short SHA1 000000000 is ambiguous" actual +' + +test_expect_success 'disambiguate tree-ish' ' + # feed tree-ish in an unambiguous way + git rev-parse --verify 0000000000cdc:a0blgqsjc && + + # ambiguous at the object name level, but there is only one + # such tree-ish (the other is a blob) + git rev-parse --verify 000000000:a0blgqsjc +' + +test_expect_success 'disambiguate blob' ' + sed -e "s/|$//" >patch <<-EOF && + diff --git a/frotz b/frotz + index 000000000..ffffff 100644 + --- a/frotz + +++ b/frotz + @@ -10,3 +10,4 @@ + 9 + | + b1rwzyc3 + +irwry + EOF + ( + GIT_INDEX_FILE=frotz && + export GIT_INDEX_FILE && + git apply --build-fake-ancestor frotz patch && + git cat-file blob :frotz >actual + ) && + test_cmp a0blgqsjc actual +' + +test_expect_success 'disambiguate tree' ' + commit=$(echo "d7xm" | git commit-tree 000000000) && + test $(git rev-parse $commit^{tree}) = $(git rev-parse 0000000000cdc) +' + +test_expect_success 'first commit' ' + # create one commit 0000000000e4f + git commit -m a2onsxbvj +' + +test_expect_success 'disambiguate commit-ish' ' + # feed commit-ish in an unambiguous way + git rev-parse --verify 0000000000e4f^{commit} && + + # ambiguous at the object name level, but there is only one + # such commit (the others are tree and blob) + git rev-parse --verify 000000000^{commit} && + + # likewise + git rev-parse --verify 000000000^0 +' + +test_expect_success 'disambiguate commit' ' + commit=$(echo "hoaxj" | git commit-tree 0000000000cdc -p 000000000) && + test $(git rev-parse $commit^) = $(git rev-parse 0000000000e4f) +' + +test_expect_success 'log name1..name2 takes only commit-ishes on both ends' ' + git log 000000000..000000000 && + git log ..000000000 && + git log 000000000.. && + git log 000000000...000000000 && + git log ...000000000 && + git log 000000000... +' + +test_expect_success 'rev-parse name1..name2 takes only commit-ishes on both ends' ' + git rev-parse 000000000..000000000 && + git rev-parse ..000000000 && + git rev-parse 000000000.. +' + +test_expect_success 'git log takes only commit-ish' ' + git log 000000000 +' + +test_expect_success 'git reset takes only commit-ish' ' + git reset 000000000 +' + +test_expect_success 'first tag' ' + # create one tag 0000000000f8f + git tag -a -m j7cp83um v1.0.0 +' + +test_expect_failure 'two semi-ambiguous commit-ish' ' + # Once the parser becomes ultra-smart, it could notice that + # 110282 before ^{commit} name many different objects, but + # that only two (HEAD and v1.0.0 tag) can be peeled to commit, + # and that peeling them down to commit yield the same commit + # without ambiguity. + git rev-parse --verify 110282^{commit} && + + # likewise + git log 000000000..000000000 && + git log ..000000000 && + git log 000000000.. && + git log 000000000...000000000 && + git log ...000000000 && + git log 000000000... +' + +test_expect_failure 'three semi-ambiguous tree-ish' ' + # Likewise for tree-ish. HEAD, v1.0.0 and HEAD^{tree} share + # the prefix but peeling them to tree yields the same thing + git rev-parse --verify 000000000^{tree} +' + +test_expect_success 'parse describe name' ' + # feed an unambiguous describe name + git rev-parse --verify v1.0.0-0-g0000000000e4f && + + # ambiguous at the object name level, but there is only one + # such commit (others are blob, tree and tag) + git rev-parse --verify v1.0.0-0-g000000000 +' + +test_expect_success 'more history' ' + # commit 0000000000043 + git mv a0blgqsjc d12cr3h8t && + echo h62xsjeu >>d12cr3h8t && + git add d12cr3h8t && + + test_tick && + git commit -m czy8f73t && + + # commit 00000000008ec + git mv d12cr3h8t j000jmpzn && + echo j08bekfvt >>j000jmpzn && + git add j000jmpzn && + + test_tick && + git commit -m ioiley5o && + + # commit 0000000005b0 + git checkout v1.0.0^0 && + git mv a0blgqsjc f5518nwu && + + for i in h62xsjeu j08bekfvt kg7xflhm + do + echo $i + done >>f5518nwu && + git add f5518nwu && + + test_tick && + git commit -m b3wettvi && + side=$(git rev-parse HEAD) && + + # commit 000000000066 + git checkout master && + + # If you use recursive, merge will fail and you will need to + # clean up a0blgqsjc as well. If you use resolve, merge will + # succeed. + test_might_fail git merge --no-commit -s recursive $side && + git rm -f f5518nwu j000jmpzn && + + test_might_fail git rm -f a0blgqsjc && + ( + git cat-file blob $side:f5518nwu + echo j3l0i9s6 + ) >ab2gs879 && + git add ab2gs879 && + + test_tick && + git commit -m ad2uee + +' + +test_expect_failure 'parse describe name taking advantage of generation' ' + # ambiguous at the object name level, but there is only one + # such commit at generation 0 + git rev-parse --verify v1.0.0-0-g000000000 && + + # likewise for generation 2 and 4 + git rev-parse --verify v1.0.0-2-g000000000 && + git rev-parse --verify v1.0.0-4-g000000000 +' + +# Note: because rev-parse does not even try to disambiguate based on +# the generation number, this test currently succeeds for a wrong +# reason. When it learns to use the generation number, the previous +# test should succeed, and also this test should fail because the +# describe name used in the test with generation number can name two +# commits. Make sure that such a future enhancement does not randomly +# pick one. +test_expect_success 'parse describe name not ignoring ambiguity' ' + # ambiguous at the object name level, and there are two such + # commits at generation 1 + test_must_fail git rev-parse --verify v1.0.0-1-g000000000 +' + +test_expect_success 'ambiguous commit-ish' ' + # Now there are many commits that begin with the + # common prefix, none of these should pick one at + # random. They all should result in ambiguity errors. + test_must_fail git rev-parse --verify 110282^{commit} && + + # likewise + test_must_fail git log 000000000..000000000 && + test_must_fail git log ..000000000 && + test_must_fail git log 000000000.. && + test_must_fail git log 000000000...000000000 && + test_must_fail git log ...000000000 && + test_must_fail git log 000000000... +' + +test_expect_success 'rev-parse --disambiguate' ' + # The test creates 16 objects that share the prefix and two + # commits created by commit-tree in earlier tests share a + # different prefix. + git rev-parse --disambiguate=000000000 >actual && + test $(wc -l <actual) = 16 && + test "$(sed -e "s/^\(.........\).*/\1/" actual | sort -u)" = 000000000 +' + +test_done diff --git a/t/t2004-checkout-cache-temp.sh b/t/t2004-checkout-cache-temp.sh index 36cca14d95..0f4b2896af 100755 --- a/t/t2004-checkout-cache-temp.sh +++ b/t/t2004-checkout-cache-temp.sh @@ -40,7 +40,7 @@ test_expect_success \ rm -f path* .merge_* out .git/index && git read-tree $t1 && git checkout-index --temp -- path1 >out && -test $(wc -l <out) = 1 && +test_line_count = 1 out && test $(cut "-d " -f2 out) = path1 && p=$(cut "-d " -f1 out) && test -f $p && @@ -51,7 +51,7 @@ test_expect_success \ rm -f path* .merge_* out .git/index && git read-tree $t1 && git checkout-index -a --temp >out && -test $(wc -l <out) = 5 && +test_line_count = 5 out && for f in path0 path1 path3 path4 asubdir/path5 do test $(grep $f out | cut "-d " -f2) = $f && @@ -69,7 +69,7 @@ test_expect_success \ 'checkout one stage 2 to temporary file' ' rm -f path* .merge_* out && git checkout-index --stage=2 --temp -- path1 >out && -test $(wc -l <out) = 1 && +test_line_count = 1 out && test $(cut "-d " -f2 out) = path1 && p=$(cut "-d " -f1 out) && test -f $p && @@ -79,7 +79,7 @@ test_expect_success \ 'checkout all stage 2 to temporary files' ' rm -f path* .merge_* out && git checkout-index --all --stage=2 --temp >out && -test $(wc -l <out) = 3 && +test_line_count = 3 out && for f in path1 path2 path4 do test $(grep $f out | cut "-d " -f2) = $f && @@ -92,13 +92,13 @@ test_expect_success \ 'checkout all stages/one file to nothing' ' rm -f path* .merge_* out && git checkout-index --stage=all --temp -- path0 >out && -test $(wc -l <out) = 0' +test_line_count = 0 out' test_expect_success \ 'checkout all stages/one file to temporary files' ' rm -f path* .merge_* out && git checkout-index --stage=all --temp -- path1 >out && -test $(wc -l <out) = 1 && +test_line_count = 1 out && test $(cut "-d " -f2 out) = path1 && cut "-d " -f1 out | (read s1 s2 s3 && test -f $s1 && @@ -112,7 +112,7 @@ test_expect_success \ 'checkout some stages/one file to temporary files' ' rm -f path* .merge_* out && git checkout-index --stage=all --temp -- path2 >out && -test $(wc -l <out) = 1 && +test_line_count = 1 out && test $(cut "-d " -f2 out) = path2 && cut "-d " -f1 out | (read s1 s2 s3 && test $s1 = . && @@ -125,7 +125,7 @@ test_expect_success \ 'checkout all stages/all files to temporary files' ' rm -f path* .merge_* out && git checkout-index -a --stage=all --temp >out && -test $(wc -l <out) = 5' +test_line_count = 5 out' test_expect_success \ '-- path0: no entry' ' @@ -185,7 +185,7 @@ test_expect_success \ 'checkout --temp within subdir' ' (cd asubdir && git checkout-index -a --stage=all >out && - test $(wc -l <out) = 1 && + test_line_count = 1 out && test $(grep path5 out | cut "-d " -f2) = path5 && grep path5 out | cut "-d " -f1 | (read s1 s2 s3 && test -f ../$s1 && @@ -203,7 +203,7 @@ t4=$(git write-tree) && rm -f .git/index && git read-tree $t4 && git checkout-index --temp -a >out && -test $(wc -l <out) = 1 && +test_line_count = 1 out && test $(cut "-d " -f2 out) = a && p=$(cut "-d " -f1 out) && test -f $p && diff --git a/t/t2015-checkout-unborn.sh b/t/t2015-checkout-unborn.sh index 6352b74e2e..37bdcedcc9 100755 --- a/t/t2015-checkout-unborn.sh +++ b/t/t2015-checkout-unborn.sh @@ -46,4 +46,15 @@ test_expect_success 'checking out another branch from unborn state' ' test_cmp expect actual ' +test_expect_success 'checking out in a newly created repo' ' + test_create_repo empty && + ( + cd empty && + git symbolic-ref HEAD >expect && + test_must_fail git checkout && + git symbolic-ref HEAD >actual && + test_cmp expect actual + ) +' + test_done diff --git a/t/t2017-checkout-orphan.sh b/t/t2017-checkout-orphan.sh index 0e3b8582f2..655f278c5f 100755 --- a/t/t2017-checkout-orphan.sh +++ b/t/t2017-checkout-orphan.sh @@ -116,4 +116,10 @@ test_expect_success '--orphan refuses to switch if a merge is needed' ' git reset --hard ' +test_expect_success 'cannot --detach on an unborn branch' ' + git checkout master && + git checkout --orphan new && + test_must_fail git checkout --detach +' + test_done diff --git a/t/t2020-checkout-detach.sh b/t/t2020-checkout-detach.sh index 068fba4c8e..81005373d7 100755 --- a/t/t2020-checkout-detach.sh +++ b/t/t2020-checkout-detach.sh @@ -11,14 +11,13 @@ check_not_detached () { git symbolic-ref -q HEAD >/dev/null } -ORPHAN_WARNING='you are leaving .* commit.*behind' PREV_HEAD_DESC='Previous HEAD position was' check_orphan_warning() { - test_i18ngrep "$ORPHAN_WARNING" "$1" && + test_i18ngrep "you are leaving $2 behind" "$1" && test_i18ngrep ! "$PREV_HEAD_DESC" "$1" } check_no_orphan_warning() { - test_i18ngrep ! "$ORPHAN_WARNING" "$1" && + test_i18ngrep ! "you are leaving .* commit.*behind" "$1" && test_i18ngrep "$PREV_HEAD_DESC" "$1" } @@ -110,12 +109,24 @@ test_expect_success 'checkout warns on orphan commits' ' git checkout --detach two && echo content >orphan && git add orphan && - git commit -a -m orphan && + git commit -a -m orphan1 && + echo new content >orphan && + git commit -a -m orphan2 && + orphan2=$(git rev-parse HEAD) && git checkout master 2>stderr ' test_expect_success 'checkout warns on orphan commits: output' ' - check_orphan_warning stderr + check_orphan_warning stderr "2 commits" +' + +test_expect_success 'checkout warns orphaning 1 of 2 commits' ' + git checkout "$orphan2" && + git checkout HEAD^ 2>stderr +' + +test_expect_success 'checkout warns orphaning 1 of 2 commits: output' ' + check_orphan_warning stderr "1 commit" ' test_expect_success 'checkout does not warn leaving ref tip' ' @@ -148,7 +159,7 @@ test_expect_success 'tracking count is accurate after orphan check' ' git config branch.child.merge refs/heads/master && git checkout child^ && git checkout child >stdout && - test_cmp expect stdout + test_i18ncmp expect stdout ' test_done diff --git a/t/t2030-unresolve-info.sh b/t/t2030-unresolve-info.sh index cb7effe0a3..f2620650ce 100755 --- a/t/t2030-unresolve-info.sh +++ b/t/t2030-unresolve-info.sh @@ -113,7 +113,7 @@ test_expect_success 'unmerge with plumbing' ' prime_resolve_undo && git update-index --unresolve fi/le && git ls-files -u >actual && - test $(wc -l <actual) = 3 + test_line_count = 3 actual ' test_expect_success 'rerere and rerere forget' ' diff --git a/t/t2107-update-index-basic.sh b/t/t2107-update-index-basic.sh index 809fafe208..0dbbb00d74 100755 --- a/t/t2107-update-index-basic.sh +++ b/t/t2107-update-index-basic.sh @@ -29,4 +29,23 @@ test_expect_success 'update-index -h with corrupt index' ' grep "[Uu]sage: git update-index" broken/usage ' +test_expect_success '--cacheinfo does not accept blob null sha1' ' + echo content >file && + git add file && + git rev-parse :file >expect && + test_must_fail git update-index --cacheinfo 100644 $_z40 file && + git rev-parse :file >actual && + test_cmp expect actual +' + +test_expect_success '--cacheinfo does not accept gitlink null sha1' ' + git init submodule && + (cd submodule && test_commit foo) && + git add submodule && + git rev-parse :submodule >expect && + test_must_fail git update-index --cacheinfo 160000 $_z40 submodule && + git rev-parse :submodule >actual && + test_cmp expect actual +' + test_done diff --git a/t/t3006-ls-files-long.sh b/t/t3006-ls-files-long.sh new file mode 100755 index 0000000000..202ad658b8 --- /dev/null +++ b/t/t3006-ls-files-long.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +test_description='overly long paths' +. ./test-lib.sh + +test_expect_success setup ' + p=filefilefilefilefilefilefilefile && + p=$p$p$p$p$p$p$p$p$p$p$p$p$p$p$p$p && + p=$p$p$p$p$p$p$p$p$p$p$p$p$p$p$p$p && + + path_a=${p}_a && + path_z=${p}_z && + + blob_a=$(echo frotz | git hash-object -w --stdin) && + blob_z=$(echo nitfol | git hash-object -w --stdin) && + + pat="100644 %s 0\t%s\n" +' + +test_expect_success 'overly-long path by itself is not a problem' ' + printf "$pat" "$blob_a" "$path_a" | + git update-index --add --index-info && + echo "$path_a" >expect && + git ls-files >actual && + test_cmp expect actual +' + +test_expect_success 'overly-long path does not replace another by mistake' ' + printf "$pat" "$blob_a" "$path_a" "$blob_z" "$path_z" | + git update-index --add --index-info && + ( + echo "$path_a" + echo "$path_z" + ) >expect && + git ls-files >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index 9fe1d8feab..a17f8b2a40 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -160,6 +160,83 @@ test_expect_success 'git branch --list -d t should fail' ' test_path_is_missing .git/refs/heads/t ' +test_expect_success 'git branch --column' ' + COLUMNS=81 git branch --column=column >actual && + cat >expected <<\EOF && + a/b/c bam foo l * master n o/p r + abc bar j/k m/m master2 o/o q +EOF + test_cmp expected actual +' + +test_expect_success 'git branch --column with an extremely long branch name' ' + long=this/is/a/part/of/long/branch/name && + long=z$long/$long/$long/$long && + test_when_finished "git branch -d $long" && + git branch $long && + COLUMNS=80 git branch --column=column >actual && + cat >expected <<EOF && + a/b/c + abc + bam + bar + foo + j/k + l + m/m +* master + master2 + n + o/o + o/p + q + r + $long +EOF + test_cmp expected actual +' + +test_expect_success 'git branch with column.*' ' + git config column.ui column && + git config column.branch "dense" && + COLUMNS=80 git branch >actual && + git config --unset column.branch && + git config --unset column.ui && + cat >expected <<\EOF && + a/b/c bam foo l * master n o/p r + abc bar j/k m/m master2 o/o q +EOF + test_cmp expected actual +' + +test_expect_success 'git branch --column -v should fail' ' + test_must_fail git branch --column -v +' + +test_expect_success 'git branch -v with column.ui ignored' ' + git config column.ui column && + COLUMNS=80 git branch -v | cut -c -10 | sed "s/ *$//" >actual && + git config --unset column.ui && + cat >expected <<\EOF && + a/b/c + abc + bam + bar + foo + j/k + l + m/m +* master + master2 + n + o/o + o/p + q + r +EOF + test_cmp expected actual +' + mv .git/config .git/config-saved test_expect_success 'git branch -m q q2 without config should succeed' ' diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh index 9f00ada5f7..1f35e55ee3 100755 --- a/t/t3300-funny-names.sh +++ b/t/t3300-funny-names.sh @@ -15,184 +15,204 @@ p0='no-funny' p1='tabs ," (dq) and spaces' p2='just space' -cat >"$p0" <<\EOF -1. A quick brown fox jumps over the lazy cat, oops dog. -2. A quick brown fox jumps over the lazy cat, oops dog. -3. A quick brown fox jumps over the lazy cat, oops dog. -EOF - -cat 2>/dev/null >"$p1" "$p0" -echo 'Foo Bar Baz' >"$p2" +test_expect_success 'setup' ' + cat >"$p0" <<-\EOF && + 1. A quick brown fox jumps over the lazy cat, oops dog. + 2. A quick brown fox jumps over the lazy cat, oops dog. + 3. A quick brown fox jumps over the lazy cat, oops dog. + EOF + + { cat "$p0" >"$p1" || :; } && + { echo "Foo Bar Baz" >"$p2" || :; } && + + if test -f "$p1" && cmp "$p0" "$p1" + then + test_set_prereq TABS_IN_FILENAMES + fi +' -if test -f "$p1" && cmp "$p0" "$p1" +if ! test_have_prereq TABS_IN_FILENAMES then - test_set_prereq TABS_IN_FILENAMES -else # since FAT/NTFS does not allow tabs in filenames, skip this test - say 'Your filesystem does not allow tabs in filenames' + skip_all='Your filesystem does not allow tabs in filenames' + test_done fi -test_expect_success TABS_IN_FILENAMES 'setup expect' " -echo 'just space -no-funny' >expected -" +test_expect_success 'setup: populate index and tree' ' + git update-index --add "$p0" "$p2" && + t0=$(git write-tree) +' -test_expect_success TABS_IN_FILENAMES 'git ls-files no-funny' \ - 'git update-index --add "$p0" "$p2" && +test_expect_success 'ls-files prints space in filename verbatim' ' + printf "%s\n" "just space" no-funny >expected && git ls-files >current && - test_cmp expected current' - -test_expect_success TABS_IN_FILENAMES 'setup expect' ' -t0=`git write-tree` && -echo "$t0" >t0 && + test_cmp expected current +' -cat > expected <<\EOF -just space -no-funny -"tabs\t,\" (dq) and spaces" -EOF +test_expect_success 'setup: add funny filename' ' + git update-index --add "$p1" && + t1=$(git write-tree) ' -test_expect_success TABS_IN_FILENAMES 'git ls-files with-funny' \ - 'git update-index --add "$p1" && +test_expect_success 'ls-files quotes funny filename' ' + cat >expected <<-\EOF && + just space + no-funny + "tabs\t,\" (dq) and spaces" + EOF git ls-files >current && - test_cmp expected current' - -test_expect_success TABS_IN_FILENAMES 'setup expect' " -echo 'just space -no-funny -tabs ,\" (dq) and spaces' >expected -" - -test_expect_success TABS_IN_FILENAMES 'git ls-files -z with-funny' \ - 'git ls-files -z | perl -pe y/\\000/\\012/ >current && - test_cmp expected current' - -test_expect_success TABS_IN_FILENAMES 'setup expect' ' -t1=`git write-tree` && -echo "$t1" >t1 && - -cat > expected <<\EOF -just space -no-funny -"tabs\t,\" (dq) and spaces" -EOF -' - -test_expect_success TABS_IN_FILENAMES 'git ls-tree with funny' \ - 'git ls-tree -r $t1 | sed -e "s/^[^ ]* //" >current && - test_cmp expected current' - -test_expect_success TABS_IN_FILENAMES 'setup expect' ' -cat > expected <<\EOF -A "tabs\t,\" (dq) and spaces" -EOF -' - -test_expect_success TABS_IN_FILENAMES 'git diff-index with-funny' \ - 'git diff-index --name-status $t0 >current && - test_cmp expected current' - -test_expect_success TABS_IN_FILENAMES 'git diff-tree with-funny' \ - 'git diff-tree --name-status $t0 $t1 >current && - test_cmp expected current' - -test_expect_success TABS_IN_FILENAMES 'setup expect' " -echo 'A -tabs ,\" (dq) and spaces' >expected -" - -test_expect_success TABS_IN_FILENAMES 'git diff-index -z with-funny' \ - 'git diff-index -z --name-status $t0 | perl -pe y/\\000/\\012/ >current && - test_cmp expected current' - -test_expect_success TABS_IN_FILENAMES 'git diff-tree -z with-funny' \ - 'git diff-tree -z --name-status $t0 $t1 | perl -pe y/\\000/\\012/ >current && - test_cmp expected current' - -test_expect_success TABS_IN_FILENAMES 'setup expect' ' -cat > expected <<\EOF -CNUM no-funny "tabs\t,\" (dq) and spaces" -EOF -' - -test_expect_success TABS_IN_FILENAMES 'git diff-tree -C with-funny' \ - 'git diff-tree -C --find-copies-harder --name-status \ - $t0 $t1 | sed -e 's/^C[0-9]*/CNUM/' >current && - test_cmp expected current' - -test_expect_success TABS_IN_FILENAMES 'setup expect' ' -cat > expected <<\EOF -RNUM no-funny "tabs\t,\" (dq) and spaces" -EOF -' - -test_expect_success TABS_IN_FILENAMES 'git diff-tree delete with-funny' \ - 'git update-index --force-remove "$p0" && - git diff-index -M --name-status \ - $t0 | sed -e 's/^R[0-9]*/RNUM/' >current && - test_cmp expected current' - -test_expect_success TABS_IN_FILENAMES 'setup expect' ' -cat > expected <<\EOF -diff --git a/no-funny "b/tabs\t,\" (dq) and spaces" -similarity index NUM% -rename from no-funny -rename to "tabs\t,\" (dq) and spaces" -EOF -' - -test_expect_success TABS_IN_FILENAMES 'git diff-tree delete with-funny' \ - 'git diff-index -M -p $t0 | - sed -e "s/index [0-9]*%/index NUM%/" >current && - test_cmp expected current' - -test_expect_success TABS_IN_FILENAMES 'setup expect' ' -chmod +x "$p1" && -cat > expected <<\EOF -diff --git a/no-funny "b/tabs\t,\" (dq) and spaces" -old mode 100644 -new mode 100755 -similarity index NUM% -rename from no-funny -rename to "tabs\t,\" (dq) and spaces" -EOF -' - -test_expect_success TABS_IN_FILENAMES 'git diff-tree delete with-funny' \ - 'git diff-index -M -p $t0 | - sed -e "s/index [0-9]*%/index NUM%/" >current && - test_cmp expected current' - -test_expect_success TABS_IN_FILENAMES 'setup expect' ' -cat >expected <<\EOF - "tabs\t,\" (dq) and spaces" - 1 file changed, 0 insertions(+), 0 deletions(-) -EOF -' - -test_expect_success TABS_IN_FILENAMES 'git diff-tree rename with-funny applied' \ - 'git diff-index -M -p $t0 | - git apply --stat | sed -e "s/|.*//" -e "s/ *\$//" >current && - test_cmp expected current' - -test_expect_success TABS_IN_FILENAMES 'setup expect' ' -cat > expected <<\EOF - no-funny - "tabs\t,\" (dq) and spaces" - 2 files changed, 3 insertions(+), 3 deletions(-) -EOF -' - -test_expect_success TABS_IN_FILENAMES 'git diff-tree delete with-funny applied' \ - 'git diff-index -p $t0 | - git apply --stat | sed -e "s/|.*//" -e "s/ *\$//" >current && - test_cmp expected current' - -test_expect_success TABS_IN_FILENAMES 'git apply non-git diff' \ - 'git diff-index -p $t0 | - sed -ne "/^[-+@]/p" | - git apply --stat | sed -e "s/|.*//" -e "s/ *\$//" >current && - test_cmp expected current' + test_cmp expected current +' + +test_expect_success 'ls-files -z does not quote funny filename' ' + cat >expected <<-\EOF && + just space + no-funny + tabs ," (dq) and spaces + EOF + git ls-files -z >ls-files.z && + "$PERL_PATH" -pe "y/\000/\012/" <ls-files.z >current && + test_cmp expected current +' + +test_expect_success 'ls-tree quotes funny filename' ' + cat >expected <<-\EOF && + just space + no-funny + "tabs\t,\" (dq) and spaces" + EOF + git ls-tree -r $t1 >ls-tree && + sed -e "s/^[^ ]* //" <ls-tree >current && + test_cmp expected current +' + +test_expect_success 'diff-index --name-status quotes funny filename' ' + cat >expected <<-\EOF && + A "tabs\t,\" (dq) and spaces" + EOF + git diff-index --name-status $t0 >current && + test_cmp expected current +' + +test_expect_success 'diff-tree --name-status quotes funny filename' ' + cat >expected <<-\EOF && + A "tabs\t,\" (dq) and spaces" + EOF + git diff-tree --name-status $t0 $t1 >current && + test_cmp expected current +' + +test_expect_success 'diff-index -z does not quote funny filename' ' + cat >expected <<-\EOF && + A + tabs ," (dq) and spaces + EOF + git diff-index -z --name-status $t0 >diff-index.z && + "$PERL_PATH" -pe "y/\000/\012/" <diff-index.z >current && + test_cmp expected current +' + +test_expect_success 'diff-tree -z does not quote funny filename' ' + cat >expected <<-\EOF && + A + tabs ," (dq) and spaces + EOF + git diff-tree -z --name-status $t0 $t1 >diff-tree.z && + "$PERL_PATH" -pe y/\\000/\\012/ <diff-tree.z >current && + test_cmp expected current +' + +test_expect_success 'diff-tree --find-copies-harder quotes funny filename' ' + cat >expected <<-\EOF && + CNUM no-funny "tabs\t,\" (dq) and spaces" + EOF + git diff-tree -C --find-copies-harder --name-status $t0 $t1 >out && + sed -e "s/^C[0-9]*/CNUM/" <out >current && + test_cmp expected current +' + +test_expect_success 'setup: remove unfunny index entry' ' + git update-index --force-remove "$p0" +' + +test_expect_success 'diff-tree -M quotes funny filename' ' + cat >expected <<-\EOF && + RNUM no-funny "tabs\t,\" (dq) and spaces" + EOF + git diff-index -M --name-status $t0 >out && + sed -e "s/^R[0-9]*/RNUM/" <out >current && + test_cmp expected current +' + +test_expect_success 'diff-index -M -p quotes funny filename' ' + cat >expected <<-\EOF && + diff --git a/no-funny "b/tabs\t,\" (dq) and spaces" + similarity index NUM% + rename from no-funny + rename to "tabs\t,\" (dq) and spaces" + EOF + git diff-index -M -p $t0 >diff && + sed -e "s/index [0-9]*%/index NUM%/" <diff >current && + test_cmp expected current +' + +test_expect_success 'setup: mode change' ' + chmod +x "$p1" +' + +test_expect_success 'diff-index -M -p with mode change quotes funny filename' ' + cat >expected <<-\EOF && + diff --git a/no-funny "b/tabs\t,\" (dq) and spaces" + old mode 100644 + new mode 100755 + similarity index NUM% + rename from no-funny + rename to "tabs\t,\" (dq) and spaces" + EOF + git diff-index -M -p $t0 >diff && + sed -e "s/index [0-9]*%/index NUM%/" <diff >current && + test_cmp expected current +' + +test_expect_success 'diffstat for rename quotes funny filename' ' + cat >expected <<-\EOF && + "tabs\t,\" (dq) and spaces" + 1 file changed, 0 insertions(+), 0 deletions(-) + EOF + git diff-index -M -p $t0 >diff && + git apply --stat <diff >diffstat && + sed -e "s/|.*//" -e "s/ *\$//" <diffstat >current && + test_i18ncmp expected current +' + +test_expect_success 'numstat for rename quotes funny filename' ' + cat >expected <<-\EOF && + 0 0 "tabs\t,\" (dq) and spaces" + EOF + git diff-index -M -p $t0 >diff && + git apply --numstat <diff >current && + test_cmp expected current +' + +test_expect_success 'numstat without -M quotes funny filename' ' + cat >expected <<-\EOF && + 0 3 no-funny + 3 0 "tabs\t,\" (dq) and spaces" + EOF + git diff-index -p $t0 >diff && + git apply --numstat <diff >current && + test_cmp expected current +' + +test_expect_success 'numstat for non-git rename diff quotes funny filename' ' + cat >expected <<-\EOF && + 0 3 no-funny + 3 0 "tabs\t,\" (dq) and spaces" + EOF + git diff-index -p $t0 >git-diff && + sed -ne "/^[-+@]/p" <git-diff >diff && + git apply --numstat <diff >current && + test_cmp expected current +' test_done diff --git a/t/t3310-notes-merge-manual-resolve.sh b/t/t3310-notes-merge-manual-resolve.sh index 4367197953..195bb97f85 100755 --- a/t/t3310-notes-merge-manual-resolve.sh +++ b/t/t3310-notes-merge-manual-resolve.sh @@ -324,7 +324,7 @@ y and z notes on 4th commit EOF git notes merge --commit && # No .git/NOTES_MERGE_* files left - test_must_fail ls .git/NOTES_MERGE_* >output 2>/dev/null && + test_might_fail ls .git/NOTES_MERGE_* >output 2>/dev/null && test_cmp /dev/null output && # Merge commit has pre-merge y and pre-merge z as parents test "$(git rev-parse refs/notes/m^1)" = "$(cat pre_merge_y)" && @@ -386,7 +386,7 @@ test_expect_success 'redo merge of z into m (== y) with default ("manual") resol test_expect_success 'abort notes merge' ' git notes merge --abort && # No .git/NOTES_MERGE_* files left - test_must_fail ls .git/NOTES_MERGE_* >output 2>/dev/null && + test_might_fail ls .git/NOTES_MERGE_* >output 2>/dev/null && test_cmp /dev/null output && # m has not moved (still == y) test "$(git rev-parse refs/notes/m)" = "$(cat pre_merge_y)" && @@ -453,7 +453,7 @@ EOF # Finalize merge git notes merge --commit && # No .git/NOTES_MERGE_* files left - test_must_fail ls .git/NOTES_MERGE_* >output 2>/dev/null && + test_might_fail ls .git/NOTES_MERGE_* >output 2>/dev/null && test_cmp /dev/null output && # Merge commit has pre-merge y and pre-merge z as parents test "$(git rev-parse refs/notes/m^1)" = "$(cat pre_merge_y)" && @@ -542,7 +542,7 @@ EOF test_expect_success 'resolve situation by aborting the notes merge' ' git notes merge --abort && # No .git/NOTES_MERGE_* files left - test_must_fail ls .git/NOTES_MERGE_* >output 2>/dev/null && + test_might_fail ls .git/NOTES_MERGE_* >output 2>/dev/null && test_cmp /dev/null output && # m has not moved (still == w) test "$(git rev-parse refs/notes/m)" = "$(git rev-parse refs/notes/w)" && @@ -553,4 +553,23 @@ test_expect_success 'resolve situation by aborting the notes merge' ' verify_notes z ' +cat >expect_notes <<EOF +foo +bar +EOF + +test_expect_success 'switch cwd before committing notes merge' ' + git notes add -m foo HEAD && + git notes --ref=other add -m bar HEAD && + test_must_fail git notes merge refs/notes/other && + ( + cd .git/NOTES_MERGE_WORKTREE && + echo "foo" > $(git rev-parse HEAD) && + echo "bar" >> $(git rev-parse HEAD) && + git notes merge --commit + ) && + git notes show HEAD > actual_notes && + test_cmp expect_notes actual_notes +' + test_done diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index e647272a01..1de0ebda25 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -68,24 +68,24 @@ test_expect_success 'rebase against master' ' test_expect_success 'rebase against master twice' ' git rebase master >out && - grep "Current branch my-topic-branch is up to date" out + test_i18ngrep "Current branch my-topic-branch is up to date" out ' test_expect_success 'rebase against master twice with --force' ' git rebase --force-rebase master >out && - grep "Current branch my-topic-branch is up to date, rebase forced" out + test_i18ngrep "Current branch my-topic-branch is up to date, rebase forced" out ' test_expect_success 'rebase against master twice from another branch' ' git checkout my-topic-branch^ && git rebase master my-topic-branch >out && - grep "Current branch my-topic-branch is up to date" out + test_i18ngrep "Current branch my-topic-branch is up to date" out ' test_expect_success 'rebase fast-forward to master' ' git checkout my-topic-branch^ && git rebase my-topic-branch >out && - grep "Fast-forwarded HEAD to my-topic-branch" out + test_i18ngrep "Fast-forwarded HEAD to my-topic-branch" out ' test_expect_success 'the rebase operation should not have destroyed author information' ' @@ -160,14 +160,12 @@ rm -f B test_expect_success 'fail when upstream arg is missing and not on branch' ' git checkout topic && - test_must_fail git rebase >output.out && - grep "You are not currently on a branch" output.out + test_must_fail git rebase ' test_expect_success 'fail when upstream arg is missing and not configured' ' git checkout -b no-config topic && - test_must_fail git rebase >output.out && - grep "branch.no-config.merge" output.out + test_must_fail git rebase ' test_expect_success 'default to @{upstream} when upstream arg is missing' ' diff --git a/t/t3401-rebase-partial.sh b/t/t3401-rebase-partial.sh index 7ba17974c5..7f8693b928 100755 --- a/t/t3401-rebase-partial.sh +++ b/t/t3401-rebase-partial.sh @@ -42,4 +42,12 @@ test_expect_success 'rebase --merge topic branch that was partially merged upstr test_path_is_missing .git/rebase-merge ' +test_expect_success 'rebase ignores empty commit' ' + git reset --hard A && + git commit --allow-empty -m empty && + test_commit D && + git rebase C && + test $(git log --format=%s C..) = "D" +' + test_done diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index b981572d73..7304b663c3 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -247,6 +247,7 @@ test_expect_success '-p handles "no changes" gracefully' ' ' test_expect_failure 'exchange two commits with -p' ' + git checkout H && FAKE_LINES="2 1" git rebase -i -p HEAD~2 && test H = $(git cat-file commit HEAD^ | sed -ne \$p) && test G = $(git cat-file commit HEAD | sed -ne \$p) @@ -323,7 +324,7 @@ test_expect_success 'verbose flag is heeded, even after --continue' ' echo resolved > file1 && git add file1 && git rebase --continue > output && - grep "^ file1 | 2 +-$" output + grep "^ file1 | 2 +-$" output ' test_expect_success 'multi-squash only fires up editor once' ' @@ -624,8 +625,38 @@ test_expect_success 'submodule rebase -i' ' FAKE_LINES="1 squash 2 3" git rebase -i A ' +test_expect_success 'submodule conflict setup' ' + git tag submodule-base && + git checkout HEAD^ && + ( + cd sub && git checkout HEAD^ && echo 4 >elif && + git add elif && git commit -m "submodule conflict" + ) && + git add sub && + test_tick && + git commit -m "Conflict in submodule" && + git tag submodule-topic +' + +test_expect_success 'rebase -i continue with only submodule staged' ' + test_must_fail git rebase -i submodule-base && + git add sub && + git rebase --continue && + test $(git rev-parse submodule-base) != $(git rev-parse HEAD) +' + +test_expect_success 'rebase -i continue with unstaged submodule' ' + git checkout submodule-topic && + git reset --hard && + test_must_fail git rebase -i submodule-base && + git reset && + git rebase --continue && + test $(git rev-parse submodule-base) = $(git rev-parse HEAD) +' + test_expect_success 'avoid unnecessary reset' ' git checkout master && + git reset --hard && test-chmtime =123456789 file3 && git update-index --refresh && HEAD=$(git rev-parse HEAD) && @@ -724,4 +755,160 @@ test_expect_success 'rebase-i history with funny messages' ' test_cmp expect actual ' + +test_expect_success 'prepare for rebase -i --exec' ' + git checkout master && + git checkout -b execute && + test_commit one_exec main.txt one_exec && + test_commit two_exec main.txt two_exec && + test_commit three_exec main.txt three_exec +' + + +test_expect_success 'running "git rebase -i --exec git show HEAD"' ' + git rebase -i --exec "git show HEAD" HEAD~2 >actual && + ( + FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" && + export FAKE_LINES && + git rebase -i HEAD~2 >expect + ) && + sed -e "1,9d" expect >expected && + test_cmp expected actual +' + + +test_expect_success 'running "git rebase --exec git show HEAD -i"' ' + git reset --hard execute && + git rebase --exec "git show HEAD" -i HEAD~2 >actual && + ( + FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" && + export FAKE_LINES && + git rebase -i HEAD~2 >expect + ) && + sed -e "1,9d" expect >expected && + test_cmp expected actual +' + + +test_expect_success 'running "git rebase -ix git show HEAD"' ' + git reset --hard execute && + git rebase -ix "git show HEAD" HEAD~2 >actual && + ( + FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" && + export FAKE_LINES && + git rebase -i HEAD~2 >expect + ) && + sed -e "1,9d" expect >expected && + test_cmp expected actual +' + + +test_expect_success 'rebase -ix with several <CMD>' ' + git reset --hard execute && + git rebase -ix "git show HEAD; pwd" HEAD~2 >actual && + ( + FAKE_LINES="1 exec_git_show_HEAD;_pwd 2 exec_git_show_HEAD;_pwd" && + export FAKE_LINES && + git rebase -i HEAD~2 >expect + ) && + sed -e "1,9d" expect >expected && + test_cmp expected actual +' + + +test_expect_success 'rebase -ix with several instances of --exec' ' + git reset --hard execute && + git rebase -i --exec "git show HEAD" --exec "pwd" HEAD~2 >actual && + ( + FAKE_LINES="1 exec_git_show_HEAD exec_pwd 2 + exec_git_show_HEAD exec_pwd" && + export FAKE_LINES && + git rebase -i HEAD~2 >expect + ) && + sed -e "1,11d" expect >expected && + test_cmp expected actual +' + + +test_expect_success 'rebase -ix with --autosquash' ' + git reset --hard execute && + git checkout -b autosquash && + echo second >second.txt && + git add second.txt && + git commit -m "fixup! two_exec" && + echo bis >bis.txt && + git add bis.txt && + git commit -m "fixup! two_exec" && + ( + git checkout -b autosquash_actual && + git rebase -i --exec "git show HEAD" --autosquash HEAD~4 >actual + ) && + git checkout autosquash && + ( + git checkout -b autosquash_expected && + FAKE_LINES="1 fixup 3 fixup 4 exec_git_show_HEAD 2 exec_git_show_HEAD" && + export FAKE_LINES && + git rebase -i HEAD~4 >expect + ) && + sed -e "1,13d" expect >expected && + test_cmp expected actual +' + + +test_expect_success 'rebase --exec without -i shows error message' ' + git reset --hard execute && + test_must_fail git rebase --exec "git show HEAD" HEAD~2 2>actual && + echo "The --exec option must be used with the --interactive option" >expected && + test_i18ncmp expected actual +' + + +test_expect_success 'rebase -i --exec without <CMD>' ' + git reset --hard execute && + test_must_fail git rebase -i --exec 2>tmp && + sed -e "1d" tmp >actual && + test_must_fail git rebase -h >expected && + test_cmp expected actual && + git checkout master +' + +test_expect_success 'rebase -i --root re-order and drop commits' ' + git checkout E && + FAKE_LINES="3 1 2 5" git rebase -i --root && + test E = $(git cat-file commit HEAD | sed -ne \$p) && + test B = $(git cat-file commit HEAD^ | sed -ne \$p) && + test A = $(git cat-file commit HEAD^^ | sed -ne \$p) && + test C = $(git cat-file commit HEAD^^^ | sed -ne \$p) && + test 0 = $(git cat-file commit HEAD^^^ | grep -c ^parent\ ) +' + +test_expect_success 'rebase -i --root retain root commit author and message' ' + git checkout A && + echo B >file7 && + git add file7 && + GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" && + FAKE_LINES="2" git rebase -i --root && + git cat-file commit HEAD | grep -q "^author Twerp Snog" && + git cat-file commit HEAD | grep -q "^different author$" +' + +test_expect_success 'rebase -i --root temporary sentinel commit' ' + git checkout B && + ( + FAKE_LINES="2" && + export FAKE_LINES && + test_must_fail git rebase -i --root + ) && + git cat-file commit HEAD | grep "^tree 4b825dc642cb" && + git rebase --abort +' + +test_expect_success 'rebase -i --root fixup root commit' ' + git checkout B && + FAKE_LINES="1 fixup 2" git rebase -i --root && + test A = $(git cat-file commit HEAD | sed -ne \$p) && + test B = $(git show HEAD:file1) && + test 0 = $(git cat-file commit HEAD | grep -c ^parent\ ) +' + test_done diff --git a/t/t3405-rebase-malformed.sh b/t/t3405-rebase-malformed.sh index e5ad67c643..19eddadcf7 100755 --- a/t/t3405-rebase-malformed.sh +++ b/t/t3405-rebase-malformed.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='rebase should not insist on git message convention' +test_description='rebase should handle arbitrary git message' . ./test-lib.sh @@ -12,6 +12,11 @@ It has two paragraphs, but its first paragraph is not friendly to oneline summary format. EOF +cat >G <<\EOF +commit log message containing a diff +EOF + + test_expect_success setup ' >file1 && @@ -19,8 +24,9 @@ test_expect_success setup ' git add file1 file2 && test_tick && git commit -m "Initial commit" && + git branch diff-in-message - git checkout -b side && + git checkout -b multi-line-subject && cat F >file2 && git add file2 && test_tick && @@ -28,6 +34,17 @@ test_expect_success setup ' git cat-file commit HEAD | sed -e "1,/^\$/d" >F0 && + git checkout diff-in-message && + echo "commit log message containing a diff" >G && + echo "" >>G + cat G >file2 && + git add file2 && + git diff --cached >>G && + test_tick && + git commit -F G && + + git cat-file commit HEAD | sed -e "1,/^\$/d" >G0 && + git checkout master && echo One >file1 && @@ -36,13 +53,20 @@ test_expect_success setup ' git commit -m "Second commit" ' -test_expect_success rebase ' +test_expect_success 'rebase commit with multi-line subject' ' - git rebase master side && + git rebase master multi-line-subject && git cat-file commit HEAD | sed -e "1,/^\$/d" >F1 && test_cmp F0 F1 && test_cmp F F0 ' +test_expect_success 'rebase commit with diff in message' ' + git rebase master diff-in-message && + git cat-file commit HEAD | sed -e "1,/^$/d" >G1 && + test_cmp G0 G1 && + test_cmp G G0 +' + test_done diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh index fe5f936988..e6a9a0d436 100755 --- a/t/t3406-rebase-message.sh +++ b/t/t3406-rebase-message.sh @@ -62,4 +62,16 @@ test_expect_success 'rebase -n overrides config rebase.stat config' ' ! grep "^ fileX | *1 +$" diffstat.txt ' +# Output to stderr: +# +# "Does not point to a valid commit: invalid-ref" +# +# NEEDSWORK: This "grep" is fine in real non-C locales, but +# GETTEXT_POISON poisons the refname along with the enclosing +# error message. +test_expect_success 'rebase --onto outputs the invalid ref' ' + test_must_fail git rebase --onto invalid-ref HEAD HEAD 2>err && + test_i18ngrep "invalid-ref" err +' + test_done diff --git a/t/t3411-rebase-preserve-around-merges.sh b/t/t3411-rebase-preserve-around-merges.sh index ace8e54e9b..dc81bf27eb 100755 --- a/t/t3411-rebase-preserve-around-merges.sh +++ b/t/t3411-rebase-preserve-around-merges.sh @@ -56,6 +56,7 @@ test_expect_success 'squash F1 into D1' ' # And rebase G1..M1 onto E2 test_expect_success 'rebase two levels of merge' ' + git checkout A1 && test_commit G1 && test_commit H1 && test_commit I1 && diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh index 086c91c7b4..0b52105728 100755 --- a/t/t3412-rebase-root.sh +++ b/t/t3412-rebase-root.sh @@ -22,8 +22,9 @@ test_expect_success 'prepare repository' ' test_commit 4 B ' -test_expect_success 'rebase --root expects --onto' ' - test_must_fail git rebase --root +test_expect_success 'rebase --root fails with too many args' ' + git checkout -B fail other && + test_must_fail git rebase --onto master --root fail fail ' test_expect_success 'setup pre-rebase hook' ' @@ -42,7 +43,7 @@ cat > expect <<EOF EOF test_expect_success 'rebase --root --onto <newbase>' ' - git checkout -b work && + git checkout -b work other && git rebase --root --onto master && git log --pretty=tformat:"%s" > rebased && test_cmp expect rebased diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh index b38be8e937..a1e86c4097 100755 --- a/t/t3415-rebase-autosquash.sh +++ b/t/t3415-rebase-autosquash.sh @@ -33,7 +33,7 @@ test_auto_fixup () { test_tick && git rebase $2 -i HEAD^^^ && git log --oneline >actual && - test 3 = $(wc -l <actual) && + test_line_count = 3 actual && git diff --exit-code $1 && test 1 = "$(git cat-file blob HEAD^:file1)" && test 1 = $(git cat-file commit HEAD^ | grep first | wc -l) @@ -62,7 +62,7 @@ test_auto_squash () { test_tick && git rebase $2 -i HEAD^^^ && git log --oneline >actual && - test 3 = $(wc -l <actual) && + test_line_count = 3 actual && git diff --exit-code $1 && test 1 = "$(git cat-file blob HEAD^:file1)" && test 2 = $(git cat-file commit HEAD^ | grep first | wc -l) @@ -90,7 +90,7 @@ test_expect_success 'misspelled auto squash' ' test_tick && git rebase --autosquash -i HEAD^^^ && git log --oneline >actual && - test 4 = $(wc -l <actual) && + test_line_count = 4 actual && git diff --exit-code final-missquash && test 0 = $(git rev-list final-missquash...HEAD | wc -l) ' @@ -109,7 +109,7 @@ test_expect_success 'auto squash that matches 2 commits' ' test_tick && git rebase --autosquash -i HEAD~4 && git log --oneline >actual && - test 4 = $(wc -l <actual) && + test_line_count = 4 actual && git diff --exit-code final-multisquash && test 1 = "$(git cat-file blob HEAD^^:file1)" && test 2 = $(git cat-file commit HEAD^^ | grep first | wc -l) && @@ -130,7 +130,7 @@ test_expect_success 'auto squash that matches a commit after the squash' ' test_tick && git rebase --autosquash -i HEAD~4 && git log --oneline >actual && - test 5 = $(wc -l <actual) && + test_line_count = 5 actual && git diff --exit-code final-presquash && test 0 = "$(git cat-file blob HEAD^^:file1)" && test 1 = "$(git cat-file blob HEAD^:file1)" && @@ -147,7 +147,7 @@ test_expect_success 'auto squash that matches a sha1' ' test_tick && git rebase --autosquash -i HEAD^^^ && git log --oneline >actual && - test 3 = $(wc -l <actual) && + test_line_count = 3 actual && git diff --exit-code final-shasquash && test 1 = "$(git cat-file blob HEAD^:file1)" && test 1 = $(git cat-file commit HEAD^ | grep squash | wc -l) @@ -163,7 +163,7 @@ test_expect_success 'auto squash that matches longer sha1' ' test_tick && git rebase --autosquash -i HEAD^^^ && git log --oneline >actual && - test 3 = $(wc -l <actual) && + test_line_count = 3 actual && git diff --exit-code final-longshasquash && test 1 = "$(git cat-file blob HEAD^:file1)" && test 1 = $(git cat-file commit HEAD^ | grep squash | wc -l) @@ -179,7 +179,7 @@ test_auto_commit_flags () { test_tick && git rebase --autosquash -i HEAD^^^ && git log --oneline >actual && - test 3 = $(wc -l <actual) && + test_line_count = 3 actual && git diff --exit-code final-commit-$1 && test 1 = "$(git cat-file blob HEAD^:file1)" && test $2 = $(git cat-file commit HEAD^ | grep first | wc -l) diff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh index c10b28cf57..5a1340cee6 100755 --- a/t/t3505-cherry-pick-empty.sh +++ b/t/t3505-cherry-pick-empty.sh @@ -18,7 +18,12 @@ test_expect_success setup ' echo third >> file1 && git add file1 && test_tick && - git commit --allow-empty-message -m "" + git commit --allow-empty-message -m "" && + + git checkout master && + git checkout -b empty-branch2 && + test_tick && + git commit --allow-empty -m "empty" ' @@ -48,4 +53,52 @@ test_expect_success 'index lockfile was removed' ' ' +test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' ' + git checkout master && + echo fourth >>file2 && + git add file2 && + git commit -m "fourth" && + test_must_fail git cherry-pick empty-branch2 +' + +test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' ' + git checkout master && + git cherry-pick --allow-empty empty-branch2 +' + +test_expect_success 'cherry pick with --keep-redundant-commits' ' + git checkout master && + git cherry-pick --keep-redundant-commits HEAD^ +' + +test_expect_success 'cherry-pick a commit that becomes no-op (prep)' ' + git checkout master && + git branch fork && + echo foo >file2 && + git add file2 && + test_tick && + git commit -m "add file2 on master" && + + git checkout fork && + echo foo >file2 && + git add file2 && + test_tick && + git commit -m "add file2 on the side" +' + +test_expect_success 'cherry-pick a no-op without --keep-redundant' ' + git reset --hard && + git checkout fork^0 && + test_must_fail git cherry-pick master +' + +test_expect_success 'cherry-pick a no-op with --keep-redundant' ' + git reset --hard && + git checkout fork^0 && + git cherry-pick --keep-redundant-commits master && + git show -s --format='%s' >actual && + echo "add file2 on master" >expect && + test_cmp expect actual +' + test_done diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh index ee1659c178..0c81b3c427 100755 --- a/t/t3507-cherry-pick-conflict.sh +++ b/t/t3507-cherry-pick-conflict.sh @@ -59,6 +59,20 @@ test_expect_success 'advice from failed cherry-pick' " test_i18ncmp expected actual " +test_expect_success 'advice from failed cherry-pick --no-commit' " + pristine_detach initial && + + picked=\$(git rev-parse --short picked) && + cat <<-EOF >expected && + error: could not apply \$picked... picked + hint: after resolving the conflicts, mark the corrected paths + hint: with 'git add <paths>' or 'git rm <paths>' + EOF + test_must_fail git cherry-pick --no-commit picked 2>actual && + + test_i18ncmp expected actual +" + test_expect_success 'failed cherry-pick sets CHERRY_PICK_HEAD' ' pristine_detach initial && test_must_fail git cherry-pick picked && diff --git a/t/t3508-cherry-pick-many-commits.sh b/t/t3508-cherry-pick-many-commits.sh index 1b3a344158..75f7ff4f2f 100755 --- a/t/t3508-cherry-pick-many-commits.sh +++ b/t/t3508-cherry-pick-many-commits.sh @@ -35,6 +35,16 @@ test_expect_success setup ' ' test_expect_success 'cherry-pick first..fourth works' ' + git checkout -f master && + git reset --hard first && + test_tick && + git cherry-pick first..fourth && + git diff --quiet other && + git diff --quiet HEAD other && + check_head_differs_from fourth +' + +test_expect_success 'output to keep user entertained during multi-pick' ' cat <<-\EOF >expected && [master OBJID] second Author: A U Thor <author@example.com> @@ -51,15 +61,22 @@ test_expect_success 'cherry-pick first..fourth works' ' git reset --hard first && test_tick && git cherry-pick first..fourth >actual && + sed -e "s/$_x05[0-9a-f][0-9a-f]/OBJID/" <actual >actual.fuzzy && + test_line_count -ge 3 actual.fuzzy && + test_i18ncmp expected actual.fuzzy +' + +test_expect_success 'cherry-pick --strategy resolve first..fourth works' ' + git checkout -f master && + git reset --hard first && + test_tick && + git cherry-pick --strategy resolve first..fourth && git diff --quiet other && git diff --quiet HEAD other && - - sed -e "s/$_x05[0-9a-f][0-9a-f]/OBJID/" <actual >actual.fuzzy && - test_cmp expected actual.fuzzy && check_head_differs_from fourth ' -test_expect_success 'cherry-pick --strategy resolve first..fourth works' ' +test_expect_success 'output during multi-pick indicates merge strategy' ' cat <<-\EOF >expected && Trying simple merge. [master OBJID] second @@ -79,11 +96,8 @@ test_expect_success 'cherry-pick --strategy resolve first..fourth works' ' git reset --hard first && test_tick && git cherry-pick --strategy resolve first..fourth >actual && - git diff --quiet other && - git diff --quiet HEAD other && sed -e "s/$_x05[0-9a-f][0-9a-f]/OBJID/" <actual >actual.fuzzy && - test_cmp expected actual.fuzzy && - check_head_differs_from fourth + test_i18ncmp expected actual.fuzzy ' test_expect_success 'cherry-pick --ff first..fourth works' ' diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh index 97f3710700..f4e6450d6a 100755 --- a/t/t3510-cherry-pick-sequence.sh +++ b/t/t3510-cherry-pick-sequence.sh @@ -31,7 +31,7 @@ test_cmp_rev () { } test_expect_success setup ' - git config advice.detachedhead false + git config advice.detachedhead false && echo unrelated >unrelated && git add unrelated && test_commit initial foo a && diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh index 9e236f9cc0..098a6ae4a0 100755 --- a/t/t3701-add-interactive.sh +++ b/t/t3701-add-interactive.sh @@ -330,4 +330,30 @@ test_expect_success PERL 'split hunk "add -p (edit)"' ' ! grep "^+15" actual ' +test_expect_success 'patch mode ignores unmerged entries' ' + git reset --hard && + test_commit conflict && + test_commit non-conflict && + git checkout -b side && + test_commit side conflict.t && + git checkout master && + test_commit master conflict.t && + test_must_fail git merge side && + echo changed >non-conflict.t && + echo y | git add -p >output && + ! grep a/conflict.t output && + cat >expected <<-\EOF && + * Unmerged path conflict.t + diff --git a/non-conflict.t b/non-conflict.t + index f766221..5ea2ed4 100644 + --- a/non-conflict.t + +++ b/non-conflict.t + @@ -1 +1 @@ + -non-conflict + +changed + EOF + git diff --cached >diff && + test_cmp expected diff +' + test_done diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh index d48a7c002d..37ddabba2d 100755 --- a/t/t3900-i18n-commit.sh +++ b/t/t3900-i18n-commit.sh @@ -160,7 +160,7 @@ test_commit_autosquash_flags () { git config --unset-all i18n.commitencoding && git rebase --autosquash -i HEAD^^^ && git log --oneline >actual && - test 3 = $(wc -l <actual) + test_line_count = 3 actual ' } diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index 663c60a12e..cd042633ba 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -432,7 +432,7 @@ test_expect_success 'stash branch - stashes on stack, stash-like argument' ' test $(git ls-files --modified | wc -l) -eq 1 ' -test_expect_success 'stash show - stashes on stack, stash-like argument' ' +test_expect_success 'stash show format defaults to --stat' ' git stash clear && test_when_finished "git reset --hard HEAD" && git reset --hard && @@ -443,10 +443,25 @@ test_expect_success 'stash show - stashes on stack, stash-like argument' ' STASH_ID=$(git stash create) && git reset --hard && cat >expected <<-EOF && - file | 1 + + file | 1 + 1 file changed, 1 insertion(+) EOF git stash show ${STASH_ID} >actual && + test_i18ncmp expected actual +' + +test_expect_success 'stash show - stashes on stack, stash-like argument' ' + git stash clear && + test_when_finished "git reset --hard HEAD" && + git reset --hard && + echo foo >> file && + git stash && + test_when_finished "git stash drop" && + echo bar >> file && + STASH_ID=$(git stash create) && + git reset --hard && + echo "1 0 file" >expected && + git stash show --numstat ${STASH_ID} >actual && test_cmp expected actual ' @@ -480,11 +495,8 @@ test_expect_success 'stash show - no stashes on stack, stash-like argument' ' echo foo >> file && STASH_ID=$(git stash create) && git reset --hard && - cat >expected <<-EOF && - file | 1 + - 1 file changed, 1 insertion(+) - EOF - git stash show ${STASH_ID} >actual && + echo "1 0 file" >expected && + git stash show --numstat ${STASH_ID} >actual && test_cmp expected actual ' diff --git a/t/t3910-mac-os-precompose.sh b/t/t3910-mac-os-precompose.sh new file mode 100755 index 0000000000..5fe57c5438 --- /dev/null +++ b/t/t3910-mac-os-precompose.sh @@ -0,0 +1,153 @@ +#!/bin/sh +# +# Copyright (c) 2012 Torsten Bögershausen +# + +test_description='utf-8 decomposed (nfd) converted to precomposed (nfc)' + +. ./test-lib.sh + +if ! test_have_prereq UTF8_NFD_TO_NFC +then + skip_all="filesystem does not corrupt utf-8" + test_done +fi + +# create utf-8 variables +Adiarnfc=`printf '\303\204'` +Adiarnfd=`printf 'A\314\210'` + +Odiarnfc=`printf '\303\226'` +Odiarnfd=`printf 'O\314\210'` +AEligatu=`printf '\303\206'` +Invalidu=`printf '\303\377'` + + +#Create a string with 255 bytes (decomposed) +Alongd=$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd #21 Byte +Alongd=$Alongd$Alongd$Alongd #63 Byte +Alongd=$Alongd$Alongd$Alongd$Alongd$Adiarnfd #255 Byte + +#Create a string with 254 bytes (precomposed) +Alongc=$AEligatu$AEligatu$AEligatu$AEligatu$AEligatu #10 Byte +Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc #50 Byte +Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc #250 Byte +Alongc=$Alongc$AEligatu$AEligatu #254 Byte + +test_expect_success "detect if nfd needed" ' + precomposeunicode=`git config core.precomposeunicode` && + test "$precomposeunicode" = false && + git config core.precomposeunicode true +' +test_expect_success "setup" ' + >x && + git add x && + git commit -m "1st commit" && + git rm x && + git commit -m "rm x" +' +test_expect_success "setup case mac" ' + git checkout -b mac_os +' +# This will test nfd2nfc in readdir() +test_expect_success "add file Adiarnfc" ' + echo f.Adiarnfc >f.$Adiarnfc && + git add f.$Adiarnfc && + git commit -m "add f.$Adiarnfc" +' +# This will test nfd2nfc in git stage() +test_expect_success "stage file d.Adiarnfd/f.Adiarnfd" ' + mkdir d.$Adiarnfd && + echo d.$Adiarnfd/f.$Adiarnfd >d.$Adiarnfd/f.$Adiarnfd && + git stage d.$Adiarnfd/f.$Adiarnfd && + git commit -m "add d.$Adiarnfd/f.$Adiarnfd" +' +test_expect_success "add link Adiarnfc" ' + ln -s d.$Adiarnfd/f.$Adiarnfd l.$Adiarnfc && + git add l.$Adiarnfc && + git commit -m "add l.Adiarnfc" +' +# This will test git log +test_expect_success "git log f.Adiar" ' + git log f.$Adiarnfc > f.Adiarnfc.log && + git log f.$Adiarnfd > f.Adiarnfd.log && + test -s f.Adiarnfc.log && + test -s f.Adiarnfd.log && + test_cmp f.Adiarnfc.log f.Adiarnfd.log && + rm f.Adiarnfc.log f.Adiarnfd.log +' +# This will test git ls-files +test_expect_success "git lsfiles f.Adiar" ' + git ls-files f.$Adiarnfc > f.Adiarnfc.log && + git ls-files f.$Adiarnfd > f.Adiarnfd.log && + test -s f.Adiarnfc.log && + test -s f.Adiarnfd.log && + test_cmp f.Adiarnfc.log f.Adiarnfd.log && + rm f.Adiarnfc.log f.Adiarnfd.log +' +# This will test git mv +test_expect_success "git mv" ' + git mv f.$Adiarnfd f.$Odiarnfc && + git mv d.$Adiarnfd d.$Odiarnfc && + git mv l.$Adiarnfd l.$Odiarnfc && + git commit -m "mv Adiarnfd Odiarnfc" +' +# Files can be checked out as nfc +# And the link has been corrected from nfd to nfc +test_expect_success "git checkout nfc" ' + rm f.$Odiarnfc && + git checkout f.$Odiarnfc +' +# Make it possible to checkout files with their NFD names +test_expect_success "git checkout file nfd" ' + rm -f f.* && + git checkout f.$Odiarnfd +' +# Make it possible to checkout links with their NFD names +test_expect_success "git checkout link nfd" ' + rm l.* && + git checkout l.$Odiarnfd +' +test_expect_success "setup case mac2" ' + git checkout master && + git reset --hard && + git checkout -b mac_os_2 +' +# This will test nfd2nfc in git commit +test_expect_success "commit file d2.Adiarnfd/f.Adiarnfd" ' + mkdir d2.$Adiarnfd && + echo d2.$Adiarnfd/f.$Adiarnfd >d2.$Adiarnfd/f.$Adiarnfd && + git add d2.$Adiarnfd/f.$Adiarnfd && + git commit -m "add d2.$Adiarnfd/f.$Adiarnfd" -- d2.$Adiarnfd/f.$Adiarnfd +' +test_expect_success "setup for long decomposed filename" ' + git checkout master && + git reset --hard && + git checkout -b mac_os_long_nfd_fn +' +test_expect_success "Add long decomposed filename" ' + echo longd >$Alongd && + git add * && + git commit -m "Long filename" +' +test_expect_success "setup for long precomposed filename" ' + git checkout master && + git reset --hard && + git checkout -b mac_os_long_nfc_fn +' +test_expect_success "Add long precomposed filename" ' + echo longc >$Alongc && + git add * && + git commit -m "Long filename" +' +# Test if the global core.precomposeunicode stops autosensing +# Must be the last test case +test_expect_success "respect git config --global core.precomposeunicode" ' + git config --global core.precomposeunicode true && + rm -rf .git && + git init && + precomposeunicode=`git config core.precomposeunicode` && + test "$precomposeunicode" = "true" +' + +test_done diff --git a/t/t4006-diff-mode.sh b/t/t4006-diff-mode.sh index ff8c2f7532..7a3e1f9a24 100755 --- a/t/t4006-diff-mode.sh +++ b/t/t4006-diff-mode.sh @@ -8,23 +8,52 @@ test_description='Test mode change diffs. ' . ./test-lib.sh -test_expect_success \ - 'setup' \ - 'echo frotz >rezrov && - git update-index --add rezrov && - tree=`git write-tree` && - echo $tree' - -test_expect_success \ - 'chmod' \ - 'test_chmod +x rezrov && - git diff-index $tree >current' - -sed -e 's/\(:100644 100755\) \('"$_x40"'\) \2 /\1 X X /' <current >check -echo ":100644 100755 X X M rezrov" >expected - -test_expect_success \ - 'verify' \ - 'test_cmp expected check' +sed_script='s/\(:100644 100755\) \('"$_x40"'\) \2 /\1 X X /' + +test_expect_success 'setup' ' + echo frotz >rezrov && + git update-index --add rezrov && + tree=`git write-tree` && + echo $tree +' + +test_expect_success 'chmod' ' + test_chmod +x rezrov && + git diff-index $tree >current && + sed -e "$sed_script" <current >check && + echo ":100644 100755 X X M rezrov" >expected && + test_cmp expected check +' + +test_expect_success 'prepare binary file' ' + git commit -m rezrov && + printf "\00\01\02\03\04\05\06" >binbin && + git add binbin && + git commit -m binbin +' + +test_expect_success '--stat output after text chmod' ' + test_chmod -x rezrov && + echo " 0 files changed" >expect && + git diff HEAD --stat >actual && + test_cmp expect actual +' + +test_expect_success '--shortstat output after text chmod' ' + git diff HEAD --shortstat >actual && + test_cmp expect actual +' + +test_expect_success '--stat output after binary chmod' ' + test_chmod +x binbin && + echo " 0 files changed" >expect && + git diff HEAD --stat >actual && + test_cmp expect actual +' + +test_expect_success '--shortstat output after binary chmod' ' + git diff HEAD --shortstat >actual && + test_cmp expect actual +' test_done diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh index 2d9f9a0cf1..ec4deea192 100755 --- a/t/t4012-diff-binary.sh +++ b/t/t4012-diff-binary.sh @@ -8,13 +8,21 @@ test_description='Binary diff and apply . ./test-lib.sh -test_expect_success 'prepare repository' \ - 'echo AIT >a && echo BIT >b && echo CIT >c && echo DIT >d && - git update-index --add a b c d && - echo git >a && - cat "$TEST_DIRECTORY"/test-binary-1.png >b && - echo git >c && - cat b b >d' +cat >expect.binary-numstat <<\EOF +1 1 a +- - b +1 1 c +- - d +EOF + +test_expect_success 'prepare repository' ' + echo AIT >a && echo BIT >b && echo CIT >c && echo DIT >d && + git update-index --add a b c d && + echo git >a && + cat "$TEST_DIRECTORY"/test-binary-1.png >b && + echo git >c && + cat b b >d +' cat > expected <<\EOF a | 2 +- @@ -23,59 +31,74 @@ cat > expected <<\EOF d | Bin 4 files changed, 2 insertions(+), 2 deletions(-) EOF -test_expect_success 'diff without --binary' \ - 'git diff | git apply --stat --summary >current && - test_cmp expected current' +test_expect_success 'apply --stat output for binary file change' ' + git diff >diff && + git apply --stat --summary <diff >current && + test_i18ncmp expected current +' + +test_expect_success 'diff --shortstat output for binary file change' ' + tail -n 1 expected >expect && + git diff --shortstat >current && + test_i18ncmp expect current +' -test_expect_success 'diff with --binary' \ - 'git diff --binary | git apply --stat --summary >current && - test_cmp expected current' +test_expect_success 'diff --shortstat output for binary file change only' ' + echo " 1 file changed, 0 insertions(+), 0 deletions(-)" >expected && + git diff --shortstat -- b >current && + test_i18ncmp expected current +' + +test_expect_success 'apply --numstat notices binary file change' ' + git diff >diff && + git apply --numstat <diff >current && + test_cmp expect.binary-numstat current +' + +test_expect_success 'apply --numstat understands diff --binary format' ' + git diff --binary >diff && + git apply --numstat <diff >current && + test_cmp expect.binary-numstat current +' # apply needs to be able to skip the binary material correctly # in order to report the line number of a corrupt patch. -test_expect_success 'apply detecting corrupt patch correctly' \ - 'git diff | sed -e 's/-CIT/xCIT/' >broken && - if git apply --stat --summary broken 2>detected - then - echo unhappy - should have detected an error - (exit 1) - else - echo happy - fi && - detected=`cat detected` && - detected=`expr "$detected" : "fatal.*at line \\([0-9]*\\)\$"` && - detected=`sed -ne "${detected}p" broken` && - test "$detected" = xCIT' - -test_expect_success 'apply detecting corrupt patch correctly' \ - 'git diff --binary | sed -e 's/-CIT/xCIT/' >broken && - if git apply --stat --summary broken 2>detected - then - echo unhappy - should have detected an error - (exit 1) - else - echo happy - fi && - detected=`cat detected` && - detected=`expr "$detected" : "fatal.*at line \\([0-9]*\\)\$"` && - detected=`sed -ne "${detected}p" broken` && - test "$detected" = xCIT' +test_expect_success 'apply detecting corrupt patch correctly' ' + git diff >output && + sed -e "s/-CIT/xCIT/" <output >broken && + test_must_fail git apply --stat --summary broken 2>detected && + detected=`cat detected` && + detected=`expr "$detected" : "fatal.*at line \\([0-9]*\\)\$"` && + detected=`sed -ne "${detected}p" broken` && + test "$detected" = xCIT +' + +test_expect_success 'apply detecting corrupt patch correctly' ' + git diff --binary | sed -e "s/-CIT/xCIT/" >broken && + test_must_fail git apply --stat --summary broken 2>detected && + detected=`cat detected` && + detected=`expr "$detected" : "fatal.*at line \\([0-9]*\\)\$"` && + detected=`sed -ne "${detected}p" broken` && + test "$detected" = xCIT +' test_expect_success 'initial commit' 'git commit -a -m initial' # Try removal (b), modification (d), and creation (e). -test_expect_success 'diff-index with --binary' \ - 'echo AIT >a && mv b e && echo CIT >c && cat e >d && - git update-index --add --remove a b c d e && - tree0=`git write-tree` && - git diff --cached --binary >current && - git apply --stat --summary current' - -test_expect_success 'apply binary patch' \ - 'git reset --hard && - git apply --binary --index <current && - tree1=`git write-tree` && - test "$tree1" = "$tree0"' +test_expect_success 'diff-index with --binary' ' + echo AIT >a && mv b e && echo CIT >c && cat e >d && + git update-index --add --remove a b c d e && + tree0=`git write-tree` && + git diff --cached --binary >current && + git apply --stat --summary current +' + +test_expect_success 'apply binary patch' ' + git reset --hard && + git apply --binary --index <current && + tree1=`git write-tree` && + test "$tree1" = "$tree0" +' test_expect_success 'diff --no-index with binary creation' ' echo Q | q_to_nul >binary && @@ -90,4 +113,23 @@ test_expect_success 'diff --no-index with binary creation' ' test_cmp expected actual ' +cat >expect <<EOF + binfile | Bin 0 -> 1026 bytes + textfile | 10000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +EOF + +test_expect_success 'diff --stat with binary files and big change count' ' + printf "\01\00%1024d" 1 >binfile && + git add binfile && + i=0 && + while test $i -lt 10000; do + echo $i && + i=$(($i + 1)) + done >textfile && + git add textfile && + git diff --cached --stat binfile textfile >output && + grep " | " output >actual && + test_cmp expect actual +' + test_done diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index 93a6f20871..e77c09c37e 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -128,7 +128,12 @@ do } >"$actual" && if test -f "$expect" then - test_cmp "$expect" "$actual" && + case $cmd in + *format-patch* | *-stat*) + test_i18ncmp "$expect" "$actual";; + *) + test_cmp "$expect" "$actual";; + esac && rm -f "$actual" else # this is to help developing new tests. diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master index 2f8560c369..9951e3677d 100644 --- a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master +++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master @@ -1,7 +1,7 @@ $ git diff-tree --cc --patch-with-stat --summary master 59d314ad6f356dd08601a4cd5e530381da3e3c64 - dir/sub | 2 ++ - file0 | 3 +++ + dir/sub | 2 ++ + file0 | 3 +++ 2 files changed, 5 insertions(+) diff --cc dir/sub diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side index 72e03c14fb..cec33fa3f0 100644 --- a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side +++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side @@ -1,8 +1,8 @@ $ git diff-tree --cc --patch-with-stat --summary side c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master index 8b357d964b..db3c0a7b2c 100644 --- a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master +++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master @@ -1,7 +1,7 @@ $ git diff-tree --cc --patch-with-stat master 59d314ad6f356dd08601a4cd5e530381da3e3c64 - dir/sub | 2 ++ - file0 | 3 +++ + dir/sub | 2 ++ + file0 | 3 +++ 2 files changed, 5 insertions(+) diff --cc dir/sub diff --git a/t/t4013/diff.diff-tree_--cc_--stat_--summary_master b/t/t4013/diff.diff-tree_--cc_--stat_--summary_master index e0568d6883..d019867dd9 100644 --- a/t/t4013/diff.diff-tree_--cc_--stat_--summary_master +++ b/t/t4013/diff.diff-tree_--cc_--stat_--summary_master @@ -1,6 +1,6 @@ $ git diff-tree --cc --stat --summary master 59d314ad6f356dd08601a4cd5e530381da3e3c64 - dir/sub | 2 ++ - file0 | 3 +++ + dir/sub | 2 ++ + file0 | 3 +++ 2 files changed, 5 insertions(+) $ diff --git a/t/t4013/diff.diff-tree_--cc_--stat_--summary_side b/t/t4013/diff.diff-tree_--cc_--stat_--summary_side index 5afc8239a1..12b2eee17e 100644 --- a/t/t4013/diff.diff-tree_--cc_--stat_--summary_side +++ b/t/t4013/diff.diff-tree_--cc_--stat_--summary_side @@ -1,8 +1,8 @@ $ git diff-tree --cc --stat --summary side c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 file3 $ diff --git a/t/t4013/diff.diff-tree_--cc_--stat_master b/t/t4013/diff.diff-tree_--cc_--stat_master index f48367a89a..40b91796b3 100644 --- a/t/t4013/diff.diff-tree_--cc_--stat_master +++ b/t/t4013/diff.diff-tree_--cc_--stat_master @@ -1,6 +1,6 @@ $ git diff-tree --cc --stat master 59d314ad6f356dd08601a4cd5e530381da3e3c64 - dir/sub | 2 ++ - file0 | 3 +++ + dir/sub | 2 ++ + file0 | 3 +++ 2 files changed, 5 insertions(+) $ diff --git a/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial index 590864c2d7..817ed06f82 100644 --- a/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial +++ b/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial @@ -1,8 +1,8 @@ $ git diff-tree --pretty=oneline --root --patch-with-stat initial 444ac553ac7612cc88969031b02b3767fb8a353a Initial - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 +++ + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ 3 files changed, 8 insertions(+) diff --git a/dir/sub b/dir/sub diff --git a/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side b/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side index e05e77875c..fe3f6b7c7e 100644 --- a/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side +++ b/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side @@ -5,9 +5,9 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/dir/sub b/dir/sub diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial index 0e2c956633..06eb77e386 100644 --- a/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial +++ b/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial @@ -5,9 +5,9 @@ Date: Mon Jun 26 00:00:00 2006 +0000 Initial --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 +++ + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ 3 files changed, 8 insertions(+) diff --git a/dir/sub b/dir/sub diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial b/t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial index 384fa44ddd..680eab5f27 100644 --- a/t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial +++ b/t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial @@ -5,9 +5,9 @@ Date: Mon Jun 26 00:00:00 2006 +0000 Initial - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 +++ + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ 3 files changed, 8 insertions(+) create mode 100644 dir/sub create mode 100644 file0 diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--stat_initial b/t/t4013/diff.diff-tree_--pretty_--root_--stat_initial index 10384a83d3..9722d1b3a7 100644 --- a/t/t4013/diff.diff-tree_--pretty_--root_--stat_initial +++ b/t/t4013/diff.diff-tree_--pretty_--root_--stat_initial @@ -5,8 +5,8 @@ Date: Mon Jun 26 00:00:00 2006 +0000 Initial - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 +++ + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ 3 files changed, 8 insertions(+) $ diff --git a/t/t4013/diff.diff-tree_--root_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--root_--patch-with-stat_initial index f57062ea07..ad69ffe647 100644 --- a/t/t4013/diff.diff-tree_--root_--patch-with-stat_initial +++ b/t/t4013/diff.diff-tree_--root_--patch-with-stat_initial @@ -1,8 +1,8 @@ $ git diff-tree --root --patch-with-stat initial 444ac553ac7612cc88969031b02b3767fb8a353a - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 +++ + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ 3 files changed, 8 insertions(+) diff --git a/dir/sub b/dir/sub diff --git a/t/t4013/diff.diff-tree_-c_--stat_--summary_master b/t/t4013/diff.diff-tree_-c_--stat_--summary_master index 7088683444..81c3021541 100644 --- a/t/t4013/diff.diff-tree_-c_--stat_--summary_master +++ b/t/t4013/diff.diff-tree_-c_--stat_--summary_master @@ -1,6 +1,6 @@ $ git diff-tree -c --stat --summary master 59d314ad6f356dd08601a4cd5e530381da3e3c64 - dir/sub | 2 ++ - file0 | 3 +++ + dir/sub | 2 ++ + file0 | 3 +++ 2 files changed, 5 insertions(+) $ diff --git a/t/t4013/diff.diff-tree_-c_--stat_--summary_side b/t/t4013/diff.diff-tree_-c_--stat_--summary_side index ef216abb1d..e8dc12bfbf 100644 --- a/t/t4013/diff.diff-tree_-c_--stat_--summary_side +++ b/t/t4013/diff.diff-tree_-c_--stat_--summary_side @@ -1,8 +1,8 @@ $ git diff-tree -c --stat --summary side c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 file3 $ diff --git a/t/t4013/diff.diff-tree_-c_--stat_master b/t/t4013/diff.diff-tree_-c_--stat_master index ad19f103eb..89d59b1548 100644 --- a/t/t4013/diff.diff-tree_-c_--stat_master +++ b/t/t4013/diff.diff-tree_-c_--stat_master @@ -1,6 +1,6 @@ $ git diff-tree -c --stat master 59d314ad6f356dd08601a4cd5e530381da3e3c64 - dir/sub | 2 ++ - file0 | 3 +++ + dir/sub | 2 ++ + file0 | 3 +++ 2 files changed, 5 insertions(+) $ diff --git a/t/t4013/diff.diff_--patch-with-stat_-r_initial..side b/t/t4013/diff.diff_--patch-with-stat_-r_initial..side index ddad917ae8..be8d1ea1bd 100644 --- a/t/t4013/diff.diff_--patch-with-stat_-r_initial..side +++ b/t/t4013/diff.diff_--patch-with-stat_-r_initial..side @@ -1,7 +1,7 @@ $ git diff --patch-with-stat -r initial..side - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/dir/sub b/dir/sub diff --git a/t/t4013/diff.diff_--patch-with-stat_initial..side b/t/t4013/diff.diff_--patch-with-stat_initial..side index bdbd114d8e..5424e6d566 100644 --- a/t/t4013/diff.diff_--patch-with-stat_initial..side +++ b/t/t4013/diff.diff_--patch-with-stat_initial..side @@ -1,7 +1,7 @@ $ git diff --patch-with-stat initial..side - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/dir/sub b/dir/sub diff --git a/t/t4013/diff.diff_--stat_initial..side b/t/t4013/diff.diff_--stat_initial..side index 6d08f3d355..b7741e2b83 100644 --- a/t/t4013/diff.diff_--stat_initial..side +++ b/t/t4013/diff.diff_--stat_initial..side @@ -1,6 +1,6 @@ $ git diff --stat initial..side - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) $ diff --git a/t/t4013/diff.diff_-r_--stat_initial..side b/t/t4013/diff.diff_-r_--stat_initial..side index 2ddb2540e6..5d514f55b9 100644 --- a/t/t4013/diff.diff_-r_--stat_initial..side +++ b/t/t4013/diff.diff_-r_--stat_initial..side @@ -1,6 +1,6 @@ $ git diff -r --stat initial..side - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) $ diff --git a/t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side b/t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side index 3cab049f7d..547ca065a5 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side +++ b/t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side @@ -12,9 +12,9 @@ Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master b/t/t4013/diff.format-patch_--attach_--stdout_initial..master index 564a4d38f2..52fedc179e 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_initial..master +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master @@ -14,9 +14,9 @@ Content-Transfer-Encoding: 8bit This is the second commit. --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 --- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- 3 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 file2 @@ -73,8 +73,8 @@ Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit --- - dir/sub | 2 ++ - file1 | 3 +++ + dir/sub | 2 ++ + file1 | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 file1 @@ -121,9 +121,9 @@ Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ index 4f28460b83..1c3cde251b 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ @@ -14,9 +14,9 @@ Content-Transfer-Encoding: 8bit This is the second commit. --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 --- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- 3 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 file2 @@ -73,8 +73,8 @@ Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit --- - dir/sub | 2 ++ - file1 | 3 +++ + dir/sub | 2 ++ + file1 | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 file1 diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..side b/t/t4013/diff.format-patch_--attach_--stdout_initial..side index b10cc2e251..4717bd8313 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_initial..side +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..side @@ -12,9 +12,9 @@ Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master b/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master index a976a8aaf4..02c4db7ec5 100644 --- a/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master +++ b/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master @@ -14,9 +14,9 @@ Content-Transfer-Encoding: 8bit This is the second commit. --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 --- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- 3 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 file2 @@ -73,8 +73,8 @@ Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit --- - dir/sub | 2 ++ - file1 | 3 +++ + dir/sub | 2 ++ + file1 | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 file1 @@ -121,9 +121,9 @@ Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master b/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master index b4fd66477a..c7677c5951 100644 --- a/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master +++ b/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master @@ -14,9 +14,9 @@ Content-Transfer-Encoding: 8bit This is the second commit. --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 --- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- 3 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 file2 @@ -73,8 +73,8 @@ Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit --- - dir/sub | 2 ++ - file1 | 3 +++ + dir/sub | 2 ++ + file1 | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 file1 @@ -121,9 +121,9 @@ Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..master b/t/t4013/diff.format-patch_--inline_--stdout_initial..master index 0d31036e7f..5b3e34e2c0 100644 --- a/t/t4013/diff.format-patch_--inline_--stdout_initial..master +++ b/t/t4013/diff.format-patch_--inline_--stdout_initial..master @@ -14,9 +14,9 @@ Content-Transfer-Encoding: 8bit This is the second commit. --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 --- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- 3 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 file2 @@ -73,8 +73,8 @@ Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit --- - dir/sub | 2 ++ - file1 | 3 +++ + dir/sub | 2 ++ + file1 | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 file1 @@ -121,9 +121,9 @@ Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..master^ b/t/t4013/diff.format-patch_--inline_--stdout_initial..master^ index 18d4714423..d13f8a8128 100644 --- a/t/t4013/diff.format-patch_--inline_--stdout_initial..master^ +++ b/t/t4013/diff.format-patch_--inline_--stdout_initial..master^ @@ -14,9 +14,9 @@ Content-Transfer-Encoding: 8bit This is the second commit. --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 --- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- 3 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 file2 @@ -73,8 +73,8 @@ Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit --- - dir/sub | 2 ++ - file1 | 3 +++ + dir/sub | 2 ++ + file1 | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 file1 diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..master^^ b/t/t4013/diff.format-patch_--inline_--stdout_initial..master^^ index 29e00ab8af..caec5537de 100644 --- a/t/t4013/diff.format-patch_--inline_--stdout_initial..master^^ +++ b/t/t4013/diff.format-patch_--inline_--stdout_initial..master^^ @@ -14,9 +14,9 @@ Content-Transfer-Encoding: 8bit This is the second commit. --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 --- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- 3 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 file2 diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..side b/t/t4013/diff.format-patch_--inline_--stdout_initial..side index 3572f20b5d..d3a6762130 100644 --- a/t/t4013/diff.format-patch_--inline_--stdout_initial..side +++ b/t/t4013/diff.format-patch_--inline_--stdout_initial..side @@ -12,9 +12,9 @@ Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^ b/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^ index 54cdcdab40..244d964fc6 100644 --- a/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^ +++ b/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^ @@ -10,10 +10,10 @@ A U Thor (2): Second Third - dir/sub | 4 ++++ - file0 | 3 +++ - file1 | 3 +++ - file2 | 3 --- + dir/sub | 4 ++++ + file0 | 3 +++ + file1 | 3 +++ + file2 | 3 --- 4 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 file1 delete mode 100644 file2 @@ -28,9 +28,9 @@ Subject: [DIFFERENT_PREFIX 1/2] Second This is the second commit. --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 --- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- 3 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 file2 @@ -73,8 +73,8 @@ Date: Mon, 26 Jun 2006 00:02:00 +0000 Subject: [DIFFERENT_PREFIX 2/2] Third --- - dir/sub | 2 ++ - file1 | 3 +++ + dir/sub | 2 ++ + file1 | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 file1 diff --git a/t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master b/t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master index 23194ebdaa..bfc287a147 100644 --- a/t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master +++ b/t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master @@ -6,9 +6,9 @@ Subject: [PATCH] Second This is the second commit. --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 --- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- 3 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 file2 @@ -51,8 +51,8 @@ Date: Mon, 26 Jun 2006 00:02:00 +0000 Subject: [PATCH] Third --- - dir/sub | 2 ++ - file1 | 3 +++ + dir/sub | 2 ++ + file1 | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 file1 @@ -85,9 +85,9 @@ Date: Mon, 26 Jun 2006 00:03:00 +0000 Subject: [PATCH] Side --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/t/t4013/diff.format-patch_--stdout_--numbered_initial..master b/t/t4013/diff.format-patch_--stdout_--numbered_initial..master index 78f1a80a97..568f6f584e 100644 --- a/t/t4013/diff.format-patch_--stdout_--numbered_initial..master +++ b/t/t4013/diff.format-patch_--stdout_--numbered_initial..master @@ -6,9 +6,9 @@ Subject: [PATCH 1/3] Second This is the second commit. --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 --- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- 3 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 file2 @@ -51,8 +51,8 @@ Date: Mon, 26 Jun 2006 00:02:00 +0000 Subject: [PATCH 2/3] Third --- - dir/sub | 2 ++ - file1 | 3 +++ + dir/sub | 2 ++ + file1 | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 file1 @@ -85,9 +85,9 @@ Date: Mon, 26 Jun 2006 00:03:00 +0000 Subject: [PATCH 3/3] Side --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/t/t4013/diff.format-patch_--stdout_initial..master b/t/t4013/diff.format-patch_--stdout_initial..master index a3dab7f773..5f0352f9f7 100644 --- a/t/t4013/diff.format-patch_--stdout_initial..master +++ b/t/t4013/diff.format-patch_--stdout_initial..master @@ -6,9 +6,9 @@ Subject: [PATCH 1/3] Second This is the second commit. --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 --- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- 3 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 file2 @@ -51,8 +51,8 @@ Date: Mon, 26 Jun 2006 00:02:00 +0000 Subject: [PATCH 2/3] Third --- - dir/sub | 2 ++ - file1 | 3 +++ + dir/sub | 2 ++ + file1 | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 file1 @@ -85,9 +85,9 @@ Date: Mon, 26 Jun 2006 00:03:00 +0000 Subject: [PATCH 3/3] Side --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/t/t4013/diff.format-patch_--stdout_initial..master^ b/t/t4013/diff.format-patch_--stdout_initial..master^ index 39f4a3f2d1..2ae454d807 100644 --- a/t/t4013/diff.format-patch_--stdout_initial..master^ +++ b/t/t4013/diff.format-patch_--stdout_initial..master^ @@ -6,9 +6,9 @@ Subject: [PATCH 1/2] Second This is the second commit. --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 --- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- 3 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 file2 @@ -51,8 +51,8 @@ Date: Mon, 26 Jun 2006 00:02:00 +0000 Subject: [PATCH 2/2] Third --- - dir/sub | 2 ++ - file1 | 3 +++ + dir/sub | 2 ++ + file1 | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 file1 diff --git a/t/t4013/diff.format-patch_--stdout_initial..side b/t/t4013/diff.format-patch_--stdout_initial..side index 88109209db..a7d52fbeea 100644 --- a/t/t4013/diff.format-patch_--stdout_initial..side +++ b/t/t4013/diff.format-patch_--stdout_initial..side @@ -5,9 +5,9 @@ Date: Mon, 26 Jun 2006 00:03:00 +0000 Subject: [PATCH] Side --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ b/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ index 4085bbde87..a18f1472a9 100644 --- a/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ +++ b/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ @@ -12,7 +12,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side --- - dir/sub | 2 ++ + dir/sub | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub @@ -31,7 +31,7 @@ Date: Mon Jun 26 00:02:00 2006 +0000 Third --- - dir/sub | 2 ++ + dir/sub | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub @@ -53,7 +53,7 @@ Date: Mon Jun 26 00:01:00 2006 +0000 This is the second commit. --- - dir/sub | 2 ++ + dir/sub | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub diff --git a/t/t4013/diff.log_--patch-with-stat_master b/t/t4013/diff.log_--patch-with-stat_master index 458627953e..ae425c4672 100644 --- a/t/t4013/diff.log_--patch-with-stat_master +++ b/t/t4013/diff.log_--patch-with-stat_master @@ -12,9 +12,9 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/dir/sub b/dir/sub @@ -54,8 +54,8 @@ Date: Mon Jun 26 00:02:00 2006 +0000 Third --- - dir/sub | 2 ++ - file1 | 3 +++ + dir/sub | 2 ++ + file1 | 3 +++ 2 files changed, 5 insertions(+) diff --git a/dir/sub b/dir/sub @@ -86,9 +86,9 @@ Date: Mon Jun 26 00:01:00 2006 +0000 This is the second commit. --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 --- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/dir/sub b/dir/sub diff --git a/t/t4013/diff.log_--patch-with-stat_master_--_dir_ b/t/t4013/diff.log_--patch-with-stat_master_--_dir_ index 6e172cfadd..d5207cadf4 100644 --- a/t/t4013/diff.log_--patch-with-stat_master_--_dir_ +++ b/t/t4013/diff.log_--patch-with-stat_master_--_dir_ @@ -12,7 +12,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side --- - dir/sub | 2 ++ + dir/sub | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub @@ -31,7 +31,7 @@ Date: Mon Jun 26 00:02:00 2006 +0000 Third --- - dir/sub | 2 ++ + dir/sub | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub @@ -53,7 +53,7 @@ Date: Mon Jun 26 00:01:00 2006 +0000 This is the second commit. --- - dir/sub | 2 ++ + dir/sub | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub diff --git a/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master index 48b0d4b91d..0fc1e8cd71 100644 --- a/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master +++ b/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master @@ -6,8 +6,8 @@ Date: Mon Jun 26 00:04:00 2006 +0000 Merge branch 'side' - dir/sub | 2 ++ - file0 | 3 +++ + dir/sub | 2 ++ + file0 | 3 +++ 2 files changed, 5 insertions(+) diff --cc dir/sub @@ -44,9 +44,9 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 file3 @@ -87,8 +87,8 @@ Date: Mon Jun 26 00:02:00 2006 +0000 Third --- - dir/sub | 2 ++ - file1 | 3 +++ + dir/sub | 2 ++ + file1 | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 file1 @@ -120,9 +120,9 @@ Date: Mon Jun 26 00:01:00 2006 +0000 This is the second commit. --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 --- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- 3 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 file2 @@ -162,9 +162,9 @@ Date: Mon Jun 26 00:00:00 2006 +0000 Initial --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 +++ + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ 3 files changed, 8 insertions(+) create mode 100644 dir/sub create mode 100644 file0 diff --git a/t/t4013/diff.log_--root_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_--patch-with-stat_--summary_master index f9dc5122e2..dffc09dde9 100644 --- a/t/t4013/diff.log_--root_--patch-with-stat_--summary_master +++ b/t/t4013/diff.log_--root_--patch-with-stat_--summary_master @@ -12,9 +12,9 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 file3 @@ -55,8 +55,8 @@ Date: Mon Jun 26 00:02:00 2006 +0000 Third --- - dir/sub | 2 ++ - file1 | 3 +++ + dir/sub | 2 ++ + file1 | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 file1 @@ -88,9 +88,9 @@ Date: Mon Jun 26 00:01:00 2006 +0000 This is the second commit. --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 --- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- 3 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 file2 @@ -130,9 +130,9 @@ Date: Mon Jun 26 00:00:00 2006 +0000 Initial --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 +++ + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ 3 files changed, 8 insertions(+) create mode 100644 dir/sub create mode 100644 file0 diff --git a/t/t4013/diff.log_--root_--patch-with-stat_master b/t/t4013/diff.log_--root_--patch-with-stat_master index 0807ece234..55aa98012d 100644 --- a/t/t4013/diff.log_--root_--patch-with-stat_master +++ b/t/t4013/diff.log_--root_--patch-with-stat_master @@ -12,9 +12,9 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/dir/sub b/dir/sub @@ -54,8 +54,8 @@ Date: Mon Jun 26 00:02:00 2006 +0000 Third --- - dir/sub | 2 ++ - file1 | 3 +++ + dir/sub | 2 ++ + file1 | 3 +++ 2 files changed, 5 insertions(+) diff --git a/dir/sub b/dir/sub @@ -86,9 +86,9 @@ Date: Mon Jun 26 00:01:00 2006 +0000 This is the second commit. --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 --- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/dir/sub b/dir/sub @@ -127,9 +127,9 @@ Date: Mon Jun 26 00:00:00 2006 +0000 Initial --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 +++ + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ 3 files changed, 8 insertions(+) diff --git a/dir/sub b/dir/sub diff --git a/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master index 84f5ef6911..019d85f7de 100644 --- a/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master +++ b/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master @@ -6,8 +6,8 @@ Date: Mon Jun 26 00:04:00 2006 +0000 Merge branch 'side' - dir/sub | 2 ++ - file0 | 3 +++ + dir/sub | 2 ++ + file0 | 3 +++ 2 files changed, 5 insertions(+) diff --combined dir/sub @@ -44,9 +44,9 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 file3 @@ -87,8 +87,8 @@ Date: Mon Jun 26 00:02:00 2006 +0000 Third --- - dir/sub | 2 ++ - file1 | 3 +++ + dir/sub | 2 ++ + file1 | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 file1 @@ -120,9 +120,9 @@ Date: Mon Jun 26 00:01:00 2006 +0000 This is the second commit. --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 --- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- 3 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 file2 @@ -162,9 +162,9 @@ Date: Mon Jun 26 00:00:00 2006 +0000 Initial --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 +++ + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ 3 files changed, 8 insertions(+) create mode 100644 dir/sub create mode 100644 file0 diff --git a/t/t4013/diff.show_--patch-with-stat_--summary_side b/t/t4013/diff.show_--patch-with-stat_--summary_side index e60384d24d..95a474ef1d 100644 --- a/t/t4013/diff.show_--patch-with-stat_--summary_side +++ b/t/t4013/diff.show_--patch-with-stat_--summary_side @@ -5,9 +5,9 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/t/t4013/diff.show_--patch-with-stat_side b/t/t4013/diff.show_--patch-with-stat_side index a3a3255fd3..974e99be82 100644 --- a/t/t4013/diff.show_--patch-with-stat_side +++ b/t/t4013/diff.show_--patch-with-stat_side @@ -5,9 +5,9 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/dir/sub b/dir/sub diff --git a/t/t4013/diff.show_--stat_--summary_side b/t/t4013/diff.show_--stat_--summary_side index d16f464aca..a71492f9bf 100644 --- a/t/t4013/diff.show_--stat_--summary_side +++ b/t/t4013/diff.show_--stat_--summary_side @@ -5,9 +5,9 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 file3 $ diff --git a/t/t4013/diff.show_--stat_side b/t/t4013/diff.show_--stat_side index 6300c0535f..9be712458f 100644 --- a/t/t4013/diff.show_--stat_side +++ b/t/t4013/diff.show_--stat_side @@ -5,8 +5,8 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) $ diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ b/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ index 16ae54345f..c8b6af2f43 100644 --- a/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ +++ b/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ @@ -5,7 +5,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side --- - dir/sub | 2 ++ + dir/sub | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub @@ -24,7 +24,7 @@ Date: Mon Jun 26 00:02:00 2006 +0000 Third --- - dir/sub | 2 ++ + dir/sub | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub @@ -46,7 +46,7 @@ Date: Mon Jun 26 00:01:00 2006 +0000 This is the second commit. --- - dir/sub | 2 ++ + dir/sub | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_master b/t/t4013/diff.whatchanged_--patch-with-stat_master index f3e45ec270..1ac431ba92 100644 --- a/t/t4013/diff.whatchanged_--patch-with-stat_master +++ b/t/t4013/diff.whatchanged_--patch-with-stat_master @@ -5,9 +5,9 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/dir/sub b/dir/sub @@ -47,8 +47,8 @@ Date: Mon Jun 26 00:02:00 2006 +0000 Third --- - dir/sub | 2 ++ - file1 | 3 +++ + dir/sub | 2 ++ + file1 | 3 +++ 2 files changed, 5 insertions(+) diff --git a/dir/sub b/dir/sub @@ -79,9 +79,9 @@ Date: Mon Jun 26 00:01:00 2006 +0000 This is the second commit. --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 --- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/dir/sub b/dir/sub diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ b/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ index c77f0bc320..b30c28588f 100644 --- a/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ +++ b/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ @@ -5,7 +5,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side --- - dir/sub | 2 ++ + dir/sub | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub @@ -24,7 +24,7 @@ Date: Mon Jun 26 00:02:00 2006 +0000 Third --- - dir/sub | 2 ++ + dir/sub | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub @@ -46,7 +46,7 @@ Date: Mon Jun 26 00:01:00 2006 +0000 This is the second commit. --- - dir/sub | 2 ++ + dir/sub | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub diff --git a/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master index 8d03efea6c..30aae7817b 100644 --- a/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master +++ b/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master @@ -6,8 +6,8 @@ Date: Mon Jun 26 00:04:00 2006 +0000 Merge branch 'side' - dir/sub | 2 ++ - file0 | 3 +++ + dir/sub | 2 ++ + file0 | 3 +++ 2 files changed, 5 insertions(+) diff --cc dir/sub @@ -44,9 +44,9 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 file3 @@ -87,8 +87,8 @@ Date: Mon Jun 26 00:02:00 2006 +0000 Third --- - dir/sub | 2 ++ - file1 | 3 +++ + dir/sub | 2 ++ + file1 | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 file1 @@ -120,9 +120,9 @@ Date: Mon Jun 26 00:01:00 2006 +0000 This is the second commit. --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 --- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- 3 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 file2 @@ -162,9 +162,9 @@ Date: Mon Jun 26 00:00:00 2006 +0000 Initial --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 +++ + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ 3 files changed, 8 insertions(+) create mode 100644 dir/sub create mode 100644 file0 diff --git a/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master index 1874d0616c..db90e51525 100644 --- a/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master +++ b/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master @@ -5,9 +5,9 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 file3 @@ -48,8 +48,8 @@ Date: Mon Jun 26 00:02:00 2006 +0000 Third --- - dir/sub | 2 ++ - file1 | 3 +++ + dir/sub | 2 ++ + file1 | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 file1 @@ -81,9 +81,9 @@ Date: Mon Jun 26 00:01:00 2006 +0000 This is the second commit. --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 --- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- 3 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 file2 @@ -123,9 +123,9 @@ Date: Mon Jun 26 00:00:00 2006 +0000 Initial --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 +++ + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ 3 files changed, 8 insertions(+) create mode 100644 dir/sub create mode 100644 file0 diff --git a/t/t4013/diff.whatchanged_--root_--patch-with-stat_master b/t/t4013/diff.whatchanged_--root_--patch-with-stat_master index 5211ff2a75..9a6cc92ce7 100644 --- a/t/t4013/diff.whatchanged_--root_--patch-with-stat_master +++ b/t/t4013/diff.whatchanged_--root_--patch-with-stat_master @@ -5,9 +5,9 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/dir/sub b/dir/sub @@ -47,8 +47,8 @@ Date: Mon Jun 26 00:02:00 2006 +0000 Third --- - dir/sub | 2 ++ - file1 | 3 +++ + dir/sub | 2 ++ + file1 | 3 +++ 2 files changed, 5 insertions(+) diff --git a/dir/sub b/dir/sub @@ -79,9 +79,9 @@ Date: Mon Jun 26 00:01:00 2006 +0000 This is the second commit. --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 --- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/dir/sub b/dir/sub @@ -120,9 +120,9 @@ Date: Mon Jun 26 00:00:00 2006 +0000 Initial --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 +++ + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ 3 files changed, 8 insertions(+) diff --git a/dir/sub b/dir/sub diff --git a/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master index ad30245a59..d1d32bd34c 100644 --- a/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master +++ b/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master @@ -6,8 +6,8 @@ Date: Mon Jun 26 00:04:00 2006 +0000 Merge branch 'side' - dir/sub | 2 ++ - file0 | 3 +++ + dir/sub | 2 ++ + file0 | 3 +++ 2 files changed, 5 insertions(+) diff --combined dir/sub @@ -44,9 +44,9 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side --- - dir/sub | 2 ++ - file0 | 3 +++ - file3 | 4 ++++ + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 file3 @@ -87,8 +87,8 @@ Date: Mon Jun 26 00:02:00 2006 +0000 Third --- - dir/sub | 2 ++ - file1 | 3 +++ + dir/sub | 2 ++ + file1 | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 file1 @@ -120,9 +120,9 @@ Date: Mon Jun 26 00:01:00 2006 +0000 This is the second commit. --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 --- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- 3 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 file2 @@ -162,9 +162,9 @@ Date: Mon Jun 26 00:00:00 2006 +0000 Initial --- - dir/sub | 2 ++ - file0 | 3 +++ - file2 | 3 +++ + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ 3 files changed, 8 insertions(+) create mode 100644 dir/sub create mode 100644 file0 diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index 7dfe716cf9..959aa26ef5 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -243,7 +243,7 @@ check_threading () { (git format-patch --stdout "$@"; echo $? > status.out) | # Prints everything between the Message-ID and In-Reply-To, # and replaces all Message-ID-lookalikes by a sequence number - perl -ne ' + "$PERL_PATH" -ne ' if (/^(message-id|references|in-reply-to)/i) { $printing = 1; } elsif (/^\S/) { @@ -518,11 +518,6 @@ test_expect_success 'shortlog of cover-letter wraps overly-long onelines' ' ' cat > expect << EOF ---- - file | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/file b/file index 40f36c6..2dc5c23 100644 --- a/file +++ b/file @@ -537,7 +532,9 @@ EOF test_expect_success 'format-patch respects -U' ' git format-patch -U4 -2 && - sed -e "1,/^\$/d" -e "/^+5/q" < 0001-This-is-an-excessively-long-subject-line-for-a-messa.patch > output && + sed -e "1,/^diff/d" -e "/^+5/q" \ + <0001-This-is-an-excessively-long-subject-line-for-a-messa.patch \ + >output && test_cmp expect output ' diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index 9059bcd69e..cc3db1304e 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -103,7 +103,7 @@ test_expect_success 'another test, with -w --ignore-space-at-eol' 'test_cmp expe git diff -w -b --ignore-space-at-eol > out test_expect_success 'another test, with -w -b --ignore-space-at-eol' 'test_cmp expect out' -tr 'Q' '\015' << EOF > expect +tr 'Q_' '\015 ' << EOF > expect diff --git a/x b/x index d99af23..8b32fb5 100644 --- a/x @@ -111,19 +111,19 @@ index d99af23..8b32fb5 100644 @@ -1,6 +1,6 @@ -whitespace at beginning + whitespace at beginning - whitespace change + whitespace change -whitespace in the middle +white space in the middle - whitespace at end + whitespace at end__ unchanged line - CR at endQ + CR at end EOF git diff -b > out test_expect_success 'another test, with -b' 'test_cmp expect out' git diff -b --ignore-space-at-eol > out test_expect_success 'another test, with -b --ignore-space-at-eol' 'test_cmp expect out' -tr 'Q' '\015' << EOF > expect +tr 'Q_' '\015 ' << EOF > expect diff --git a/x b/x index d99af23..8b32fb5 100644 --- a/x @@ -135,9 +135,9 @@ index d99af23..8b32fb5 100644 + whitespace at beginning +whitespace change +white space in the middle - whitespace at end + whitespace at end__ unchanged line - CR at endQ + CR at end EOF git diff --ignore-space-at-eol > out test_expect_success 'another test, with --ignore-space-at-eol' 'test_cmp expect out' diff --git a/t/t4016-diff-quote.sh b/t/t4016-diff-quote.sh index ab0c2f0574..97b81778cb 100755 --- a/t/t4016-diff-quote.sh +++ b/t/t4016-diff-quote.sh @@ -57,22 +57,33 @@ test_expect_success TABS_IN_FILENAMES 'git diff --summary -M HEAD' ' test_cmp expect actual ' -test_expect_success TABS_IN_FILENAMES 'setup expected files' ' -cat >expect <<\EOF - pathname.1 => "Rpathname\twith HT.0" | 0 - pathname.3 => "Rpathname\nwith LF.0" | 0 - "pathname\twith HT.3" => "Rpathname\nwith LF.1" | 0 - pathname.2 => Rpathname with SP.0 | 0 - "pathname\twith HT.2" => Rpathname with SP.1 | 0 - pathname.0 => Rpathname.0 | 0 - "pathname\twith HT.0" => Rpathname.1 | 0 - 7 files changed, 0 insertions(+), 0 deletions(-) -EOF +test_expect_success TABS_IN_FILENAMES 'git diff --numstat -M HEAD' ' + cat >expect <<-\EOF && + 0 0 pathname.1 => "Rpathname\twith HT.0" + 0 0 pathname.3 => "Rpathname\nwith LF.0" + 0 0 "pathname\twith HT.3" => "Rpathname\nwith LF.1" + 0 0 pathname.2 => Rpathname with SP.0 + 0 0 "pathname\twith HT.2" => Rpathname with SP.1 + 0 0 pathname.0 => Rpathname.0 + 0 0 "pathname\twith HT.0" => Rpathname.1 + EOF + git diff --numstat -M HEAD >actual && + test_cmp expect actual ' test_expect_success TABS_IN_FILENAMES 'git diff --stat -M HEAD' ' + cat >expect <<-\EOF && + pathname.1 => "Rpathname\twith HT.0" | 0 + pathname.3 => "Rpathname\nwith LF.0" | 0 + "pathname\twith HT.3" => "Rpathname\nwith LF.1" | 0 + pathname.2 => Rpathname with SP.0 | 0 + "pathname\twith HT.2" => Rpathname with SP.1 | 0 + pathname.0 => Rpathname.0 | 0 + "pathname\twith HT.0" => Rpathname.1 | 0 + 7 files changed, 0 insertions(+), 0 deletions(-) + EOF git diff --stat -M HEAD >actual && - test_cmp expect actual + test_i18ncmp expect actual ' test_done diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh index 083f62d1d6..2e7d73f090 100755 --- a/t/t4020-diff-external.sh +++ b/t/t4020-diff-external.sh @@ -48,7 +48,53 @@ test_expect_success 'GIT_EXTERNAL_DIFF environment and --no-ext-diff' ' ' +test_expect_success SYMLINKS 'typechange diff' ' + rm -f file && + ln -s elif file && + GIT_EXTERNAL_DIFF=echo git diff | { + read path oldfile oldhex oldmode newfile newhex newmode && + test "z$path" = zfile && + test "z$oldmode" = z100644 && + test "z$newhex" = "z$_z40" && + test "z$newmode" = z120000 && + oh=$(git rev-parse --verify HEAD:file) && + test "z$oh" = "z$oldhex" + } && + GIT_EXTERNAL_DIFF=echo git diff --no-ext-diff >actual && + git diff >expect && + test_cmp expect actual +' + +test_expect_success 'diff.external' ' + git reset --hard && + echo third >file && + test_config diff.external echo && + git diff | { + read path oldfile oldhex oldmode newfile newhex newmode && + test "z$path" = zfile && + test "z$oldmode" = z100644 && + test "z$newhex" = "z$_z40" && + test "z$newmode" = z100644 && + oh=$(git rev-parse --verify HEAD:file) && + test "z$oh" = "z$oldhex" + } +' + +test_expect_success 'diff.external should apply only to diff' ' + test_config diff.external echo && + git log -p -1 HEAD | + grep "^diff --git a/file b/file" +' + +test_expect_success 'diff.external and --no-ext-diff' ' + test_config diff.external echo && + git diff --no-ext-diff | + grep "^diff --git a/file b/file" +' + test_expect_success 'diff attribute' ' + git reset --hard && + echo third >file && git config diff.parrot.command echo && @@ -113,12 +159,25 @@ test_expect_success 'diff attribute and --no-ext-diff' ' ' +test_expect_success 'GIT_EXTERNAL_DIFF trumps diff.external' ' + >.gitattributes && + test_config diff.external "echo ext-global" && + GIT_EXTERNAL_DIFF="echo ext-env" git diff | grep ext-env +' + +test_expect_success 'attributes trump GIT_EXTERNAL_DIFF and diff.external' ' + test_config diff.foo.command "echo ext-attribute" && + test_config diff.external "echo ext-global" && + echo "file diff=foo" >.gitattributes && + GIT_EXTERNAL_DIFF="echo ext-env" git diff | grep ext-attribute +' + test_expect_success 'no diff with -diff' ' echo >.gitattributes "file -diff" && git diff | grep Binary ' -echo NULZbetweenZwords | perl -pe 'y/Z/\000/' > file +echo NULZbetweenZwords | "$PERL_PATH" -pe 'y/Z/\000/' > file test_expect_success 'force diff with "diff"' ' echo >.gitattributes "file diff" && diff --git a/t/t4022-diff-rewrite.sh b/t/t4022-diff-rewrite.sh index c00a94b9ba..2d030a4ec3 100755 --- a/t/t4022-diff-rewrite.sh +++ b/t/t4022-diff-rewrite.sh @@ -66,5 +66,35 @@ test_expect_success 'suppress deletion diff with -B -D' ' grep -v "Linus Torvalds" actual ' +test_expect_success 'prepare a file that ends with an incomplete line' ' + test_seq 1 99 >seq && + printf 100 >>seq && + git add seq && + git commit seq -m seq +' + +test_expect_success 'rewrite the middle 90% of sequence file and terminate with newline' ' + test_seq 1 5 >seq && + test_seq 9331 9420 >>seq && + test_seq 96 100 >>seq +' + +test_expect_success 'confirm that sequence file is considered a rewrite' ' + git diff -B seq >res && + grep "dissimilarity index" res +' + +test_expect_success 'no newline at eof is on its own line without -B' ' + git diff seq >res && + grep "^\\\\ " res && + ! grep "^..*\\\\ " res +' + +test_expect_success 'no newline at eof is on its own line with -B' ' + git diff -B seq >res && + grep "^\\\\ " res && + ! grep "^..*\\\\ " res +' + test_done diff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh index 3ccc237a8d..36e2f075c9 100755 --- a/t/t4029-diff-trailing-space.sh +++ b/t/t4029-diff-trailing-space.sh @@ -27,7 +27,7 @@ test_expect_success \ git config --bool diff.suppressBlankEmpty true && git diff f > actual && test_cmp exp actual && - perl -i.bak -p -e "s/^\$/ /" exp && + "$PERL_PATH" -i.bak -p -e "s/^\$/ /" exp && git config --bool diff.suppressBlankEmpty false && git diff f > actual && test_cmp exp actual && diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh index 4ac162cfcf..eebb1eed8b 100755 --- a/t/t4030-diff-textconv.sh +++ b/t/t4030-diff-textconv.sh @@ -21,7 +21,7 @@ EOF cat >hexdump <<'EOF' #!/bin/sh -perl -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1" +"$PERL_PATH" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1" EOF chmod +x hexdump @@ -85,13 +85,17 @@ test_expect_success 'status -v produces text' ' ' cat >expect.stat <<'EOF' - file | Bin 2 -> 4 bytes + file | Bin 2 -> 4 bytes 1 file changed, 0 insertions(+), 0 deletions(-) EOF test_expect_success 'diffstat does not run textconv' ' echo file diff=fail >.gitattributes && git diff --stat HEAD^ HEAD >actual && - test_cmp expect.stat actual + test_i18ncmp expect.stat actual && + + head -n1 <expect.stat >expect.line1 && + head -n1 <actual >actual.line1 && + test_cmp expect.line1 actual.line1 ' # restore working setup echo file diff=foo >.gitattributes diff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh index 7d7470f21b..eacc6694f7 100755 --- a/t/t4031-diff-rewrite-binary.sh +++ b/t/t4031-diff-rewrite-binary.sh @@ -44,17 +44,23 @@ test_expect_success 'rewrite diff can show binary patch' ' grep "GIT binary patch" diff ' -test_expect_success 'rewrite diff --stat shows binary changes' ' +test_expect_success 'rewrite diff --numstat shows binary changes' ' + git diff -B --numstat --summary >diff && + grep -e "- - " diff && + grep " rewrite file" diff +' + +test_expect_success 'diff --stat counts binary rewrite as 0 lines' ' git diff -B --stat --summary >diff && grep "Bin" diff && - grep "0 insertions.*0 deletions" diff && + test_i18ngrep "0 insertions.*0 deletions" diff && grep " rewrite file" diff ' { echo "#!$SHELL_PATH" cat <<'EOF' -perl -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1" +"$PERL_PATH" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1" EOF } >dump chmod +x dump diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh index 5c2012111c..30d42cb3bf 100755 --- a/t/t4034-diff-words.sh +++ b/t/t4034-diff-words.sh @@ -3,6 +3,7 @@ test_description='word diff colors' . ./test-lib.sh +. "$TEST_DIRECTORY"/diff-lib.sh cat >pre.simple <<-\EOF h(4) @@ -293,6 +294,10 @@ test_expect_success '--word-diff=none' ' word_diff --word-diff=plain --word-diff=none ' +test_expect_success 'unset default driver' ' + test_unconfig diff.wordregex +' + test_language_driver bibtex test_language_driver cpp test_language_driver csharp @@ -348,4 +353,35 @@ test_expect_success 'word-diff with no newline at EOF' ' word_diff --word-diff=plain ' +test_expect_success 'setup history with two files' ' + echo "a b; c" >a.tex && + echo "a b; c" >z.txt && + git add a.tex z.txt && + git commit -minitial && + + # modify both + echo "a bx; c" >a.tex && + echo "a bx; c" >z.txt && + git commit -mmodified -a +' + +test_expect_success 'wordRegex for the first file does not apply to the second' ' + echo "*.tex diff=tex" >.gitattributes && + git config diff.tex.wordRegex "[a-z]+|." && + cat >expect <<-\EOF && + diff --git a/a.tex b/a.tex + --- a/a.tex + +++ b/a.tex + @@ -1 +1 @@ + a [-b-]{+bx+}; c + diff --git a/z.txt b/z.txt + --- a/z.txt + +++ b/z.txt + @@ -1 +1 @@ + a [-b;-]{+bx;+} c + EOF + git diff --word-diff HEAD~ >actual && + compare_diff_patch expect actual +' + test_done diff --git a/t/t4035-diff-quiet.sh b/t/t4035-diff-quiet.sh index e747e84227..231412d100 100755 --- a/t/t4035-diff-quiet.sh +++ b/t/t4035-diff-quiet.sh @@ -10,71 +10,142 @@ test_expect_success 'setup' ' git commit -m first && echo 2 >b && git add . && - git commit -a -m second + git commit -a -m second && + mkdir -p test-outside/repo && ( + cd test-outside/repo && + git init && + echo "1 1" >a && + git add . && + git commit -m 1 + ) && + mkdir -p test-outside/non/git && ( + cd test-outside/non/git && + echo "1 1" >a && + echo "1 1" >matching-file && + echo "1 1 " >trailing-space && + echo "1 1" >extra-space && + echo "2" >never-match + ) ' test_expect_success 'git diff-tree HEAD^ HEAD' ' git diff-tree --quiet HEAD^ HEAD >cnt - test $? = 1 && test $(wc -l <cnt) = 0 + test $? = 1 && test_line_count = 0 cnt ' test_expect_success 'git diff-tree HEAD^ HEAD -- a' ' git diff-tree --quiet HEAD^ HEAD -- a >cnt - test $? = 0 && test $(wc -l <cnt) = 0 + test $? = 0 && test_line_count = 0 cnt ' test_expect_success 'git diff-tree HEAD^ HEAD -- b' ' git diff-tree --quiet HEAD^ HEAD -- b >cnt - test $? = 1 && test $(wc -l <cnt) = 0 + test $? = 1 && test_line_count = 0 cnt ' # this diff outputs one line: sha1 of the given head test_expect_success 'echo HEAD | git diff-tree --stdin' ' echo $(git rev-parse HEAD) | git diff-tree --quiet --stdin >cnt - test $? = 1 && test $(wc -l <cnt) = 1 + test $? = 1 && test_line_count = 1 cnt ' test_expect_success 'git diff-tree HEAD HEAD' ' git diff-tree --quiet HEAD HEAD >cnt - test $? = 0 && test $(wc -l <cnt) = 0 + test $? = 0 && test_line_count = 0 cnt ' test_expect_success 'git diff-files' ' git diff-files --quiet >cnt - test $? = 0 && test $(wc -l <cnt) = 0 + test $? = 0 && test_line_count = 0 cnt ' test_expect_success 'git diff-index --cached HEAD' ' git diff-index --quiet --cached HEAD >cnt - test $? = 0 && test $(wc -l <cnt) = 0 + test $? = 0 && test_line_count = 0 cnt ' test_expect_success 'git diff-index --cached HEAD^' ' git diff-index --quiet --cached HEAD^ >cnt - test $? = 1 && test $(wc -l <cnt) = 0 + test $? = 1 && test_line_count = 0 cnt ' test_expect_success 'git diff-index --cached HEAD^' ' echo text >>b && echo 3 >c && git add . && { git diff-index --quiet --cached HEAD^ >cnt - test $? = 1 && test $(wc -l <cnt) = 0 + test $? = 1 && test_line_count = 0 cnt } ' test_expect_success 'git diff-tree -Stext HEAD^ HEAD -- b' ' git commit -m "text in b" && { git diff-tree --quiet -Stext HEAD^ HEAD -- b >cnt - test $? = 1 && test $(wc -l <cnt) = 0 + test $? = 1 && test_line_count = 0 cnt } ' test_expect_success 'git diff-tree -Snot-found HEAD^ HEAD -- b' ' git diff-tree --quiet -Snot-found HEAD^ HEAD -- b >cnt - test $? = 0 && test $(wc -l <cnt) = 0 + test $? = 0 && test_line_count = 0 cnt ' test_expect_success 'git diff-files' ' echo 3 >>c && { git diff-files --quiet >cnt - test $? = 1 && test $(wc -l <cnt) = 0 + test $? = 1 && test_line_count = 0 cnt } ' test_expect_success 'git diff-index --cached HEAD' ' git update-index c && { git diff-index --quiet --cached HEAD >cnt - test $? = 1 && test $(wc -l <cnt) = 0 + test $? = 1 && test_line_count = 0 cnt } ' +test_expect_success 'git diff, one file outside repo' ' + ( + cd test-outside/repo && + test_expect_code 0 git diff --quiet a ../non/git/matching-file && + test_expect_code 1 git diff --quiet a ../non/git/extra-space + ) +' + +test_expect_success 'git diff, both files outside repo' ' + ( + GIT_CEILING_DIRECTORIES="$TRASH_DIRECTORY/test-outside" && + export GIT_CEILING_DIRECTORIES && + cd test-outside/non/git && + test_expect_code 0 git diff --quiet a matching-file && + test_expect_code 1 git diff --quiet a extra-space + ) +' + +test_expect_success 'git diff --ignore-space-at-eol, one file outside repo' ' + ( + cd test-outside/repo && + test_expect_code 0 git diff --quiet --ignore-space-at-eol a ../non/git/trailing-space && + test_expect_code 1 git diff --quiet --ignore-space-at-eol a ../non/git/extra-space + ) +' + +test_expect_success 'git diff --ignore-space-at-eol, both files outside repo' ' + ( + GIT_CEILING_DIRECTORIES="$TRASH_DIRECTORY/test-outside" && + export GIT_CEILING_DIRECTORIES && + cd test-outside/non/git && + test_expect_code 0 git diff --quiet --ignore-space-at-eol a trailing-space && + test_expect_code 1 git diff --quiet --ignore-space-at-eol a extra-space + ) +' + +test_expect_success 'git diff --ignore-all-space, one file outside repo' ' + ( + cd test-outside/repo && + test_expect_code 0 git diff --quiet --ignore-all-space a ../non/git/trailing-space && + test_expect_code 0 git diff --quiet --ignore-all-space a ../non/git/extra-space && + test_expect_code 1 git diff --quiet --ignore-all-space a ../non/git/never-match + ) +' + +test_expect_success 'git diff --ignore-all-space, both files outside repo' ' + ( + GIT_CEILING_DIRECTORIES="$TRASH_DIRECTORY/test-outside" && + export GIT_CEILING_DIRECTORIES && + cd test-outside/non/git && + test_expect_code 0 git diff --quiet --ignore-all-space a trailing-space && + test_expect_code 0 git diff --quiet --ignore-all-space a extra-space && + test_expect_code 1 git diff --quiet --ignore-all-space a never-match + ) +' + test_done diff --git a/t/t4041-diff-submodule-option.sh b/t/t4041-diff-submodule-option.sh index bf9a7526bd..6c01d0c056 100755 --- a/t/t4041-diff-submodule-option.sh +++ b/t/t4041-diff-submodule-option.sh @@ -458,4 +458,38 @@ EOF test_cmp expected actual ' +test_expect_success 'diff --submodule with objects referenced by alternates' ' + mkdir sub_alt && + (cd sub_alt && + git init && + echo a >a && + git add a && + git commit -m a + ) && + mkdir super && + (cd super && + git clone -s ../sub_alt sub && + git init && + git add sub && + git commit -m "sub a" + ) && + (cd sub_alt && + sha1_before=$(git rev-parse --short HEAD) + echo b >b && + git add b && + git commit -m b + sha1_after=$(git rev-parse --short HEAD) + echo "Submodule sub $sha1_before..$sha1_after: + > b" >../expected + ) && + (cd super && + (cd sub && + git fetch && + git checkout origin/master + ) && + git diff --submodule > ../actual + ) + test_cmp expected actual +' + test_done diff --git a/t/t4043-diff-rename-binary.sh b/t/t4043-diff-rename-binary.sh index 06012811a1..2a2cf91352 100755 --- a/t/t4043-diff-rename-binary.sh +++ b/t/t4043-diff-rename-binary.sh @@ -23,9 +23,8 @@ test_expect_success 'move the files into a "sub" directory' ' ' cat > expected <<\EOF - bar => sub/bar | Bin 5 -> 5 bytes - foo => sub/foo | 0 - 2 files changed, 0 insertions(+), 0 deletions(-) +- - bar => sub/bar +0 0 foo => sub/foo diff --git a/bar b/sub/bar similarity index 100% @@ -38,7 +37,8 @@ rename to sub/foo EOF test_expect_success 'git show -C -C report renames' ' - git show -C -C --raw --binary --stat | tail -n 12 > current && + git show -C -C --raw --binary --numstat >patch-with-stat && + tail -n 11 patch-with-stat >current && test_cmp expected current ' diff --git a/t/t4045-diff-relative.sh b/t/t4045-diff-relative.sh index bd119be106..3950f5034d 100755 --- a/t/t4045-diff-relative.sh +++ b/t/t4045-diff-relative.sh @@ -29,15 +29,27 @@ test_expect_success "-p $*" " " } +check_numstat() { +expect=$1; shift +cat >expected <<EOF +1 0 $expect +EOF +test_expect_success "--numstat $*" " + echo '1 0 $expect' >expected && + git diff --numstat $* HEAD^ >actual && + test_cmp expected actual +" +} + check_stat() { expect=$1; shift cat >expected <<EOF - $expect | 1 + + $expect | 1 + 1 file changed, 1 insertion(+) EOF test_expect_success "--stat $*" " git diff --stat $* HEAD^ >actual && - test_cmp expected actual + test_i18ncmp expected actual " } @@ -52,7 +64,7 @@ test_expect_success "--raw $*" " " } -for type in diff stat raw; do +for type in diff numstat stat raw; do check_$type file2 --relative=subdir/ check_$type file2 --relative=subdir check_$type dir/file2 --relative=sub diff --git a/t/t4047-diff-dirstat.sh b/t/t4047-diff-dirstat.sh index 29e80a58cd..ed7e093366 100755 --- a/t/t4047-diff-dirstat.sh +++ b/t/t4047-diff-dirstat.sh @@ -252,50 +252,47 @@ EOF ' cat <<EOF >expect_diff_stat - changed/text | 2 +- - dst/copy/changed/text | 10 ++++++++++ - dst/copy/rearranged/text | 10 ++++++++++ - dst/copy/unchanged/text | 10 ++++++++++ - dst/move/changed/text | 10 ++++++++++ - dst/move/rearranged/text | 10 ++++++++++ - dst/move/unchanged/text | 10 ++++++++++ - rearranged/text | 2 +- - src/move/changed/text | 10 ---------- - src/move/rearranged/text | 10 ---------- - src/move/unchanged/text | 10 ---------- - 11 files changed, 62 insertions(+), 32 deletions(-) +1 1 changed/text +10 0 dst/copy/changed/text +10 0 dst/copy/rearranged/text +10 0 dst/copy/unchanged/text +10 0 dst/move/changed/text +10 0 dst/move/rearranged/text +10 0 dst/move/unchanged/text +1 1 rearranged/text +0 10 src/move/changed/text +0 10 src/move/rearranged/text +0 10 src/move/unchanged/text EOF cat <<EOF >expect_diff_stat_M - changed/text | 2 +- - dst/copy/changed/text | 10 ++++++++++ - dst/copy/rearranged/text | 10 ++++++++++ - dst/copy/unchanged/text | 10 ++++++++++ - {src => dst}/move/changed/text | 2 +- - {src => dst}/move/rearranged/text | 2 +- - {src => dst}/move/unchanged/text | 0 - rearranged/text | 2 +- - 8 files changed, 34 insertions(+), 4 deletions(-) +1 1 changed/text +10 0 dst/copy/changed/text +10 0 dst/copy/rearranged/text +10 0 dst/copy/unchanged/text +1 1 {src => dst}/move/changed/text +1 1 {src => dst}/move/rearranged/text +0 0 {src => dst}/move/unchanged/text +1 1 rearranged/text EOF cat <<EOF >expect_diff_stat_CC - changed/text | 2 +- - {src => dst}/copy/changed/text | 2 +- - {src => dst}/copy/rearranged/text | 2 +- - {src => dst}/copy/unchanged/text | 0 - {src => dst}/move/changed/text | 2 +- - {src => dst}/move/rearranged/text | 2 +- - {src => dst}/move/unchanged/text | 0 - rearranged/text | 2 +- - 8 files changed, 6 insertions(+), 6 deletions(-) -EOF - -test_expect_success 'sanity check setup (--stat)' ' - git diff --stat HEAD^..HEAD >actual_diff_stat && +1 1 changed/text +1 1 {src => dst}/copy/changed/text +1 1 {src => dst}/copy/rearranged/text +0 0 {src => dst}/copy/unchanged/text +1 1 {src => dst}/move/changed/text +1 1 {src => dst}/move/rearranged/text +0 0 {src => dst}/move/unchanged/text +1 1 rearranged/text +EOF + +test_expect_success 'sanity check setup (--numstat)' ' + git diff --numstat HEAD^..HEAD >actual_diff_stat && test_cmp expect_diff_stat actual_diff_stat && - git diff --stat -M HEAD^..HEAD >actual_diff_stat_M && + git diff --numstat -M HEAD^..HEAD >actual_diff_stat_M && test_cmp expect_diff_stat_M actual_diff_stat_M && - git diff --stat -C -C HEAD^..HEAD >actual_diff_stat_CC && + git diff --numstat -C -C HEAD^..HEAD >actual_diff_stat_CC && test_cmp expect_diff_stat_CC actual_diff_stat_CC ' diff --git a/t/t4049-diff-stat-count.sh b/t/t4049-diff-stat-count.sh index a6d1887536..b41eb61ca8 100755 --- a/t/t4049-diff-stat-count.sh +++ b/t/t4049-diff-stat-count.sh @@ -14,12 +14,12 @@ test_expect_success setup ' echo a >a && echo b >b && cat >expect <<-\EOF - a | 1 + - b | 1 + + a | 1 + + b | 1 + 2 files changed, 2 insertions(+) EOF git diff --stat --stat-count=2 >actual && - test_cmp expect actual + test_i18ncmp expect actual ' test_done diff --git a/t/t4052-stat-output.sh b/t/t4052-stat-output.sh new file mode 100755 index 0000000000..b68afefa3c --- /dev/null +++ b/t/t4052-stat-output.sh @@ -0,0 +1,336 @@ +#!/bin/sh +# +# Copyright (c) 2012 Zbigniew Jędrzejewski-Szmek +# + +test_description='test --stat output of various commands' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-terminal.sh + +# 120 character name +name=aaaaaaaaaa +name=$name$name$name$name$name$name$name$name$name$name$name$name +test_expect_success 'preparation' ' + >"$name" && + git add "$name" && + git commit -m message && + echo a >"$name" && + git commit -m message "$name" +' + +while read cmd args +do + cat >expect <<-'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 + + EOF + test_expect_success "$cmd: small change with long name gives more space to the name" ' + git $cmd $args >output && + grep " | " output >actual && + test_cmp expect actual + ' + + cat >expect <<-'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 + + EOF + test_expect_success "$cmd --stat=width: a long name is given more room when the bar is short" ' + git $cmd $args --stat=40 >output && + grep " | " output >actual && + test_cmp expect actual + ' + + test_expect_success "$cmd --stat-width=width with long name" ' + git $cmd $args --stat-width=40 >output && + grep " | " output >actual && + test_cmp expect actual + ' + + cat >expect <<-'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 + + EOF + test_expect_success "$cmd --stat=...,name-width with long name" ' + git $cmd $args --stat=60,30 >output && + grep " | " output >actual && + test_cmp expect actual + ' + + test_expect_success "$cmd --stat-name-width with long name" ' + git $cmd $args --stat-name-width=30 >output && + grep " | " output >actual && + test_cmp expect actual + ' +done <<\EOF +format-patch -1 --stdout +diff HEAD^ HEAD --stat +show --stat +log -1 --stat +EOF + + +test_expect_success 'preparation for big change tests' ' + >abcd && + git add abcd && + git commit -m message && + i=0 && + while test $i -lt 1000 + do + echo $i && i=$(($i + 1)) + done >abcd && + git commit -m message abcd +' + +cat >expect80 <<'EOF' + abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +EOF +cat >expect80-graph <<'EOF' +| abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +EOF +cat >expect200 <<'EOF' + abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +EOF +cat >expect200-graph <<'EOF' +| abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +EOF +while read verb expect cmd args +do + test_expect_success "$cmd $verb COLUMNS (big change)" ' + COLUMNS=200 git $cmd $args >output + grep " | " output >actual && + test_cmp "$expect" actual + ' + + test "$cmd" != diff || continue + + test_expect_success "$cmd --graph $verb COLUMNS (big change)" ' + COLUMNS=200 git $cmd $args --graph >output + grep " | " output >actual && + test_cmp "$expect-graph" actual + ' +done <<\EOF +ignores expect80 format-patch -1 --stdout +respects expect200 diff HEAD^ HEAD --stat +respects expect200 show --stat +respects expect200 log -1 --stat +EOF + +cat >expect40 <<'EOF' + abcd | 1000 ++++++++++++++++++++++++++ +EOF +cat >expect40-graph <<'EOF' +| abcd | 1000 ++++++++++++++++++++++++ +EOF +while read verb expect cmd args +do + test_expect_success "$cmd $verb not enough COLUMNS (big change)" ' + COLUMNS=40 git $cmd $args >output + grep " | " output >actual && + test_cmp "$expect" actual + ' + + test "$cmd" != diff || continue + + test_expect_success "$cmd --graph $verb not enough COLUMNS (big change)" ' + COLUMNS=40 git $cmd $args --graph >output + grep " | " output >actual && + test_cmp "$expect-graph" actual + ' +done <<\EOF +ignores expect80 format-patch -1 --stdout +respects expect40 diff HEAD^ HEAD --stat +respects expect40 show --stat +respects expect40 log -1 --stat +EOF + +cat >expect40 <<'EOF' + abcd | 1000 ++++++++++++++++++++++++++ +EOF +cat >expect40-graph <<'EOF' +| abcd | 1000 ++++++++++++++++++++++++++ +EOF +while read verb expect cmd args +do + test_expect_success "$cmd $verb statGraphWidth config" ' + git -c diff.statGraphWidth=26 $cmd $args >output + grep " | " output >actual && + test_cmp "$expect" actual + ' + + test "$cmd" != diff || continue + + test_expect_success "$cmd --graph $verb statGraphWidth config" ' + git -c diff.statGraphWidth=26 $cmd $args --graph >output + grep " | " output >actual && + test_cmp "$expect-graph" actual + ' +done <<\EOF +ignores expect80 format-patch -1 --stdout +respects expect40 diff HEAD^ HEAD --stat +respects expect40 show --stat +respects expect40 log -1 --stat +EOF + + +cat >expect <<'EOF' + abcd | 1000 ++++++++++++++++++++++++++ +EOF +cat >expect-graph <<'EOF' +| abcd | 1000 ++++++++++++++++++++++++++ +EOF +while read cmd args +do + test_expect_success "$cmd --stat=width with big change" ' + git $cmd $args --stat=40 >output + grep " | " output >actual && + test_cmp expect actual + ' + + test_expect_success "$cmd --stat-width=width with big change" ' + git $cmd $args --stat-width=40 >output + grep " | " output >actual && + test_cmp expect actual + ' + + test_expect_success "$cmd --stat-graph-width with big change" ' + git $cmd $args --stat-graph-width=26 >output + grep " | " output >actual && + test_cmp expect actual + ' + + test "$cmd" != diff || continue + + test_expect_success "$cmd --stat-width=width --graph with big change" ' + git $cmd $args --stat-width=40 --graph >output + grep " | " output >actual && + test_cmp expect-graph actual + ' + + test_expect_success "$cmd --stat-graph-width --graph with big change" ' + git $cmd $args --stat-graph-width=26 --graph >output + grep " | " output >actual && + test_cmp expect-graph actual + ' +done <<\EOF +format-patch -1 --stdout +diff HEAD^ HEAD --stat +show --stat +log -1 --stat +EOF + +test_expect_success 'preparation for long filename tests' ' + cp abcd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa && + git add aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa && + git commit -m message +' + +cat >expect <<'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++ +EOF +cat >expect-graph <<'EOF' +| ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++ +EOF +while read cmd args +do + test_expect_success "$cmd --stat=width with big change is more balanced" ' + git $cmd $args --stat-width=60 >output && + grep " | " output >actual && + test_cmp expect actual + ' + + test "$cmd" != diff || continue + + test_expect_success "$cmd --stat=width --graph with big change is balanced" ' + git $cmd $args --stat-width=60 --graph >output && + grep " | " output >actual && + test_cmp expect-graph actual + ' +done <<\EOF +format-patch -1 --stdout +diff HEAD^ HEAD --stat +show --stat +log -1 --stat +EOF + +cat >expect80 <<'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++ +EOF +cat >expect80-graph <<'EOF' +| ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++ +EOF +cat >expect200 <<'EOF' + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +EOF +cat >expect200-graph <<'EOF' +| aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +EOF +while read verb expect cmd args +do + test_expect_success "$cmd $verb COLUMNS (long filename)" ' + COLUMNS=200 git $cmd $args >output + grep " | " output >actual && + test_cmp "$expect" actual + ' + + test "$cmd" != diff || continue + + test_expect_success "$cmd --graph $verb COLUMNS (long filename)" ' + COLUMNS=200 git $cmd $args --graph >output + grep " | " output >actual && + test_cmp "$expect-graph" actual + ' +done <<\EOF +ignores expect80 format-patch -1 --stdout +respects expect200 diff HEAD^ HEAD --stat +respects expect200 show --stat +respects expect200 log -1 --stat +EOF + +cat >expect1 <<'EOF' + ...aaaaaaa | 1000 ++++++ +EOF +cat >expect1-graph <<'EOF' +| ...aaaaaaa | 1000 ++++++ +EOF +while read verb expect cmd args +do + test_expect_success COLUMNS_CAN_BE_1 \ + "$cmd $verb prefix greater than COLUMNS (big change)" ' + COLUMNS=1 git $cmd $args >output + grep " | " output >actual && + test_cmp "$expect" actual + ' + + test "$cmd" != diff || continue + + test_expect_success COLUMNS_CAN_BE_1 \ + "$cmd --graph $verb prefix greater than COLUMNS (big change)" ' + COLUMNS=1 git $cmd $args --graph >output + grep " | " output >actual && + test_cmp "$expect-graph" actual + ' +done <<\EOF +ignores expect80 format-patch -1 --stdout +respects expect1 diff HEAD^ HEAD --stat +respects expect1 show --stat +respects expect1 log -1 --stat +EOF + +cat >expect <<'EOF' + abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +EOF +test_expect_success 'merge --stat respects COLUMNS (big change)' ' + git checkout -b branch HEAD^^ && + COLUMNS=100 git merge --stat --no-ff master^ >output && + grep " | " output >actual + test_cmp expect actual +' + +cat >expect <<'EOF' + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++++++++++++++++++++++++++++++++++++ +EOF +test_expect_success 'merge --stat respects COLUMNS (long filename)' ' + COLUMNS=100 git merge --stat --no-ff master >output && + grep " | " output >actual + test_cmp expect actual +' + +test_done diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh new file mode 100755 index 0000000000..979e98398b --- /dev/null +++ b/t/t4053-diff-no-index.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +test_description='diff --no-index' + +. ./test-lib.sh + +test_expect_success 'setup' ' + mkdir a && + mkdir b && + echo 1 >a/1 && + echo 2 >a/2 && + git init repo && + echo 1 >repo/a && + mkdir -p non/git && + echo 1 >non/git/a && + echo 1 >non/git/b +' + +test_expect_success 'git diff --no-index directories' ' + git diff --no-index a b >cnt + test $? = 1 && test_line_count = 14 cnt +' + +test_expect_success 'git diff --no-index relative path outside repo' ' + ( + cd repo && + test_expect_code 0 git diff --no-index a ../non/git/a && + test_expect_code 0 git diff --no-index ../non/git/a ../non/git/b + ) +' + +test_done diff --git a/t/t4054-diff-bogus-tree.sh b/t/t4054-diff-bogus-tree.sh new file mode 100755 index 0000000000..0843c87890 --- /dev/null +++ b/t/t4054-diff-bogus-tree.sh @@ -0,0 +1,83 @@ +#!/bin/sh + +test_description='test diff with a bogus tree containing the null sha1' +. ./test-lib.sh + +empty_tree=4b825dc642cb6eb9a060e54bf8d69288fbee4904 + +test_expect_success 'create bogus tree' ' + bogus_tree=$( + printf "100644 fooQQQQQQQQQQQQQQQQQQQQQ" | + q_to_nul | + git hash-object -w --stdin -t tree + ) +' + +test_expect_success 'create tree with matching file' ' + echo bar >foo && + git add foo && + good_tree=$(git write-tree) + blob=$(git rev-parse :foo) +' + +test_expect_success 'raw diff shows null sha1 (addition)' ' + echo ":000000 100644 $_z40 $_z40 A foo" >expect && + git diff-tree $empty_tree $bogus_tree >actual && + test_cmp expect actual +' + +test_expect_success 'raw diff shows null sha1 (removal)' ' + echo ":100644 000000 $_z40 $_z40 D foo" >expect && + git diff-tree $bogus_tree $empty_tree >actual && + test_cmp expect actual +' + +test_expect_success 'raw diff shows null sha1 (modification)' ' + echo ":100644 100644 $blob $_z40 M foo" >expect && + git diff-tree $good_tree $bogus_tree >actual && + test_cmp expect actual +' + +test_expect_success 'raw diff shows null sha1 (other direction)' ' + echo ":100644 100644 $_z40 $blob M foo" >expect && + git diff-tree $bogus_tree $good_tree >actual && + test_cmp expect actual +' + +test_expect_success 'raw diff shows null sha1 (reverse)' ' + echo ":100644 100644 $_z40 $blob M foo" >expect && + git diff-tree -R $good_tree $bogus_tree >actual && + test_cmp expect actual +' + +test_expect_success 'raw diff shows null sha1 (index)' ' + echo ":100644 100644 $_z40 $blob M foo" >expect && + git diff-index $bogus_tree >actual && + test_cmp expect actual +' + +test_expect_success 'patch fails due to bogus sha1 (addition)' ' + test_must_fail git diff-tree -p $empty_tree $bogus_tree +' + +test_expect_success 'patch fails due to bogus sha1 (removal)' ' + test_must_fail git diff-tree -p $bogus_tree $empty_tree +' + +test_expect_success 'patch fails due to bogus sha1 (modification)' ' + test_must_fail git diff-tree -p $good_tree $bogus_tree +' + +test_expect_success 'patch fails due to bogus sha1 (other direction)' ' + test_must_fail git diff-tree -p $bogus_tree $good_tree +' + +test_expect_success 'patch fails due to bogus sha1 (reverse)' ' + test_must_fail git diff-tree -R -p $good_tree $bogus_tree +' + +test_expect_success 'patch fails due to bogus sha1 (index)' ' + test_must_fail git diff-index -p $bogus_tree +' + +test_done diff --git a/t/t4100-apply-stat.sh b/t/t4100-apply-stat.sh index 9b433de836..744b8e51be 100755 --- a/t/t4100-apply-stat.sh +++ b/t/t4100-apply-stat.sh @@ -17,13 +17,13 @@ do test_expect_success "$title" ' git apply --stat --summary \ <"$TEST_DIRECTORY/t4100/t-apply-$num.patch" >current && - test_cmp "$TEST_DIRECTORY"/t4100/t-apply-$num.expect current + test_i18ncmp "$TEST_DIRECTORY"/t4100/t-apply-$num.expect current ' test_expect_success "$title with recount" ' sed -e "$UNC" <"$TEST_DIRECTORY/t4100/t-apply-$num.patch" | git apply --recount --stat --summary >current && - test_cmp "$TEST_DIRECTORY"/t4100/t-apply-$num.expect current + test_i18ncmp "$TEST_DIRECTORY"/t4100/t-apply-$num.expect current ' done <<\EOF rename diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh index dbbf56cba9..99627bc6d6 100755 --- a/t/t4103-apply-binary.sh +++ b/t/t4103-apply-binary.sh @@ -25,10 +25,10 @@ test_expect_success 'setup' " git commit -m 'Initial Version' 2>/dev/null && git checkout -b binary && - perl -pe 'y/x/\000/' <file1 >file3 && + "$PERL_PATH" -pe 'y/x/\000/' <file1 >file3 && cat file3 >file4 && git add file2 && - perl -pe 'y/\000/v/' <file3 >file1 && + "$PERL_PATH" -pe 'y/\000/v/' <file3 >file1 && rm -f file2 && git update-index --add --remove file1 file2 file3 file4 && git commit -m 'Second Version' && diff --git a/t/t4108-apply-threeway.sh b/t/t4108-apply-threeway.sh new file mode 100755 index 0000000000..fa5d4efb89 --- /dev/null +++ b/t/t4108-apply-threeway.sh @@ -0,0 +1,157 @@ +#!/bin/sh + +test_description='git apply --3way' + +. ./test-lib.sh + +create_file () { + for i + do + echo "$i" + done +} + +sanitize_conflicted_diff () { + sed -e ' + /^index /d + s/^\(+[<>][<>][<>][<>]*\) .*/\1/ + ' +} + +test_expect_success setup ' + test_tick && + create_file >one 1 2 3 4 5 6 7 && + cat one >two && + git add one two && + git commit -m initial && + + git branch side && + + test_tick && + create_file >one 1 two 3 4 5 six 7 && + create_file >two 1 two 3 4 5 6 7 && + git commit -a -m master && + + git checkout side && + create_file >one 1 2 3 4 five 6 7 && + create_file >two 1 2 3 4 five 6 7 && + git commit -a -m side && + + git checkout master +' + +test_expect_success 'apply without --3way' ' + git diff side^ side >P.diff && + + # should fail to apply + git reset --hard && + git checkout master^0 && + test_must_fail git apply --index P.diff && + # should leave things intact + git diff-files --exit-code && + git diff-index --exit-code --cached HEAD +' + +test_expect_success 'apply with --3way' ' + # Merging side should be similar to applying this patch + git diff ...side >P.diff && + + # The corresponding conflicted merge + git reset --hard && + git checkout master^0 && + test_must_fail git merge --no-commit side && + git ls-files -s >expect.ls && + git diff HEAD | sanitize_conflicted_diff >expect.diff && + + # should fail to apply + git reset --hard && + git checkout master^0 && + test_must_fail git apply --index --3way P.diff && + git ls-files -s >actual.ls && + git diff HEAD | sanitize_conflicted_diff >actual.diff && + + # The result should resemble the corresponding merge + test_cmp expect.ls actual.ls && + test_cmp expect.diff actual.diff +' + +test_expect_success 'apply with --3way with rerere enabled' ' + git config rerere.enabled true && + + # Merging side should be similar to applying this patch + git diff ...side >P.diff && + + # The corresponding conflicted merge + git reset --hard && + git checkout master^0 && + test_must_fail git merge --no-commit side && + + # Manually resolve and record the resolution + create_file 1 two 3 4 five six 7 >one && + git rerere && + cat one >expect && + + # should fail to apply + git reset --hard && + git checkout master^0 && + test_must_fail git apply --index --3way P.diff && + + # but rerere should have replayed the recorded resolution + test_cmp expect one +' + +test_expect_success 'apply -3 with add/add conflict setup' ' + git reset --hard && + + git checkout -b adder && + create_file 1 2 3 4 5 6 7 >three && + create_file 1 2 3 4 5 6 7 >four && + git add three four && + git commit -m "add three and four" && + + git checkout -b another adder^ && + create_file 1 2 3 4 5 6 7 >three && + create_file 1 2 3 four 5 6 7 >four && + git add three four && + git commit -m "add three and four" && + + # Merging another should be similar to applying this patch + git diff adder...another >P.diff && + + git checkout adder^0 && + test_must_fail git merge --no-commit another && + git ls-files -s >expect.ls && + git diff HEAD | sanitize_conflicted_diff >expect.diff +' + +test_expect_success 'apply -3 with add/add conflict' ' + # should fail to apply ... + git reset --hard && + git checkout adder^0 && + test_must_fail git apply --index --3way P.diff && + # ... and leave conflicts in the index and in the working tree + git ls-files -s >actual.ls && + git diff HEAD | sanitize_conflicted_diff >actual.diff && + + # The result should resemble the corresponding merge + test_cmp expect.ls actual.ls && + test_cmp expect.diff actual.diff +' + +test_expect_success 'apply -3 with add/add conflict (dirty working tree)' ' + # should fail to apply ... + git reset --hard && + git checkout adder^0 && + echo >>four && + cat four >four.save && + cat three >three.save && + git ls-files -s >expect.ls && + test_must_fail git apply --index --3way P.diff && + # ... and should not touch anything + git ls-files -s >actual.ls && + test_cmp expect.ls actual.ls && + test_cmp four.save four && + test_cmp three.save three +' + +test_done diff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh index 2298ece801..fca815392e 100755 --- a/t/t4116-apply-reverse.sh +++ b/t/t4116-apply-reverse.sh @@ -12,14 +12,14 @@ test_description='git apply in reverse test_expect_success setup ' for i in a b c d e f g h i j k l m n; do echo $i; done >file1 && - perl -pe "y/ijk/\\000\\001\\002/" <file1 >file2 && + "$PERL_PATH" -pe "y/ijk/\\000\\001\\002/" <file1 >file2 && git add file1 file2 && git commit -m initial && git tag initial && for i in a b c g h i J K L m o n p q; do echo $i; done >file1 && - perl -pe "y/mon/\\000\\001\\002/" <file1 >file2 && + "$PERL_PATH" -pe "y/mon/\\000\\001\\002/" <file1 >file2 && git commit -a -m second && git tag second && diff --git a/t/t4117-apply-reject.sh b/t/t4117-apply-reject.sh index e9ccd161ee..8e15ecbdfd 100755 --- a/t/t4117-apply-reject.sh +++ b/t/t4117-apply-reject.sh @@ -46,6 +46,14 @@ test_expect_success setup ' cat file1 >saved.file1 ' +test_expect_success 'apply --reject is incompatible with --3way' ' + test_when_finished "cat saved.file1 >file1" && + git diff >patch.0 && + git checkout file1 && + test_must_fail git apply --reject --3way patch.0 && + git diff --exit-code +' + test_expect_success 'apply without --reject should fail' ' if git apply patch.1 diff --git a/t/t4150-am.sh b/t/t4150-am.sh index 658354a6ce..cdafd7e7c1 100755 --- a/t/t4150-am.sh +++ b/t/t4150-am.sh @@ -238,7 +238,7 @@ test_expect_success 'am stays in branch' ' test_expect_success 'am --signoff does not add Signed-off-by: line if already there' ' git format-patch --stdout HEAD^ >patch3 && - sed -e "/^Subject/ s,\[PATCH,Re: Re: Re: & 1/5 v2," patch3 >patch4 && + sed -e "/^Subject/ s,\[PATCH,Re: Re: Re: & 1/5 v2] [foo," patch3 >patch4 && rm -fr .git/rebase-apply && git reset --hard && git checkout HEAD^ && @@ -260,7 +260,17 @@ test_expect_success 'am --keep really keeps the subject' ' git am --keep patch4 && ! test -d .git/rebase-apply && git cat-file commit HEAD >actual && - grep "Re: Re: Re: \[PATCH 1/5 v2\] third" actual + grep "Re: Re: Re: \[PATCH 1/5 v2\] \[foo\] third" actual +' + +test_expect_success 'am --keep-non-patch really keeps the non-patch part' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout HEAD^ && + git am --keep-non-patch patch4 && + ! test -d .git/rebase-apply && + git cat-file commit HEAD >actual && + grep "^\[foo\] third" actual ' test_expect_success 'am -3 falls back to 3-way merge' ' @@ -515,9 +525,9 @@ test_expect_success 'am empty-file does not infloop' ' git reset --hard && touch empty-file && test_tick && - { git am empty-file > actual 2>&1 && false || :; } && + test_must_fail git am empty-file 2>actual && echo Patch format detection failed. >expected && - test_cmp expected actual + test_i18ncmp expected actual ' test_done diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh index 36255d608a..3ab670d36a 100755 --- a/t/t4200-rerere.sh +++ b/t/t4200-rerere.sh @@ -78,7 +78,7 @@ test_expect_success 'activate rerere, old style (conflicting merge)' ' test_might_fail git config --unset rerere.enabled && test_must_fail git merge first && - sha1=$(perl -pe "s/ .*//" .git/MERGE_RR) && + sha1=$("$PERL_PATH" -pe "s/ .*//" .git/MERGE_RR) && rr=.git/rr-cache/$sha1 && grep "^=======\$" $rr/preimage && ! test -f $rr/postimage && @@ -91,7 +91,7 @@ test_expect_success 'rerere.enabled works, too' ' git reset --hard && test_must_fail git merge first && - sha1=$(perl -pe "s/ .*//" .git/MERGE_RR) && + sha1=$("$PERL_PATH" -pe "s/ .*//" .git/MERGE_RR) && rr=.git/rr-cache/$sha1 && grep ^=======$ $rr/preimage ' @@ -101,7 +101,7 @@ test_expect_success 'set up rr-cache' ' git config rerere.enabled true && git reset --hard && test_must_fail git merge first && - sha1=$(perl -pe "s/ .*//" .git/MERGE_RR) && + sha1=$("$PERL_PATH" -pe "s/ .*//" .git/MERGE_RR) && rr=.git/rr-cache/$sha1 ' @@ -185,7 +185,7 @@ test_expect_success 'rerere updates postimage timestamp' ' test_expect_success 'rerere clear' ' rm $rr/postimage && - echo "$sha1 a1" | perl -pe "y/\012/\000/" >.git/MERGE_RR && + echo "$sha1 a1" | "$PERL_PATH" -pe "y/\012/\000/" >.git/MERGE_RR && git rerere clear && ! test -d $rr ' diff --git a/t/t4202-log.sh b/t/t4202-log.sh index 222f7559e9..71be59d446 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -516,4 +516,294 @@ test_expect_success 'show added path under "--follow -M"' ' ) ' +cat >expect <<\EOF +* commit COMMIT_OBJECT_NAME +|\ Merge: MERGE_PARENTS +| | Author: A U Thor <author@example.com> +| | +| | Merge HEADS DESCRIPTION +| | +| * commit COMMIT_OBJECT_NAME +| | Author: A U Thor <author@example.com> +| | +| | reach +| | --- +| | reach.t | 1 + +| | 1 file changed, 1 insertion(+) +| | +| | diff --git a/reach.t b/reach.t +| | new file mode 100644 +| | index 0000000..10c9591 +| | --- /dev/null +| | +++ b/reach.t +| | @@ -0,0 +1 @@ +| | +reach +| | +| \ +*-. \ commit COMMIT_OBJECT_NAME +|\ \ \ Merge: MERGE_PARENTS +| | | | Author: A U Thor <author@example.com> +| | | | +| | | | Merge HEADS DESCRIPTION +| | | | +| | * | commit COMMIT_OBJECT_NAME +| | |/ Author: A U Thor <author@example.com> +| | | +| | | octopus-b +| | | --- +| | | octopus-b.t | 1 + +| | | 1 file changed, 1 insertion(+) +| | | +| | | diff --git a/octopus-b.t b/octopus-b.t +| | | new file mode 100644 +| | | index 0000000..d5fcad0 +| | | --- /dev/null +| | | +++ b/octopus-b.t +| | | @@ -0,0 +1 @@ +| | | +octopus-b +| | | +| * | commit COMMIT_OBJECT_NAME +| |/ Author: A U Thor <author@example.com> +| | +| | octopus-a +| | --- +| | octopus-a.t | 1 + +| | 1 file changed, 1 insertion(+) +| | +| | diff --git a/octopus-a.t b/octopus-a.t +| | new file mode 100644 +| | index 0000000..11ee015 +| | --- /dev/null +| | +++ b/octopus-a.t +| | @@ -0,0 +1 @@ +| | +octopus-a +| | +* | commit COMMIT_OBJECT_NAME +|/ Author: A U Thor <author@example.com> +| +| seventh +| --- +| seventh.t | 1 + +| 1 file changed, 1 insertion(+) +| +| diff --git a/seventh.t b/seventh.t +| new file mode 100644 +| index 0000000..9744ffc +| --- /dev/null +| +++ b/seventh.t +| @@ -0,0 +1 @@ +| +seventh +| +* commit COMMIT_OBJECT_NAME +|\ Merge: MERGE_PARENTS +| | Author: A U Thor <author@example.com> +| | +| | Merge branch 'tangle' +| | +| * commit COMMIT_OBJECT_NAME +| |\ Merge: MERGE_PARENTS +| | | Author: A U Thor <author@example.com> +| | | +| | | Merge branch 'side' (early part) into tangle +| | | +| * | commit COMMIT_OBJECT_NAME +| |\ \ Merge: MERGE_PARENTS +| | | | Author: A U Thor <author@example.com> +| | | | +| | | | Merge branch 'master' (early part) into tangle +| | | | +| * | | commit COMMIT_OBJECT_NAME +| | | | Author: A U Thor <author@example.com> +| | | | +| | | | tangle-a +| | | | --- +| | | | tangle-a | 1 + +| | | | 1 file changed, 1 insertion(+) +| | | | +| | | | diff --git a/tangle-a b/tangle-a +| | | | new file mode 100644 +| | | | index 0000000..7898192 +| | | | --- /dev/null +| | | | +++ b/tangle-a +| | | | @@ -0,0 +1 @@ +| | | | +a +| | | | +* | | | commit COMMIT_OBJECT_NAME +|\ \ \ \ Merge: MERGE_PARENTS +| | | | | Author: A U Thor <author@example.com> +| | | | | +| | | | | Merge branch 'side' +| | | | | +| * | | | commit COMMIT_OBJECT_NAME +| | |_|/ Author: A U Thor <author@example.com> +| |/| | +| | | | side-2 +| | | | --- +| | | | 2 | 1 + +| | | | 1 file changed, 1 insertion(+) +| | | | +| | | | diff --git a/2 b/2 +| | | | new file mode 100644 +| | | | index 0000000..0cfbf08 +| | | | --- /dev/null +| | | | +++ b/2 +| | | | @@ -0,0 +1 @@ +| | | | +2 +| | | | +| * | | commit COMMIT_OBJECT_NAME +| | | | Author: A U Thor <author@example.com> +| | | | +| | | | side-1 +| | | | --- +| | | | 1 | 1 + +| | | | 1 file changed, 1 insertion(+) +| | | | +| | | | diff --git a/1 b/1 +| | | | new file mode 100644 +| | | | index 0000000..d00491f +| | | | --- /dev/null +| | | | +++ b/1 +| | | | @@ -0,0 +1 @@ +| | | | +1 +| | | | +* | | | commit COMMIT_OBJECT_NAME +| | | | Author: A U Thor <author@example.com> +| | | | +| | | | Second +| | | | --- +| | | | one | 1 + +| | | | 1 file changed, 1 insertion(+) +| | | | +| | | | diff --git a/one b/one +| | | | new file mode 100644 +| | | | index 0000000..9a33383 +| | | | --- /dev/null +| | | | +++ b/one +| | | | @@ -0,0 +1 @@ +| | | | +case +| | | | +* | | | commit COMMIT_OBJECT_NAME +| |_|/ Author: A U Thor <author@example.com> +|/| | +| | | sixth +| | | --- +| | | a/two | 1 - +| | | 1 file changed, 1 deletion(-) +| | | +| | | diff --git a/a/two b/a/two +| | | deleted file mode 100644 +| | | index 9245af5..0000000 +| | | --- a/a/two +| | | +++ /dev/null +| | | @@ -1 +0,0 @@ +| | | -ni +| | | +* | | commit COMMIT_OBJECT_NAME +| | | Author: A U Thor <author@example.com> +| | | +| | | fifth +| | | --- +| | | a/two | 1 + +| | | 1 file changed, 1 insertion(+) +| | | +| | | diff --git a/a/two b/a/two +| | | new file mode 100644 +| | | index 0000000..9245af5 +| | | --- /dev/null +| | | +++ b/a/two +| | | @@ -0,0 +1 @@ +| | | +ni +| | | +* | | commit COMMIT_OBJECT_NAME +|/ / Author: A U Thor <author@example.com> +| | +| | fourth +| | --- +| | ein | 1 + +| | 1 file changed, 1 insertion(+) +| | +| | diff --git a/ein b/ein +| | new file mode 100644 +| | index 0000000..9d7e69f +| | --- /dev/null +| | +++ b/ein +| | @@ -0,0 +1 @@ +| | +ichi +| | +* | commit COMMIT_OBJECT_NAME +|/ Author: A U Thor <author@example.com> +| +| third +| --- +| ichi | 1 + +| one | 1 - +| 2 files changed, 1 insertion(+), 1 deletion(-) +| +| diff --git a/ichi b/ichi +| new file mode 100644 +| index 0000000..9d7e69f +| --- /dev/null +| +++ b/ichi +| @@ -0,0 +1 @@ +| +ichi +| diff --git a/one b/one +| deleted file mode 100644 +| index 9d7e69f..0000000 +| --- a/one +| +++ /dev/null +| @@ -1 +0,0 @@ +| -ichi +| +* commit COMMIT_OBJECT_NAME +| Author: A U Thor <author@example.com> +| +| second +| --- +| one | 2 +- +| 1 file changed, 1 insertion(+), 1 deletion(-) +| +| diff --git a/one b/one +| index 5626abf..9d7e69f 100644 +| --- a/one +| +++ b/one +| @@ -1 +1 @@ +| -one +| +ichi +| +* commit COMMIT_OBJECT_NAME + Author: A U Thor <author@example.com> + + initial + --- + one | 1 + + 1 file changed, 1 insertion(+) + + diff --git a/one b/one + new file mode 100644 + index 0000000..5626abf + --- /dev/null + +++ b/one + @@ -0,0 +1 @@ + +one +EOF + +sanitize_output () { + sed -e 's/ *$//' \ + -e 's/commit [0-9a-f]*$/commit COMMIT_OBJECT_NAME/' \ + -e 's/Merge: [ 0-9a-f]*$/Merge: MERGE_PARENTS/' \ + -e 's/Merge tag.*/Merge HEADS DESCRIPTION/' \ + -e 's/Merge commit.*/Merge HEADS DESCRIPTION/' \ + -e 's/, 0 deletions(-)//' \ + -e 's/, 0 insertions(+)//' \ + -e 's/ 1 files changed, / 1 file changed, /' \ + -e 's/, 1 deletions(-)/, 1 deletion(-)/' \ + -e 's/, 1 insertions(+)/, 1 insertion(+)/' +} + +test_expect_success 'log --graph with diff and stats' ' + git log --graph --pretty=short --stat -p >actual && + sanitize_output >actual.sanitized <actual && + test_cmp expect actual.sanitized +' + test_done diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh index 2ae9faa8b3..4afd77815f 100755 --- a/t/t4205-log-pretty-formats.sh +++ b/t/t4205-log-pretty-formats.sh @@ -71,4 +71,32 @@ test_expect_success 'alias loop' ' test_must_fail git log --pretty=test-foo ' +test_expect_success 'NUL separation' ' + printf "add bar\0initial" >expected && + git log -z --pretty="format:%s" >actual && + test_cmp expected actual +' + +test_expect_success 'NUL termination' ' + printf "add bar\0initial\0" >expected && + git log -z --pretty="tformat:%s" >actual && + test_cmp expected actual +' + +test_expect_success 'NUL separation with --stat' ' + stat0_part=$(git diff --stat HEAD^ HEAD) && + stat1_part=$(git diff --stat --root HEAD^) && + printf "add bar\n$stat0_part\n\0initial\n$stat1_part\n" >expected && + git log -z --stat --pretty="format:%s" >actual && + test_cmp expected actual +' + +test_expect_failure 'NUL termination with --stat' ' + stat0_part=$(git diff --stat HEAD^ HEAD) && + stat1_part=$(git diff --stat --root HEAD^) && + printf "add bar\n$stat0_part\n\0initial\n$stat1_part\n\0" >expected && + git log -z --stat --pretty="tformat:%s" >actual && + test_cmp expected actual +' + test_done diff --git a/t/t4209-log-pickaxe.sh b/t/t4209-log-pickaxe.sh new file mode 100755 index 0000000000..eed727341d --- /dev/null +++ b/t/t4209-log-pickaxe.sh @@ -0,0 +1,119 @@ +#!/bin/sh + +test_description='log --grep/--author/--regexp-ignore-case/-S/-G' +. ./test-lib.sh + +test_expect_success setup ' + >file && + git add file && + test_tick && + git commit -m initial && + + echo Picked >file && + test_tick && + git commit -a --author="Another Person <another@example.com>" -m second +' + +test_expect_success 'log --grep' ' + git log --grep=initial --format=%H >actual && + git rev-parse --verify HEAD^ >expect && + test_cmp expect actual +' + +test_expect_success 'log --grep --regexp-ignore-case' ' + git log --regexp-ignore-case --grep=InItial --format=%H >actual && + git rev-parse --verify HEAD^ >expect && + test_cmp expect actual +' + +test_expect_success 'log --grep -i' ' + git log -i --grep=InItial --format=%H >actual && + git rev-parse --verify HEAD^ >expect && + test_cmp expect actual +' + +test_expect_success 'log --author --regexp-ignore-case' ' + git log --regexp-ignore-case --author=person --format=%H >actual && + git rev-parse --verify HEAD >expect && + test_cmp expect actual +' + +test_expect_success 'log --author -i' ' + git log -i --author=person --format=%H >actual && + git rev-parse --verify HEAD >expect && + test_cmp expect actual +' + +test_expect_success 'log -G (nomatch)' ' + git log -Gpicked --format=%H >actual && + >expect && + test_cmp expect actual +' + +test_expect_success 'log -G (match)' ' + git log -GPicked --format=%H >actual && + git rev-parse --verify HEAD >expect && + test_cmp expect actual +' + +test_expect_success 'log -G --regexp-ignore-case (nomatch)' ' + git log --regexp-ignore-case -Gpickle --format=%H >actual && + >expect && + test_cmp expect actual +' + +test_expect_success 'log -G -i (nomatch)' ' + git log -i -Gpickle --format=%H >actual && + >expect && + test_cmp expect actual +' + +test_expect_success 'log -G --regexp-ignore-case (match)' ' + git log --regexp-ignore-case -Gpicked --format=%H >actual && + git rev-parse --verify HEAD >expect && + test_cmp expect actual +' + +test_expect_success 'log -G -i (match)' ' + git log -i -Gpicked --format=%H >actual && + git rev-parse --verify HEAD >expect && + test_cmp expect actual +' + +test_expect_success 'log -S (nomatch)' ' + git log -Spicked --format=%H >actual && + >expect && + test_cmp expect actual +' + +test_expect_success 'log -S (match)' ' + git log -SPicked --format=%H >actual && + git rev-parse --verify HEAD >expect && + test_cmp expect actual +' + +test_expect_success 'log -S --regexp-ignore-case (match)' ' + git log --regexp-ignore-case -Spicked --format=%H >actual && + git rev-parse --verify HEAD >expect && + test_cmp expect actual +' + +test_expect_success 'log -S -i (match)' ' + git log -i -Spicked --format=%H >actual && + git rev-parse --verify HEAD >expect && + test_cmp expect actual +' + +test_expect_success 'log -S --regexp-ignore-case (nomatch)' ' + git log --regexp-ignore-case -Spickle --format=%H >actual && + >expect && + test_cmp expect actual +' + +test_expect_success 'log -S -i (nomatch)' ' + git log -i -Spickle --format=%H >actual && + >expect && + test_cmp expect actual +' + +test_done diff --git a/t/t4253-am-keep-cr-dos.sh b/t/t4253-am-keep-cr-dos.sh index 735e55d77c..553fe3e88e 100755 --- a/t/t4253-am-keep-cr-dos.sh +++ b/t/t4253-am-keep-cr-dos.sh @@ -62,7 +62,7 @@ test_expect_success 'am with dos files config am.keepcr' ' git diff --exit-code master ' -test_expect_success 'am with dos files config am.keepcr overriden by --no-keep-cr' ' +test_expect_success 'am with dos files config am.keepcr overridden by --no-keep-cr' ' git config am.keepcr 1 && git checkout -b dosfiles-conf-keepcr-override initial && git format-patch -k initial..master && @@ -83,7 +83,7 @@ test_expect_success 'am with dos files with --keep-cr continue' ' git diff --exit-code master ' -test_expect_success 'am with unix files config am.keepcr overriden by --no-keep-cr' ' +test_expect_success 'am with unix files config am.keepcr overridden by --no-keep-cr' ' git config am.keepcr 1 && git checkout -b unixfiles-conf-keepcr-override initial && cp -f file1 file && diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index 527c9e7548..ecf00edab2 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -31,6 +31,26 @@ GUNZIP=${GUNZIP:-gzip -d} SUBSTFORMAT=%H%n +check_zip() { + zipfile=$1.zip + listfile=$1.lst + dir=$1 + dir_with_prefix=$dir/$2 + + test_expect_success UNZIP " extract ZIP archive" " + (mkdir $dir && cd $dir && $UNZIP ../$zipfile) + " + + test_expect_success UNZIP " validate filenames" " + (cd ${dir_with_prefix}a && find .) | sort >$listfile && + test_cmp a.lst $listfile + " + + test_expect_success UNZIP " validate file contents" " + diff -r a ${dir_with_prefix}a + " +} + test_expect_success \ 'populate workdir' \ 'mkdir a b c && @@ -84,6 +104,12 @@ test_expect_success \ 'git archive vs. git tar-tree' \ 'test_cmp b.tar b2.tar' +test_expect_success 'git archive on large files' ' + test_config core.bigfilethreshold 1 && + git archive HEAD >b3.tar && + test_cmp b.tar b3.tar +' + test_expect_success \ 'git archive in a bare repo' \ '(cd bare.git && git archive HEAD) >b3.tar' @@ -175,10 +201,19 @@ test_expect_success \ test_cmp a/substfile2 g/prefix/a/substfile2 ' +$UNZIP -v >/dev/null 2>&1 +if [ $? -eq 127 ]; then + say "Skipping ZIP tests, because unzip was not found" +else + test_set_prereq UNZIP +fi + test_expect_success \ 'git archive --format=zip' \ 'git archive --format=zip HEAD >d.zip' +check_zip d + test_expect_success \ 'git archive --format=zip in a bare repo' \ '(cd bare.git && git archive --format=zip HEAD) >d1.zip' @@ -201,42 +236,25 @@ test_expect_success 'git archive with --output, override inferred format' ' test_cmp b.tar d4.zip ' -$UNZIP -v >/dev/null 2>&1 -if [ $? -eq 127 ]; then - say "Skipping ZIP tests, because unzip was not found" -else - test_set_prereq UNZIP -fi - -test_expect_success UNZIP \ - 'extract ZIP archive' \ - '(mkdir d && cd d && $UNZIP ../d.zip)' - -test_expect_success UNZIP \ - 'validate filenames' \ - '(cd d/a && find .) | sort >d.lst && - test_cmp a.lst d.lst' - -test_expect_success UNZIP \ - 'validate file contents' \ - 'diff -r a d/a' - test_expect_success \ 'git archive --format=zip with prefix' \ 'git archive --format=zip --prefix=prefix/ HEAD >e.zip' -test_expect_success UNZIP \ - 'extract ZIP archive with prefix' \ - '(mkdir e && cd e && $UNZIP ../e.zip)' +check_zip e prefix/ -test_expect_success UNZIP \ - 'validate filenames with prefix' \ - '(cd e/prefix/a && find .) | sort >e.lst && - test_cmp a.lst e.lst' +test_expect_success 'git archive -0 --format=zip on large files' ' + test_config core.bigfilethreshold 1 && + git archive -0 --format=zip HEAD >large.zip +' -test_expect_success UNZIP \ - 'validate file contents with prefix' \ - 'diff -r a e/prefix/a' +check_zip large + +test_expect_success 'git archive --format=zip on large files' ' + test_config core.bigfilethreshold 1 && + git archive --format=zip HEAD >large-compressed.zip +' + +check_zip large-compressed test_expect_success \ 'git archive --list outside of a git repo' \ diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh index ebc36c1758..81904d9ec8 100755 --- a/t/t5100-mailinfo.sh +++ b/t/t5100-mailinfo.sh @@ -65,7 +65,7 @@ test_expect_success 'respect NULs' ' git mailsplit -d3 -o. "$TEST_DIRECTORY"/t5100/nul-plain && test_cmp "$TEST_DIRECTORY"/t5100/nul-plain 001 && (cat 001 | git mailinfo msg patch) && - test 4 = $(wc -l < patch) + test_line_count = 4 patch ' diff --git a/t/t5100/patch0001 b/t/t5100/patch0001 index 8ce155167d..02c97746d6 100644 --- a/t/t5100/patch0001 +++ b/t/t5100/patch0001 @@ -1,5 +1,5 @@ --- - foo | 2 +- + foo | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/foo b/foo diff --git a/t/t5100/patch0002 b/t/t5100/patch0002 index 8ce155167d..02c97746d6 100644 --- a/t/t5100/patch0002 +++ b/t/t5100/patch0002 @@ -1,5 +1,5 @@ --- - foo | 2 +- + foo | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/foo b/foo diff --git a/t/t5100/patch0003 b/t/t5100/patch0003 index 8ce155167d..02c97746d6 100644 --- a/t/t5100/patch0003 +++ b/t/t5100/patch0003 @@ -1,5 +1,5 @@ --- - foo | 2 +- + foo | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/foo b/foo diff --git a/t/t5100/patch0005 b/t/t5100/patch0005 index 7d24b24af8..ab7a38373b 100644 --- a/t/t5100/patch0005 +++ b/t/t5100/patch0005 @@ -1,7 +1,7 @@ --- - Documentation/git-cvsimport-script.txt | 9 ++++++++- - git-cvsimport-script | 4 ++-- + Documentation/git-cvsimport-script.txt | 9 ++++++++- + git-cvsimport-script | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) 50452f9c0c2df1f04d83a26266ba704b13861632 diff --git a/t/t5100/patch0006 b/t/t5100/patch0006 index 8ce155167d..02c97746d6 100644 --- a/t/t5100/patch0006 +++ b/t/t5100/patch0006 @@ -1,5 +1,5 @@ --- - foo | 2 +- + foo | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/foo b/foo diff --git a/t/t5100/patch0010 b/t/t5100/patch0010 index f055481d56..436821c97a 100644 --- a/t/t5100/patch0010 +++ b/t/t5100/patch0010 @@ -1,5 +1,5 @@ --- - builtin-mailinfo.c | 2 +- + builtin-mailinfo.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c diff --git a/t/t5100/patch0011 b/t/t5100/patch0011 index 8841d3c139..0988713761 100644 --- a/t/t5100/patch0011 +++ b/t/t5100/patch0011 @@ -1,5 +1,5 @@ --- - builtin-mailinfo.c | 4 ++-- + builtin-mailinfo.c | 4 ++-- diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c index 3e5fe51..aabfe5c 100644 diff --git a/t/t5100/patch0014 b/t/t5100/patch0014 index 124efd234f..3f3825f9f2 100644 --- a/t/t5100/patch0014 +++ b/t/t5100/patch0014 @@ -1,5 +1,5 @@ --- - builtin-mailinfo.c | 37 ++++++++++++++++++++++++++++++++++++- + builtin-mailinfo.c | 37 ++++++++++++++++++++++++++++++++++++- 1 files changed, 36 insertions(+), 1 deletions(-) diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c diff --git a/t/t5100/patch0014--scissors b/t/t5100/patch0014--scissors index 124efd234f..3f3825f9f2 100644 --- a/t/t5100/patch0014--scissors +++ b/t/t5100/patch0014--scissors @@ -1,5 +1,5 @@ --- - builtin-mailinfo.c | 37 ++++++++++++++++++++++++++++++++++++- + builtin-mailinfo.c | 37 ++++++++++++++++++++++++++++++++++++- 1 files changed, 36 insertions(+), 1 deletions(-) diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c diff --git a/t/t5100/sample.mbox b/t/t5100/sample.mbox index de1031241d..34a09a0fc1 100644 --- a/t/t5100/sample.mbox +++ b/t/t5100/sample.mbox @@ -12,7 +12,7 @@ Subject: [PATCH] a commit. Here is a patch from A U Thor. --- - foo | 2 +- + foo | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/foo b/foo @@ -52,7 +52,7 @@ two truly blank and another full of spaces in between. Hope this helps. --- - foo | 2 +- + foo | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/foo b/foo @@ -83,7 +83,7 @@ Message-Id: <nitpicker.12121212@example.net> Hopefully this would fix the problem stated there. --- - foo | 2 +- + foo | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/foo b/foo @@ -249,8 +249,8 @@ actual flags. Signed-off-by: David K=E5gedal <davidk@lysator.liu.se> --- - Documentation/git-cvsimport-script.txt | 9 ++++++++- - git-cvsimport-script | 4 ++-- + Documentation/git-cvsimport-script.txt | 9 ++++++++- + git-cvsimport-script | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) 50452f9c0c2df1f04d83a26266ba704b13861632 @@ -379,7 +379,7 @@ Subject: [PATCH] a commit. Here is a patch from A U Thor. --- - foo | 2 +- + foo | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/foo b/foo @@ -449,7 +449,7 @@ memcmp("Subject: ", header[i], 7) will never match. Signed-off-by: Lukas Sandström <lukass@etek.chalmers.se> Signed-off-by: Junio C Hamano <gitster@pobox.com> --- - builtin-mailinfo.c | 2 +- + builtin-mailinfo.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c @@ -482,7 +482,7 @@ Content-Transfer-Encoding: quoted-printable Here comes a commit log message, and its second line is here. --- - builtin-mailinfo.c | 4 ++-- + builtin-mailinfo.c | 4 ++-- diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c index 3e5fe51..aabfe5c 100644 @@ -587,7 +587,7 @@ everything before it in the message body. Signed-off-by: Junio C Hamano <gitster@pobox.com> --- - builtin-mailinfo.c | 37 ++++++++++++++++++++++++++++++++++++- + builtin-mailinfo.c | 37 ++++++++++++++++++++++++++++++++++++- 1 files changed, 36 insertions(+), 1 deletions(-) diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c diff --git a/t/t5150-request-pull.sh b/t/t5150-request-pull.sh index 2af8947eeb..432f98c357 100755 --- a/t/t5150-request-pull.sh +++ b/t/t5150-request-pull.sh @@ -216,7 +216,7 @@ test_expect_success 'pull request format' ' git request-pull initial "$downstream_url" >../request ) && <request sed -nf fuzz.sed >request.fuzzy && - test_cmp expect request.fuzzy + test_i18ncmp expect request.fuzzy ' diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index 602806d09c..2e52f8b838 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -13,9 +13,9 @@ TRASH=`pwd` test_expect_success \ 'setup' \ 'rm -f .git/index* && - perl -e "print \"a\" x 4096;" > a && - perl -e "print \"b\" x 4096;" > b && - perl -e "print \"c\" x 4096;" > c && + "$PERL_PATH" -e "print \"a\" x 4096;" > a && + "$PERL_PATH" -e "print \"b\" x 4096;" > b && + "$PERL_PATH" -e "print \"c\" x 4096;" > c && test-genrandom "seed a" 2097152 > a_big && test-genrandom "seed b" 2097152 > b_big && git update-index --add a a_big b b_big c && @@ -38,6 +38,10 @@ test_expect_success \ 'pack without delta' \ 'packname_1=$(git pack-objects --window=0 test-1 <obj-list)' +test_expect_success \ + 'pack-objects with bogus arguments' \ + 'test_must_fail git pack-objects --window=0 test-1 blah blah <obj-list' + rm -fr .git2 mkdir .git2 @@ -125,7 +129,7 @@ test_expect_success \ cd "$TRASH" test_expect_success 'compare delta flavors' ' - perl -e '\'' + "$PERL_PATH" -e '\'' defined($_ = -s $_) or die for @ARGV; exit 1 if $ARGV[0] <= $ARGV[1]; '\'' test-2-$packname_2.pack test-3-$packname_3.pack @@ -414,4 +418,9 @@ test_expect_success \ 'test_must_fail git index-pack -o bad.idx test-3.pack 2>msg && grep "SHA1 COLLISION FOUND" msg' +test_expect_success \ + 'make sure index-pack detects the SHA1 collision (large blobs)' \ + 'test_must_fail git -c core.bigfilethreshold=1 index-pack -o bad.idx test-3.pack 2>msg && + grep "SHA1 COLLISION FOUND" msg' + test_done diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh index f8fa92446c..fe82025d4a 100755 --- a/t/t5302-pack-index.sh +++ b/t/t5302-pack-index.sh @@ -74,6 +74,10 @@ test_expect_success 'index-pack --verify on index version 2' ' ' test_expect_success \ + 'pack-objects --index-version=2, is not accepted' \ + 'test_must_fail git pack-objects --index-version=2, test-3 <obj-list' + +test_expect_success \ 'index v2: force some 64-bit offsets with pack-objects' \ 'pack3=$(git pack-objects --index-version=2,0x40000 test-3 <obj-list)' diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh index 5f6cd4f333..5b1250f0d2 100755 --- a/t/t5303-pack-corruption-resilience.sh +++ b/t/t5303-pack-corruption-resilience.sh @@ -98,7 +98,7 @@ test_expect_success \ 'create_new_pack && git prune-packed && chmod +w ${pack}.pack && - perl -i.bak -pe "s/ base /abcdef/" ${pack}.pack && + "$PERL_PATH" -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' @@ -155,7 +155,7 @@ test_expect_success \ 'create_new_pack && git prune-packed && chmod +w ${pack}.pack && - perl -i.bak -pe "s/ delta1 /abcdefgh/" ${pack}.pack && + "$PERL_PATH" -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' diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh index 9bf69e9a0f..e80a2af348 100755 --- a/t/t5500-fetch-pack.sh +++ b/t/t5500-fetch-pack.sh @@ -114,8 +114,24 @@ pull_to_client 2nd "refs/heads/B" $((64*3)) pull_to_client 3rd "refs/heads/A" $((1*3)) +test_expect_success 'single branch clone' ' + git clone --single-branch "file://$(pwd)/." singlebranch +' + +test_expect_success 'single branch object count' ' + GIT_DIR=singlebranch/.git git count-objects -v | + grep "^in-pack:" > count.singlebranch && + echo "in-pack: 198" >expected && + test_cmp expected count.singlebranch +' + +test_expect_success 'single given branch clone' ' + git clone --single-branch --branch A "file://$(pwd)/." branch-a && + test_must_fail git --git-dir=branch-a/.git rev-parse origin/B +' + test_expect_success 'clone shallow' ' - git clone --depth 2 "file://$(pwd)/." shallow + git clone --no-single-branch --depth 2 "file://$(pwd)/." shallow ' test_expect_success 'clone shallow object count' ' @@ -248,4 +264,137 @@ test_expect_success 'clone shallow object count' ' grep "^count: 52" count.shallow ' +test_expect_success 'clone shallow without --no-single-branch' ' + git clone --depth 1 "file://$(pwd)/." shallow2 +' + +test_expect_success 'clone shallow object count' ' + ( + cd shallow2 && + git count-objects -v + ) > count.shallow2 && + grep "^in-pack: 6" count.shallow2 +' + +test_expect_success 'clone shallow with --branch' ' + git clone --depth 1 --branch A "file://$(pwd)/." shallow3 +' + +test_expect_success 'clone shallow object count' ' + echo "in-pack: 6" > count3.expected && + GIT_DIR=shallow3/.git git count-objects -v | + grep "^in-pack" > count3.actual && + test_cmp count3.expected count3.actual +' + +test_expect_success 'clone shallow with detached HEAD' ' + git checkout HEAD^ && + git clone --depth 1 "file://$(pwd)/." shallow5 && + git checkout - && + GIT_DIR=shallow5/.git git rev-parse HEAD >actual && + git rev-parse HEAD^ >expected && + test_cmp expected actual +' + +test_expect_success 'shallow clone pulling tags' ' + git tag -a -m A TAGA1 A && + git tag -a -m B TAGB1 B && + git tag TAGA2 A && + git tag TAGB2 B && + git clone --depth 1 "file://$(pwd)/." shallow6 && + + cat >taglist.expected <<\EOF && +TAGB1 +TAGB2 +EOF + GIT_DIR=shallow6/.git git tag -l >taglist.actual && + test_cmp taglist.expected taglist.actual && + + echo "in-pack: 7" > count6.expected && + GIT_DIR=shallow6/.git git count-objects -v | + grep "^in-pack" > count6.actual && + test_cmp count6.expected count6.actual +' + +test_expect_success 'shallow cloning single tag' ' + git clone --depth 1 --branch=TAGB1 "file://$(pwd)/." shallow7 && + cat >taglist.expected <<\EOF && +TAGB1 +TAGB2 +EOF + GIT_DIR=shallow7/.git git tag -l >taglist.actual && + test_cmp taglist.expected taglist.actual && + + echo "in-pack: 7" > count7.expected && + GIT_DIR=shallow7/.git git count-objects -v | + grep "^in-pack" > count7.actual && + test_cmp count7.expected count7.actual +' + +test_expect_success 'setup tests for the --stdin parameter' ' + for head in C D E F + do + add $head + done && + for head in A B C D E F + do + git tag $head $head + done && + cat >input <<-\EOF + refs/heads/C + refs/heads/A + refs/heads/D + refs/tags/C + refs/heads/B + refs/tags/A + refs/heads/E + refs/tags/B + refs/tags/E + refs/tags/D + EOF + sort <input >expect && + ( + echo refs/heads/E && + echo refs/tags/E && + cat input + ) >input.dup +' + +test_expect_success 'fetch refs from cmdline' ' + ( + cd client && + git fetch-pack --no-progress .. $(cat ../input) + ) >output && + cut -d " " -f 2 <output | sort >actual && + test_cmp expect actual +' + +test_expect_success 'fetch refs from stdin' ' + ( + cd client && + git fetch-pack --stdin --no-progress .. <../input + ) >output && + cut -d " " -f 2 <output | sort >actual && + test_cmp expect actual +' + +test_expect_success 'fetch mixed refs from cmdline and stdin' ' + ( + cd client && + tail -n +5 ../input | + git fetch-pack --stdin --no-progress .. $(head -n 4 ../input) + ) >output && + cut -d " " -f 2 <output | sort >actual && + test_cmp expect actual +' + +test_expect_success 'test duplicate refs from stdin' ' + ( + cd client && + test_must_fail git fetch-pack --stdin --no-progress .. <../input.dup + ) >output && + cut -d " " -f 2 <output | sort >actual && + test_cmp expect actual +' + test_done diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 308c02ea75..d7a19a1829 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -162,6 +162,36 @@ test_expect_success 'fetch following tags' ' ' +test_expect_success 'fetch uses remote ref names to describe new refs' ' + cd "$D" && + git init descriptive && + ( + cd descriptive && + git config remote.o.url .. && + git config remote.o.fetch "refs/heads/*:refs/crazyheads/*" && + git config --add remote.o.fetch "refs/others/*:refs/heads/*" && + git fetch o + ) && + git tag -a -m "Descriptive tag" descriptive-tag && + git branch descriptive-branch && + git checkout descriptive-branch && + echo "Nuts" >crazy && + git add crazy && + git commit -a -m "descriptive commit" && + git update-ref refs/others/crazy HEAD && + ( + cd descriptive && + git fetch o 2>actual && + grep " -> refs/crazyheads/descriptive-branch$" actual | + test_i18ngrep "new branch" && + grep " -> descriptive-tag$" actual | + test_i18ngrep "new tag" && + grep " -> crazy$" actual | + test_i18ngrep "new ref" + ) && + git checkout master +' + test_expect_success 'fetch must not resolve short tag name' ' cd "$D" && diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh index 6764d511ce..d16e5d384a 100755 --- a/t/t5512-ls-remote.sh +++ b/t/t5512-ls-remote.sh @@ -87,17 +87,15 @@ test_expect_success 'use branch.<name>.remote if possible' ' test_expect_success 'confuses pattern as remote when no remote specified' ' cat >exp <<-\EOF && fatal: '\''refs*master'\'' does not appear to be a git repository - fatal: The remote end hung up unexpectedly + fatal: Could not read from remote repository. + + Please make sure you have the correct access rights + and the repository exists. EOF # - # Do not expect "git ls-remote <pattern>" to work; ls-remote, correctly, - # confuses <pattern> for <remote>. Although ugly, this behaviour is akin - # to the confusion of refspecs for remotes by git-fetch and git-push, - # eg: - # - # $ git fetch branch - # - + # Do not expect "git ls-remote <pattern>" to work; ls-remote needs + # <remote> if you want to feed <pattern>, just like you cannot say + # fetch <branch>. # We could just as easily have used "master"; the "*" emphasizes its # role as a pattern. test_must_fail git ls-remote refs*master >actual 2>&1 && diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index b69cf574d7..b5417cc951 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -979,4 +979,20 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'push --prune' ' + mk_test heads/master heads/second heads/foo heads/bar && + git push --prune testrepo && + check_push_result $the_commit heads/master && + check_push_result $the_first_commit heads/second && + ! check_push_result $the_first_commit heads/foo heads/bar +' + +test_expect_success 'push --prune refspec' ' + mk_test tmp/master tmp/second tmp/foo tmp/bar && + git push --prune testrepo "refs/heads/*:refs/tmp/*" && + check_push_result $the_commit tmp/master && + check_push_result $the_first_commit tmp/second && + ! check_push_result $the_first_commit tmp/foo tmp/bar +' + test_done diff --git a/t/t5528-push-default.sh b/t/t5528-push-default.sh new file mode 100755 index 0000000000..4736da8f36 --- /dev/null +++ b/t/t5528-push-default.sh @@ -0,0 +1,118 @@ +#!/bin/sh + +test_description='check various push.default settings' +. ./test-lib.sh + +test_expect_success 'setup bare remotes' ' + git init --bare repo1 && + git remote add parent1 repo1 && + git init --bare repo2 && + git remote add parent2 repo2 && + test_commit one && + git push parent1 HEAD && + git push parent2 HEAD +' + +# $1 = local revision +# $2 = remote revision (tested to be equal to the local one) +check_pushed_commit () { + git log -1 --format='%h %s' "$1" >expect && + git --git-dir=repo1 log -1 --format='%h %s' "$2" >actual && + test_cmp expect actual +} + +# $1 = push.default value +# $2 = expected target branch for the push +test_push_success () { + git -c push.default="$1" push && + check_pushed_commit HEAD "$2" +} + +# $1 = push.default value +# check that push fails and does not modify any remote branch +test_push_failure () { + git --git-dir=repo1 log --no-walk --format='%h %s' --all >expect && + test_must_fail git -c push.default="$1" push && + git --git-dir=repo1 log --no-walk --format='%h %s' --all >actual && + test_cmp expect actual +} + +test_expect_success '"upstream" pushes to configured upstream' ' + git checkout master && + test_config branch.master.remote parent1 && + test_config branch.master.merge refs/heads/foo && + test_commit two && + test_push_success upstream foo +' + +test_expect_success '"upstream" does not push on unconfigured remote' ' + git checkout master && + test_unconfig branch.master.remote && + test_config push.default upstream && + test_commit three && + test_push_failure upstream +' + +test_expect_success '"upstream" does not push on unconfigured branch' ' + git checkout master && + test_config branch.master.remote parent1 && + test_unconfig branch.master.merge && + test_config push.default upstream + test_commit four && + test_push_failure upstream +' + +test_expect_success '"upstream" does not push when remotes do not match' ' + git checkout master && + test_config branch.master.remote parent1 && + test_config branch.master.merge refs/heads/foo && + test_config push.default upstream && + test_commit five && + test_must_fail git push parent2 +' + +test_expect_success 'push from/to new branch with upstream, matching and simple' ' + git checkout -b new-branch && + test_push_failure simple && + test_push_failure matching && + test_push_failure upstream +' + +test_expect_success 'push from/to new branch with current creates remote branch' ' + test_config branch.new-branch.remote repo1 && + git checkout new-branch && + test_push_success current new-branch +' + +test_expect_success 'push to existing branch, with no upstream configured' ' + test_config branch.master.remote repo1 && + git checkout master && + test_push_failure simple && + test_push_failure upstream +' + +test_expect_success 'push to existing branch, upstream configured with same name' ' + test_config branch.master.remote repo1 && + test_config branch.master.merge refs/heads/master && + git checkout master && + test_commit six && + test_push_success upstream master && + test_commit seven && + test_push_success simple master +' + +test_expect_success 'push to existing branch, upstream configured with different name' ' + test_config branch.master.remote repo1 && + test_config branch.master.merge refs/heads/other-name && + git checkout master && + test_commit eight && + test_push_success upstream other-name && + test_commit nine && + test_push_failure simple && + git --git-dir=repo1 log -1 --format="%h %s" "other-name" >expect-other-name && + test_push_success current master && + git --git-dir=repo1 log -1 --format="%h %s" "other-name" >actual-other-name && + test_cmp expect-other-name actual-other-name +' + +test_done diff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh index 30bec4b5f9..1947c28c64 100755 --- a/t/t5531-deep-submodule-push.sh +++ b/t/t5531-deep-submodule-push.sh @@ -119,4 +119,98 @@ test_expect_success 'push succeeds if submodule has no remote and is on the firs ) ' +test_expect_success 'push unpushed submodules when not needed' ' + ( + cd work && + ( + cd gar/bage && + git checkout master && + >junk5 && + git add junk5 && + git commit -m "Fifth junk" && + git push && + git rev-parse origin/master >../../../expected + ) && + git checkout master && + git add gar/bage && + git commit -m "Fifth commit for gar/bage" && + git push --recurse-submodules=on-demand ../pub.git master + ) && + ( + cd submodule.git && + git rev-parse master >../actual + ) && + test_cmp expected actual +' + +test_expect_success 'push unpushed submodules when not needed 2' ' + ( + cd submodule.git && + git rev-parse master >../expected + ) && + ( + cd work && + ( + cd gar/bage && + >junk6 && + git add junk6 && + git commit -m "Sixth junk" + ) && + >junk2 && + git add junk2 && + git commit -m "Second junk for work" && + git push --recurse-submodules=on-demand ../pub.git master + ) && + ( + cd submodule.git && + git rev-parse master >../actual + ) && + test_cmp expected actual +' + +test_expect_success 'push unpushed submodules recursively' ' + ( + cd work && + ( + cd gar/bage && + git checkout master && + > junk7 && + git add junk7 && + git commit -m "Seventh junk" && + git rev-parse master >../../../expected + ) && + git checkout master && + git add gar/bage && + git commit -m "Seventh commit for gar/bage" && + git push --recurse-submodules=on-demand ../pub.git master + ) && + ( + cd submodule.git && + git rev-parse master >../actual + ) && + test_cmp expected actual +' + +test_expect_success 'push unpushable submodule recursively fails' ' + ( + cd work && + ( + cd gar/bage && + git rev-parse origin/master >../../../expected && + git checkout master~0 && + > junk8 && + git add junk8 && + git commit -m "Eighth junk" + ) && + git add gar/bage && + git commit -m "Eighth commit for gar/bage" && + test_must_fail git push --recurse-submodules=on-demand ../pub.git master + ) && + ( + cd submodule.git && + git rev-parse master >../actual + ) && + test_cmp expected actual +' + test_done diff --git a/t/t5532-fetch-proxy.sh b/t/t5532-fetch-proxy.sh index 62f2460047..5531bd1af4 100755 --- a/t/t5532-fetch-proxy.sh +++ b/t/t5532-fetch-proxy.sh @@ -15,7 +15,7 @@ test_expect_success 'setup remote repo' ' cat >proxy <<'EOF' #!/bin/sh echo >&2 "proxying for $*" -cmd=`perl -e ' +cmd=`"$PERL_PATH" -e ' read(STDIN, $buf, 4); my $n = hex($buf) - 4; read(STDIN, $buf, $n); diff --git a/t/t5541-http-push.sh b/t/t5541-http-push.sh index cc6f081711..624633aced 100755 --- a/t/t5541-http-push.sh +++ b/t/t5541-http-push.sh @@ -30,6 +30,7 @@ test_expect_success 'setup remote repository' ' git clone --bare test_repo test_repo.git && cd test_repo.git && git config http.receivepack true && + git config core.logallrefupdates true && ORIG_HEAD=$(git rev-parse --verify HEAD) && cd - && mv test_repo.git "$HTTPD_DOCUMENT_ROOT_PATH" @@ -63,7 +64,10 @@ test_expect_success 'no empty path components' ' test_expect_success 'clone remote repository' ' rm -rf test_repo_clone && - git clone $HTTPD_URL/smart/test_repo.git test_repo_clone + git clone $HTTPD_URL/smart/test_repo.git test_repo_clone && + ( + cd test_repo_clone && git config push.default matching + ) ' test_expect_success 'push to remote repository (standard)' ' @@ -167,7 +171,7 @@ test_expect_success 'push fails for non-fast-forward refs unmatched by remote he ' test_expect_success 'push fails for non-fast-forward refs unmatched by remote helper: our output' ' - test_i18ngrep "To prevent you from losing history, non-fast-forward updates were rejected" \ + test_i18ngrep "Updates were rejected because" \ output ' @@ -215,12 +219,55 @@ test_expect_success 'push --mirror to repo with alternates' ' git push --mirror "$HTTPD_URL"/smart/alternates-mirror.git ' -test_expect_success TTY 'quiet push' ' +test_expect_success TTY 'push shows progress when stderr is a tty' ' + cd "$ROOT_PATH"/test_repo_clone && + test_commit noisy && + test_terminal git push >output 2>&1 && + grep "^Writing objects" output +' + +test_expect_success TTY 'push --quiet silences status and progress' ' cd "$ROOT_PATH"/test_repo_clone && test_commit quiet && - test_terminal git push --quiet --no-progress 2>&1 | tee output && + test_terminal git push --quiet >output 2>&1 && test_cmp /dev/null output ' +test_expect_success TTY 'push --no-progress silences progress but not status' ' + cd "$ROOT_PATH"/test_repo_clone && + test_commit no-progress && + test_terminal git push --no-progress >output 2>&1 && + grep "^To http" output && + ! grep "^Writing objects" +' + +test_expect_success 'push --progress shows progress to non-tty' ' + cd "$ROOT_PATH"/test_repo_clone && + test_commit progress && + git push --progress >output 2>&1 && + grep "^To http" output && + grep "^Writing objects" output +' + +test_expect_success 'http push gives sane defaults to reflog' ' + cd "$ROOT_PATH"/test_repo_clone && + test_commit reflog-test && + git push "$HTTPD_URL"/smart/test_repo.git && + git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \ + log -g -1 --format="%gn <%ge>" >actual && + echo "anonymous <anonymous@http.127.0.0.1>" >expect && + test_cmp expect actual +' + +test_expect_success 'http push respects GIT_COMMITTER_* in reflog' ' + cd "$ROOT_PATH"/test_repo_clone && + test_commit custom-reflog-test && + git push "$HTTPD_URL"/smart_custom_env/test_repo.git && + git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \ + log -g -1 --format="%gn <%ge>" >actual && + echo "Custom User <custom@example.com>" >expect && + test_cmp expect actual +' + stop_httpd test_done diff --git a/t/t5550-http-fetch.sh b/t/t5550-http-fetch.sh index e5e6b8f643..b06f817af3 100755 --- a/t/t5550-http-fetch.sh +++ b/t/t5550-http-fetch.sh @@ -13,17 +13,22 @@ LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5550'} start_httpd test_expect_success 'setup repository' ' - echo content >file && + echo content1 >file && git add file && git commit -m one + echo content2 >file && + git add file && + git commit -m two ' -test_expect_success 'create http-accessible bare repository' ' - mkdir "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && +test_expect_success 'create http-accessible bare repository with loose objects' ' + cp -a .git "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && (cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && - git --bare init && + git config core.bare true && + mkdir -p hooks && echo "exec git update-server-info" >hooks/post-update && - chmod +x hooks/post-update + chmod +x hooks/post-update && + hooks/post-update ) && git remote add public "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && git push public master:master diff --git a/t/t5551-http-fetch.sh b/t/t5551-http-fetch.sh index 26d355725f..91eaf53d1d 100755 --- a/t/t5551-http-fetch.sh +++ b/t/t5551-http-fetch.sh @@ -109,5 +109,36 @@ test_expect_success 'follow redirects (302)' ' git clone $HTTPD_URL/smart-redir-temp/repo.git --quiet repo-t ' +test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE + +test_expect_success EXPENSIVE 'create 50,000 tags in the repo' ' + ( + cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + for i in `test_seq 50000` + do + echo "commit refs/heads/too-many-refs" + echo "mark :$i" + echo "committer git <git@example.com> $i +0000" + echo "data 0" + echo "M 644 inline bla.txt" + echo "data 4" + echo "bla" + # make every commit dangling by always + # rewinding the branch after each commit + echo "reset refs/heads/too-many-refs" + echo "from :1" + done | git fast-import --export-marks=marks && + + # now assign tags to all the dangling commits we created above + tag=$("$PERL_PATH" -e "print \"bla\" x 30") && + sed -e "s/^:\(.\+\) \(.\+\)$/\2 refs\/tags\/$tag-\1/" <marks >>packed-refs + ) +' + +test_expect_success EXPENSIVE 'clone the 50,000 tag repo to check OS command line overflow' ' + git clone $HTTPD_URL/smart/repo.git too-many-refs 2>err && + test_line_count = 0 err +' + stop_httpd test_done diff --git a/t/t5570-git-daemon.sh b/t/t5570-git-daemon.sh new file mode 100755 index 0000000000..a3a4e47e1d --- /dev/null +++ b/t/t5570-git-daemon.sh @@ -0,0 +1,146 @@ +#!/bin/sh + +test_description='test fetching over git protocol' +. ./test-lib.sh + +LIB_GIT_DAEMON_PORT=${LIB_GIT_DAEMON_PORT-5570} +. "$TEST_DIRECTORY"/lib-git-daemon.sh +start_git_daemon + +test_expect_success 'setup repository' ' + echo content >file && + git add file && + git commit -m one +' + +test_expect_success 'create git-accessible bare repository' ' + mkdir "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" && + (cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" && + git --bare init && + : >git-daemon-export-ok + ) && + git remote add public "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" && + git push public master:master +' + +test_expect_success 'clone git repository' ' + git clone "$GIT_DAEMON_URL/repo.git" clone && + test_cmp file clone/file +' + +test_expect_success 'fetch changes via git protocol' ' + echo content >>file && + git commit -a -m two && + git push public && + (cd clone && git pull) && + test_cmp file clone/file +' + +test_expect_failure 'remote detects correct HEAD' ' + git push public master:other && + (cd clone && + git remote set-head -d origin && + git remote set-head -a origin && + git symbolic-ref refs/remotes/origin/HEAD > output && + echo refs/remotes/origin/master > expect && + test_cmp expect output + ) +' + +test_expect_success 'prepare pack objects' ' + cp -R "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo.git "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git && + (cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git && + git --bare repack -a -d + ) +' + +test_expect_success 'fetch notices corrupt pack' ' + cp -R "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad1.git && + (cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad1.git && + p=`ls objects/pack/pack-*.pack` && + chmod u+w $p && + printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc + ) && + mkdir repo_bad1.git && + (cd repo_bad1.git && + git --bare init && + test_must_fail git --bare fetch "$GIT_DAEMON_URL/repo_bad1.git" && + test 0 = `ls objects/pack/pack-*.pack | wc -l` + ) +' + +test_expect_success 'fetch notices corrupt idx' ' + cp -R "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_pack.git "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad2.git && + (cd "$GIT_DAEMON_DOCUMENT_ROOT_PATH"/repo_bad2.git && + p=`ls objects/pack/pack-*.idx` && + chmod u+w $p && + printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc + ) && + mkdir repo_bad2.git && + (cd repo_bad2.git && + git --bare init && + test_must_fail git --bare fetch "$GIT_DAEMON_URL/repo_bad2.git" && + test 0 = `ls objects/pack | wc -l` + ) +' + +test_remote_error() +{ + do_export=YesPlease + while test $# -gt 0 + do + case $1 in + -x) + shift + chmod -x "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" + ;; + -n) + shift + do_export= + ;; + *) + break + esac + done + + msg=$1 + shift + cmd=$1 + shift + repo=$1 + shift || error "invalid number of arguments" + + if test -x "$GIT_DAEMON_DOCUMENT_ROOT_PATH/$repo" + then + if test -n "$do_export" + then + : >"$GIT_DAEMON_DOCUMENT_ROOT_PATH/$repo/git-daemon-export-ok" + else + rm -f "$GIT_DAEMON_DOCUMENT_ROOT_PATH/$repo/git-daemon-export-ok" + fi + fi + + test_must_fail git "$cmd" "$GIT_DAEMON_URL/$repo" "$@" 2>output && + echo "fatal: remote error: $msg: /$repo" >expect && + test_cmp expect output + ret=$? + chmod +x "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" + (exit $ret) +} + +msg="access denied or repository not exported" +test_expect_success 'clone non-existent' "test_remote_error '$msg' clone nowhere.git " +test_expect_success 'push disabled' "test_remote_error '$msg' push repo.git master" +test_expect_success 'read access denied' "test_remote_error -x '$msg' fetch repo.git " +test_expect_success 'not exported' "test_remote_error -n '$msg' fetch repo.git " + +stop_git_daemon +start_git_daemon --informative-errors + +test_expect_success 'clone non-existent' "test_remote_error 'no such repository' clone nowhere.git " +test_expect_success 'push disabled' "test_remote_error 'service not enabled' push repo.git master" +test_expect_success 'read access denied' "test_remote_error -x 'no such repository' fetch repo.git " +test_expect_success 'not exported' "test_remote_error -n 'repository not exported' fetch repo.git " + +stop_git_daemon +test_done diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index 87ee01662c..67869b4813 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -9,10 +9,13 @@ test_expect_success setup ' rm -fr .git && test_create_repo src && ( - cd src - >file - git add file - git commit -m initial + cd src && + >file && + git add file && + git commit -m initial && + echo 1 >file && + git add file && + git commit -m updated ) ' @@ -88,6 +91,26 @@ test_expect_success 'clone --mirror' ' ' +test_expect_success 'clone --mirror with detached HEAD' ' + + ( cd src && git checkout HEAD^ && git rev-parse HEAD >../expected ) && + git clone --mirror src mirror.detached && + ( cd src && git checkout - ) && + GIT_DIR=mirror.detached git rev-parse HEAD >actual && + test_cmp expected actual + +' + +test_expect_success 'clone --bare with detached HEAD' ' + + ( cd src && git checkout HEAD^ && git rev-parse HEAD >../expected ) && + git clone --bare src bare.detached && + ( cd src && git checkout - ) && + GIT_DIR=bare.detached git rev-parse HEAD >actual && + test_cmp expected actual + +' + test_expect_success 'clone --bare names the local repository <name>.git' ' git clone --bare src && @@ -248,4 +271,13 @@ test_expect_success 'clone from original with relative alternate' ' grep /src/\\.git/objects target-10/objects/info/alternates ' +test_expect_success 'clone checking out a tag' ' + git clone --branch=some-tag src dst.tag && + GIT_DIR=src/.git git rev-parse some-tag >expected && + test_cmp expected dst.tag/.git/HEAD && + GIT_DIR=dst.tag/.git git config remote.origin.fetch >fetch.actual && + echo "+refs/heads/*:refs/remotes/origin/*" >fetch.expected && + test_cmp fetch.expected fetch.actual +' + test_done diff --git a/t/t5700-clone-reference.sh b/t/t5700-clone-reference.sh index c4c375ac04..c47d450cc3 100755 --- a/t/t5700-clone-reference.sh +++ b/t/t5700-clone-reference.sh @@ -34,7 +34,7 @@ test_expect_success 'cloning with reference (-l -s)' \ cd "$base_dir" test_expect_success 'existence of info/alternates' \ -'test `wc -l <C/.git/objects/info/alternates` = 2' +'test_line_count = 2 C/.git/objects/info/alternates' cd "$base_dir" @@ -52,18 +52,18 @@ test_cmp expected current' cd "$base_dir" -rm -f "$U" +rm -f "$U.D" test_expect_success 'cloning with reference (no -l -s)' \ -'GIT_DEBUG_SEND_PACK=3 git clone --reference B "file://$(pwd)/A" D 3>"$U"' +'GIT_DEBUG_SEND_PACK=3 git clone --reference B "file://$(pwd)/A" D 3>"$U.D"' test_expect_success 'fetched no objects' \ -'! grep "^want" "$U"' +'! grep "^want" "$U.D"' cd "$base_dir" test_expect_success 'existence of info/alternates' \ -'test `wc -l <D/.git/objects/info/alternates` = 1' +'test_line_count = 1 D/.git/objects/info/alternates' cd "$base_dir" @@ -153,4 +153,32 @@ test_expect_success 'clone with reference from a tagged repository' ' git clone --reference=A A I ' +test_expect_success 'prepare branched repository' ' + git clone A J && + ( + cd J && + git checkout -b other master^ && + echo other >otherfile && + git add otherfile && + git commit -m other && + git checkout master + ) +' + +rm -f "$U.K" + +test_expect_success 'fetch with incomplete alternates' ' + git init K && + echo "$base_dir/A/.git/objects" >K/.git/objects/info/alternates && + ( + cd K && + git remote add J "file://$base_dir/J" && + GIT_DEBUG_SEND_PACK=3 git fetch J 3>"$U.K" + ) && + master_object=$(cd A && git for-each-ref --format="%(objectname)" refs/heads/master) && + ! grep "^want $master_object" "$U.K" && + tag_object=$(cd A && git for-each-ref --format="%(objectname)" refs/tags/HEAD) && + ! grep "^want $tag_object" "$U.K" +' + test_done diff --git a/t/t5701-clone-local.sh b/t/t5701-clone-local.sh index 6972258b27..7ff6e0e16c 100755 --- a/t/t5701-clone-local.sh +++ b/t/t5701-clone-local.sh @@ -3,7 +3,10 @@ test_description='test local clone' . ./test-lib.sh -D=`pwd` +repo_is_hardlinked() { + find "$1/objects" -type f -links 1 >output && + test_line_count = 0 output +} test_expect_success 'preparing origin repository' ' : >file && git add . && git commit -m1 && @@ -19,105 +22,72 @@ test_expect_success 'preparing origin repository' ' ' test_expect_success 'local clone without .git suffix' ' - cd "$D" && git clone -l -s a b && - cd b && + (cd b && test "$(GIT_CONFIG=.git/config git config --bool core.bare)" = false && - git fetch + git fetch) ' test_expect_success 'local clone with .git suffix' ' - cd "$D" && git clone -l -s a.git c && - cd c && - git fetch + (cd c && git fetch) ' test_expect_success 'local clone from x' ' - cd "$D" && git clone -l -s x y && - cd y && - git fetch + (cd y && git fetch) ' test_expect_success 'local clone from x.git that does not exist' ' - cd "$D" && - if git clone -l -s x.git z - then - echo "Oops, should have failed" - false - else - echo happy - fi + test_must_fail git clone -l -s x.git z ' test_expect_success 'With -no-hardlinks, local will make a copy' ' - cd "$D" && git clone --bare --no-hardlinks x w && - cd w && - linked=$(find objects -type f ! -links 1 | wc -l) && - test 0 = $linked + ! repo_is_hardlinked w ' test_expect_success 'Even without -l, local will make a hardlink' ' - cd "$D" && rm -fr w && git clone -l --bare x w && - cd w && - copied=$(find objects -type f -links 1 | wc -l) && - test 0 = $copied + repo_is_hardlinked w ' test_expect_success 'local clone of repo with nonexistent ref in HEAD' ' - cd "$D" && echo "ref: refs/heads/nonexistent" > a.git/HEAD && git clone a d && - cd d && + (cd d && git fetch && - test ! -e .git/refs/remotes/origin/HEAD' + test ! -e .git/refs/remotes/origin/HEAD) +' test_expect_success 'bundle clone without .bundle suffix' ' - cd "$D" && git clone dir/b3 && - cd b3 && - git fetch + (cd b3 && git fetch) ' test_expect_success 'bundle clone with .bundle suffix' ' - cd "$D" && git clone b1.bundle && - cd b1 && - git fetch + (cd b1 && git fetch) ' test_expect_success 'bundle clone from b4' ' - cd "$D" && git clone b4 bdl && - cd bdl && - git fetch + (cd bdl && git fetch) ' test_expect_success 'bundle clone from b4.bundle that does not exist' ' - cd "$D" && - if git clone b4.bundle bb - then - echo "Oops, should have failed" - false - else - echo happy - fi + test_must_fail git clone b4.bundle bb ' test_expect_success 'bundle clone with nonexistent HEAD' ' - cd "$D" && git clone b2.bundle b2 && - cd b2 && + (cd b2 && git fetch && - test ! -e .git/refs/heads/master + test_must_fail git rev-parse --verify refs/heads/master) ' test_expect_success 'clone empty repository' ' - cd "$D" && mkdir empty && (cd empty && git init && @@ -135,7 +105,6 @@ test_expect_success 'clone empty repository' ' ' test_expect_success 'clone empty repository, and then push should not segfault.' ' - cd "$D" && rm -fr empty/ empty-clone/ && mkdir empty && (cd empty && git init) && @@ -145,16 +114,24 @@ test_expect_success 'clone empty repository, and then push should not segfault.' ' test_expect_success 'cloning non-existent directory fails' ' - cd "$D" && rm -rf does-not-exist && test_must_fail git clone does-not-exist ' test_expect_success 'cloning non-git directory fails' ' - cd "$D" && rm -rf not-a-git-repo not-a-git-repo-clone && mkdir not-a-git-repo && test_must_fail git clone not-a-git-repo not-a-git-repo-clone ' +test_expect_success 'cloning file:// does not hardlink' ' + git clone --bare file://"$(pwd)"/a non-local && + ! repo_is_hardlinked non-local +' + +test_expect_success 'cloning a local path with --no-local does not hardlink' ' + git clone --bare --no-local a force-nonlocal && + ! repo_is_hardlinked force-nonlocal +' + test_done diff --git a/t/t5706-clone-branch.sh b/t/t5706-clone-branch.sh index f3f9a76056..56be67e07e 100755 --- a/t/t5706-clone-branch.sh +++ b/t/t5706-clone-branch.sh @@ -57,12 +57,8 @@ test_expect_success 'clone -b does not munge remotes/origin/HEAD' ' ) ' -test_expect_success 'clone -b with bogus branch chooses HEAD' ' - git clone -b bogus parent clone-bogus && - (cd clone-bogus && - check_HEAD master && - check_file one - ) +test_expect_success 'clone -b with bogus branch' ' + test_must_fail git clone -b bogus parent clone-bogus ' test_done diff --git a/t/t5710-info-alternate.sh b/t/t5710-info-alternate.sh index ef7127c1b3..aa045295de 100755 --- a/t/t5710-info-alternate.sh +++ b/t/t5710-info-alternate.sh @@ -18,7 +18,7 @@ reachable_via() { test_valid_repo() { git fsck --full > fsck.log && - test `wc -l < fsck.log` = 0 + test_line_count = 0 fsck.log } base_dir=`pwd` diff --git a/t/t5800-remote-helpers.sh b/t/t5800-remote-helpers.sh index 1c62001fce..5702334510 100755 --- a/t/t5800-remote-helpers.sh +++ b/t/t5800-remote-helpers.sh @@ -72,6 +72,19 @@ test_expect_success 'pushing to local repo' ' compare_refs localclone HEAD server HEAD ' +# Generally, skip this test. It demonstrates a now-fixed race in +# git-remote-testgit, but is too slow to leave in for general use. +: test_expect_success 'racily pushing to local repo' ' + test_when_finished "rm -rf server2 localclone2" && + cp -a server server2 && + git clone "testgit::${PWD}/server2" localclone2 && + (cd localclone2 && + echo content >>file && + git commit -a -m three && + GIT_REMOTE_TESTGIT_SLEEPY=2 git push) && + compare_refs localclone2 HEAD server2 HEAD +' + test_expect_success 'synch with changes from localclone' ' (cd clone && git pull) diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh index 444279077e..f94f0c48e6 100755 --- a/t/t6006-rev-list-format.sh +++ b/t/t6006-rev-list-format.sh @@ -188,23 +188,23 @@ test_expect_success 'empty email' ' test_expect_success 'del LF before empty (1)' ' git show -s --pretty=format:"%s%n%-b%nThanks%n" HEAD^^ >actual && - test $(wc -l <actual) = 2 + test_line_count = 2 actual ' test_expect_success 'del LF before empty (2)' ' git show -s --pretty=format:"%s%n%-b%nThanks%n" HEAD >actual && - test $(wc -l <actual) = 6 && + test_line_count = 6 actual && grep "^$" actual ' test_expect_success 'add LF before non-empty (1)' ' git show -s --pretty=format:"%s%+b%nThanks%n" HEAD^^ >actual && - test $(wc -l <actual) = 2 + test_line_count = 2 actual ' test_expect_success 'add LF before non-empty (2)' ' git show -s --pretty=format:"%s%+b%nThanks%n" HEAD >actual && - test $(wc -l <actual) = 6 && + test_line_count = 6 actual && grep "^$" actual ' @@ -278,8 +278,16 @@ test_expect_success 'oneline with empty message' ' git commit -m "dummy" --allow-empty && git filter-branch --msg-filter "sed -e s/dummy//" HEAD^^.. && git rev-list --oneline HEAD >test.txt && - test $(git rev-list --oneline HEAD | wc -l) -eq 5 && - test $(git rev-list --oneline --graph HEAD | wc -l) -eq 5 + test_line_count = 5 test.txt && + git rev-list --oneline --graph HEAD >testg.txt && + test_line_count = 5 testg.txt +' + +test_expect_success 'single-character name is parsed correctly' ' + git commit --author="a <a@example.com>" --allow-empty -m foo && + echo "a <a@example.com>" >expect && + git log -1 --format="%an <%ae>" >actual && + test_cmp expect actual ' test_done diff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh index e51eb41f4b..bbb0581f88 100755 --- a/t/t6011-rev-list-with-bad-commit.sh +++ b/t/t6011-rev-list-with-bad-commit.sh @@ -37,7 +37,7 @@ test_expect_success 'verify number of revisions' \ test_expect_success 'corrupt second commit object' \ ' - perl -i.bak -pe "s/second commit/socond commit/" .git/objects/pack/*.pack && + "$PERL_PATH" -i.bak -pe "s/second commit/socond commit/" .git/objects/pack/*.pack && test_must_fail git fsck --full ' diff --git a/t/t6013-rev-list-reverse-parents.sh b/t/t6013-rev-list-reverse-parents.sh index 59fc2f06e0..892a537989 100755 --- a/t/t6013-rev-list-reverse-parents.sh +++ b/t/t6013-rev-list-reverse-parents.sh @@ -25,7 +25,7 @@ test_expect_success 'set up --reverse example' ' test_expect_success '--reverse --parents --full-history combines correctly' ' git rev-list --parents --full-history master -- foo | - perl -e "print reverse <>" > expected && + "$PERL_PATH" -e "print reverse <>" > expected && git rev-list --reverse --parents --full-history master -- foo \ > actual && test_cmp actual expected @@ -33,7 +33,7 @@ test_expect_success '--reverse --parents --full-history combines correctly' ' test_expect_success '--boundary does too' ' git rev-list --boundary --parents --full-history master ^root -- foo | - perl -e "print reverse <>" > expected && + "$PERL_PATH" -e "print reverse <>" > expected && git rev-list --boundary --reverse --parents --full-history \ master ^root -- foo > actual && test_cmp actual expected diff --git a/t/t6022-merge-rename.sh b/t/t6022-merge-rename.sh index 9d8584e957..c680f789a7 100755 --- a/t/t6022-merge-rename.sh +++ b/t/t6022-merge-rename.sh @@ -242,10 +242,10 @@ test_expect_success 'merge of identical changes in a renamed file' ' rm -f A M N && git reset --hard && git checkout change+rename && - GIT_MERGE_VERBOSITY=3 git merge change | grep "^Skipped B" && + GIT_MERGE_VERBOSITY=3 git merge change | test_i18ngrep "^Skipped B" && git reset --hard HEAD^ && git checkout change && - GIT_MERGE_VERBOSITY=3 git merge change+rename | grep "^Skipped B" + GIT_MERGE_VERBOSITY=3 git merge change+rename | test_i18ngrep "^Skipped B" ' test_expect_success 'setup for rename + d/f conflicts' ' @@ -303,9 +303,9 @@ test_expect_success 'Rename+D/F conflict; renamed file merges but dir in way' ' git checkout -q renamed-file-has-no-conflicts^0 && test_must_fail git merge --strategy=recursive dir-in-way >output && - grep "CONFLICT (modify/delete): dir/file-in-the-way" output && - grep "Auto-merging dir" output && - grep "Adding as dir~HEAD instead" output && + test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output && + test_i18ngrep "Auto-merging dir" output && + test_i18ngrep "Adding as dir~HEAD instead" output && test 3 -eq "$(git ls-files -u | wc -l)" && test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" && @@ -325,9 +325,9 @@ test_expect_success 'Same as previous, but merged other way' ' test_must_fail git merge --strategy=recursive renamed-file-has-no-conflicts >output 2>errors && ! grep "error: refusing to lose untracked file at" errors && - grep "CONFLICT (modify/delete): dir/file-in-the-way" output && - grep "Auto-merging dir" output && - grep "Adding as dir~renamed-file-has-no-conflicts instead" output && + test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output && + test_i18ngrep "Auto-merging dir" output && + test_i18ngrep "Adding as dir~renamed-file-has-no-conflicts instead" output && test 3 -eq "$(git ls-files -u | wc -l)" && test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" && @@ -884,4 +884,20 @@ test_expect_success 'no spurious "refusing to lose untracked" message' ' ! grep "refusing to lose untracked file" errors.txt ' +test_expect_success 'do not follow renames for empty files' ' + git checkout -f -b empty-base && + >empty1 && + git add empty1 && + git commit -m base && + echo content >empty1 && + git add empty1 && + git commit -m fill && + git checkout -b empty-topic HEAD^ && + git mv empty1 empty2 && + git commit -m rename && + test_must_fail git merge empty-base && + >expect && + test_cmp expect empty2 +' + test_done diff --git a/t/t6028-merge-up-to-date.sh b/t/t6028-merge-up-to-date.sh index a91644e3b2..c518e9c30c 100755 --- a/t/t6028-merge-up-to-date.sh +++ b/t/t6028-merge-up-to-date.sh @@ -16,7 +16,12 @@ test_expect_success setup ' test_tick && git commit -m second && git tag c1 && - git branch test + git branch test && + echo third >file && + git add file && + test_tick && + git commit -m third && + git tag c2 ' test_expect_success 'merge -s recursive up-to-date' ' @@ -74,4 +79,14 @@ test_expect_success 'merge -s subtree up-to-date' ' ' +test_expect_success 'merge fast-forward octopus' ' + + git reset --hard c0 && + test_tick && + git merge c1 c2 + expect=$(git rev-parse c2) && + current=$(git rev-parse HEAD) && + test "$expect" = "$current" +' + test_done diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh index 691e4a4481..72e28ee535 100755 --- a/t/t6030-bisect-porcelain.sh +++ b/t/t6030-bisect-porcelain.sh @@ -480,7 +480,7 @@ test_expect_success 'many merge bases creation' ' git merge -m "merge HASH7 and SIDE_HASH7" "$HASH7" && B_HASH=$(git rev-parse --verify HEAD) && git merge-base --all "$A_HASH" "$B_HASH" > merge_bases.txt && - test $(wc -l < merge_bases.txt) = "2" && + test_line_count = 2 merge_bases.txt && grep "$HASH5" merge_bases.txt && grep "$SIDE_HASH5" merge_bases.txt ' diff --git a/t/t6032-merge-large-rename.sh b/t/t6032-merge-large-rename.sh index 94f010be8a..15beecc3c6 100755 --- a/t/t6032-merge-large-rename.sh +++ b/t/t6032-merge-large-rename.sh @@ -97,7 +97,7 @@ test_expect_success 'setup large simple rename' ' test_expect_success 'massive simple rename does not spam added files' ' sane_unset GIT_MERGE_VERBOSITY && git merge --no-stat simple-rename | grep -v Removing >output && - test 5 -gt "$(wc -l < output)" + test_line_count -lt 5 output ' test_done diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh index 19272bc551..ec2b516c3f 100755 --- a/t/t6040-tracking-info.sh +++ b/t/t6040-tracking-info.sh @@ -71,13 +71,13 @@ test_expect_success 'checkout' ' ( cd test && git checkout b1 ) >actual && - grep "have 1 and 1 different" actual + test_i18ngrep "have 1 and 1 different" actual ' test_expect_success 'checkout with local tracked branch' ' git checkout master && git checkout follower >actual && - grep "is ahead of" actual + test_i18ngrep "is ahead of" actual ' test_expect_success 'status' ' @@ -87,14 +87,14 @@ test_expect_success 'status' ' # reports nothing to commit test_must_fail git commit --dry-run ) >actual && - grep "have 1 and 1 different" actual + test_i18ngrep "have 1 and 1 different" actual ' test_expect_success 'fail to track lightweight tags' ' git checkout master && git tag light && test_must_fail git branch --track lighttrack light >actual && - test_must_fail grep "set up to track" actual && + test_i18ngrep ! "set up to track" actual && test_must_fail git checkout lighttrack ' @@ -102,7 +102,7 @@ test_expect_success 'fail to track annotated tags' ' git checkout master && git tag -m heavy heavy && test_must_fail git branch --track heavytrack heavy >actual && - test_must_fail grep "set up to track" actual && + test_i18ngrep ! "set up to track" actual && test_must_fail git checkout heavytrack ' diff --git a/t/t6042-merge-rename-corner-cases.sh b/t/t6042-merge-rename-corner-cases.sh index 32591f9413..411550d2b6 100755 --- a/t/t6042-merge-rename-corner-cases.sh +++ b/t/t6042-merge-rename-corner-cases.sh @@ -104,7 +104,7 @@ test_expect_failure 'conflict caused if rename not detected' ' test 0 -eq $(git ls-files -u | wc -l) && test 0 -eq $(git ls-files -o | wc -l) && - test 6 -eq $(wc -l < c) && + test_line_count = 6 c && test $(git rev-parse HEAD:a) = $(git rev-parse B:a) && test $(git rev-parse HEAD:b) = $(git rev-parse A:b) ' @@ -380,7 +380,7 @@ test_expect_success 'handle rename/rename (2to1) conflict correctly' ' git checkout B^0 && test_must_fail git merge -s recursive C^0 >out && - grep "CONFLICT (rename/rename)" out && + test_i18ngrep "CONFLICT (rename/rename)" out && test 2 -eq $(git ls-files -s | wc -l) && test 2 -eq $(git ls-files -u | wc -l) && diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh index 9a16806921..992c2a0467 100755 --- a/t/t6200-fmt-merge-msg.sh +++ b/t/t6200-fmt-merge-msg.sh @@ -35,15 +35,18 @@ test_expect_success setup ' echo "l3" >two && test_tick && - git commit -a -m "Left #3" && + GIT_COMMITTER_NAME="Another Committer" \ + GIT_AUTHOR_NAME="Another Author" git commit -a -m "Left #3" && echo "l4" >two && test_tick && - git commit -a -m "Left #4" && + GIT_COMMITTER_NAME="Another Committer" \ + GIT_AUTHOR_NAME="Another Author" git commit -a -m "Left #4" && echo "l5" >two && test_tick && - git commit -a -m "Left #5" && + GIT_COMMITTER_NAME="Another Committer" \ + GIT_AUTHOR_NAME="Another Author" git commit -a -m "Left #5" && git tag tag-l5 && git checkout right && @@ -99,6 +102,8 @@ test_expect_success '[merge] summary/log configuration' ' cat >expected <<-EOF && Merge branch ${apos}left${apos} + # By Another Author (3) and A U Thor (2) + # Via Another Committer * left: Left #5 Left #4 @@ -144,6 +149,8 @@ test_expect_success 'merge.log=3 limits shortlog length' ' cat >expected <<-EOF && Merge branch ${apos}left${apos} + # By Another Author (3) and A U Thor (2) + # Via Another Committer * left: (5 commits) Left #5 Left #4 @@ -159,6 +166,8 @@ test_expect_success 'merge.log=5 shows all 5 commits' ' cat >expected <<-EOF && Merge branch ${apos}left${apos} + # By Another Author (3) and A U Thor (2) + # Via Another Committer * left: Left #5 Left #4 @@ -181,6 +190,8 @@ test_expect_success '--log=3 limits shortlog length' ' cat >expected <<-EOF && Merge branch ${apos}left${apos} + # By Another Author (3) and A U Thor (2) + # Via Another Committer * left: (5 commits) Left #5 Left #4 @@ -196,6 +207,8 @@ test_expect_success '--log=5 shows all 5 commits' ' cat >expected <<-EOF && Merge branch ${apos}left${apos} + # By Another Author (3) and A U Thor (2) + # Via Another Committer * left: Left #5 Left #4 @@ -225,6 +238,8 @@ test_expect_success 'fmt-merge-msg -m' ' cat >expected.log <<-EOF && Sync with left + # By Another Author (3) and A U Thor (2) + # Via Another Committer * ${apos}left${apos} of $(pwd): Left #5 Left #4 @@ -256,6 +271,8 @@ test_expect_success 'setup: expected shortlog for two branches' ' cat >expected <<-EOF Merge branches ${apos}left${apos} and ${apos}right${apos} + # By Another Author (3) and A U Thor (2) + # Via Another Committer * left: Left #5 Left #4 @@ -379,6 +396,8 @@ test_expect_success 'merge-msg two tags' ' Common #2 Common #1 + # By Another Author (3) and A U Thor (2) + # Via Another Committer * tag ${apos}tag-l5${apos}: Left #5 Left #4 @@ -407,6 +426,8 @@ test_expect_success 'merge-msg tag and branch' ' Common #2 Common #1 + # By Another Author (3) and A U Thor (2) + # Via Another Committer * left: Left #5 Left #4 diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh index e0227730de..4d13e10de1 100755 --- a/t/t7003-filter-branch.sh +++ b/t/t7003-filter-branch.sh @@ -5,7 +5,8 @@ test_description='git filter-branch' test_expect_success 'setup' ' test_commit A && - test_commit B && + GIT_COMMITTER_DATE="@0 +0000" GIT_AUTHOR_DATE="@0 +0000" && + test_commit --notick B && git checkout -b branch B && test_commit D && mkdir dir && diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 4ef79aabc4..5189446534 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -263,6 +263,50 @@ test_expect_success 'tag -l can accept multiple patterns' ' test_cmp expect actual ' +test_expect_success 'listing tags in column' ' + COLUMNS=40 git tag -l --column=row >actual && + cat >expected <<\EOF && +a1 aa1 cba t210 t211 +v0.2.1 v1.0 v1.0.1 v1.1.3 +EOF + test_cmp expected actual +' + +test_expect_success 'listing tags in column with column.*' ' + git config column.tag row && + git config column.ui dense && + COLUMNS=40 git tag -l >actual && + git config --unset column.ui && + git config --unset column.tag && + cat >expected <<\EOF && +a1 aa1 cba t210 t211 +v0.2.1 v1.0 v1.0.1 v1.1.3 +EOF + test_cmp expected actual +' + +test_expect_success 'listing tag with -n --column should fail' ' + test_must_fail git tag --column -n +' + +test_expect_success 'listing tags -n in column with column.ui ignored' ' + git config column.ui "row dense" && + COLUMNS=40 git tag -l -n >actual && + git config --unset column.ui && + cat >expected <<\EOF && +a1 Foo +aa1 Foo +cba Foo +t210 Foo +t211 Foo +v0.2.1 Foo +v1.0 Foo +v1.0.1 Foo +v1.1.3 Foo +EOF + test_cmp expected actual +' + # creating and verifying lightweight tags: test_expect_success \ @@ -1282,4 +1326,43 @@ test_expect_success 'mixing incompatibles modes and options is forbidden' ' test_must_fail git tag -v -s ' +# check points-at + +test_expect_success '--points-at cannot be used in non-list mode' ' + test_must_fail git tag --points-at=v4.0 foo +' + +test_expect_success '--points-at finds lightweight tags' ' + echo v4.0 >expect && + git tag --points-at v4.0 >actual && + test_cmp expect actual +' + +test_expect_success '--points-at finds annotated tags of commits' ' + git tag -m "v4.0, annotated" annotated-v4.0 v4.0 && + echo annotated-v4.0 >expect && + git tag -l --points-at v4.0 "annotated*" >actual && + test_cmp expect actual +' + +test_expect_success '--points-at finds annotated tags of tags' ' + git tag -m "describing the v4.0 tag object" \ + annotated-again-v4.0 annotated-v4.0 && + cat >expect <<-\EOF && + annotated-again-v4.0 + annotated-v4.0 + EOF + git tag --points-at=annotated-v4.0 >actual && + test_cmp expect actual +' + +test_expect_success 'multiple --points-at are OR-ed together' ' + cat >expect <<-\EOF && + v2.0 + v3.0 + EOF + git tag --points-at=v2.0 --points-at=v3.0 >actual && + test_cmp expect actual +' + test_done diff --git a/t/t7007-show.sh b/t/t7007-show.sh index cce222f052..a40cd3630c 100755 --- a/t/t7007-show.sh +++ b/t/t7007-show.sh @@ -17,4 +17,95 @@ test_expect_success 'showing a tag that point at a missing object' ' test_must_fail git --no-pager show foo-tag ' +test_expect_success 'set up a bit of history' ' + test_commit main1 && + test_commit main2 && + test_commit main3 && + git tag -m "annotated tag" annotated && + git checkout -b side HEAD^^ && + test_commit side2 && + test_commit side3 +' + +test_expect_success 'showing two commits' ' + cat >expect <<-EOF && + commit $(git rev-parse main2) + commit $(git rev-parse main3) + EOF + git show main2 main3 >actual && + grep ^commit actual >actual.filtered && + test_cmp expect actual.filtered +' + +test_expect_success 'showing a range walks (linear)' ' + cat >expect <<-EOF && + commit $(git rev-parse main3) + commit $(git rev-parse main2) + EOF + git show main1..main3 >actual && + grep ^commit actual >actual.filtered && + test_cmp expect actual.filtered +' + +test_expect_success 'showing a range walks (Y shape, ^ first)' ' + cat >expect <<-EOF && + commit $(git rev-parse main3) + commit $(git rev-parse main2) + EOF + git show ^side3 main3 >actual && + grep ^commit actual >actual.filtered && + test_cmp expect actual.filtered +' + +test_expect_success 'showing a range walks (Y shape, ^ last)' ' + cat >expect <<-EOF && + commit $(git rev-parse main3) + commit $(git rev-parse main2) + EOF + git show main3 ^side3 >actual && + grep ^commit actual >actual.filtered && + test_cmp expect actual.filtered +' + +test_expect_success 'showing with -N walks' ' + cat >expect <<-EOF && + commit $(git rev-parse main3) + commit $(git rev-parse main2) + EOF + git show -2 main3 >actual && + grep ^commit actual >actual.filtered && + test_cmp expect actual.filtered +' + +test_expect_success 'showing annotated tag' ' + cat >expect <<-EOF && + tag annotated + commit $(git rev-parse annotated^{commit}) + EOF + git show annotated >actual && + grep -E "^(commit|tag)" actual >actual.filtered && + test_cmp expect actual.filtered +' + +test_expect_success 'showing annotated tag plus commit' ' + cat >expect <<-EOF && + tag annotated + commit $(git rev-parse annotated^{commit}) + commit $(git rev-parse side3) + EOF + git show annotated side3 >actual && + grep -E "^(commit|tag)" actual >actual.filtered && + test_cmp expect actual.filtered +' + +test_expect_success 'showing range' ' + cat >expect <<-EOF && + commit $(git rev-parse main3) + commit $(git rev-parse main2) + EOF + git show ^side3 annotated >actual && + grep -E "^(commit|tag)" actual >actual.filtered && + test_cmp expect actual.filtered +' + test_done diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh index b8cb4906aa..f4f38a5e73 100755 --- a/t/t7060-wtstatus.sh +++ b/t/t7060-wtstatus.sh @@ -30,6 +30,9 @@ test_expect_success 'Report new path with conflict' ' cat >expect <<EOF # On branch side +# You have unmerged paths. +# (fix conflicts and run "git commit") +# # Unmerged paths: # (use "git add/rm <file>..." as appropriate to mark resolution) # @@ -118,4 +121,97 @@ test_expect_success 'git diff-index --cached -C shows 2 copies + 1 unmerged' ' test_cmp expected actual ' + +test_expect_success 'status when conflicts with add and rm advice (deleted by them)' ' + git reset --hard && + git checkout master && + test_commit init main.txt init && + git checkout -b second_branch && + git rm main.txt && + git commit -m "main.txt deleted on second_branch" && + test_commit second conflict.txt second && + git checkout master && + test_commit on_second main.txt on_second && + test_commit master conflict.txt master && + test_must_fail git merge second_branch && + cat >expected <<-\EOF && + # On branch master + # You have unmerged paths. + # (fix conflicts and run "git commit") + # + # Unmerged paths: + # (use "git add/rm <file>..." as appropriate to mark resolution) + # + # both added: conflict.txt + # deleted by them: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'prepare for conflicts' ' + git reset --hard && + git checkout -b conflict && + test_commit one main.txt one && + git branch conflict_second && + git mv main.txt sub_master.txt && + git commit -m "main.txt renamed in sub_master.txt" && + git checkout conflict_second && + git mv main.txt sub_second.txt && + git commit -m "main.txt renamed in sub_second.txt" +' + + +test_expect_success 'status when conflicts with add and rm advice (both deleted)' ' + test_must_fail git merge conflict && + cat >expected <<-\EOF && + # On branch conflict_second + # You have unmerged paths. + # (fix conflicts and run "git commit") + # + # Unmerged paths: + # (use "git add/rm <file>..." as appropriate to mark resolution) + # + # both deleted: main.txt + # added by them: sub_master.txt + # added by us: sub_second.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status when conflicts with only rm advice (both deleted)' ' + git reset --hard conflict_second && + test_must_fail git merge conflict && + git add sub_master.txt && + git add sub_second.txt && + cat >expected <<-\EOF && + # On branch conflict_second + # You have unmerged paths. + # (fix conflicts and run "git commit") + # + # Changes to be committed: + # + # new file: sub_master.txt + # + # Unmerged paths: + # (use "git rm <file>..." to mark resolution) + # + # both deleted: main.txt + # + # Untracked files not listed (use -u option to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual && + git reset --hard && + git checkout master +' + + test_done diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 07fb53adcb..be9672e5a0 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -229,7 +229,7 @@ test_expect_success 'checkout to detach HEAD (with advice declined)' ' git checkout -f renamer && git clean -f && git checkout renamer^ 2>messages && test_i18ngrep "HEAD is now at 7329388" messages && - test 1 -eq $(wc -l <messages) && + test_line_count = 1 messages && H=$(git rev-parse --verify HEAD) && M=$(git show-ref -s --verify refs/heads/master) && test "z$H" = "z$M" && @@ -247,7 +247,7 @@ test_expect_success 'checkout to detach HEAD' ' git checkout -f renamer && git clean -f && git checkout renamer^ 2>messages && test_i18ngrep "HEAD is now at 7329388" messages && - test 1 -lt $(wc -l <messages) && + test_line_count -gt 1 messages && H=$(git rev-parse --verify HEAD) && M=$(git show-ref -s --verify refs/heads/master) && test "z$H" = "z$M" && diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh index 800b5368a5..ccfb54de7a 100755 --- a/t/t7300-clean.sh +++ b/t/t7300-clean.sh @@ -399,8 +399,8 @@ test_expect_success SANITY 'removal failure' ' ' test_expect_success 'nested git work tree' ' - rm -fr foo bar && - mkdir foo bar && + rm -fr foo bar baz && + mkdir -p foo bar baz/boo && ( cd foo && git init && @@ -412,15 +412,24 @@ test_expect_success 'nested git work tree' ' cd bar && >goodbye.people ) && + ( + cd baz/boo && + git init && + >deeper.world + git add . && + git commit -a -m deeply.nested + ) && git clean -f -d && test -f foo/.git/index && test -f foo/hello.world && + test -f baz/boo/.git/index && + test -f baz/boo/deeper.world && ! test -d bar ' test_expect_success 'force removal of nested git work tree' ' - rm -fr foo bar && - mkdir foo bar && + rm -fr foo bar baz && + mkdir -p foo bar baz/boo && ( cd foo && git init && @@ -432,9 +441,17 @@ test_expect_success 'force removal of nested git work tree' ' cd bar && >goodbye.people ) && + ( + cd baz/boo && + git init && + >deeper.world + git add . && + git commit -a -m deeply.nested + ) && git clean -f -f -d && ! test -d foo && - ! test -d bar + ! test -d bar && + ! test -d baz ' test_expect_success 'git clean -e' ' diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index 695f7afdf3..c73bec9551 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -79,6 +79,15 @@ test_expect_success 'submodule add' ' cd addtest && git submodule add -q "$submodurl" submod >actual && test ! -s actual && + echo "gitdir: ../.git/modules/submod" >expect && + test_cmp expect submod/.git && + ( + cd submod && + git config core.worktree >actual && + echo "../../../submod" >expect && + test_cmp expect actual && + rm -f actual expect + ) && git submodule init ) && @@ -225,7 +234,7 @@ EOF test_expect_success 'status should only print one line' ' git submodule status >lines && - test $(wc -l <lines) = 1 + test_line_count = 1 lines ' test_expect_success 'setup - fetch commit name from submodule' ' @@ -474,21 +483,72 @@ test_expect_success 'set up for relative path tests' ' git add sub && git config -f .gitmodules submodule.sub.path sub && git config -f .gitmodules submodule.sub.url ../subrepo && - cp .git/config pristine-.git-config + cp .git/config pristine-.git-config && + cp .gitmodules pristine-.gitmodules ) ' -test_expect_success 'relative path works with URL' ' +test_expect_success '../subrepo works with URL - ssh://hostname/repo' ' ( cd reltest && cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && git config remote.origin.url ssh://hostname/repo && git submodule init && test "$(git config submodule.sub.url)" = ssh://hostname/subrepo ) ' -test_expect_success 'relative path works with user@host:path' ' +test_expect_success '../subrepo works with port-qualified URL - ssh://hostname:22/repo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url ssh://hostname:22/repo && + git submodule init && + test "$(git config submodule.sub.url)" = ssh://hostname:22/subrepo + ) +' + +# About the choice of the path in the next test: +# - double-slash side-steps path mangling issues on Windows +# - it is still an absolute local path +# - there cannot be a server with a blank in its name just in case the +# path is used erroneously to access a //server/share style path +test_expect_success '../subrepo path works with local path - //somewhere else/repo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url "//somewhere else/repo" && + git submodule init && + test "$(git config submodule.sub.url)" = "//somewhere else/subrepo" + ) +' + +test_expect_success '../subrepo works with file URL - file:///tmp/repo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url file:///tmp/repo && + git submodule init && + test "$(git config submodule.sub.url)" = file:///tmp/subrepo + ) +' + +test_expect_success '../subrepo works with helper URL- helper:://hostname/repo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url helper:://hostname/repo && + git submodule init && + test "$(git config submodule.sub.url)" = helper:://hostname/subrepo + ) +' + +test_expect_success '../subrepo works with scp-style URL - user@host:repo' ' ( cd reltest && cp pristine-.git-config .git/config && @@ -498,4 +558,109 @@ test_expect_success 'relative path works with user@host:path' ' ) ' +test_expect_success '../subrepo works with scp-style URL - user@host:path/to/repo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url user@host:path/to/repo && + git submodule init && + test "$(git config submodule.sub.url)" = user@host:path/to/subrepo + ) +' + +test_expect_success '../subrepo works with relative local path - foo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url foo && + # actual: fails with an error + git submodule init && + test "$(git config submodule.sub.url)" = subrepo + ) +' + +test_expect_success '../subrepo works with relative local path - foo/bar' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url foo/bar && + git submodule init && + test "$(git config submodule.sub.url)" = foo/subrepo + ) +' + +test_expect_success '../subrepo works with relative local path - ./foo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url ./foo && + git submodule init && + test "$(git config submodule.sub.url)" = subrepo + ) +' + +test_expect_success '../subrepo works with relative local path - ./foo/bar' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url ./foo/bar && + git submodule init && + test "$(git config submodule.sub.url)" = foo/subrepo + ) +' + +test_expect_success '../subrepo works with relative local path - ../foo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url ../foo && + git submodule init && + test "$(git config submodule.sub.url)" = ../subrepo + ) +' + +test_expect_success '../subrepo works with relative local path - ../foo/bar' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url ../foo/bar && + git submodule init && + test "$(git config submodule.sub.url)" = ../foo/subrepo + ) +' + +test_expect_success '../bar/a/b/c works with relative local path - ../foo/bar.git' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + mkdir -p a/b/c && + (cd a/b/c; git init) && + git config remote.origin.url ../foo/bar.git && + git submodule add ../bar/a/b/c ./a/b/c && + git submodule init && + test "$(git config submodule.a/b/c.url)" = ../foo/bar/a/b/c + ) +' + +test_expect_success 'moving the superproject does not break submodules' ' + ( + cd addtest && + git submodule status >expect + ) + mv addtest addtest2 && + ( + cd addtest2 && + git submodule status >actual && + test_cmp expect actual + ) +' + test_done diff --git a/t/t7403-submodule-sync.sh b/t/t7403-submodule-sync.sh index 3620215c1f..524d5c1b21 100755 --- a/t/t7403-submodule-sync.sh +++ b/t/t7403-submodule-sync.sh @@ -26,7 +26,9 @@ test_expect_success setup ' (cd super-clone && git submodule update --init) && git clone super empty-clone && (cd empty-clone && git submodule init) && - git clone super top-only-clone + git clone super top-only-clone && + git clone super relative-clone && + (cd relative-clone && git submodule update --init) ' test_expect_success 'change submodule' ' @@ -86,4 +88,90 @@ test_expect_success '"git submodule sync" should not vivify uninteresting submod ) ' +test_expect_success '"git submodule sync" handles origin URL of the form foo' ' + (cd relative-clone && + git remote set-url origin foo && + git submodule sync && + (cd submodule && + #actual fails with: "cannot strip off url foo + test "$(git config remote.origin.url)" = "../submodule" + ) + ) +' + +test_expect_success '"git submodule sync" handles origin URL of the form foo/bar' ' + (cd relative-clone && + git remote set-url origin foo/bar && + git submodule sync && + (cd submodule && + #actual foo/submodule + test "$(git config remote.origin.url)" = "../foo/submodule" + ) + ) +' + +test_expect_success '"git submodule sync" handles origin URL of the form ./foo' ' + (cd relative-clone && + git remote set-url origin ./foo && + git submodule sync && + (cd submodule && + #actual ./submodule + test "$(git config remote.origin.url)" = "../submodule" + ) + ) +' + +test_expect_success '"git submodule sync" handles origin URL of the form ./foo/bar' ' + (cd relative-clone && + git remote set-url origin ./foo/bar && + git submodule sync && + (cd submodule && + #actual ./foo/submodule + test "$(git config remote.origin.url)" = "../foo/submodule" + ) + ) +' + +test_expect_success '"git submodule sync" handles origin URL of the form ../foo' ' + (cd relative-clone && + git remote set-url origin ../foo && + git submodule sync && + (cd submodule && + #actual ../submodule + test "$(git config remote.origin.url)" = "../../submodule" + ) + ) +' + +test_expect_success '"git submodule sync" handles origin URL of the form ../foo/bar' ' + (cd relative-clone && + git remote set-url origin ../foo/bar && + git submodule sync && + (cd submodule && + #actual ../foo/submodule + test "$(git config remote.origin.url)" = "../../foo/submodule" + ) + ) +' + +test_expect_success '"git submodule sync" handles origin URL of the form ../foo/bar with deeply nested submodule' ' + (cd relative-clone && + git remote set-url origin ../foo/bar && + mkdir -p a/b/c && + ( cd a/b/c && + git init && + :> .gitignore && + git add .gitignore && + test_tick && + git commit -m "initial commit" ) && + git submodule add ../bar/a/b/c ./a/b/c && + git submodule sync && + (cd a/b/c && + #actual ../foo/bar/a/b/c + test "$(git config remote.origin.url)" = "../../../../foo/bar/a/b/c" + ) + ) +' + + test_done diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh index 5b97222c48..646298b212 100755 --- a/t/t7406-submodule-update.sh +++ b/t/t7406-submodule-update.sh @@ -367,7 +367,7 @@ test_expect_success 'submodule update continues after checkout error' ' git submodule init && git commit -am "new_submodule" && (cd submodule2 && - git rev-parse --max-count=1 HEAD > ../expect + git rev-parse --verify HEAD >../expect ) && (cd submodule && test_commit "update_submodule" file @@ -384,7 +384,7 @@ test_expect_success 'submodule update continues after checkout error' ' git checkout HEAD^ && test_must_fail git submodule update && (cd submodule2 && - git rev-parse --max-count=1 HEAD > ../actual + git rev-parse --verify HEAD >../actual ) && test_cmp expect actual ) @@ -413,7 +413,7 @@ test_expect_success 'submodule update continues after recursive checkout error' test_commit "update_submodule_again_again" file ) && (cd submodule2 && - git rev-parse --max-count=1 HEAD > ../expect && + git rev-parse --verify HEAD >../expect && test_commit "update_submodule2_again" file ) && git add submodule && @@ -428,7 +428,7 @@ test_expect_success 'submodule update continues after recursive checkout error' ) && test_must_fail git submodule update --recursive && (cd submodule2 && - git rev-parse --max-count=1 HEAD > ../actual + git rev-parse --verify HEAD >../actual ) && test_cmp expect actual ) @@ -460,12 +460,12 @@ test_expect_success 'submodule update exit immediately in case of merge conflict ) && git checkout HEAD^ && (cd submodule2 && - git rev-parse --max-count=1 HEAD > ../expect + git rev-parse --verify HEAD >../expect ) && git config submodule.submodule.update merge && test_must_fail git submodule update && (cd submodule2 && - git rev-parse --max-count=1 HEAD > ../actual + git rev-parse --verify HEAD >../actual ) && test_cmp expect actual ) @@ -495,12 +495,12 @@ test_expect_success 'submodule update exit immediately after recursive rebase er ) && git checkout HEAD^ && (cd submodule2 && - git rev-parse --max-count=1 HEAD > ../expect + git rev-parse --verify HEAD >../expect ) && git config submodule.submodule.update rebase && test_must_fail git submodule update && (cd submodule2 && - git rev-parse --max-count=1 HEAD > ../actual + git rev-parse --verify HEAD >../actual ) && test_cmp expect actual ) @@ -619,4 +619,34 @@ test_expect_success 'submodule add properly re-creates deeper level submodules' ) ' +test_expect_success 'submodule update properly revives a moved submodule' ' + (cd super && + git commit -am "pre move" && + git status >expect&& + H=$(cd submodule2; git rev-parse HEAD) && + git rm --cached submodule2 && + rm -rf submodule2 && + mkdir -p "moved/sub module" && + git update-index --add --cacheinfo 160000 $H "moved/sub module" && + git config -f .gitmodules submodule.submodule2.path "moved/sub module" + git commit -am "post move" && + git submodule update && + git status >actual && + test_cmp expect actual + ) +' + +test_expect_success SYMLINKS 'submodule update can handle symbolic links in pwd' ' + mkdir -p linked/dir && + ln -s linked/dir linkto && + ( + cd linkto && + git clone "$TRASH_DIRECTORY"/super_update_r2 super && + ( + cd super && + git submodule update --init --recursive + ) + ) +' + test_done diff --git a/t/t7408-submodule-reference.sh b/t/t7408-submodule-reference.sh index ab37c368d0..b770b2f04d 100755 --- a/t/t7408-submodule-reference.sh +++ b/t/t7408-submodule-reference.sh @@ -28,7 +28,7 @@ git prune' cd "$base_dir" -test_expect_success 'preparing supermodule' \ +test_expect_success 'preparing superproject' \ 'test_create_repo super && cd super && echo file > file && git add file && @@ -43,7 +43,7 @@ git commit -m B-super-added' cd "$base_dir" test_expect_success 'after add: existence of info/alternates' \ -'test `wc -l <super/.git/modules/sub/objects/info/alternates` = 1' +'test_line_count = 1 super/.git/modules/sub/objects/info/alternates' cd "$base_dir" @@ -55,7 +55,7 @@ diff expected current' cd "$base_dir" -test_expect_success 'cloning supermodule' \ +test_expect_success 'cloning superproject' \ 'git clone super super-clone' cd "$base_dir" @@ -66,7 +66,7 @@ test_expect_success 'update with reference' \ cd "$base_dir" test_expect_success 'after update: existence of info/alternates' \ -'test `wc -l <super-clone/.git/modules/sub/objects/info/alternates` = 1' +'test_line_count = 1 super-clone/.git/modules/sub/objects/info/alternates' cd "$base_dir" diff --git a/t/t7409-submodule-detached-worktree.sh b/t/t7409-submodule-detached-worktree.sh new file mode 100755 index 0000000000..2fec13dcd3 --- /dev/null +++ b/t/t7409-submodule-detached-worktree.sh @@ -0,0 +1,78 @@ +#!/bin/sh +# +# Copyright (c) 2012 Daniel Graña +# + +test_description='Test submodules on detached working tree + +This test verifies that "git submodule" initialization, update and addition works +on detahced working trees +' + +TEST_NO_CREATE_REPO=1 +. ./test-lib.sh + +test_expect_success 'submodule on detached working tree' ' + git init --bare remote && + test_create_repo bundle1 && + ( + cd bundle1 && + test_commit "shoot" && + git rev-parse --verify HEAD >../expect + ) && + mkdir home && + ( + cd home && + export GIT_WORK_TREE="$(pwd)" GIT_DIR="$(pwd)/.dotfiles" && + git clone --bare ../remote .dotfiles && + git submodule add ../bundle1 .vim/bundle/sogood && + test_commit "sogood" && + ( + unset GIT_WORK_TREE GIT_DIR && + cd .vim/bundle/sogood && + git rev-parse --verify HEAD >actual && + test_cmp ../../../../expect actual + ) && + git push origin master + ) && + mkdir home2 && + ( + cd home2 && + git clone --bare ../remote .dotfiles && + export GIT_WORK_TREE="$(pwd)" GIT_DIR="$(pwd)/.dotfiles" && + git checkout master && + git submodule update --init && + ( + unset GIT_WORK_TREE GIT_DIR && + cd .vim/bundle/sogood && + git rev-parse --verify HEAD >actual && + test_cmp ../../../../expect actual + ) + ) +' + +test_expect_success 'submodule on detached working pointed by core.worktree' ' + mkdir home3 && + ( + cd home3 && + export GIT_DIR="$(pwd)/.dotfiles" && + git clone --bare ../remote "$GIT_DIR" && + git config core.bare false && + git config core.worktree .. && + git checkout master && + git submodule add ../bundle1 .vim/bundle/dupe && + test_commit "dupe" && + git push origin master + ) && + ( + cd home && + export GIT_DIR="$(pwd)/.dotfiles" && + git config core.bare false && + git config core.worktree .. && + git pull && + git submodule update --init && + test -f .vim/bundle/dupe/shoot.t + ) +' + +test_done diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh index 8bb38337a9..195e7477d8 100755 --- a/t/t7501-commit.sh +++ b/t/t7501-commit.sh @@ -30,10 +30,12 @@ test_expect_success 'setup: initial commit' ' ' test_expect_success '-m and -F do not mix' ' + git checkout HEAD file && echo >>file && git add file && test_must_fail git commit -m foo -m bar -F file ' test_expect_success '-m and -C do not mix' ' + git checkout HEAD file && echo >>file && git add file && test_must_fail git commit -C HEAD -m illegal ' @@ -79,7 +81,19 @@ test_expect_success 'empty commit message' ' test_must_fail git commit -F msg -a ' +test_expect_success 'template "emptyness" check does not kick in with -F' ' + git checkout HEAD file && echo >>file && git add file && + git commit -t file -F file +' + +test_expect_success 'template "emptyness" check' ' + git checkout HEAD file && echo >>file && git add file && + test_must_fail git commit -t file 2>err && + test_i18ngrep "did not edit" err +' + test_expect_success 'setup: commit message from file' ' + git checkout HEAD file && echo >>file && git add file && echo this is the commit message, coming from a file >msg && git commit -F msg -a ' @@ -94,6 +108,16 @@ test_expect_success 'amend commit' ' EDITOR=./editor git commit --amend ' +test_expect_success 'amend --only ignores staged contents' ' + cp file file.expect && + echo changed >file && + git add file && + git commit --no-edit --amend --only && + git cat-file blob HEAD:file >file.actual && + test_cmp file.expect file.actual && + git diff --exit-code +' + test_expect_success 'set up editor' ' cat >editor <<-\EOF && #!/bin/sh @@ -124,6 +148,21 @@ test_expect_success '--amend --edit' ' test_cmp expect msg ' +test_expect_success '--amend --edit of empty message' ' + cat >replace <<-\EOF && + #!/bin/sh + echo "amended" >"$1" + EOF + chmod 755 replace && + git commit --allow-empty --allow-empty-message -m "" && + echo more bongo >file && + git add file && + EDITOR=./replace git commit --edit --amend && + git diff-tree -s --format=%s HEAD >msg && + ./replace expect && + test_cmp expect msg +' + test_expect_success '-m --edit' ' echo amended >expect && git commit --allow-empty -m buffer && @@ -473,4 +512,16 @@ test_expect_success 'amend can copy notes' ' ' +test_expect_success 'commit a file whose name is a dash' ' + git reset --hard && + for i in 1 2 3 4 5 + do + echo $i + done >./- && + git add ./- && + test_tick && + git commit -m "add dash" >output </dev/null && + test_i18ngrep " changed, 5 insertions" output +' + test_done diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh index 3f3adc31b9..deb187eb7b 100755 --- a/t/t7502-commit.sh +++ b/t/t7502-commit.sh @@ -235,44 +235,56 @@ test_expect_success 'cleanup commit messages (strip,-F,-e): output' ' test_i18ncmp expect actual ' -echo "# -# Author: $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> -#" >> expect - -test_expect_success 'author different from committer' ' +test_expect_success 'message shows author when it is not equal to committer' ' echo >>negative && - test_might_fail git commit -e -m "sample" && - head -n 7 .git/COMMIT_EDITMSG >actual && - test_i18ncmp expect actual + git commit -e -m "sample" -a && + test_i18ngrep \ + "^# Author: *A U Thor <author@example.com>\$" \ + .git/COMMIT_EDITMSG ' -mv expect expect.tmp -sed '$d' < expect.tmp > expect -rm -f expect.tmp -echo "# Committer: -#" >> expect +test_expect_success 'setup auto-ident prerequisite' ' + if (sane_unset GIT_COMMITTER_EMAIL && + sane_unset GIT_COMMITTER_NAME && + git var GIT_COMMITTER_IDENT); then + test_set_prereq AUTOIDENT + else + test_set_prereq NOAUTOIDENT + fi +' -test_expect_success 'committer is automatic' ' +test_expect_success AUTOIDENT 'message shows committer when it is automatic' ' echo >>negative && ( sane_unset GIT_COMMITTER_EMAIL && sane_unset GIT_COMMITTER_NAME && - # must fail because there is no change - test_must_fail git commit -e -m "sample" + git commit -e -m "sample" -a ) && - head -n 8 .git/COMMIT_EDITMSG | \ - sed "s/^# Committer: .*/# Committer:/" >actual - test_i18ncmp expect actual + # the ident is calculated from the system, so we cannot + # check the actual value, only that it is there + test_i18ngrep "^# Committer: " .git/COMMIT_EDITMSG ' -pwd=`pwd` -cat >> .git/FAKE_EDITOR << EOF -#! /bin/sh -echo editor started > "$pwd/.git/result" +write_script .git/FAKE_EDITOR <<EOF +echo editor started > "$(pwd)/.git/result" exit 0 EOF -chmod +x .git/FAKE_EDITOR + +test_expect_success NOAUTOIDENT 'do not fire editor when committer is bogus' ' + >.git/result + >expect && + + echo >>negative && + ( + sane_unset GIT_COMMITTER_EMAIL && + sane_unset GIT_COMMITTER_NAME && + GIT_EDITOR="\"$(pwd)/.git/FAKE_EDITOR\"" && + export GIT_EDITOR && + test_must_fail git commit -e -m sample -a + ) && + test_cmp expect .git/result +' test_expect_success 'do not fire editor in the presence of conflicts' ' @@ -293,16 +305,14 @@ test_expect_success 'do not fire editor in the presence of conflicts' ' test_must_fail git cherry-pick -n master && echo "editor not started" >.git/result && ( - GIT_EDITOR="$(pwd)/.git/FAKE_EDITOR" && + GIT_EDITOR="\"$(pwd)/.git/FAKE_EDITOR\"" && export GIT_EDITOR && test_must_fail git commit ) && test "$(cat .git/result)" = "editor not started" ' -pwd=`pwd` -cat >.git/FAKE_EDITOR <<EOF -#! $SHELL_PATH +write_script .git/FAKE_EDITOR <<EOF # kill -TERM command added below. EOF @@ -335,17 +345,16 @@ test_expect_success 'A single-liner subject with a token plus colon is not a foo git reset --hard && git commit -s -m "hello: kitty" --allow-empty && git cat-file commit HEAD | sed -e "1,/^$/d" >actual && - test $(wc -l <actual) = 3 + test_line_count = 3 actual ' -cat >.git/FAKE_EDITOR <<EOF -#!$SHELL_PATH -mv "\$1" "\$1.orig" +write_script .git/FAKE_EDITOR <<\EOF +mv "$1" "$1.orig" ( echo message - cat "\$1.orig" -) >"\$1" + cat "$1.orig" +) >"$1" EOF echo '## Custom template' >template diff --git a/t/t7503-pre-commit-hook.sh b/t/t7503-pre-commit-hook.sh index ee7f0cd459..984889b39d 100755 --- a/t/t7503-pre-commit-hook.sh +++ b/t/t7503-pre-commit-hook.sh @@ -118,4 +118,22 @@ test_expect_success 'with failing hook requiring GIT_PREFIX' ' git checkout -- file ' +test_expect_success 'check the author in hook' ' + write_script "$HOOK" <<-\EOF && + test "$GIT_AUTHOR_NAME" = "New Author" && + test "$GIT_AUTHOR_EMAIL" = "newauthor@example.com" + EOF + test_must_fail git commit --allow-empty -m "by a.u.thor" && + ( + GIT_AUTHOR_NAME="New Author" && + GIT_AUTHOR_EMAIL="newauthor@example.com" && + export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL && + git commit --allow-empty -m "by new.author via env" && + git show -s + ) && + git commit --author="New Author <newauthor@example.com>" \ + --allow-empty -m "by new.author via command line" && + git show -s +' + test_done diff --git a/t/t7508-status.sh b/t/t7508-status.sh index fc57b135c5..c206f4777a 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -59,6 +59,30 @@ test_expect_success 'status (1)' ' test_i18ngrep "use \"git rm --cached <file>\.\.\.\" to unstage" output ' +test_expect_success 'status --column' ' + COLUMNS=50 git status --column="column dense" >output && + cat >expect <<\EOF && +# On branch master +# Changes to be committed: +# (use "git reset HEAD <file>..." to unstage) +# +# new file: dir2/added +# +# Changes not staged for commit: +# (use "git add <file>..." to update what will be committed) +# (use "git checkout -- <file>..." to discard changes in working directory) +# +# modified: dir1/modified +# +# Untracked files: +# (use "git add <file>..." to include in what will be committed) +# +# dir1/untracked dir2/untracked untracked +# dir2/modified output +EOF + test_cmp expect output +' + cat >expect <<\EOF # On branch master # Changes to be committed: @@ -271,6 +295,15 @@ test_expect_success 'status -s -b' ' ' +test_expect_success 'status -s -z -b' ' + tr "\\n" Q <expect >expect.q && + mv expect.q expect && + git status -s -z -b >output && + nul_to_q <output >output.q && + mv output.q output && + test_cmp expect output +' + test_expect_success 'setup dir3' ' mkdir dir3 && : >dir3/untracked1 && @@ -647,9 +680,14 @@ test_expect_success 'status --porcelain ignores color.status' ' git config --unset color.status git config --unset color.ui -test_expect_success 'status --porcelain ignores -b' ' +test_expect_success 'status --porcelain respects -b' ' git status --porcelain -b >output && + { + echo "## master" && + cat expect + } >tmp && + mv tmp expect && test_cmp expect output ' @@ -903,7 +941,7 @@ test_expect_success 'status -s submodule summary (clean submodule)' ' test_expect_success 'status -z implies porcelain' ' git status --porcelain | - perl -pe "s/\012/\000/g" >expect && + "$PERL_PATH" -pe "s/\012/\000/g" >expect && git status -z >output && test_cmp expect output ' diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh new file mode 100755 index 0000000000..b3f6eb9c68 --- /dev/null +++ b/t/t7512-status-help.sh @@ -0,0 +1,649 @@ +#!/bin/sh +# +# Copyright (c) 2012 Valentin Duperray, Lucien Kong, Franck Jonas, +# Thomas Nguy, Khoi Nguyen +# Grenoble INP Ensimag +# + +test_description='git status advices' + +. ./test-lib.sh + +. "$TEST_DIRECTORY"/lib-rebase.sh + +set_fake_editor + +test_expect_success 'prepare for conflicts' ' + test_commit init main.txt init && + git branch conflicts && + test_commit on_master main.txt on_master && + git checkout conflicts && + test_commit on_conflicts main.txt on_conflicts +' + + +test_expect_success 'status when conflicts unresolved' ' + test_must_fail git merge master && + cat >expected <<-\EOF && + # On branch conflicts + # You have unmerged paths. + # (fix conflicts and run "git commit") + # + # 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_i18ncmp expected actual +' + + +test_expect_success 'status when conflicts resolved before commit' ' + git reset --hard conflicts && + test_must_fail git merge master && + echo one >main.txt && + git add main.txt && + cat >expected <<-\EOF && + # On branch conflicts + # All conflicts fixed but you are still merging. + # (use "git commit" to conclude merge) + # + # Changes to be committed: + # + # modified: main.txt + # + # Untracked files not listed (use -u option to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'prepare for rebase conflicts' ' + git reset --hard master && + git checkout -b rebase_conflicts && + test_commit one_rebase main.txt one && + test_commit two_rebase main.txt two && + test_commit three_rebase main.txt three +' + + +test_expect_success 'status when rebase in progress before resolving conflicts' ' + test_when_finished "git rebase --abort" && + test_must_fail git rebase HEAD^ --onto HEAD^^ && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently rebasing. + # (fix conflicts and then run "git rebase --continue") + # (use "git rebase --skip" to skip this patch) + # (use "git rebase --abort" to check out the original branch) + # + # Unmerged paths: + # (use "git reset HEAD <file>..." to unstage) + # (use "git add <file>..." to mark resolution) + # + # both modified: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status when rebase in progress before rebase --continue' ' + git reset --hard rebase_conflicts && + test_when_finished "git rebase --abort" && + test_must_fail git rebase HEAD^ --onto HEAD^^ && + echo three >main.txt && + git add main.txt && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently rebasing. + # (all conflicts fixed: run "git rebase --continue") + # + # Changes to be committed: + # (use "git reset HEAD <file>..." to unstage) + # + # modified: main.txt + # + # Untracked files not listed (use -u option to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'prepare for rebase_i_conflicts' ' + git reset --hard master && + git checkout -b rebase_i_conflicts && + test_commit one_unmerge main.txt one_unmerge && + git branch rebase_i_conflicts_second && + test_commit one_master main.txt one_master && + git checkout rebase_i_conflicts_second && + test_commit one_second main.txt one_second +' + + +test_expect_success 'status during rebase -i when conflicts unresolved' ' + test_when_finished "git rebase --abort" && + test_must_fail git rebase -i rebase_i_conflicts && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently rebasing. + # (fix conflicts and then run "git rebase --continue") + # (use "git rebase --skip" to skip this patch) + # (use "git rebase --abort" to check out the original branch) + # + # Unmerged paths: + # (use "git reset HEAD <file>..." to unstage) + # (use "git add <file>..." to mark resolution) + # + # both modified: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status during rebase -i after resolving conflicts' ' + git reset --hard rebase_i_conflicts_second && + test_when_finished "git rebase --abort" && + test_must_fail git rebase -i rebase_i_conflicts && + git add main.txt && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently rebasing. + # (all conflicts fixed: run "git rebase --continue") + # + # Changes to be committed: + # (use "git reset HEAD <file>..." to unstage) + # + # modified: main.txt + # + # Untracked files not listed (use -u option to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status when rebasing -i in edit mode' ' + git reset --hard master && + git checkout -b rebase_i_edit && + test_commit one_rebase_i main.txt one && + test_commit two_rebase_i main.txt two && + test_commit three_rebase_i main.txt three && + FAKE_LINES="1 edit 2" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~2 && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status when splitting a commit' ' + git reset --hard master && + git checkout -b split_commit && + test_commit one_split main.txt one && + test_commit two_split main.txt two && + test_commit three_split main.txt three && + test_commit four_split main.txt four && + FAKE_LINES="1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git reset HEAD^ && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently splitting a commit during a rebase. + # (Once your working directory is clean, run "git rebase --continue") + # + # Changes not staged for commit: + # (use "git add <file>..." to update what will be committed) + # (use "git checkout -- <file>..." to discard changes in working directory) + # + # modified: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status after editing the last commit with --amend during a rebase -i' ' + git reset --hard master && + git checkout -b amend_last && + test_commit one_amend main.txt one && + test_commit two_amend main.txt two && + test_commit three_amend main.txt three && + test_commit four_amend main.txt four && + FAKE_LINES="1 2 edit 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git commit --amend -m "foo" && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'prepare for several edits' ' + git reset --hard master && + git checkout -b several_edits && + test_commit one_edits main.txt one && + test_commit two_edits main.txt two && + test_commit three_edits main.txt three && + test_commit four_edits main.txt four +' + + +test_expect_success 'status: (continue first edit) second edit' ' + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git rebase --continue && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (continue first edit) second edit and split' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git rebase --continue && + git reset HEAD^ && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently splitting a commit during a rebase. + # (Once your working directory is clean, run "git rebase --continue") + # + # Changes not staged for commit: + # (use "git add <file>..." to update what will be committed) + # (use "git checkout -- <file>..." to discard changes in working directory) + # + # modified: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (continue first edit) second edit and amend' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git rebase --continue && + git commit --amend -m "foo" && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (amend first edit) second edit' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git commit --amend -m "a" && + git rebase --continue && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (amend first edit) second edit and split' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git commit --amend -m "b" && + git rebase --continue && + git reset HEAD^ && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently splitting a commit during a rebase. + # (Once your working directory is clean, run "git rebase --continue") + # + # Changes not staged for commit: + # (use "git add <file>..." to update what will be committed) + # (use "git checkout -- <file>..." to discard changes in working directory) + # + # modified: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (amend first edit) second edit and amend' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git commit --amend -m "c" && + git rebase --continue && + git commit --amend -m "d" && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (split first edit) second edit' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git reset HEAD^ && + git add main.txt && + git commit -m "e" && + git rebase --continue && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (split first edit) second edit and split' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git reset HEAD^ && + git add main.txt && + git commit --amend -m "f" && + git rebase --continue && + git reset HEAD^ && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently splitting a commit during a rebase. + # (Once your working directory is clean, run "git rebase --continue") + # + # Changes not staged for commit: + # (use "git add <file>..." to update what will be committed) + # (use "git checkout -- <file>..." to discard changes in working directory) + # + # modified: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (split first edit) second edit and amend' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git reset HEAD^ && + git add main.txt && + git commit --amend -m "g" && + git rebase --continue && + git commit --amend -m "h" && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'prepare am_session' ' + git reset --hard master && + git checkout -b am_session && + test_commit one_am one.txt "one" && + test_commit two_am two.txt "two" && + test_commit three_am three.txt "three" +' + + +test_expect_success 'status in an am session: file already exists' ' + git checkout -b am_already_exists && + test_when_finished "rm Maildir/* && git am --abort" && + git format-patch -1 -oMaildir && + test_must_fail git am Maildir/*.patch && + cat >expected <<-\EOF && + # On branch am_already_exists + # You are in the middle of an am session. + # (fix conflicts and then run "git am --resolved") + # (use "git am --skip" to skip this patch) + # (use "git am --abort" to restore the original branch) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status in an am session: file does not exist' ' + git reset --hard am_session && + git checkout -b am_not_exists && + git rm three.txt && + git commit -m "delete three.txt" && + test_when_finished "rm Maildir/* && git am --abort" && + git format-patch -1 -oMaildir && + test_must_fail git am Maildir/*.patch && + cat >expected <<-\EOF && + # On branch am_not_exists + # You are in the middle of an am session. + # (fix conflicts and then run "git am --resolved") + # (use "git am --skip" to skip this patch) + # (use "git am --abort" to restore the original branch) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status in an am session: empty patch' ' + git reset --hard am_session && + git checkout -b am_empty && + test_when_finished "rm Maildir/* && git am --abort" && + git format-patch -3 -oMaildir && + git rm one.txt two.txt three.txt && + git commit -m "delete all am_empty" && + echo error >Maildir/0002-two_am.patch && + test_must_fail git am Maildir/*.patch && + cat >expected <<-\EOF && + # On branch am_empty + # You are in the middle of an am session. + # The current patch is empty. + # (use "git am --skip" to skip this patch) + # (use "git am --abort" to restore the original branch) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status when bisecting' ' + git reset --hard master && + git checkout -b bisect && + test_commit one_bisect main.txt one && + test_commit two_bisect main.txt two && + test_commit three_bisect main.txt three && + test_when_finished "git bisect reset" && + git bisect start && + git bisect bad && + git bisect good one_bisect && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently bisecting. + # (use "git bisect reset" to get back to the original branch) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status when rebase conflicts with statushints disabled' ' + git reset --hard master && + git checkout -b statushints_disabled && + test_when_finished "git config --local advice.statushints true" && + git config --local advice.statushints false && + test_commit one_statushints main.txt one && + test_commit two_statushints main.txt two && + test_commit three_statushints main.txt three && + test_when_finished "git rebase --abort" && + test_must_fail git rebase HEAD^ --onto HEAD^^ && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently rebasing. + # + # Unmerged paths: + # both modified: main.txt + # + no changes added to commit + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'prepare for cherry-pick conflicts' ' + git reset --hard master && + git checkout -b cherry_branch && + test_commit one_cherry main.txt one && + test_commit two_cherries main.txt two && + git checkout -b cherry_branch_second && + test_commit second_cherry main.txt second && + git checkout cherry_branch && + test_commit three_cherries main.txt three +' + + +test_expect_success 'status when cherry-picking before resolving conflicts' ' + test_when_finished "git cherry-pick --abort" && + test_must_fail git cherry-pick cherry_branch_second && + cat >expected <<-\EOF && + # On branch cherry_branch + # You are currently cherry-picking. + # (fix conflicts and run "git commit") + # + # 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_i18ncmp expected actual +' + + +test_expect_success 'status when cherry-picking after resolving conflicts' ' + git reset --hard cherry_branch && + test_when_finished "git cherry-pick --abort" && + test_must_fail git cherry-pick cherry_branch_second && + echo end >main.txt && + git add main.txt && + cat >expected <<-\EOF && + # On branch cherry_branch + # You are currently cherry-picking. + # (all conflicts fixed: run "git commit") + # + # Changes to be committed: + # + # modified: main.txt + # + # Untracked files not listed (use -u option to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_done diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 5783ebf3ab..955f09f8e8 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -54,9 +54,9 @@ Trying simple merge with c2 Trying simple merge with c3 Trying simple merge with c4 Merge made by the 'octopus' strategy. - c2.c | 1 + - c3.c | 1 + - c4.c | 1 + + c2.c | 1 + + c3.c | 1 + + c4.c | 1 + 3 files changed, 3 insertions(+) create mode 100644 c2.c create mode 100644 c3.c @@ -66,29 +66,27 @@ EOF test_expect_success 'merge output uses pretty names' ' git reset --hard c1 && git merge c2 c3 c4 >actual && - test_cmp actual expected + test_i18ncmp expected actual ' cat >expected <<\EOF -Already up-to-date with c4 -Trying simple merge with c5 -Merge made by the 'octopus' strategy. - c5.c | 1 + +Merge made by the 'recursive' strategy. + c5.c | 1 + 1 file changed, 1 insertion(+) create mode 100644 c5.c EOF -test_expect_success 'merge up-to-date output uses pretty names' ' - git merge c4 c5 >actual && - test_cmp actual expected +test_expect_success 'merge reduces irrelevant remote heads' ' + GIT_MERGE_VERBOSITY=0 git merge c4 c5 >actual && + test_i18ncmp expected actual ' cat >expected <<\EOF Fast-forwarding to: c1 Trying simple merge with c2 Merge made by the 'octopus' strategy. - c1.c | 1 + - c2.c | 1 + + c1.c | 1 + + c2.c | 1 + 2 files changed, 2 insertions(+) create mode 100644 c1.c create mode 100644 c2.c @@ -97,7 +95,7 @@ EOF test_expect_success 'merge fast-forward output uses pretty names' ' git reset --hard c0 && git merge c1 c2 >actual && - test_cmp actual expected + test_i18ncmp expected actual ' test_done diff --git a/t/t7603-merge-reduce-heads.sh b/t/t7603-merge-reduce-heads.sh index 7e17eb490d..98948955ae 100755 --- a/t/t7603-merge-reduce-heads.sh +++ b/t/t7603-merge-reduce-heads.sh @@ -57,7 +57,36 @@ test_expect_success 'merge c1 with c2, c3, c4, c5' ' test -f c2.c && test -f c3.c && test -f c4.c && - test -f c5.c + test -f c5.c && + git show --format=%s -s >actual && + ! grep c1 actual && + grep c2 actual && + grep c3 actual && + ! grep c4 actual && + grep c5 actual +' + +test_expect_success 'pull c2, c3, c4, c5 into c1' ' + git reset --hard c1 && + git pull . c2 c3 c4 c5 && + test "$(git rev-parse c1)" != "$(git rev-parse HEAD)" && + test "$(git rev-parse c1)" = "$(git rev-parse HEAD^1)" && + test "$(git rev-parse c2)" = "$(git rev-parse HEAD^2)" && + test "$(git rev-parse c3)" = "$(git rev-parse HEAD^3)" && + test "$(git rev-parse c5)" = "$(git rev-parse HEAD^4)" && + git diff --exit-code && + test -f c0.c && + test -f c1.c && + test -f c2.c && + test -f c3.c && + test -f c4.c && + test -f c5.c && + git show --format=%s -s >actual && + ! grep c1 actual && + grep c2 actual && + grep c3 actual && + ! grep c4 actual && + grep c5 actual ' test_expect_success 'setup' ' @@ -113,4 +142,23 @@ test_expect_success 'verify merge result' ' test $(git rev-parse HEAD^1) = $(git rev-parse E2) && test $(git rev-parse HEAD^2) = $(git rev-parse I2) ' + +test_expect_success 'fast-forward to redundant refs' ' + git reset --hard c0 && + git merge c4 c5 +' + +test_expect_success 'verify merge result' ' + test $(git rev-parse HEAD) = $(git rev-parse c5) +' + +test_expect_success 'merge up-to-date redundant refs' ' + git reset --hard c5 && + git merge c0 c4 +' + +test_expect_success 'verify merge result' ' + test $(git rev-parse HEAD) = $(git rev-parse c5) +' + test_done diff --git a/t/t7607-merge-overwrite.sh b/t/t7607-merge-overwrite.sh index aa74184c31..6547eb8f54 100755 --- a/t/t7607-merge-overwrite.sh +++ b/t/t7607-merge-overwrite.sh @@ -92,6 +92,15 @@ test_expect_success 'will not overwrite removed file with staged changes' ' test_cmp important c1.c ' +test_expect_failure 'will not overwrite unstaged changes in renamed file' ' + git reset --hard c1 && + git mv c1.c other.c && + git commit -m rename && + cp important other.c && + git merge c1a && + test_cmp important other.c +' + test_expect_success 'will not overwrite untracked subtree' ' git reset --hard c0 && rm -rf sub && diff --git a/t/t7701-repack-unpack-unreachable.sh b/t/t7701-repack-unpack-unreachable.sh index 200ab61278..b8d4cdea8c 100755 --- a/t/t7701-repack-unpack-unreachable.sh +++ b/t/t7701-repack-unpack-unreachable.sh @@ -95,4 +95,18 @@ test_expect_success 'unpacked objects receive timestamp of pack file' ' compare_mtimes < mtimes ' +test_expect_success 'do not bother loosening old objects' ' + obj1=$(echo one | git hash-object -w --stdin) && + obj2=$(echo two | 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) && + git prune-packed && + git cat-file -p $obj1 && + git cat-file -p $obj2 && + test-chmtime =-86400 .git/objects/pack/pack-$pack2.pack && + git repack -A -d --unpack-unreachable=1.hour.ago && + git cat-file -p $obj1 && + test_must_fail git cat-file -p $obj2 +' + test_done diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh index 4fb4c9384a..9c3e997b9d 100755 --- a/t/t7800-difftool.sh +++ b/t/t7800-difftool.sh @@ -83,6 +83,17 @@ test_expect_success PERL 'difftool ignores bad --tool values' ' test "$diff" = "" ' +test_expect_success PERL 'difftool forwards arguments to diff' ' + >for-diff && + git add for-diff && + echo changes>for-diff && + git add for-diff && + diff=$(git difftool --cached --no-prompt -- for-diff) && + test "$diff" = "" && + git reset -- for-diff && + rm for-diff +' + test_expect_success PERL 'difftool honors --gui' ' git config merge.tool bogus-tool && git config diff.tool bogus-tool && @@ -94,6 +105,19 @@ test_expect_success PERL 'difftool honors --gui' ' restore_test_defaults ' +test_expect_success PERL 'difftool --gui last setting wins' ' + git config diff.guitool bogus-tool && + git difftool --no-prompt --gui --no-gui && + + git config merge.tool bogus-tool && + git config diff.tool bogus-tool && + git config diff.guitool test-tool && + diff=$(git difftool --no-prompt --no-gui --gui branch) && + test "$diff" = "branch" && + + restore_test_defaults +' + test_expect_success PERL 'difftool --gui works without configured diff.guitool' ' git config diff.tool test-tool && @@ -306,4 +330,48 @@ test_expect_success PERL 'say no to the second file' ' echo "$diff" | stdin_doesnot_contain br2 ' +test_expect_success PERL 'difftool --tool-help' ' + tool_help=$(git difftool --tool-help) && + echo "$tool_help" | stdin_contains tool +' + +test_expect_success PERL 'setup change in subdirectory' ' + git checkout master && + mkdir sub && + echo master >sub/sub && + git add sub/sub && + git commit -m "added sub/sub" && + echo test >>file && + echo test >>sub/sub && + git add . && + git commit -m "modified both" +' + +test_expect_success PERL 'difftool -d' ' + diff=$(git difftool -d --extcmd ls branch) && + echo "$diff" | stdin_contains sub && + echo "$diff" | stdin_contains file +' + +test_expect_success PERL 'difftool --dir-diff' ' + diff=$(git difftool --dir-diff --extcmd ls branch) && + echo "$diff" | stdin_contains sub && + echo "$diff" | stdin_contains file +' + +test_expect_success PERL 'difftool --dir-diff ignores --prompt' ' + diff=$(git difftool --dir-diff --prompt --extcmd ls branch) && + echo "$diff" | stdin_contains sub && + echo "$diff" | stdin_contains file +' + +test_expect_success PERL 'difftool --dir-diff from subdirectory' ' + ( + cd sub && + diff=$(git difftool --dir-diff --extcmd ls branch) && + echo "$diff" | stdin_contains sub && + echo "$diff" | stdin_contains file + ) +' + test_done diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index 75f4716d8c..523d04123d 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -47,6 +47,13 @@ test_expect_success setup ' echo vvv >t/v && mkdir t/a && echo vvv >t/a/v && + { + echo "line without leading space1" + echo " line with leading space1" + echo " line with leading space2" + echo " line with leading space3" + echo "line without leading space2" + } >space && git add . && test_tick && git commit -m initial @@ -344,6 +351,11 @@ test_expect_success 'grep -f, multiple patterns' ' test_cmp expected actual ' +test_expect_success 'grep, multiple patterns' ' + git grep "$(cat patterns)" >actual && + test_cmp expected actual +' + cat >expected <<EOF file:foo mmap bar file:foo_mmap bar @@ -387,17 +399,6 @@ test_expect_success 'grep -q, silently report matches' ' test_cmp empty actual ' -# Create 1024 file names that sort between "y" and "z" to make sure -# the two files are handled by different calls to an external grep. -# This depends on MAXARGS in builtin-grep.c being 1024 or less. -c32="0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v" -test_expect_success 'grep -C1, hunk mark between files' ' - for a in $c32; do for b in $c32; do : >y-$a$b; done; done && - git add y-?? && - git grep -C1 "^[yz]" >actual && - test_cmp expected actual -' - test_expect_success 'grep -C1 hunk mark between files' ' git grep -C1 "^[yz]" >actual && test_cmp expected actual @@ -893,4 +894,20 @@ test_expect_success 'mimic ack-grep --group' ' test_cmp expected actual ' +cat >expected <<EOF +space: line with leading space1 +space: line with leading space2 +space: line with leading space3 +EOF + +test_expect_success LIBPCRE 'grep -E "^ "' ' + git grep -E "^ " space >actual && + test_cmp expected actual +' + +test_expect_success LIBPCRE 'grep -P "^ "' ' + git grep -P "^ " space >actual && + test_cmp expected actual +' + test_done diff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh index c3c22f7764..bf6caa4dc3 100755 --- a/t/t8006-blame-textconv.sh +++ b/t/t8006-blame-textconv.sh @@ -10,7 +10,7 @@ find_blame() { cat >helper <<'EOF' #!/bin/sh grep -q '^bin: ' "$1" || { echo "E: $1 is not \"binary\" file" 1>&2; exit 1; } -perl -p -e 's/^bin: /converted: /' "$1" +"$PERL_PATH" -p -e 's/^bin: /converted: /' "$1" EOF chmod +x helper diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 8c12c65c72..035122808b 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -841,6 +841,19 @@ test_expect_success $PREREQ '--compose adds MIME for utf8 subject' ' grep "^Subject: =?UTF-8?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1 ' +test_expect_success $PREREQ 'utf8 author is correctly passed on' ' + clean_fake_sendmail && + test_commit weird_author && + test_when_finished "git reset --hard HEAD^" && + git commit --amend --author "Füñný Nâmé <odd_?=mail@example.com>" && + git format-patch --stdout -1 >funny_name.patch && + git send-email --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + funny_name.patch && + grep "^From: Füñný Nâmé <odd_?=mail@example.com>" msgtxt1 +' + test_expect_success $PREREQ 'detects ambiguous reference/file conflict' ' echo master > master && git add master && diff --git a/t/t9002-column.sh b/t/t9002-column.sh new file mode 100755 index 0000000000..89983527b6 --- /dev/null +++ b/t/t9002-column.sh @@ -0,0 +1,180 @@ +#!/bin/sh + +test_description='git column' +. ./test-lib.sh + +test_expect_success 'setup' ' + cat >lista <<\EOF +one +two +three +four +five +six +seven +eight +nine +ten +eleven +EOF +' + +test_expect_success 'never' ' + git column --indent=Z --mode=never <lista >actual && + test_cmp lista actual +' + +test_expect_success 'always' ' + cat >expected <<\EOF && +Zone +Ztwo +Zthree +Zfour +Zfive +Zsix +Zseven +Zeight +Znine +Zten +Zeleven +EOF + git column --indent=Z --mode=plain <lista >actual && + test_cmp expected actual +' + +test_expect_success '80 columns' ' + cat >expected <<\EOF && +one two three four five six seven eight nine ten eleven +EOF + COLUMNS=80 git column --mode=column <lista >actual && + test_cmp expected actual +' + +cat >expected <<\EOF +one +two +three +four +five +six +seven +eight +nine +ten +eleven +EOF + +test_expect_success COLUMNS_CAN_BE_1 'COLUMNS = 1' ' + COLUMNS=1 git column --mode=column <lista >actual && + test_cmp expected actual +' + +test_expect_success 'width = 1' ' + git column --mode=column --width=1 <lista >actual && + test_cmp expected actual +' + +COLUMNS=20 +export COLUMNS + +test_expect_success '20 columns' ' + cat >expected <<\EOF && +one seven +two eight +three nine +four ten +five eleven +six +EOF + git column --mode=column <lista >actual && + test_cmp expected actual +' + +test_expect_success '20 columns, nodense' ' + cat >expected <<\EOF && +one seven +two eight +three nine +four ten +five eleven +six +EOF + git column --mode=column,nodense < lista > actual && + test_cmp expected actual +' + +test_expect_success '20 columns, dense' ' + cat >expected <<\EOF && +one five nine +two six ten +three seven eleven +four eight +EOF + git column --mode=column,dense < lista > actual && + test_cmp expected actual +' + +test_expect_success '20 columns, padding 2' ' + cat >expected <<\EOF && +one seven +two eight +three nine +four ten +five eleven +six +EOF + git column --mode=column --padding 2 <lista >actual && + test_cmp expected actual +' + +test_expect_success '20 columns, indented' ' + cat >expected <<\EOF && + one seven + two eight + three nine + four ten + five eleven + six +EOF + git column --mode=column --indent=" " <lista >actual && + test_cmp expected actual +' + +test_expect_success '20 columns, row first' ' + cat >expected <<\EOF && +one two +three four +five six +seven eight +nine ten +eleven +EOF + git column --mode=row <lista >actual && + test_cmp expected actual +' + +test_expect_success '20 columns, row first, nodense' ' + cat >expected <<\EOF && +one two +three four +five six +seven eight +nine ten +eleven +EOF + git column --mode=row,nodense <lista >actual && + test_cmp expected actual +' + +test_expect_success '20 columns, row first, dense' ' + cat >expected <<\EOF && +one two three +four five six +seven eight nine +ten eleven +EOF + git column --mode=row,dense <lista >actual && + test_cmp expected actual +' + +test_done diff --git a/t/t9010-svn-fe.sh b/t/t9010-svn-fe.sh index 6f6175a8f7..b7eed2489f 100755 --- a/t/t9010-svn-fe.sh +++ b/t/t9010-svn-fe.sh @@ -5,8 +5,27 @@ test_description='check svn dumpfile importer' . ./test-lib.sh reinit_git () { + if ! test_declared_prereq PIPE + then + echo >&4 "reinit_git: need to declare PIPE prerequisite" + return 127 + fi rm -fr .git && - git init + rm -f stream backflow && + git init && + mkfifo stream backflow +} + +try_dump () { + input=$1 && + maybe_fail_svnfe=${2:+test_$2} && + maybe_fail_fi=${3:+test_$3} && + + { + $maybe_fail_svnfe test-svn-fe "$input" >stream 3<backflow & + } && + $maybe_fail_fi git fast-import --cat-blob-fd=3 <stream 3>backflow && + wait $! } properties () { @@ -35,21 +54,27 @@ text_no_props () { >empty -test_expect_success 'empty dump' ' +test_expect_success 'setup: have pipes?' ' + rm -f frob && + if mkfifo frob + then + test_set_prereq PIPE + fi +' + +test_expect_success PIPE 'empty dump' ' reinit_git && echo "SVN-fs-dump-format-version: 2" >input && - test-svn-fe input >stream && - git fast-import <stream + try_dump input ' -test_expect_success 'v4 dumps not supported' ' +test_expect_success PIPE 'v4 dumps not supported' ' reinit_git && echo "SVN-fs-dump-format-version: 4" >v4.dump && - test_must_fail test-svn-fe v4.dump >stream && - test_cmp empty stream + try_dump v4.dump must_fail ' -test_expect_failure 'empty revision' ' +test_expect_failure PIPE 'empty revision' ' reinit_git && printf "rev <nobody, nobody@local>: %s\n" "" "" >expect && cat >emptyrev.dump <<-\EOF && @@ -64,13 +89,12 @@ test_expect_failure 'empty revision' ' Content-length: 0 EOF - test-svn-fe emptyrev.dump >stream && - git fast-import <stream && + try_dump emptyrev.dump && git log -p --format="rev <%an, %ae>: %s" HEAD >actual && test_cmp expect actual ' -test_expect_success 'empty properties' ' +test_expect_success PIPE 'empty properties' ' reinit_git && printf "rev <nobody, nobody@local>: %s\n" "" "" >expect && cat >emptyprop.dump <<-\EOF && @@ -88,13 +112,12 @@ test_expect_success 'empty properties' ' PROPS-END EOF - test-svn-fe emptyprop.dump >stream && - git fast-import <stream && + try_dump emptyprop.dump && git log -p --format="rev <%an, %ae>: %s" HEAD >actual && test_cmp expect actual ' -test_expect_success 'author name and commit message' ' +test_expect_success PIPE 'author name and commit message' ' reinit_git && echo "<author@example.com, author@example.com@local>" >expect.author && cat >message <<-\EOF && @@ -121,15 +144,14 @@ test_expect_success 'author name and commit message' ' echo && cat props } >log.dump && - test-svn-fe log.dump >stream && - git fast-import <stream && + try_dump log.dump && git log -p --format="%B" HEAD >actual.log && git log --format="<%an, %ae>" >actual.author && test_cmp message actual.log && test_cmp expect.author actual.author ' -test_expect_success 'unsupported properties are ignored' ' +test_expect_success PIPE 'unsupported properties are ignored' ' reinit_git && echo author >expect && cat >extraprop.dump <<-\EOF && @@ -149,13 +171,12 @@ test_expect_success 'unsupported properties are ignored' ' author PROPS-END EOF - test-svn-fe extraprop.dump >stream && - git fast-import <stream && + try_dump extraprop.dump && git log -p --format=%an HEAD >actual && test_cmp expect actual ' -test_expect_failure 'timestamp and empty file' ' +test_expect_failure PIPE 'timestamp and empty file' ' echo author@example.com >expect.author && echo 1999-01-01 >expect.date && echo file >expect.files && @@ -186,8 +207,7 @@ test_expect_failure 'timestamp and empty file' ' EOF } >emptyfile.dump && - test-svn-fe emptyfile.dump >stream && - git fast-import <stream && + try_dump emptyfile.dump && git log --format=%an HEAD >actual.author && git log --date=short --format=%ad HEAD >actual.date && git ls-tree -r --name-only HEAD >actual.files && @@ -198,7 +218,7 @@ test_expect_failure 'timestamp and empty file' ' test_cmp empty file ' -test_expect_success 'directory with files' ' +test_expect_success PIPE 'directory with files' ' reinit_git && printf "%s\n" directory/file1 directory/file2 >expect.files && echo hi >hi && @@ -242,8 +262,7 @@ test_expect_success 'directory with files' ' EOF text_no_props hi } >directory.dump && - test-svn-fe directory.dump >stream && - git fast-import <stream && + try_dump directory.dump && git ls-tree -r --name-only HEAD >actual.files && git checkout HEAD directory && @@ -252,7 +271,107 @@ test_expect_success 'directory with files' ' test_cmp hi directory/file2 ' -test_expect_success 'node without action' ' +test_expect_success PIPE 'branch name with backslash' ' + reinit_git && + sort <<-\EOF >expect.branch-files && + trunk/file1 + trunk/file2 + "branches/UpdateFOPto094\\/file1" + "branches/UpdateFOPto094\\/file2" + EOF + + echo hi >hi && + echo hello >hello && + { + properties \ + svn:author author@example.com \ + svn:date "1999-02-02T00:01:02.000000Z" \ + svn:log "add directory with some files in it" && + echo PROPS-END + } >props.setup && + { + properties \ + svn:author brancher@example.com \ + svn:date "2007-12-06T21:38:34.000000Z" \ + svn:log "Updating fop to .94 and adjust fo-stylesheets" && + echo PROPS-END + } >props.branch && + { + cat <<-EOF && + SVN-fs-dump-format-version: 3 + + Revision-number: 1 + EOF + echo Prop-content-length: $(wc -c <props.setup) && + echo Content-length: $(wc -c <props.setup) && + echo && + cat props.setup && + cat <<-\EOF && + + Node-path: trunk + Node-kind: dir + Node-action: add + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Node-path: branches + Node-kind: dir + Node-action: add + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Node-path: trunk/file1 + Node-kind: file + Node-action: add + EOF + text_no_props hello && + cat <<-\EOF && + Node-path: trunk/file2 + Node-kind: file + Node-action: add + EOF + text_no_props hi && + cat <<-\EOF && + + Revision-number: 2 + EOF + echo Prop-content-length: $(wc -c <props.branch) && + echo Content-length: $(wc -c <props.branch) && + echo && + cat props.branch && + cat <<-\EOF + + Node-path: branches/UpdateFOPto094\ + Node-kind: dir + Node-action: add + Node-copyfrom-rev: 1 + Node-copyfrom-path: trunk + + Node-kind: dir + Node-action: add + Prop-content-length: 34 + Content-length: 34 + + K 13 + svn:mergeinfo + V 0 + + PROPS-END + EOF + } >branch.dump && + try_dump branch.dump && + + git ls-tree -r --name-only HEAD | + sort >actual.branch-files && + test_cmp expect.branch-files actual.branch-files +' + +test_expect_success PIPE 'node without action' ' + reinit_git && cat >inaction.dump <<-\EOF && SVN-fs-dump-format-version: 3 @@ -269,10 +388,11 @@ test_expect_success 'node without action' ' PROPS-END EOF - test_must_fail test-svn-fe inaction.dump + try_dump inaction.dump must_fail ' -test_expect_success 'action: add node without text' ' +test_expect_success PIPE 'action: add node without text' ' + reinit_git && cat >textless.dump <<-\EOF && SVN-fs-dump-format-version: 3 @@ -290,10 +410,10 @@ test_expect_success 'action: add node without text' ' PROPS-END EOF - test_must_fail test-svn-fe textless.dump + try_dump textless.dump must_fail ' -test_expect_failure 'change file mode but keep old content' ' +test_expect_failure PIPE 'change file mode but keep old content' ' reinit_git && cat >expect <<-\EOF && OBJID @@ -356,8 +476,7 @@ test_expect_failure 'change file mode but keep old content' ' PROPS-END EOF - test-svn-fe filemode.dump >stream && - git fast-import <stream && + try_dump filemode.dump && { git rev-list HEAD | git diff-tree --root --stdin | @@ -370,7 +489,7 @@ test_expect_failure 'change file mode but keep old content' ' test_cmp hello actual.target ' -test_expect_success 'NUL in property value' ' +test_expect_success PIPE 'NUL in property value' ' reinit_git && echo "commit message" >expect.message && { @@ -391,13 +510,12 @@ test_expect_success 'NUL in property value' ' echo && cat props } >nulprop.dump && - test-svn-fe nulprop.dump >stream && - git fast-import <stream && + try_dump nulprop.dump && git diff-tree --always -s --format=%s HEAD >actual.message && test_cmp expect.message actual.message ' -test_expect_success 'NUL in log message, file content, and property name' ' +test_expect_success PIPE 'NUL in log message, file content, and property name' ' # Caveat: svnadmin 1.6.16 (r1073529) truncates at \0 in the # svn:specialQnotreally example. reinit_git && @@ -458,8 +576,7 @@ test_expect_success 'NUL in log message, file content, and property name' ' link hello EOF } >8bitclean.dump && - test-svn-fe 8bitclean.dump >stream && - git fast-import <stream && + try_dump 8bitclean.dump && { git rev-list HEAD | git diff-tree --root --stdin | @@ -478,7 +595,7 @@ test_expect_success 'NUL in log message, file content, and property name' ' test_cmp expect.hello2 actual.hello2 ' -test_expect_success 'change file mode and reiterate content' ' +test_expect_success PIPE 'change file mode and reiterate content' ' reinit_git && cat >expect <<-\EOF && OBJID @@ -490,7 +607,7 @@ test_expect_success 'change file mode and reiterate content' ' EOF echo "link hello" >expect.blob && echo hello >hello && - cat >filemode.dump <<-\EOF && + cat >filemode2.dump <<-\EOF && SVN-fs-dump-format-version: 3 Revision-number: 1 @@ -545,8 +662,7 @@ test_expect_success 'change file mode and reiterate content' ' PROPS-END link hello EOF - test-svn-fe filemode.dump >stream && - git fast-import <stream && + try_dump filemode2.dump && { git rev-list HEAD | git diff-tree --root --stdin | @@ -559,7 +675,8 @@ test_expect_success 'change file mode and reiterate content' ' test_cmp hello actual.target ' -test_expect_success 'deltas not supported' ' +test_expect_success PIPE 'deltas supported' ' + reinit_git && { # (old) h + (inline) ello + (old) \n printf "SVNQ%b%b%s" "Q\003\006\005\004" "\001Q\0204\001\002" "ello" | @@ -619,10 +736,10 @@ test_expect_success 'deltas not supported' ' echo PROPS-END && cat delta } >delta.dump && - test_must_fail test-svn-fe delta.dump + try_dump delta.dump ' -test_expect_success 'property deltas supported' ' +test_expect_success PIPE 'property deltas supported' ' reinit_git && cat >expect <<-\EOF && OBJID @@ -678,8 +795,7 @@ test_expect_success 'property deltas supported' ' PROPS-END EOF } >propdelta.dump && - test-svn-fe propdelta.dump >stream && - git fast-import <stream && + try_dump propdelta.dump && { git rev-list HEAD | git diff-tree --stdin | @@ -688,7 +804,7 @@ test_expect_success 'property deltas supported' ' test_cmp expect actual ' -test_expect_success 'properties on /' ' +test_expect_success PIPE 'properties on /' ' reinit_git && cat <<-\EOF >expect && OBJID @@ -733,8 +849,7 @@ test_expect_success 'properties on /' ' PROPS-END EOF - test-svn-fe changeroot.dump >stream && - git fast-import <stream && + try_dump changeroot.dump && { git rev-list HEAD | git diff-tree --root --always --stdin | @@ -743,7 +858,7 @@ test_expect_success 'properties on /' ' test_cmp expect actual ' -test_expect_success 'deltas for typechange' ' +test_expect_success PIPE 'deltas for typechange' ' reinit_git && cat >expect <<-\EOF && OBJID @@ -819,8 +934,7 @@ test_expect_success 'deltas for typechange' ' PROPS-END link testing 321 EOF - test-svn-fe deleteprop.dump >stream && - git fast-import <stream && + try_dump deleteprop.dump && { git rev-list HEAD | git diff-tree --root --stdin | @@ -829,6 +943,143 @@ test_expect_success 'deltas for typechange' ' test_cmp expect actual ' +test_expect_success PIPE 'deltas need not consume the whole preimage' ' + reinit_git && + cat >expect <<-\EOF && + OBJID + :120000 100644 OBJID OBJID T postimage + OBJID + :100644 120000 OBJID OBJID T postimage + OBJID + :000000 100644 OBJID OBJID A postimage + EOF + echo "first preimage" >expect.1 && + printf target >expect.2 && + printf lnk >expect.3 && + { + printf "SVNQ%b%b%b" "QQ\017\001\017" "\0217" "first preimage\n" | + q_to_nul + } >delta.1 && + { + properties svn:special "*" && + echo PROPS-END + } >symlink.props && + { + printf "SVNQ%b%b%b" "Q\002\013\004\012" "\0201\001\001\0211" "lnk target" | + q_to_nul + } >delta.2 && + { + printf "SVNQ%b%b" "Q\004\003\004Q" "\001Q\002\002" | + q_to_nul + } >delta.3 && + { + cat <<-\EOF && + SVN-fs-dump-format-version: 3 + + Revision-number: 1 + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Node-path: postimage + Node-kind: file + Node-action: add + Text-delta: true + Prop-content-length: 10 + EOF + echo Text-content-length: $(wc -c <delta.1) && + echo Content-length: $((10 + $(wc -c <delta.1))) && + echo && + echo PROPS-END && + cat delta.1 && + cat <<-\EOF && + + Revision-number: 2 + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Node-path: postimage + Node-kind: file + Node-action: change + Text-delta: true + EOF + echo Prop-content-length: $(wc -c <symlink.props) && + echo Text-content-length: $(wc -c <delta.2) && + echo Content-length: $(($(wc -c <symlink.props) + $(wc -c <delta.2))) && + echo && + cat symlink.props && + cat delta.2 && + cat <<-\EOF && + + Revision-number: 3 + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Node-path: postimage + Node-kind: file + Node-action: change + Text-delta: true + Prop-content-length: 10 + EOF + echo Text-content-length: $(wc -c <delta.3) && + echo Content-length: $((10 + $(wc -c <delta.3))) && + echo && + echo PROPS-END && + cat delta.3 && + echo + } >deltapartial.dump && + try_dump deltapartial.dump && + { + git rev-list HEAD | + git diff-tree --root --stdin | + sed "s/$_x40/OBJID/g" + } >actual && + test_cmp expect actual && + git show HEAD:postimage >actual.3 && + git show HEAD^:postimage >actual.2 && + git show HEAD^^:postimage >actual.1 && + test_cmp expect.1 actual.1 && + test_cmp expect.2 actual.2 && + test_cmp expect.3 actual.3 +' + +test_expect_success PIPE 'no hang for delta trying to read past end of preimage' ' + reinit_git && + { + # COPY 1 + printf "SVNQ%b%b" "Q\001\001\002Q" "\001Q" | + q_to_nul + } >greedy.delta && + { + cat <<-\EOF && + SVN-fs-dump-format-version: 3 + + Revision-number: 1 + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Node-path: bootstrap + Node-kind: file + Node-action: add + Text-delta: true + Prop-content-length: 10 + EOF + echo Text-content-length: $(wc -c <greedy.delta) && + echo Content-length: $((10 + $(wc -c <greedy.delta))) && + echo && + echo PROPS-END && + cat greedy.delta && + echo + } >greedydelta.dump && + try_dump greedydelta.dump must_fail might_fail +' test_expect_success 'set up svn repo' ' svnconf=$PWD/svnconf && @@ -844,12 +1095,12 @@ test_expect_success 'set up svn repo' ' fi ' -test_expect_success SVNREPO 't9135/svn.dump' ' - git init simple-git && - test-svn-fe "$TEST_DIRECTORY/t9135/svn.dump" >simple.fe && +test_expect_success SVNREPO,PIPE 't9135/svn.dump' ' + mkdir -p simple-git && ( cd simple-git && - git fast-import <../simple.fe + reinit_git && + try_dump "$TEST_DIRECTORY/t9135/svn.dump" ) && ( cd simple-svnco && diff --git a/t/t9011-svn-da.sh b/t/t9011-svn-da.sh new file mode 100755 index 0000000000..b38d16f9db --- /dev/null +++ b/t/t9011-svn-da.sh @@ -0,0 +1,248 @@ +#!/bin/sh + +test_description='test parsing of svndiff0 files + +Using the "test-svn-fe -d" helper, check that svn-fe correctly +interprets deltas using various facilities (some from the spec, +some only learned from practice). +' +. ./test-lib.sh + +>empty +printf foo >preimage + +test_expect_success 'reject empty delta' ' + test_must_fail test-svn-fe -d preimage empty 0 +' + +test_expect_success 'delta can empty file' ' + printf "SVNQ" | q_to_nul >clear.delta && + test-svn-fe -d preimage clear.delta 4 >actual && + test_cmp empty actual +' + +test_expect_success 'reject svndiff2' ' + printf "SVN\002" >bad.filetype && + test_must_fail test-svn-fe -d preimage bad.filetype 4 +' + +test_expect_success 'one-window empty delta' ' + printf "SVNQ%s" "QQQQQ" | q_to_nul >clear.onewindow && + test-svn-fe -d preimage clear.onewindow 9 >actual && + test_cmp empty actual +' + +test_expect_success 'reject incomplete window header' ' + printf "SVNQ%s" "QQQQQ" | q_to_nul >clear.onewindow && + printf "SVNQ%s" "QQ" | q_to_nul >clear.partialwindow && + test_must_fail test-svn-fe -d preimage clear.onewindow 6 && + test_must_fail test-svn-fe -d preimage clear.partialwindow 6 +' + +test_expect_success 'reject declared delta longer than actual delta' ' + printf "SVNQ%s" "QQQQQ" | q_to_nul >clear.onewindow && + printf "SVNQ%s" "QQ" | q_to_nul >clear.partialwindow && + test_must_fail test-svn-fe -d preimage clear.onewindow 14 && + test_must_fail test-svn-fe -d preimage clear.partialwindow 9 +' + +test_expect_success 'two-window empty delta' ' + printf "SVNQ%s%s" "QQQQQ" "QQQQQ" | q_to_nul >clear.twowindow && + test-svn-fe -d preimage clear.twowindow 14 >actual && + test_must_fail test-svn-fe -d preimage clear.twowindow 13 && + test_cmp empty actual +' + +test_expect_success 'noisy zeroes' ' + printf "SVNQ%s" \ + "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQ" | + tr R "\200" | + q_to_nul >clear.noisy && + len=$(wc -c <clear.noisy) && + test-svn-fe -d preimage clear.noisy $len && + test_cmp empty actual +' + +test_expect_success 'reject variable-length int in magic' ' + printf "SVNRQ" | tr R "\200" | q_to_nul >clear.badmagic && + test_must_fail test-svn-fe -d preimage clear.badmagic 5 +' + +test_expect_success 'reject truncated integer' ' + printf "SVNQ%s%s" "QQQQQ" "QQQQRRQ" | + tr R "\200" | + q_to_nul >clear.fullint && + printf "SVNQ%s%s" "QQQQQ" "QQQQRR" | + tr RT "\201" | + q_to_nul >clear.partialint && + test_must_fail test-svn-fe -d preimage clear.fullint 15 && + test-svn-fe -d preimage clear.fullint 16 && + test_must_fail test-svn-fe -d preimage clear.partialint 15 +' + +test_expect_success 'nonempty (but unused) preimage view' ' + printf "SVNQ%b" "Q\003QQQ" | q_to_nul >clear.readpreimage && + test-svn-fe -d preimage clear.readpreimage 9 >actual && + test_cmp empty actual +' + +test_expect_success 'preimage view: right endpoint cannot backtrack' ' + printf "SVNQ%b%b" "Q\003QQQ" "Q\002QQQ" | + q_to_nul >clear.backtrack && + test_must_fail test-svn-fe -d preimage clear.backtrack 14 +' + +test_expect_success 'preimage view: left endpoint can advance' ' + printf "SVNQ%b%b" "Q\003QQQ" "\001\002QQQ" | + q_to_nul >clear.preshrink && + printf "SVNQ%b%b" "Q\003QQQ" "\001\001QQQ" | + q_to_nul >clear.shrinkbacktrack && + test-svn-fe -d preimage clear.preshrink 14 >actual && + test_must_fail test-svn-fe -d preimage clear.shrinkbacktrack 14 && + test_cmp empty actual +' + +test_expect_success 'preimage view: offsets compared by value' ' + printf "SVNQ%b%b" "\001\001QQQ" "\0200Q\003QQQ" | + q_to_nul >clear.noisybacktrack && + printf "SVNQ%b%b" "\001\001QQQ" "\0200\001\002QQQ" | + q_to_nul >clear.noisyadvance && + test_must_fail test-svn-fe -d preimage clear.noisybacktrack 15 && + test-svn-fe -d preimage clear.noisyadvance 15 && + test_cmp empty actual +' + +test_expect_success 'preimage view: reject truncated preimage' ' + printf "SVNQ%b" "\010QQQQ" | q_to_nul >clear.lateemptyread && + printf "SVNQ%b" "\010\001QQQ" | q_to_nul >clear.latenonemptyread && + printf "SVNQ%b" "\001\010QQQ" | q_to_nul >clear.longread && + test_must_fail test-svn-fe -d preimage clear.lateemptyread 9 && + test_must_fail test-svn-fe -d preimage clear.latenonemptyread 9 && + test_must_fail test-svn-fe -d preimage clear.longread 9 +' + +test_expect_success 'forbid unconsumed inline data' ' + printf "SVNQ%b%s%b%s" "QQQQ\003" "bar" "QQQQ\001" "x" | + q_to_nul >inline.clear && + test_must_fail test-svn-fe -d preimage inline.clear 18 >actual +' + +test_expect_success 'reject truncated inline data' ' + printf "SVNQ%b%s" "QQQQ\003" "b" | q_to_nul >inline.trunc && + test_must_fail test-svn-fe -d preimage inline.trunc 10 +' + +test_expect_success 'reject truncated inline data (after instruction section)' ' + printf "SVNQ%b%b%s" "QQ\001\001\003" "\0201" "b" | q_to_nul >insn.trunc && + test_must_fail test-svn-fe -d preimage insn.trunc 11 +' + +test_expect_success 'copyfrom_data' ' + echo hi >expect && + printf "SVNQ%b%b%b" "QQ\003\001\003" "\0203" "hi\n" | q_to_nul >copydat && + test-svn-fe -d preimage copydat 13 >actual && + test_cmp expect actual +' + +test_expect_success 'multiple copyfrom_data' ' + echo hi >expect && + printf "SVNQ%b%b%b%b%b" "QQ\003\002\003" "\0201\0202" "hi\n" \ + "QQQ\002Q" "\0200Q" | q_to_nul >copy.multi && + len=$(wc -c <copy.multi) && + test-svn-fe -d preimage copy.multi $len >actual && + test_cmp expect actual +' + +test_expect_success 'incomplete multiple insn' ' + printf "SVNQ%b%b%b" "QQ\003\002\003" "\0203\0200" "hi\n" | + q_to_nul >copy.partial && + len=$(wc -c <copy.partial) && + test_must_fail test-svn-fe -d preimage copy.partial $len +' + +test_expect_success 'catch attempt to copy missing data' ' + printf "SVNQ%b%b%s%b%s" "QQ\002\002\001" "\0201\0201" "X" \ + "QQQQ\002" "YZ" | + q_to_nul >copy.incomplete && + len=$(wc -c <copy.incomplete) && + test_must_fail test-svn-fe -d preimage copy.incomplete $len +' + +test_expect_success 'copyfrom target to repeat data' ' + printf foofoo >expect && + printf "SVNQ%b%b%s" "QQ\006\004\003" "\0203\0100\003Q" "foo" | + q_to_nul >copytarget.repeat && + len=$(wc -c <copytarget.repeat) && + test-svn-fe -d preimage copytarget.repeat $len >actual && + test_cmp expect actual +' + +test_expect_success 'copyfrom target out of order' ' + printf foooof >expect && + printf "SVNQ%b%b%s" \ + "QQ\006\007\003" "\0203\0101\002\0101\001\0101Q" "foo" | + q_to_nul >copytarget.reverse && + len=$(wc -c <copytarget.reverse) && + test-svn-fe -d preimage copytarget.reverse $len >actual && + test_cmp expect actual +' + +test_expect_success 'catch copyfrom future' ' + printf "SVNQ%b%b%s" "QQ\004\004\003" "\0202\0101\002\0201" "XYZ" | + q_to_nul >copytarget.infuture && + len=$(wc -c <copytarget.infuture) && + test_must_fail test-svn-fe -d preimage copytarget.infuture $len +' + +test_expect_success 'copy to sustain' ' + printf XYXYXYXYXYXZ >expect && + printf "SVNQ%b%b%s" "QQ\014\004\003" "\0202\0111Q\0201" "XYZ" | + q_to_nul >copytarget.sustain && + len=$(wc -c <copytarget.sustain) && + test-svn-fe -d preimage copytarget.sustain $len >actual && + test_cmp expect actual +' + +test_expect_success 'catch copy that overflows' ' + printf "SVNQ%b%b%s" "QQ\003\003\001" "\0201\0177Q" X | + q_to_nul >copytarget.overflow && + len=$(wc -c <copytarget.overflow) && + test_must_fail test-svn-fe -d preimage copytarget.overflow $len +' + +test_expect_success 'copyfrom source' ' + printf foo >expect && + printf "SVNQ%b%b" "Q\003\003\002Q" "\003Q" | q_to_nul >copysource.all && + test-svn-fe -d preimage copysource.all 11 >actual && + test_cmp expect actual +' + +test_expect_success 'copy backwards' ' + printf oof >expect && + printf "SVNQ%b%b" "Q\003\003\006Q" "\001\002\001\001\001Q" | + q_to_nul >copysource.rev && + test-svn-fe -d preimage copysource.rev 15 >actual && + test_cmp expect actual +' + +test_expect_success 'offsets are relative to window' ' + printf fo >expect && + printf "SVNQ%b%b%b%b" "Q\003\001\002Q" "\001Q" \ + "\002\001\001\002Q" "\001Q" | + q_to_nul >copysource.two && + test-svn-fe -d preimage copysource.two 18 >actual && + test_cmp expect actual +' + +test_expect_success 'example from notes/svndiff' ' + printf aaaaccccdddddddd >expect && + printf aaaabbbbcccc >source && + printf "SVNQ%b%b%s" "Q\014\020\007\001" \ + "\004Q\004\010\0201\0107\010" d | + q_to_nul >delta.example && + len=$(wc -c <delta.example) && + test-svn-fe -d source delta.example $len >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh index b041516a1d..749b75e8d4 100755 --- a/t/t9100-git-svn-basic.sh +++ b/t/t9100-git-svn-basic.sh @@ -65,7 +65,8 @@ test_expect_success "$name" " git update-index --add dir/file/file && git commit -m '$name' && test_must_fail git svn set-tree --find-copies-harder --rmdir \ - ${remotes_git_svn}..mybranch" || true + ${remotes_git_svn}..mybranch +" name='detect node change from directory to file #1' @@ -79,7 +80,8 @@ test_expect_success "$name" ' git update-index --add -- bar && git commit -m "$name" && test_must_fail git svn set-tree --find-copies-harder --rmdir \ - ${remotes_git_svn}..mybranch2' || true + ${remotes_git_svn}..mybranch2 +' name='detect node change from file to directory #2' @@ -92,9 +94,12 @@ test_expect_success "$name" ' echo yyy > bar/zzz/yyy && git update-index --add bar/zzz/yyy && git commit -m "$name" && - test_must_fail git svn set-tree --find-copies-harder --rmdir \ - ${remotes_git_svn}..mybranch3' || true - + git svn set-tree --find-copies-harder --rmdir \ + ${remotes_git_svn}..mybranch3 && + svn_cmd up "$SVN_TREE" && + test -d "$SVN_TREE"/bar/zzz && + test -e "$SVN_TREE"/bar/zzz/yyy +' name='detect node change from directory to file #2' test_expect_success "$name" ' @@ -107,7 +112,8 @@ test_expect_success "$name" ' git update-index --add -- dir && git commit -m "$name" && test_must_fail git svn set-tree --find-copies-harder --rmdir \ - ${remotes_git_svn}..mybranch4' || true + ${remotes_git_svn}..mybranch4 +' name='remove executable bit from a file' @@ -134,10 +140,10 @@ test_expect_success "$name" ' test -x "$SVN_TREE"/exec.sh' -name='executable file becomes a symlink to bar/zzz (file)' +name='executable file becomes a symlink to file' test_expect_success "$name" ' rm exec.sh && - ln -s bar/zzz exec.sh && + ln -s file exec.sh && git update-index exec.sh && git commit -m "$name" && git svn set-tree --find-copies-harder --rmdir \ @@ -148,19 +154,19 @@ test_expect_success "$name" ' name='new symlink is added to a file that was also just made executable' test_expect_success "$name" ' - chmod +x bar/zzz && - ln -s bar/zzz exec-2.sh && - git update-index --add bar/zzz exec-2.sh && + chmod +x file && + ln -s file exec-2.sh && + git update-index --add file exec-2.sh && git commit -m "$name" && git svn set-tree --find-copies-harder --rmdir \ ${remotes_git_svn}..mybranch5 && svn_cmd up "$SVN_TREE" && - test -x "$SVN_TREE"/bar/zzz && + test -x "$SVN_TREE"/file && test -h "$SVN_TREE"/exec-2.sh' name='modify a symlink to become a file' test_expect_success "$name" ' - echo git help > help || true && + echo git help >help && rm exec-2.sh && cp help exec-2.sh && git update-index exec-2.sh && @@ -195,14 +201,15 @@ name='check imported tree checksums expected tree checksums' rm -f expected if test_have_prereq UTF8 then - echo tree bf522353586b1b883488f2bc73dab0d9f774b9a9 > expected + echo tree dc68b14b733e4ec85b04ab6f712340edc5dc936e > expected fi cat >> expected <<\EOF -tree 83654bb36f019ae4fe77a0171f81075972087624 -tree 031b8d557afc6fea52894eaebb45bec52f1ba6d1 -tree 0b094cbff17168f24c302e297f55bfac65eb8bd3 -tree d667270a1f7b109f5eb3aaea21ede14b56bfdd6e -tree 56a30b966619b863674f5978696f4a3594f2fca9 +tree c3322890dcf74901f32d216f05c5044f670ce632 +tree d3ccd5035feafd17b030c5732e7808cc49122853 +tree d03e1630363d4881e68929d532746b20b0986b83 +tree 149d63cd5878155c846e8c55d7d8487de283f89e +tree 312b76e4f64ce14893aeac8591eb3960b065e247 +tree 149d63cd5878155c846e8c55d7d8487de283f89e tree d667270a1f7b109f5eb3aaea21ede14b56bfdd6e tree 8f51f74cf0163afc9ad68a4b1537288c4558b5a4 EOF diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh index 289fc313fb..ee73013eed 100755 --- a/t/t9107-git-svn-migrate.sh +++ b/t/t9107-git-svn-migrate.sh @@ -27,15 +27,17 @@ test_expect_success 'setup old-looking metadata' ' head=`git rev-parse --verify refs/heads/git-svn-HEAD^0` test_expect_success 'git-svn-HEAD is a real HEAD' "test -n '$head'" +svnrepo_escaped=`echo $svnrepo | sed 's/ /%20/'` + test_expect_success 'initialize old-style (v0) git svn layout' ' mkdir -p "$GIT_DIR"/git-svn/info "$GIT_DIR"/svn/info && echo "$svnrepo" > "$GIT_DIR"/git-svn/info/url && echo "$svnrepo" > "$GIT_DIR"/svn/info/url && git svn migrate && - ! test -d "$GIT_DIR"/git svn && + ! test -d "$GIT_DIR"/git-svn && git rev-parse --verify refs/${remotes_git_svn}^0 && git rev-parse --verify refs/remotes/svn^0 && - test "$(git config --get svn-remote.svn.url)" = "$svnrepo" && + test "$(git config --get svn-remote.svn.url)" = "$svnrepo_escaped" && test `git config --get svn-remote.svn.fetch` = \ ":refs/${remotes_git_svn}" ' diff --git a/t/t9118-git-svn-funky-branch-names.sh b/t/t9118-git-svn-funky-branch-names.sh index 63fc982c8c..193d3cabdd 100755 --- a/t/t9118-git-svn-funky-branch-names.sh +++ b/t/t9118-git-svn-funky-branch-names.sh @@ -32,6 +32,11 @@ test_expect_success 'setup svnrepo' ' start_httpd ' +# SVN 1.7 will truncate "not-a%40{0]" to just "not-a". +# Look at what SVN wound up naming the branch and use that. +# Be sure to escape the @ if it shows up. +non_reflog=`svn_cmd ls "$svnrepo/pr ject/branches" | grep not-a | sed 's/\///' | sed 's/@/%40/'` + test_expect_success 'test clone with funky branch names' ' git svn clone -s "$svnrepo/pr ject" project && ( @@ -42,7 +47,7 @@ test_expect_success 'test clone with funky branch names' ' git rev-parse "refs/remotes/%2Eleading_dot" && git rev-parse "refs/remotes/trailing_dot%2E" && git rev-parse "refs/remotes/trailing_dotlock%2Elock" && - git rev-parse "refs/remotes/not-a%40{0}reflog" + git rev-parse "refs/remotes/$non_reflog" ) ' diff --git a/t/t9129-git-svn-i18n-commitencoding.sh b/t/t9129-git-svn-i18n-commitencoding.sh index 8cfdfe790f..9a40f1e199 100755 --- a/t/t9129-git-svn-i18n-commitencoding.sh +++ b/t/t9129-git-svn-i18n-commitencoding.sh @@ -29,7 +29,7 @@ fi compare_svn_head_with () { # extract just the log message and strip out committer info. # don't use --limit here since svn 1.1.x doesn't have it, - LC_ALL="$a_utf8_locale" svn log `git svn info --url` | perl -w -e ' + LC_ALL="$a_utf8_locale" svn log `git svn info --url` | "$PERL_PATH" -w -e ' use bytes; $/ = ("-"x72) . "\n"; my @x = <STDIN>; diff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh index d60da63f7a..c17aa3186f 100755 --- a/t/t9137-git-svn-dcommit-clobber-series.sh +++ b/t/t9137-git-svn-dcommit-clobber-series.sh @@ -20,8 +20,8 @@ test_expect_success '(supposedly) non-conflicting change from SVN' ' test x"`sed -n -e 61p < file`" = x61 && svn_cmd co "$svnrepo" tmp && (cd tmp && - perl -i.bak -p -e "s/^58$/5588/" file && - perl -i.bak -p -e "s/^61$/6611/" file && + "$PERL_PATH" -i.bak -p -e "s/^58$/5588/" file && + "$PERL_PATH" -i.bak -p -e "s/^61$/6611/" file && poke file && test x"`sed -n -e 58p < file`" = x5588 && test x"`sed -n -e 61p < file`" = x6611 && @@ -40,8 +40,8 @@ test_expect_success 'some unrelated changes to git' " test_expect_success 'change file but in unrelated area' " test x\"\`sed -n -e 4p < file\`\" = x4 && test x\"\`sed -n -e 7p < file\`\" = x7 && - perl -i.bak -p -e 's/^4\$/4444/' file && - perl -i.bak -p -e 's/^7\$/7777/' file && + "$PERL_PATH" -i.bak -p -e 's/^4\$/4444/' file && + "$PERL_PATH" -i.bak -p -e 's/^7\$/7777/' file && test x\"\`sed -n -e 4p < file\`\" = x4444 && test x\"\`sed -n -e 7p < file\`\" = x7777 && git commit -m '4 => 4444, 7 => 7777' file && diff --git a/t/t9163-git-svn-reset-clears-caches.sh b/t/t9163-git-svn-reset-clears-caches.sh new file mode 100755 index 0000000000..cd4c662ba2 --- /dev/null +++ b/t/t9163-git-svn-reset-clears-caches.sh @@ -0,0 +1,78 @@ +#!/bin/sh +# +# Copyright (c) 2012 Peter Baumann +# + +test_description='git svn reset clears memoized caches' +. ./lib-git-svn.sh + +svn_ver="$(svn --version --quiet)" +case $svn_ver in +0.* | 1.[0-4].*) + skip_all="skipping git-svn test - SVN too old ($svn_ver)" + test_done + ;; +esac + +# ... a - b - m <- trunk +# \ / +# ... c <- branch1 +# +# SVN Commits not interesting for this test are abbreviated with "..." +# +test_expect_success 'initialize source svn repo' ' + svn_cmd mkdir -m "create trunk" "$svnrepo"/trunk && + svn_cmd mkdir -m "create branches" "$svnrepo/branches" && + svn_cmd co "$svnrepo"/trunk "$SVN_TREE" && + ( + cd "$SVN_TREE" && + touch foo && + svn_cmd add foo && + svn_cmd commit -m "a" && + svn_cmd cp -m branch "$svnrepo"/trunk "$svnrepo"/branches/branch1 && + svn_cmd switch "$svnrepo"/branches/branch1 && + touch bar && + svn_cmd add bar && + svn_cmd commit -m b && + svn_cmd switch "$svnrepo"/trunk && + touch baz && + svn_cmd add baz && + svn_cmd commit -m c && + svn_cmd up && + svn_cmd merge "$svnrepo"/branches/branch1 && + svn_cmd commit -m "m" + ) && + rm -rf "$SVN_TREE" +' + +test_expect_success 'fetch to merge-base (a)' ' + git svn init -s "$svnrepo" && + git svn fetch --revision BASE:3 +' + +# git svn rebase looses the merge commit +# +# ... a - b - m <- trunk +# \ +# ... c +# +test_expect_success 'rebase looses SVN merge (m)' ' + git svn rebase && + git svn fetch && + test 1 = $(git cat-file -p master|grep parent|wc -l) +' + +# git svn fetch creates correct history with merge commit +# +# ... a - b - m <- trunk +# \ / +# ... c <- branch1 +# +test_expect_success 'reset and fetch gets the SVN merge (m) correctly' ' + git svn reset -r 3 && + git reset --hard trunk && + git svn fetch && + test 2 = $(git cat-file -p trunk|grep parent|wc -l) +' + +test_done diff --git a/t/t9164-git-svn-dcommit-concrrent.sh b/t/t9164-git-svn-dcommit-concrrent.sh new file mode 100755 index 0000000000..aac2ddadf2 --- /dev/null +++ b/t/t9164-git-svn-dcommit-concrrent.sh @@ -0,0 +1,216 @@ +#!/bin/sh +# +# Copyright (c) 2012 Robert Luberda +# + +test_description='concurrent git svn dcommit' +. ./lib-git-svn.sh + + + +test_expect_success 'setup svn repository' ' + svn_cmd checkout "$svnrepo" work.svn && + ( + cd work.svn && + echo >file && echo > auto_updated_file + svn_cmd add file auto_updated_file && + svn_cmd commit -m "initial commit" + ) && + svn_cmd checkout "$svnrepo" work-auto-commits.svn +' +N=0 +next_N() +{ + N=$(( $N + 1 )) +} + +# Setup SVN repository hooks to emulate SVN failures or concurrent commits +# The function adds +# either pre-commit hook, which causes SVN commit given in second argument +# to fail +# or post-commit hook, which creates a new commit (a new line added to +# auto_updated_file) after given SVN commit +# The first argument contains a type of the hook +# The second argument contains a number (not SVN revision) of commit +# the hook should be applied for (each time the hook is run, the given +# number is decreased by one until it gets 0, in which case the hook +# will execute its real action) +setup_hook() +{ + hook_type="$1" # "pre-commit" or "post-commit" + skip_revs="$2" + [ "$hook_type" = "pre-commit" ] || + [ "$hook_type" = "post-commit" ] || + { echo "ERROR: invalid argument ($hook_type)" \ + "passed to setup_hook" >&2 ; return 1; } + echo "cnt=$skip_revs" > "$hook_type-counter" + rm -f "$rawsvnrepo/hooks/"*-commit # drop previous hooks + hook="$rawsvnrepo/hooks/$hook_type" + cat > "$hook" <<- 'EOF1' + #!/bin/sh + set -e + cd "$1/.." # "$1" is repository location + exec >> svn-hook.log 2>&1 + hook="$(basename "$0")" + echo "*** Executing $hook $@" + set -x + . ./$hook-counter + cnt="$(($cnt - 1))" + echo "cnt=$cnt" > ./$hook-counter + [ "$cnt" = "0" ] || exit 0 +EOF1 + if [ "$hook_type" = "pre-commit" ]; then + echo "echo 'commit disallowed' >&2; exit 1" >> "$hook" + else + echo "PATH=\"$PATH\"; export PATH" >> $hook + echo "svnconf=\"$svnconf\"" >> $hook + cat >> "$hook" <<- 'EOF2' + cd work-auto-commits.svn + svn up --config-dir "$svnconf" + echo "$$" >> auto_updated_file + svn commit --config-dir "$svnconf" \ + -m "auto-committing concurrent change" + exit 0 +EOF2 + fi + chmod 755 "$hook" +} + +check_contents() +{ + gitdir="$1" + (cd ../work.svn && svn_cmd up) && + test_cmp file ../work.svn/file && + test_cmp auto_updated_file ../work.svn/auto_updated_file +} + +test_expect_success 'check if post-commit hook creates a concurrent commit' ' + setup_hook post-commit 1 && + ( + cd work.svn && + cp auto_updated_file au_file_saved && + echo 1 >> file && + svn_cmd commit -m "changing file" && + svn_cmd up && + test_must_fail test_cmp auto_updated_file au_file_saved + ) +' + +test_expect_success 'check if pre-commit hook fails' ' + setup_hook pre-commit 2 && + ( + cd work.svn && + echo 2 >> file && + svn_cmd commit -m "changing file once again" && + echo 3 >> file && + test_must_fail svn_cmd commit -m "this commit should fail" && + svn_cmd revert file + ) +' + +test_expect_success 'dcommit error handling' ' + setup_hook pre-commit 2 && + next_N && git svn clone "$svnrepo" work$N.git && + ( + cd work$N.git && + echo 1 >> file && git commit -am "commit change $N.1" && + echo 2 >> file && git commit -am "commit change $N.2" && + echo 3 >> file && git commit -am "commit change $N.3" && + # should fail to dcommit 2nd and 3rd change + # but still should leave the repository in reasonable state + test_must_fail git svn dcommit && + git update-index --refresh && + git show HEAD~2 | grep -q git-svn-id && + ! git show HEAD~1 | grep -q git-svn-id && + ! git show HEAD | grep -q git-svn-id + ) +' + +test_expect_success 'dcommit concurrent change in non-changed file' ' + setup_hook post-commit 2 && + next_N && git svn clone "$svnrepo" work$N.git && + ( + cd work$N.git && + echo 1 >> file && git commit -am "commit change $N.1" && + echo 2 >> file && git commit -am "commit change $N.2" && + echo 3 >> file && git commit -am "commit change $N.3" && + # should rebase and leave the repository in reasonable state + git svn dcommit && + git update-index --refresh && + check_contents && + git show HEAD~3 | grep -q git-svn-id && + git show HEAD~2 | grep -q git-svn-id && + git show HEAD~1 | grep -q auto-committing && + git show HEAD | grep -q git-svn-id + ) +' + +# An utility function used in the following test +delete_first_line() +{ + file="$1" && + sed 1d < "$file" > "${file}.tmp" && + rm "$file" && + mv "${file}.tmp" "$file" +} + +test_expect_success 'dcommit concurrent non-conflicting change' ' + setup_hook post-commit 2 && + next_N && git svn clone "$svnrepo" work$N.git && + ( + cd work$N.git && + cat file >> auto_updated_file && + git commit -am "commit change $N.1" && + delete_first_line auto_updated_file && + git commit -am "commit change $N.2" && + delete_first_line auto_updated_file && + git commit -am "commit change $N.3" && + # should rebase and leave the repository in reasonable state + git svn dcommit && + git update-index --refresh && + check_contents && + git show HEAD~3 | grep -q git-svn-id && + git show HEAD~2 | grep -q git-svn-id && + git show HEAD~1 | grep -q auto-committing && + git show HEAD | grep -q git-svn-id + ) +' + +test_expect_success 'dcommit --no-rebase concurrent non-conflicting change' ' + setup_hook post-commit 2 && + next_N && git svn clone "$svnrepo" work$N.git && + ( + cd work$N.git && + cat file >> auto_updated_file && + git commit -am "commit change $N.1" && + delete_first_line auto_updated_file && + git commit -am "commit change $N.2" && + delete_first_line auto_updated_file && + git commit -am "commit change $N.3" && + # should fail as rebase is needed + test_must_fail git svn dcommit --no-rebase && + # but should leave HEAD unchanged + git update-index --refresh && + ! git show HEAD~2 | grep -q git-svn-id && + ! git show HEAD~1 | grep -q git-svn-id && + ! git show HEAD | grep -q git-svn-id + ) +' + +test_expect_success 'dcommit fails on concurrent conflicting change' ' + setup_hook post-commit 1 && + next_N && git svn clone "$svnrepo" work$N.git && + ( + cd work$N.git && + echo a >> file && + git commit -am "commit change $N.1" && + echo b >> auto_updated_file && + git commit -am "commit change $N.2" && + echo c >> auto_updated_file && + git commit -am "commit change $N.3" && + test_must_fail git svn dcommit && # rebase should fail + test_must_fail git update-index --refresh + ) +' + +test_done diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 0f5b5e5964..2fcf269469 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -12,7 +12,7 @@ test_description='test git fast-import utility' # This could be written as "head -c $1", but IRIX "head" does not # support the -c option. head_c () { - perl -e ' + "$PERL_PATH" -e ' my $len = $ARGV[1]; while ($len > 0) { my $s; @@ -24,6 +24,13 @@ head_c () { ' - "$1" } +verify_packs () { + for p in .git/objects/pack/*.pack + do + git verify-pack "$@" "$p" || return + done +} + file2_data='file2 second line of EOF' @@ -105,9 +112,10 @@ test_expect_success \ 'A: create pack from stdin' \ 'git fast-import --export-marks=marks.out <input && git whatchanged master' -test_expect_success \ - 'A: verify pack' \ - 'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done' + +test_expect_success 'A: verify pack' ' + verify_packs +' cat >expect <<EOF author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE @@ -252,9 +260,11 @@ test_expect_success \ 'A: verify marks import does not crash' \ 'git fast-import --import-marks=marks.out <input && git whatchanged verify--import-marks' -test_expect_success \ - 'A: verify pack' \ - 'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done' + +test_expect_success 'A: verify pack' ' + verify_packs +' + cat >expect <<EOF :000000 100755 0000000000000000000000000000000000000000 7123f7f44e39be127c5eb701e5968176ee9d78b1 A copy-of-file2 EOF @@ -514,9 +524,11 @@ test_expect_success \ 'C: incremental import create pack from stdin' \ 'git fast-import <input && git whatchanged branch' -test_expect_success \ - 'C: verify pack' \ - 'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done' + +test_expect_success 'C: verify pack' ' + verify_packs +' + test_expect_success \ 'C: validate reuse existing blob' \ 'test $newf = `git rev-parse --verify branch:file2/newf` && @@ -572,9 +584,10 @@ test_expect_success \ 'D: inline data in commit' \ 'git fast-import <input && git whatchanged branch' -test_expect_success \ - 'D: verify pack' \ - 'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done' + +test_expect_success 'D: verify pack' ' + verify_packs +' cat >expect <<EOF :000000 100755 0000000000000000000000000000000000000000 35a59026a33beac1569b1c7f66f3090ce9c09afc A newdir/exec.sh @@ -618,9 +631,10 @@ test_expect_success 'E: rfc2822 date, --date-format=raw' ' test_expect_success \ 'E: rfc2822 date, --date-format=rfc2822' \ 'git fast-import --date-format=rfc2822 <input' -test_expect_success \ - 'E: verify pack' \ - 'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done' + +test_expect_success 'E: verify pack' ' + verify_packs +' cat >expect <<EOF author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> 1170778938 -0500 @@ -669,9 +683,10 @@ test_expect_success \ fi fi ' -test_expect_success \ - 'F: verify pack' \ - 'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done' + +test_expect_success 'F: verify pack' ' + verify_packs +' cat >expect <<EOF tree `git rev-parse branch~1^{tree}` @@ -705,9 +720,11 @@ INPUT_END test_expect_success \ 'G: non-fast-forward update forced' \ 'git fast-import --force <input' -test_expect_success \ - 'G: verify pack' \ - 'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done' + +test_expect_success 'G: verify pack' ' + verify_packs +' + test_expect_success \ 'G: branch changed, but logged' \ 'test $old_branch != `git rev-parse --verify branch^0` && @@ -742,9 +759,10 @@ test_expect_success \ 'H: deletall, add 1' \ 'git fast-import <input && git whatchanged H' -test_expect_success \ - 'H: verify pack' \ - 'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done' + +test_expect_success 'H: verify pack' ' + verify_packs +' cat >expect <<EOF :100755 000000 f1fb5da718392694d0076d677d6d0e364c79b0bc 0000000000000000000000000000000000000000 D file2/newf @@ -1639,7 +1657,7 @@ M 160000 :6 sub INPUT_END test_expect_success \ - 'P: supermodule & submodule mix' \ + 'P: superproject & submodule mix' \ 'git fast-import <input && git checkout subuse1 && rm -rf sub && mkdir sub && (cd sub && @@ -1857,9 +1875,10 @@ test_expect_success \ 'Q: commit notes' \ 'git fast-import <input && git whatchanged notes-test' -test_expect_success \ - 'Q: verify pack' \ - 'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done' + +test_expect_success 'Q: verify pack' ' + verify_packs +' commit1=$(git rev-parse notes-test~2) commit2=$(git rev-parse notes-test^) @@ -2098,7 +2117,7 @@ test_expect_success \ grep :1 git.marks' test_expect_success \ - 'R: export-marks options can be overriden by commandline options' \ + 'R: export-marks options can be overridden by commandline options' \ 'cat input | git fast-import --export-marks=other.marks && grep :1 other.marks' @@ -2616,13 +2635,14 @@ test_expect_success \ 'R: blob bigger than threshold' \ 'test_create_repo R && git --git-dir=R/.git fast-import --big-file-threshold=1 <input' -test_expect_success \ - 'R: verify created pack' \ - ': >verify && - for p in R/.git/objects/pack/*.pack; - do - git verify-pack -v $p >>verify || exit; - done' + +test_expect_success 'R: verify created pack' ' + ( + cd R && + verify_packs -v > ../verify + ) +' + test_expect_success \ 'R: verify written objects' \ 'git --git-dir=R/.git cat-file blob big-file:big1 >actual && @@ -2635,4 +2655,291 @@ test_expect_success \ 'n=$(grep $a verify | wc -l) && test 1 = $n' +### +### series S +### +# +# Make sure missing spaces and EOLs after mark references +# cause errors. +# +# Setup: +# +# 1--2--4 +# \ / +# -3- +# +# commit marks: 301, 302, 303, 304 +# blob marks: 403, 404, resp. +# note mark: 202 +# +# The error message when a space is missing not at the +# end of the line is: +# +# Missing space after .. +# +# or when extra characters come after the mark at the end +# of the line: +# +# Garbage after .. +# +# or when the dataref is neither "inline " or a known SHA1, +# +# Invalid dataref .. +# +test_tick + +cat >input <<INPUT_END +commit refs/heads/S +mark :301 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE +data <<COMMIT +commit 1 +COMMIT +M 100644 inline hello.c +data <<BLOB +blob 1 +BLOB + +commit refs/heads/S +mark :302 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE +data <<COMMIT +commit 2 +COMMIT +from :301 +M 100644 inline hello.c +data <<BLOB +blob 2 +BLOB + +blob +mark :403 +data <<BLOB +blob 3 +BLOB + +blob +mark :202 +data <<BLOB +note 2 +BLOB +INPUT_END + +test_expect_success 'S: initialize for S tests' ' + git fast-import --export-marks=marks <input +' + +# +# filemodify, three datarefs +# +test_expect_success 'S: filemodify with garbage after mark must fail' ' + test_must_fail git fast-import --import-marks=marks <<-EOF 2>err && + commit refs/heads/S + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + commit N + COMMIT + M 100644 :403x hello.c + EOF + cat err && + test_i18ngrep "space after mark" err +' + +# inline is misspelled; fast-import thinks it is some unknown dataref +test_expect_success 'S: filemodify with garbage after inline must fail' ' + test_must_fail git fast-import --import-marks=marks <<-EOF 2>err && + commit refs/heads/S + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + commit N + COMMIT + M 100644 inlineX hello.c + data <<BLOB + inline + BLOB + EOF + cat err && + test_i18ngrep "nvalid dataref" err +' + +test_expect_success 'S: filemodify with garbage after sha1 must fail' ' + sha1=$(grep :403 marks | cut -d\ -f2) && + test_must_fail git fast-import --import-marks=marks <<-EOF 2>err && + commit refs/heads/S + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + commit N + COMMIT + M 100644 ${sha1}x hello.c + EOF + cat err && + test_i18ngrep "space after SHA1" err +' + +# +# notemodify, three ways to say dataref +# +test_expect_success 'S: notemodify with garabge after mark dataref must fail' ' + test_must_fail git fast-import --import-marks=marks <<-EOF 2>err && + commit refs/heads/S + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + commit S note dataref markref + COMMIT + N :202x :302 + EOF + cat err && + test_i18ngrep "space after mark" err +' + +test_expect_success 'S: notemodify with garbage after inline dataref must fail' ' + test_must_fail git fast-import --import-marks=marks <<-EOF 2>err && + commit refs/heads/S + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + commit S note dataref inline + COMMIT + N inlineX :302 + data <<BLOB + note blob + BLOB + EOF + cat err && + test_i18ngrep "nvalid dataref" err +' + +test_expect_success 'S: notemodify with garbage after sha1 dataref must fail' ' + sha1=$(grep :202 marks | cut -d\ -f2) && + test_must_fail git fast-import --import-marks=marks <<-EOF 2>err && + commit refs/heads/S + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + commit S note dataref sha1 + COMMIT + N ${sha1}x :302 + EOF + cat err && + test_i18ngrep "space after SHA1" err +' + +# +# notemodify, mark in committish +# +test_expect_success 'S: notemodify with garbarge after mark committish must fail' ' + test_must_fail git fast-import --import-marks=marks <<-EOF 2>err && + commit refs/heads/Snotes + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + commit S note committish + COMMIT + N :202 :302x + EOF + cat err && + test_i18ngrep "after mark" err +' + +# +# from +# +test_expect_success 'S: from with garbage after mark must fail' ' + # no && + git fast-import --import-marks=marks --export-marks=marks <<-EOF 2>err + commit refs/heads/S2 + mark :303 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + commit 3 + COMMIT + from :301x + M 100644 :403 hello.c + EOF + + ret=$? && + echo returned $ret && + test $ret -ne 0 && # failed, but it created the commit + + # go create the commit, need it for merge test + git fast-import --import-marks=marks --export-marks=marks <<-EOF && + commit refs/heads/S2 + mark :303 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + commit 3 + COMMIT + from :301 + M 100644 :403 hello.c + EOF + + # now evaluate the error + cat err && + test_i18ngrep "after mark" err +' + + +# +# merge +# +test_expect_success 'S: merge with garbage after mark must fail' ' + test_must_fail git fast-import --import-marks=marks <<-EOF 2>err && + commit refs/heads/S + mark :304 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + merge 4 + COMMIT + from :302 + merge :303x + M 100644 :403 hello.c + EOF + cat err && + test_i18ngrep "after mark" err +' + +# +# tag, from markref +# +test_expect_success 'S: tag with garbage after mark must fail' ' + test_must_fail git fast-import --import-marks=marks <<-EOF 2>err && + tag refs/tags/Stag + from :302x + tagger $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<TAG + tag S + TAG + EOF + cat err && + test_i18ngrep "after mark" err +' + +# +# cat-blob markref +# +test_expect_success 'S: cat-blob with garbage after mark must fail' ' + test_must_fail git fast-import --import-marks=marks <<-EOF 2>err && + cat-blob :403x + EOF + cat err && + test_i18ngrep "after mark" err +' + +# +# ls markref +# +test_expect_success 'S: ls with garbage after mark must fail' ' + test_must_fail git fast-import --import-marks=marks <<-EOF 2>err && + ls :302x hello.c + EOF + cat err && + test_i18ngrep "space after mark" err +' + +test_expect_success 'S: ls with garbage after sha1 must fail' ' + sha1=$(grep :302 marks | cut -d\ -f2) && + test_must_fail git fast-import --import-marks=marks <<-EOF 2>err && + ls ${sha1}x hello.c + EOF + cat err && + test_i18ngrep "space after tree-ish" err +' + test_done diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh index 950d0ff498..3e821f958b 100755 --- a/t/t9350-fast-export.sh +++ b/t/t9350-fast-export.sh @@ -86,7 +86,7 @@ test_expect_success 'import/export-marks' ' git checkout -b marks master && git fast-export --export-marks=tmp-marks HEAD && test -s tmp-marks && - test $(wc -l < tmp-marks) -eq 3 && + test_line_count = 3 tmp-marks && test $( git fast-export --import-marks=tmp-marks\ --export-marks=tmp-marks HEAD | @@ -101,7 +101,7 @@ test_expect_success 'import/export-marks' ' grep ^commit\ | wc -l) \ -eq 1 && - test $(wc -l < tmp-marks) -eq 4 + test_line_count = 4 tmp-marks ' @@ -424,13 +424,13 @@ test_expect_success 'fast-export quotes pathnames' ' --cacheinfo 100644 $blob "path with \\backslash" \ --cacheinfo 100644 $blob "path with space" && git commit -m addition && - git ls-files -z -s | perl -0pe "s{\\t}{$&subdir/}" >index && + git ls-files -z -s | "$PERL_PATH" -0pe "s{\\t}{$&subdir/}" >index && git read-tree --empty && git update-index -z --index-info <index && git commit -m rename && git read-tree --empty && git commit -m deletion && - git fast-export HEAD >export.out && + git fast-export -M HEAD >export.out && git rev-list HEAD >expect && git init result && cd result && diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh index 9199550ef4..806623e885 100755 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@ -476,14 +476,14 @@ test_expect_success 'cvs status' ' cd cvswork && GIT_CONFIG="$git_config" cvs update && GIT_CONFIG="$git_config" cvs status | grep "^File: status.file" >../out && - test $(wc -l <../out) = 2 + 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 $(wc -l <../out) = 1 + test_line_count = 1 ../out ' cd "$WORKDIR" @@ -500,8 +500,8 @@ 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 "^master[ ]\+master$" < out && - ! grep -v "^master[ ]\+master$" < out + grep "^master[ ][ ]*master$" <out && + ! grep -v "^master[ ][ ]*master$" <out ' #------------ diff --git a/t/t9501-gitweb-standalone-http-status.sh b/t/t9501-gitweb-standalone-http-status.sh index 31076edc5b..ef86948d21 100755 --- a/t/t9501-gitweb-standalone-http-status.sh +++ b/t/t9501-gitweb-standalone-http-status.sh @@ -12,6 +12,13 @@ code and message.' . ./gitweb-lib.sh +# +# Gitweb only provides the functionality tested by the 'modification times' +# tests if it can access a date parser from one of these modules: +# +perl -MHTTP::Date -e 0 >/dev/null 2>&1 && test_set_prereq DATE_PARSER +perl -MTime::ParseDate -e 0 >/dev/null 2>&1 && test_set_prereq DATE_PARSER + # ---------------------------------------------------------------------- # snapshot settings @@ -92,7 +99,7 @@ test_debug 'cat gitweb.output' test_expect_success 'snapshots: bad tree-ish id (tagged object)' ' echo object > tag-object && git add tag-object && - git commit -m "Object to be tagged" && + test_tick && git commit -m "Object to be tagged" && git tag tagged-object `git hash-object tag-object` && gitweb_run "p=.git;a=snapshot;h=tagged-object;sf=tgz" && grep "400 - Object is not a tree-ish" gitweb.output @@ -112,6 +119,64 @@ test_expect_success 'snapshots: bad object id' ' ' test_debug 'cat gitweb.output' +# ---------------------------------------------------------------------- +# modification times (Last-Modified and If-Modified-Since) + +test_expect_success DATE_PARSER 'modification: feed last-modified' ' + gitweb_run "p=.git;a=atom;h=master" && + grep "Status: 200 OK" gitweb.headers && + grep "Last-modified: Thu, 7 Apr 2005 22:14:13 +0000" gitweb.headers +' +test_debug 'cat gitweb.headers' + +test_expect_success DATE_PARSER 'modification: feed if-modified-since (modified)' ' + export HTTP_IF_MODIFIED_SINCE="Wed, 6 Apr 2005 22:14:13 +0000" && + test_when_finished "unset HTTP_IF_MODIFIED_SINCE" && + gitweb_run "p=.git;a=atom;h=master" && + grep "Status: 200 OK" gitweb.headers +' +test_debug 'cat gitweb.headers' + +test_expect_success DATE_PARSER 'modification: feed if-modified-since (unmodified)' ' + export HTTP_IF_MODIFIED_SINCE="Thu, 7 Apr 2005 22:14:13 +0000" && + test_when_finished "unset HTTP_IF_MODIFIED_SINCE" && + gitweb_run "p=.git;a=atom;h=master" && + grep "Status: 304 Not Modified" gitweb.headers +' +test_debug 'cat gitweb.headers' + +test_expect_success DATE_PARSER 'modification: snapshot last-modified' ' + gitweb_run "p=.git;a=snapshot;h=master;sf=tgz" && + grep "Status: 200 OK" gitweb.headers && + grep "Last-modified: Thu, 7 Apr 2005 22:14:13 +0000" gitweb.headers +' +test_debug 'cat gitweb.headers' + +test_expect_success DATE_PARSER 'modification: snapshot if-modified-since (modified)' ' + export HTTP_IF_MODIFIED_SINCE="Wed, 6 Apr 2005 22:14:13 +0000" && + test_when_finished "unset HTTP_IF_MODIFIED_SINCE" && + gitweb_run "p=.git;a=snapshot;h=master;sf=tgz" && + grep "Status: 200 OK" gitweb.headers +' +test_debug 'cat gitweb.headers' + +test_expect_success DATE_PARSER 'modification: snapshot if-modified-since (unmodified)' ' + export HTTP_IF_MODIFIED_SINCE="Thu, 7 Apr 2005 22:14:13 +0000" && + test_when_finished "unset HTTP_IF_MODIFIED_SINCE" && + gitweb_run "p=.git;a=snapshot;h=master;sf=tgz" && + grep "Status: 304 Not Modified" gitweb.headers +' +test_debug 'cat gitweb.headers' + +test_expect_success DATE_PARSER 'modification: tree snapshot' ' + ID=`git rev-parse --verify HEAD^{tree}` && + export HTTP_IF_MODIFIED_SINCE="Wed, 6 Apr 2005 22:14:13 +0000" && + test_when_finished "unset HTTP_IF_MODIFIED_SINCE" && + gitweb_run "p=.git;a=snapshot;h=$ID;sf=tgz" && + grep "Status: 200 OK" gitweb.headers && + ! grep -i "last-modified" gitweb.headers +' +test_debug 'cat gitweb.headers' # ---------------------------------------------------------------------- # load checking diff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh index 486c8eeb7e..b7ad716b09 100755 --- a/t/t9800-git-p4-basic.sh +++ b/t/t9800-git-p4-basic.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-p4 tests' +test_description='git p4 tests' . ./lib-git-p4.sh @@ -20,8 +20,8 @@ test_expect_success 'add p4 files' ' ) ' -test_expect_success 'basic git-p4 clone' ' - "$GITP4" clone --dest="$git" //depot && +test_expect_success 'basic git p4 clone' ' + git p4 clone --dest="$git" //depot && test_when_finished cleanup_git && ( cd "$git" && @@ -30,8 +30,8 @@ test_expect_success 'basic git-p4 clone' ' ) ' -test_expect_success 'git-p4 clone @all' ' - "$GITP4" clone --dest="$git" //depot@all && +test_expect_success 'git p4 clone @all' ' + git p4 clone --dest="$git" //depot@all && test_when_finished cleanup_git && ( cd "$git" && @@ -40,12 +40,13 @@ test_expect_success 'git-p4 clone @all' ' ) ' -test_expect_success 'git-p4 sync uninitialized repo' ' +test_expect_success 'git p4 sync uninitialized repo' ' test_create_repo "$git" && test_when_finished cleanup_git && ( cd "$git" && - test_must_fail "$GITP4" sync + test_must_fail git p4 sync 2>errs && + test_i18ngrep "Perhaps you never did" errs ) ' @@ -53,13 +54,13 @@ test_expect_success 'git-p4 sync uninitialized repo' ' # Create a git repo by hand. Add a commit so that HEAD is valid. # Test imports a new p4 repository into a new git branch. # -test_expect_success 'git-p4 sync new branch' ' +test_expect_success 'git p4 sync new branch' ' test_create_repo "$git" && test_when_finished cleanup_git && ( cd "$git" && test_commit head && - "$GITP4" sync --branch=refs/remotes/p4/depot //depot@all && + git p4 sync --branch=refs/remotes/p4/depot //depot@all && git log --oneline p4/depot >lines && test_line_count = 2 lines ) @@ -76,7 +77,7 @@ test_expect_success 'clone two dirs' ' p4 add sub2/f2 && p4 submit -d "sub2/f2" ) && - "$GITP4" clone --dest="$git" //depot/sub1 //depot/sub2 && + git p4 clone --dest="$git" //depot/sub1 //depot/sub2 && test_when_finished cleanup_git && ( cd "$git" && @@ -94,7 +95,7 @@ test_expect_success 'clone two dirs, @all' ' p4 add sub1/f3 && p4 submit -d "sub1/f3" ) && - "$GITP4" clone --dest="$git" //depot/sub1@all //depot/sub2@all && + git p4 clone --dest="$git" //depot/sub1@all //depot/sub2@all && test_when_finished cleanup_git && ( cd "$git" && @@ -112,7 +113,7 @@ test_expect_success 'clone two dirs, @all, conflicting files' ' p4 add sub2/f3 && p4 submit -d "sub2/f3" ) && - "$GITP4" clone --dest="$git" //depot/sub1@all //depot/sub2@all && + git p4 clone --dest="$git" //depot/sub1@all //depot/sub2@all && test_when_finished cleanup_git && ( cd "$git" && @@ -126,45 +127,25 @@ test_expect_success 'clone two dirs, @all, conflicting files' ' ' test_expect_success 'exit when p4 fails to produce marshaled output' ' - badp4dir="$TRASH_DIRECTORY/badp4dir" && - mkdir "$badp4dir" && - test_when_finished "rm \"$badp4dir/p4\" && rmdir \"$badp4dir\"" && - cat >"$badp4dir"/p4 <<-EOF && + mkdir badp4dir && + test_when_finished "rm badp4dir/p4 && rmdir badp4dir" && + cat >badp4dir/p4 <<-EOF && #!$SHELL_PATH exit 1 EOF - chmod 755 "$badp4dir"/p4 && - PATH="$badp4dir:$PATH" "$GITP4" clone --dest="$git" //depot >errs 2>&1 ; retval=$? && - test $retval -eq 1 && - test_must_fail grep -q Traceback errs -' - -test_expect_success 'add p4 files with wildcards in the names' ' + chmod 755 badp4dir/p4 && ( - cd "$cli" && - echo file-wild-hash >file-wild#hash && - echo file-wild-star >file-wild\*star && - echo file-wild-at >file-wild@at && - echo file-wild-percent >file-wild%percent && - p4 add -f file-wild* && - p4 submit -d "file wildcards" - ) -' - -test_expect_success 'wildcard files git-p4 clone' ' - "$GITP4" clone --dest="$git" //depot && - test_when_finished cleanup_git && - ( - cd "$git" && - test -f file-wild#hash && - test -f file-wild\*star && - test -f file-wild@at && - test -f file-wild%percent - ) + PATH="$TRASH_DIRECTORY/badp4dir:$PATH" && + export PATH && + test_expect_code 1 git p4 clone --dest="$git" //depot >errs 2>&1 + ) && + cat errs && + ! test_i18ngrep Traceback errs ' test_expect_success 'clone bare' ' - "$GITP4" clone --dest="$git" --bare //depot && + rm -rf "$git" && + git p4 clone --dest="$git" --bare //depot && test_when_finished cleanup_git && ( cd "$git" && @@ -174,138 +155,6 @@ test_expect_success 'clone bare' ' ) ' -p4_add_user() { - name=$1 fullname=$2 && - p4 user -f -i <<-EOF && - User: $name - Email: $name@localhost - FullName: $fullname - EOF - p4 passwd -P secret $name -} - -p4_grant_admin() { - name=$1 && - { - p4 protect -o && - echo " admin user $name * //depot/..." - } | p4 protect -i -} - -p4_check_commit_author() { - file=$1 user=$2 && - p4 changes -m 1 //depot/$file | grep -q $user -} - -make_change_by_user() { - file=$1 name=$2 email=$3 && - echo "username: a change by $name" >>"$file" && - git add "$file" && - git commit --author "$name <$email>" -m "a change by $name" -} - -# Test username support, submitting as user 'alice' -test_expect_success 'preserve users' ' - p4_add_user alice Alice && - p4_add_user bob Bob && - p4_grant_admin alice && - "$GITP4" clone --dest="$git" //depot && - test_when_finished cleanup_git && - ( - cd "$git" && - echo "username: a change by alice" >>file1 && - echo "username: a change by bob" >>file2 && - git commit --author "Alice <alice@localhost>" -m "a change by alice" file1 && - git commit --author "Bob <bob@localhost>" -m "a change by bob" file2 && - git config git-p4.skipSubmitEditCheck true && - P4EDITOR=touch P4USER=alice P4PASSWD=secret "$GITP4" commit --preserve-user && - p4_check_commit_author file1 alice && - p4_check_commit_author file2 bob - ) -' - -# Test username support, submitting as bob, who lacks admin rights. Should -# not submit change to p4 (git diff should show deltas). -test_expect_success 'refuse to preserve users without perms' ' - "$GITP4" clone --dest="$git" //depot && - test_when_finished cleanup_git && - ( - cd "$git" && - git config git-p4.skipSubmitEditCheck true && - echo "username-noperms: a change by alice" >>file1 && - git commit --author "Alice <alice@localhost>" -m "perms: a change by alice" file1 && - P4EDITOR=touch P4USER=bob P4PASSWD=secret && - export P4EDITOR P4USER P4PASSWD && - test_must_fail "$GITP4" commit --preserve-user && - ! git diff --exit-code HEAD..p4/master - ) -' - -# What happens with unknown author? Without allowMissingP4Users it should fail. -test_expect_success 'preserve user where author is unknown to p4' ' - "$GITP4" clone --dest="$git" //depot && - test_when_finished cleanup_git && - ( - cd "$git" && - git config git-p4.skipSubmitEditCheck true && - echo "username-bob: a change by bob" >>file1 && - git commit --author "Bob <bob@localhost>" -m "preserve: a change by bob" file1 && - echo "username-unknown: a change by charlie" >>file1 && - git commit --author "Charlie <charlie@localhost>" -m "preserve: a change by charlie" file1 && - P4EDITOR=touch P4USER=alice P4PASSWD=secret && - export P4EDITOR P4USER P4PASSWD && - test_must_fail "$GITP4" commit --preserve-user && - ! git diff --exit-code HEAD..p4/master && - - echo "$0: repeat with allowMissingP4Users enabled" && - git config git-p4.allowMissingP4Users true && - git config git-p4.preserveUser true && - "$GITP4" commit && - git diff --exit-code HEAD..p4/master && - p4_check_commit_author file1 alice - ) -' - -# If we're *not* using --preserve-user, git-p4 should warn if we're submitting -# changes that are not all ours. -# Test: user in p4 and user unknown to p4. -# Test: warning disabled and user is the same. -test_expect_success 'not preserving user with mixed authorship' ' - "$GITP4" clone --dest="$git" //depot && - test_when_finished cleanup_git && - ( - cd "$git" && - git config git-p4.skipSubmitEditCheck true && - p4_add_user derek Derek && - - make_change_by_user usernamefile3 Derek derek@localhost && - P4EDITOR=cat P4USER=alice P4PASSWD=secret && - export P4EDITOR P4USER P4PASSWD && - "$GITP4" commit |\ - grep "git author derek@localhost does not match" && - - make_change_by_user usernamefile3 Charlie charlie@localhost && - "$GITP4" commit |\ - grep "git author charlie@localhost does not match" && - - make_change_by_user usernamefile3 alice alice@localhost && - "$GITP4" commit |\ - test_must_fail grep "git author.*does not match" && - - git config git-p4.skipUserNameCheck true && - make_change_by_user usernamefile3 Charlie charlie@localhost && - "$GITP4" commit |\ - test_must_fail grep "git author.*does not match" && - - p4_check_commit_author usernamefile3 alice - ) -' - -marshal_dump() { - what=$1 - "$PYTHON_PATH" -c 'import marshal, sys; d = marshal.load(sys.stdin); print d["'$what'"]' -} - # Sleep a bit so that the top-most p4 change did not happen "now". Then # import the repo and make sure that the initial import has the same time # as the top-most change. @@ -313,7 +162,7 @@ test_expect_success 'initial import time from top change time' ' p4change=$(p4 -G changes -m 1 //depot/... | marshal_dump change) && p4time=$(p4 -G changes -m 1 //depot/... | marshal_dump time) && sleep 3 && - "$GITP4" clone --dest="$git" //depot && + git p4 clone --dest="$git" //depot && test_when_finished cleanup_git && ( cd "$git" && @@ -323,146 +172,6 @@ test_expect_success 'initial import time from top change time' ' ) ' -# Rename a file and confirm that rename is not detected in P4. -# Rename the new file again with detectRenames option enabled and confirm that -# this is detected in P4. -# Rename the new file again adding an extra line, configure a big threshold in -# detectRenames and confirm that rename is not detected in P4. -# Repeat, this time with a smaller threshold and confirm that the rename is -# detected in P4. -test_expect_success 'detect renames' ' - "$GITP4" clone --dest="$git" //depot@all && - test_when_finished cleanup_git && - ( - cd "$git" && - git config git-p4.skipSubmitEditCheck true && - - git mv file1 file4 && - git commit -a -m "Rename file1 to file4" && - git diff-tree -r -M HEAD && - "$GITP4" submit && - p4 filelog //depot/file4 && - p4 filelog //depot/file4 | test_must_fail grep -q "branch from" && - - git mv file4 file5 && - git commit -a -m "Rename file4 to file5" && - git diff-tree -r -M HEAD && - git config git-p4.detectRenames true && - "$GITP4" submit && - p4 filelog //depot/file5 && - p4 filelog //depot/file5 | grep -q "branch from //depot/file4" && - - git mv file5 file6 && - echo update >>file6 && - git add file6 && - git commit -a -m "Rename file5 to file6 with changes" && - git diff-tree -r -M HEAD && - level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") && - test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 && - git config git-p4.detectRenames $(($level + 2)) && - "$GITP4" submit && - p4 filelog //depot/file6 && - p4 filelog //depot/file6 | test_must_fail grep -q "branch from" && - - git mv file6 file7 && - echo update >>file7 && - git add file7 && - git commit -a -m "Rename file6 to file7 with changes" && - git diff-tree -r -M HEAD && - level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") && - test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 && - git config git-p4.detectRenames $(($level - 2)) && - "$GITP4" submit && - p4 filelog //depot/file7 && - p4 filelog //depot/file7 | grep -q "branch from //depot/file6" - ) -' - -# Copy a file and confirm that copy is not detected in P4. -# Copy a file with detectCopies option enabled and confirm that copy is not -# detected in P4. -# Modify and copy a file with detectCopies option enabled and confirm that copy -# is detected in P4. -# Copy a file with detectCopies and detectCopiesHarder options enabled and -# confirm that copy is detected in P4. -# Modify and copy a file, configure a bigger threshold in detectCopies and -# confirm that copy is not detected in P4. -# Modify and copy a file, configure a smaller threshold in detectCopies and -# confirm that copy is detected in P4. -test_expect_success 'detect copies' ' - "$GITP4" clone --dest="$git" //depot@all && - test_when_finished cleanup_git && - ( - cd "$git" && - git config git-p4.skipSubmitEditCheck true && - - cp file2 file8 && - git add file8 && - git commit -a -m "Copy file2 to file8" && - git diff-tree -r -C HEAD && - "$GITP4" submit && - p4 filelog //depot/file8 && - p4 filelog //depot/file8 | test_must_fail grep -q "branch from" && - - cp file2 file9 && - git add file9 && - git commit -a -m "Copy file2 to file9" && - git diff-tree -r -C HEAD && - git config git-p4.detectCopies true && - "$GITP4" submit && - p4 filelog //depot/file9 && - p4 filelog //depot/file9 | test_must_fail grep -q "branch from" && - - echo "file2" >>file2 && - cp file2 file10 && - git add file2 file10 && - git commit -a -m "Modify and copy file2 to file10" && - git diff-tree -r -C HEAD && - "$GITP4" submit && - p4 filelog //depot/file10 && - p4 filelog //depot/file10 | grep -q "branch from //depot/file" && - - cp file2 file11 && - git add file11 && - git commit -a -m "Copy file2 to file11" && - git diff-tree -r -C --find-copies-harder HEAD && - src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && - test "$src" = file10 && - git config git-p4.detectCopiesHarder true && - "$GITP4" submit && - p4 filelog //depot/file11 && - p4 filelog //depot/file11 | grep -q "branch from //depot/file" && - - cp file2 file12 && - echo "some text" >>file12 && - git add file12 && - git commit -a -m "Copy file2 to file12 with changes" && - git diff-tree -r -C --find-copies-harder HEAD && - level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") && - test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 && - src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && - test "$src" = file10 && - git config git-p4.detectCopies $(($level + 2)) && - "$GITP4" submit && - p4 filelog //depot/file12 && - p4 filelog //depot/file12 | test_must_fail grep -q "branch from" && - - cp file2 file13 && - echo "different text" >>file13 && - git add file13 && - git commit -a -m "Copy file2 to file13 with changes" && - git diff-tree -r -C --find-copies-harder HEAD && - level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") && - test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 && - src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && - test "$src" = file10 && - git config git-p4.detectCopies $(($level - 2)) && - "$GITP4" submit && - p4 filelog //depot/file13 && - p4 filelog //depot/file13 | grep -q "branch from //depot/file" - ) -' - test_expect_success 'kill p4d' ' kill_p4d ' diff --git a/t/t9801-git-p4-branch.sh b/t/t9801-git-p4-branch.sh index a25f18d36a..99fe16b72d 100755 --- a/t/t9801-git-p4-branch.sh +++ b/t/t9801-git-p4-branch.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-p4 p4 branching tests' +test_description='git p4 tests for p4 branches' . ./lib-git-p4.sh @@ -63,7 +63,7 @@ test_expect_success 'basic p4 branches' ' test_expect_success 'import main, no branch detection' ' test_when_finished cleanup_git && - "$GITP4" clone --dest="$git" //depot/main@all && + git p4 clone --dest="$git" //depot/main@all && ( cd "$git" && git log --oneline --graph --decorate --all && @@ -74,7 +74,7 @@ test_expect_success 'import main, no branch detection' ' test_expect_success 'import branch1, no branch detection' ' test_when_finished cleanup_git && - "$GITP4" clone --dest="$git" //depot/branch1@all && + git p4 clone --dest="$git" //depot/branch1@all && ( cd "$git" && git log --oneline --graph --decorate --all && @@ -85,7 +85,7 @@ test_expect_success 'import branch1, no branch detection' ' test_expect_success 'import branch2, no branch detection' ' test_when_finished cleanup_git && - "$GITP4" clone --dest="$git" //depot/branch2@all && + git p4 clone --dest="$git" //depot/branch2@all && ( cd "$git" && git log --oneline --graph --decorate --all && @@ -96,7 +96,7 @@ test_expect_success 'import branch2, no branch detection' ' test_expect_success 'import depot, no branch detection' ' test_when_finished cleanup_git && - "$GITP4" clone --dest="$git" //depot@all && + git p4 clone --dest="$git" //depot@all && ( cd "$git" && git log --oneline --graph --decorate --all && @@ -107,7 +107,7 @@ test_expect_success 'import depot, no branch detection' ' test_expect_success 'import depot, branch detection' ' test_when_finished cleanup_git && - "$GITP4" clone --dest="$git" --detect-branches //depot@all && + git p4 clone --dest="$git" --detect-branches //depot@all && ( cd "$git" && @@ -132,7 +132,7 @@ test_expect_success 'import depot, branch detection, branchList branch definitio ( cd "$git" && git config git-p4.branchList main:branch1 && - "$GITP4" clone --dest=. --detect-branches //depot@all && + git p4 clone --dest=. --detect-branches //depot@all && git log --oneline --graph --decorate --all && @@ -172,9 +172,9 @@ test_expect_success 'add simple p4 branches' ' echo file1 >file1 && echo file2 >file2 && p4 add file1 file2 && - p4 submit -d "branch1" && + p4 submit -d "Create branch1" && p4 integrate //depot/branch1/... //depot/branch2/... && - p4 submit -d "branch2" && + p4 submit -d "Integrate branch2 from branch1" && echo file3 >file3 && p4 add file3 && p4 submit -d "add file3 in branch1" && @@ -182,50 +182,234 @@ test_expect_success 'add simple p4 branches' ' echo update >>file2 && p4 submit -d "update file2 in branch1" && p4 integrate //depot/branch1/... //depot/branch3/... && - p4 submit -d "branch3" + p4 submit -d "Integrate branch3 from branch1" ) ' # Configure branches through git-config and clone them. # All files are tested to make sure branches were cloned correctly. # Finally, make an update to branch1 on P4 side to check if it is imported -# correctly by git-p4. -test_expect_success 'git-p4 clone simple branches' ' +# correctly by git p4. +test_expect_success 'git p4 clone simple branches' ' test_when_finished cleanup_git && test_create_repo "$git" && ( cd "$git" && git config git-p4.branchList branch1:branch2 && git config --add git-p4.branchList branch1:branch3 && - "$GITP4" clone --dest=. --detect-branches //depot@all && + git p4 clone --dest=. --detect-branches //depot@all && git log --all --graph --decorate --stat && git reset --hard p4/depot/branch1 && test -f file1 && test -f file2 && test -f file3 && - grep -q update file2 && + grep update file2 && git reset --hard p4/depot/branch2 && test -f file1 && test -f file2 && test ! -f file3 && - test_must_fail grep -q update file2 && + ! grep update file2 && git reset --hard p4/depot/branch3 && test -f file1 && test -f file2 && test -f file3 && - grep -q update file2 && + grep update file2 && cd "$cli" && cd branch1 && p4 edit file2 && echo file2_ >>file2 && - p4 submit -d "update file2 in branch3" && + p4 submit -d "update file2 in branch1" && + cd "$git" && + git reset --hard p4/depot/branch1 && + git p4 rebase && + grep file2_ file2 + ) +' + +# Create a complex branch structure in P4 depot to check if they are correctly +# cloned. The branches are created from older changelists to check if git p4 is +# able to correctly detect them. +# The final expected structure is: +# `branch1 +# | `- file1 +# | `- file2 (updated) +# | `- file3 +# `branch2 +# | `- file1 +# | `- file2 +# `branch3 +# | `- file1 +# | `- file2 (updated) +# | `- file3 +# `branch4 +# | `- file1 +# | `- file2 +# `branch5 +# `- file1 +# `- file2 +# `- file3 +test_expect_success 'git p4 add complex branches' ' + ( + cd "$cli" && + changelist=$(p4 changes -m1 //depot/... | cut -d" " -f2) && + changelist=$(($changelist - 5)) && + p4 integrate //depot/branch1/...@$changelist //depot/branch4/... && + p4 submit -d "Integrate branch4 from branch1@${changelist}" && + changelist=$(($changelist + 2)) && + p4 integrate //depot/branch1/...@$changelist //depot/branch5/... && + p4 submit -d "Integrate branch5 from branch1@${changelist}" + ) +' + +# Configure branches through git-config and clone them. git p4 will only be able +# to clone the original structure if it is able to detect the origin changelist +# of each branch. +test_expect_success 'git p4 clone complex branches' ' + test_when_finished cleanup_git && + test_create_repo "$git" && + ( + cd "$git" && + git config git-p4.branchList branch1:branch2 && + git config --add git-p4.branchList branch1:branch3 && + git config --add git-p4.branchList branch1:branch4 && + git config --add git-p4.branchList branch1:branch5 && + git p4 clone --dest=. --detect-branches //depot@all && + git log --all --graph --decorate --stat && + git reset --hard p4/depot/branch1 && + test_path_is_file file1 && + test_path_is_file file2 && + test_path_is_file file3 && + grep update file2 && + git reset --hard p4/depot/branch2 && + test_path_is_file file1 && + test_path_is_file file2 && + test_path_is_missing file3 && + ! grep update file2 && + git reset --hard p4/depot/branch3 && + test_path_is_file file1 && + test_path_is_file file2 && + test_path_is_file file3 && + grep update file2 && + git reset --hard p4/depot/branch4 && + test_path_is_file file1 && + test_path_is_file file2 && + test_path_is_missing file3 && + ! grep update file2 && + git reset --hard p4/depot/branch5 && + test_path_is_file file1 && + test_path_is_file file2 && + test_path_is_file file3 && + ! grep update file2 && + test_path_is_missing .git/git-p4-tmp + ) +' + +# Move branch3/file3 to branch4/file3 in a single changelist +test_expect_success 'git p4 submit to two branches in a single changelist' ' + ( + cd "$cli" && + p4 integrate //depot/branch3/file3 //depot/branch4/file3 && + p4 delete //depot/branch3/file3 && + p4 submit -d "Move branch3/file3 to branch4/file3" + ) +' + +# Confirm that changes to two branches done in a single changelist +# are correctly imported by git p4 +test_expect_success 'git p4 sync changes to two branches in the same changelist' ' + test_when_finished cleanup_git && + test_create_repo "$git" && + ( cd "$git" && + git config git-p4.branchList branch1:branch2 && + git config --add git-p4.branchList branch1:branch3 && + git config --add git-p4.branchList branch1:branch4 && + git config --add git-p4.branchList branch1:branch5 && + git p4 clone --dest=. --detect-branches //depot@all && + git log --all --graph --decorate --stat && git reset --hard p4/depot/branch1 && - "$GITP4" rebase && - grep -q file2_ file2 + test_path_is_file file1 && + test_path_is_file file2 && + test_path_is_file file3 && + grep update file2 && + git reset --hard p4/depot/branch2 && + test_path_is_file file1 && + test_path_is_file file2 && + test_path_is_missing file3 && + ! grep update file2 && + git reset --hard p4/depot/branch3 && + test_path_is_file file1 && + test_path_is_file file2 && + test_path_is_missing file3 && + grep update file2 && + git reset --hard p4/depot/branch4 && + test_path_is_file file1 && + test_path_is_file file2 && + test_path_is_file file3 && + ! grep update file2 && + git reset --hard p4/depot/branch5 && + test_path_is_file file1 && + test_path_is_file file2 && + test_path_is_file file3 && + ! grep update file2 && + test_path_is_missing .git/git-p4-tmp ) ' +# Create a branch by integrating a single file +test_expect_success 'git p4 file subset branch' ' + ( + cd "$cli" && + p4 integrate //depot/branch1/file1 //depot/branch6/file1 && + p4 submit -d "Integrate file1 alone from branch1 to branch6" + ) +' + +# Check if git p4 creates a new branch containing a single file, +# instead of keeping the old files from the original branch +test_expect_failure 'git p4 clone file subset branch' ' + test_when_finished cleanup_git && + test_create_repo "$git" && + ( + cd "$git" && + git config git-p4.branchList branch1:branch2 && + git config --add git-p4.branchList branch1:branch3 && + git config --add git-p4.branchList branch1:branch4 && + git config --add git-p4.branchList branch1:branch5 && + git config --add git-p4.branchList branch1:branch6 && + git p4 clone --dest=. --detect-branches //depot@all && + git log --all --graph --decorate --stat && + git reset --hard p4/depot/branch1 && + test_path_is_file file1 && + test_path_is_file file2 && + test_path_is_file file3 && + grep update file2 && + git reset --hard p4/depot/branch2 && + test_path_is_file file1 && + test_path_is_file file2 && + test_path_is_missing file3 && + ! grep update file2 && + git reset --hard p4/depot/branch3 && + test_path_is_file file1 && + test_path_is_file file2 && + test_path_is_missing file3 && + grep update file2 && + git reset --hard p4/depot/branch4 && + test_path_is_file file1 && + test_path_is_file file2 && + test_path_is_file file3 && + ! grep update file2 && + git reset --hard p4/depot/branch5 && + test_path_is_file file1 && + test_path_is_file file2 && + test_path_is_file file3 && + ! grep update file2 && + git reset --hard p4/depot/branch6 && + test_path_is_file file1 && + test_path_is_missing file2 && + test_path_is_missing file3 + ) +' test_expect_success 'kill p4d' ' kill_p4d ' diff --git a/t/t9802-git-p4-filetype.sh b/t/t9802-git-p4-filetype.sh index 992bb8cf0b..21924dfd7d 100755 --- a/t/t9802-git-p4-filetype.sh +++ b/t/t9802-git-p4-filetype.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-p4 p4 filetype tests' +test_description='git p4 filetype tests' . ./lib-git-p4.sh @@ -37,7 +37,7 @@ test_expect_success 'utf-16 file create' ' test_expect_success 'utf-16 file test' ' test_when_finished cleanup_git && - "$GITP4" clone --dest="$git" //depot@all && + git p4 clone --dest="$git" //depot@all && ( cd "$git" && @@ -84,7 +84,7 @@ test_expect_success 'keyword file test' ' build_smush && test_when_finished rm -f k_smush.py ko_smush.py && test_when_finished cleanup_git && - "$GITP4" clone --dest="$git" //depot@all && + git p4 clone --dest="$git" //depot@all && ( cd "$git" && @@ -94,7 +94,7 @@ test_expect_success 'keyword file test' ' "$PYTHON_PATH" "$TRASH_DIRECTORY/ko_smush.py" <"$cli/k-text-ko" >cli-k-text-ko-smush && test_cmp cli-k-text-ko-smush k-text-ko && - # utf16, even though p4 expands keywords, git-p4 does not + # utf16, even though p4 expands keywords, git p4 does not # try to undo that test_cmp "$cli/k-utf16-k" k-utf16-k && test_cmp "$cli/k-utf16-ko" k-utf16-ko @@ -125,7 +125,7 @@ test_expect_success 'ignore apple' ' p4 submit -d appledouble ) && test_when_finished cleanup_git && - "$GITP4" clone --dest="$git" //depot@all && + git p4 clone --dest="$git" //depot@all && ( cd "$git" && test ! -f double.png diff --git a/t/t9803-git-p4-shell-metachars.sh b/t/t9803-git-p4-shell-metachars.sh index db04375a13..fbacff34fe 100755 --- a/t/t9803-git-p4-shell-metachars.sh +++ b/t/t9803-git-p4-shell-metachars.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-p4 transparency to shell metachars in filenames' +test_description='git p4 transparency to shell metachars in filenames' . ./lib-git-p4.sh @@ -18,7 +18,7 @@ test_expect_success 'init depot' ' ' test_expect_success 'shell metachars in filenames' ' - "$GITP4" clone --dest="$git" //depot && + git p4 clone --dest="$git" //depot && test_when_finished cleanup_git && ( cd "$git" && @@ -28,7 +28,7 @@ test_expect_success 'shell metachars in filenames' ' echo f2 >"file with spaces" && git add "file with spaces" && git commit -m "add files" && - P4EDITOR=touch "$GITP4" submit + P4EDITOR=touch git p4 submit ) && ( cd "$cli" && @@ -39,7 +39,7 @@ test_expect_success 'shell metachars in filenames' ' ' test_expect_success 'deleting with shell metachars' ' - "$GITP4" clone --dest="$git" //depot && + git p4 clone --dest="$git" //depot && test_when_finished cleanup_git && ( cd "$git" && @@ -47,7 +47,7 @@ test_expect_success 'deleting with shell metachars' ' git rm foo\$bar && git rm file\ with\ spaces && git commit -m "remove files" && - P4EDITOR=touch "$GITP4" submit + P4EDITOR=touch git p4 submit ) && ( cd "$cli" && @@ -57,6 +57,54 @@ test_expect_success 'deleting with shell metachars' ' ) ' +# Create a branch with a shell metachar in its name +# +# 1. //depot/main +# 2. //depot/branch$3 + +test_expect_success 'branch with shell char' ' + test_when_finished cleanup_git && + test_create_repo "$git" && + ( + cd "$cli" && + + mkdir -p main && + + echo f1 >main/f1 && + p4 add main/f1 && + p4 submit -d "main/f1" && + + p4 integrate //depot/main/... //depot/branch\$3/... && + p4 submit -d "integrate main to branch\$3" && + + echo f1 >branch\$3/shell_char_branch_file && + p4 add branch\$3/shell_char_branch_file && + p4 submit -d "branch\$3/shell_char_branch_file" && + + p4 branch -i <<-EOF && + Branch: branch\$3 + View: //depot/main/... //depot/branch\$3/... + EOF + + p4 edit main/f1 && + echo "a change" >> main/f1 && + p4 submit -d "a change" main/f1 && + + p4 integrate -b branch\$3 && + p4 resolve -am branch\$3/... && + p4 submit -d "integrate main to branch\$3" && + + cd "$git" && + + git config git-p4.branchList main:branch\$3 && + git p4 clone --dest=. --detect-branches //depot@all && + git log --all --graph --decorate --stat && + git reset --hard p4/depot/branch\$3 && + test -f shell_char_branch_file && + test -f f1 + ) +' + test_expect_success 'kill p4d' ' kill_p4d ' diff --git a/t/t9804-git-p4-label.sh b/t/t9804-git-p4-label.sh new file mode 100755 index 0000000000..e30f80e617 --- /dev/null +++ b/t/t9804-git-p4-label.sh @@ -0,0 +1,115 @@ +#!/bin/sh + +test_description='git p4 label tests' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +# Basic p4 label tests. +# +# Note: can't have more than one label per commit - others +# are silently discarded. +# +test_expect_success 'basic p4 labels' ' + test_when_finished cleanup_git && + ( + cd "$cli" && + mkdir -p main && + + echo f1 >main/f1 && + p4 add main/f1 && + p4 submit -d "main/f1" && + + echo f2 >main/f2 && + p4 add main/f2 && + p4 submit -d "main/f2" && + + echo f3 >main/file_with_\$metachar && + p4 add main/file_with_\$metachar && + p4 submit -d "file with metachar" && + + p4 tag -l tag_f1_only main/f1 && + p4 tag -l tag_with\$_shell_char main/... && + + echo f4 >main/f4 && + p4 add main/f4 && + p4 submit -d "main/f4" && + + p4 label -i <<-EOF && + Label: long_label + Description: + A Label first line + A Label second line + View: //depot/... + EOF + + p4 tag -l long_label ... && + + p4 labels ... && + + git p4 clone --dest="$git" --detect-labels //depot@all && + cd "$git" && + + git tag && + git tag >taglist && + test_line_count = 3 taglist && + + cd main && + git checkout tag_tag_f1_only && + ! test -f f2 && + git checkout tag_tag_with\$_shell_char && + test -f f1 && test -f f2 && test -f file_with_\$metachar && + + git show tag_long_label | grep -q "A Label second line" + ) +' + +# Test some label corner cases: +# +# - two tags on the same file; both should be available +# - a tag that is only on one file; this kind of tag +# cannot be imported (at least not easily). + +test_expect_failure 'two labels on the same changelist' ' + test_when_finished cleanup_git && + ( + cd "$cli" && + mkdir -p main && + + p4 edit main/f1 main/f2 && + echo "hello world" >main/f1 && + echo "not in the tag" >main/f2 && + p4 submit -d "main/f[12]: testing two labels" && + + p4 tag -l tag_f1_1 main/... && + p4 tag -l tag_f1_2 main/... && + + p4 labels ... && + + git p4 clone --dest="$git" --detect-labels //depot@all && + cd "$git" && + + git tag | grep tag_f1 && + git tag | grep -q tag_f1_1 && + git tag | grep -q tag_f1_2 && + + cd main && + + git checkout tag_tag_f1_1 && + ls && + test -f f1 && + + git checkout tag_tag_f1_2 && + ls && + test -f f1 + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9805-git-p4-skip-submit-edit.sh b/t/t9805-git-p4-skip-submit-edit.sh index df929e0555..fb3c8ec12c 100755 --- a/t/t9805-git-p4-skip-submit-edit.sh +++ b/t/t9805-git-p4-skip-submit-edit.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-p4 skipSubmitEdit config variables' +test_description='git p4 skipSubmitEdit config variables' . ./lib-git-p4.sh @@ -19,33 +19,33 @@ test_expect_success 'init depot' ' # this works because EDITOR is set to : test_expect_success 'no config, unedited, say yes' ' - "$GITP4" clone --dest="$git" //depot && + git p4 clone --dest="$git" //depot && test_when_finished cleanup_git && ( cd "$git" && echo line >>file1 && git commit -a -m "change 2" && - echo y | "$GITP4" submit && + echo y | git p4 submit && p4 changes //depot/... >wc && test_line_count = 2 wc ) ' test_expect_success 'no config, unedited, say no' ' - "$GITP4" clone --dest="$git" //depot && + git p4 clone --dest="$git" //depot && test_when_finished cleanup_git && ( cd "$git" && echo line >>file1 && git commit -a -m "change 3 (not really)" && - printf "bad response\nn\n" | "$GITP4" submit && + printf "bad response\nn\n" | git p4 submit && p4 changes //depot/... >wc && test_line_count = 2 wc ) ' test_expect_success 'skipSubmitEdit' ' - "$GITP4" clone --dest="$git" //depot && + git p4 clone --dest="$git" //depot && test_when_finished cleanup_git && ( cd "$git" && @@ -54,21 +54,21 @@ test_expect_success 'skipSubmitEdit' ' git config core.editor /bin/false && echo line >>file1 && git commit -a -m "change 3" && - "$GITP4" submit && + git p4 submit && p4 changes //depot/... >wc && test_line_count = 3 wc ) ' test_expect_success 'skipSubmitEditCheck' ' - "$GITP4" clone --dest="$git" //depot && + git p4 clone --dest="$git" //depot && test_when_finished cleanup_git && ( cd "$git" && git config git-p4.skipSubmitEditCheck true && echo line >>file1 && git commit -a -m "change 4" && - "$GITP4" submit && + git p4 submit && p4 changes //depot/... >wc && test_line_count = 4 wc ) @@ -76,22 +76,21 @@ test_expect_success 'skipSubmitEditCheck' ' # check the normal case, where the template really is edited test_expect_success 'no config, edited' ' - "$GITP4" clone --dest="$git" //depot && + git p4 clone --dest="$git" //depot && test_when_finished cleanup_git && - ed="$TRASH_DIRECTORY/ed.sh" && - test_when_finished "rm \"$ed\"" && - cat >"$ed" <<-EOF && + test_when_finished "rm ed.sh" && + cat >ed.sh <<-EOF && #!$SHELL_PATH sleep 1 touch "\$1" exit 0 EOF - chmod 755 "$ed" && + chmod 755 ed.sh && ( cd "$git" && echo line >>file1 && git commit -a -m "change 5" && - EDITOR="\"$ed\"" "$GITP4" submit && + P4EDITOR="" EDITOR="\"$TRASH_DIRECTORY/ed.sh\"" git p4 submit && p4 changes //depot/... >wc && test_line_count = 5 wc ) diff --git a/t/t9806-git-p4-options.sh b/t/t9806-git-p4-options.sh index 1f1952a657..fa40cc8bb5 100755 --- a/t/t9806-git-p4-options.sh +++ b/t/t9806-git-p4-options.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-p4 options' +test_description='git p4 options' . ./lib-git-p4.sh @@ -24,11 +24,11 @@ test_expect_success 'init depot' ' ' test_expect_success 'clone no --git-dir' ' - test_must_fail "$GITP4" clone --git-dir=xx //depot + test_must_fail git p4 clone --git-dir=xx //depot ' test_expect_success 'clone --branch' ' - "$GITP4" clone --branch=refs/remotes/p4/sb --dest="$git" //depot && + git p4 clone --branch=refs/remotes/p4/sb --dest="$git" //depot && test_when_finished cleanup_git && ( cd "$git" && @@ -39,10 +39,9 @@ test_expect_success 'clone --branch' ' ' test_expect_success 'clone --changesfile' ' - cf="$TRASH_DIRECTORY/cf" && - test_when_finished "rm \"$cf\"" && - printf "1\n3\n" >"$cf" && - "$GITP4" clone --changesfile="$cf" --dest="$git" //depot && + test_when_finished "rm cf" && + printf "1\n3\n" >cf && + git p4 clone --changesfile="$TRASH_DIRECTORY/cf" --dest="$git" //depot && test_when_finished cleanup_git && ( cd "$git" && @@ -55,17 +54,16 @@ test_expect_success 'clone --changesfile' ' ' test_expect_success 'clone --changesfile, @all' ' - cf="$TRASH_DIRECTORY/cf" && - test_when_finished "rm \"$cf\"" && - printf "1\n3\n" >"$cf" && - test_must_fail "$GITP4" clone --changesfile="$cf" --dest="$git" //depot@all + test_when_finished "rm cf" && + printf "1\n3\n" >cf && + test_must_fail git p4 clone --changesfile="$TRASH_DIRECTORY/cf" --dest="$git" //depot@all ' # imports both master and p4/master in refs/heads # requires --import-local on sync to find p4 refs/heads # does not update master on sync, just p4/master test_expect_success 'clone/sync --import-local' ' - "$GITP4" clone --import-local --dest="$git" //depot@1,2 && + git p4 clone --import-local --dest="$git" //depot@1,2 && test_when_finished cleanup_git && ( cd "$git" && @@ -73,9 +71,9 @@ test_expect_success 'clone/sync --import-local' ' test_line_count = 2 lines && git log --oneline refs/heads/p4/master >lines && test_line_count = 2 lines && - test_must_fail "$GITP4" sync && + test_must_fail git p4 sync && - "$GITP4" sync --import-local && + git p4 sync --import-local && git log --oneline refs/heads/master >lines && test_line_count = 2 lines && git log --oneline refs/heads/p4/master >lines && @@ -84,7 +82,7 @@ test_expect_success 'clone/sync --import-local' ' ' test_expect_success 'clone --max-changes' ' - "$GITP4" clone --dest="$git" --max-changes 2 //depot@all && + git p4 clone --dest="$git" --max-changes 2 //depot@all && test_when_finished cleanup_git && ( cd "$git" && @@ -101,7 +99,7 @@ test_expect_success 'clone --keep-path' ' p4 add sub/dir/f4 && p4 submit -d "change 4" ) && - "$GITP4" clone --dest="$git" --keep-path //depot/sub/dir@all && + git p4 clone --dest="$git" --keep-path //depot/sub/dir@all && test_when_finished cleanup_git && ( cd "$git" && @@ -109,7 +107,7 @@ test_expect_success 'clone --keep-path' ' test_path_is_file sub/dir/f4 ) && cleanup_git && - "$GITP4" clone --dest="$git" //depot/sub/dir@all && + git p4 clone --dest="$git" //depot/sub/dir@all && ( cd "$git" && test_path_is_file f4 && @@ -126,9 +124,9 @@ test_expect_success 'clone --use-client-spec' ' ( # big usage message exec >/dev/null && - test_must_fail "$GITP4" clone --dest="$git" --use-client-spec + test_must_fail git p4 clone --dest="$git" --use-client-spec ) && - cli2="$TRASH_DIRECTORY/cli2" && + cli2=$(test-path-utils real_path "$TRASH_DIRECTORY/cli2") && mkdir -p "$cli2" && test_when_finished "rmdir \"$cli2\"" && ( @@ -142,24 +140,23 @@ test_expect_success 'clone --use-client-spec' ' ) && P4CLIENT=client2 && test_when_finished cleanup_git && - "$GITP4" clone --dest="$git" --use-client-spec //depot/... && + git p4 clone --dest="$git" --use-client-spec //depot/... && ( cd "$git" && test_path_is_file bus/dir/f4 && - test_path_is_file file1 + test_path_is_missing file1 ) && cleanup_git && # same thing again, this time with variable instead of option - mkdir "$git" && ( cd "$git" && git init && git config git-p4.useClientSpec true && - "$GITP4" sync //depot/... && + git p4 sync //depot/... && git checkout -b master p4/master && test_path_is_file bus/dir/f4 && - test_path_is_file file1 + test_path_is_missing file1 ) ' diff --git a/t/t9807-git-p4-submit.sh b/t/t9807-git-p4-submit.sh index b1f61e3db5..9394fd4e9b 100755 --- a/t/t9807-git-p4-submit.sh +++ b/t/t9807-git-p4-submit.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-p4 submit' +test_description='git p4 submit' . ./lib-git-p4.sh @@ -19,7 +19,7 @@ test_expect_success 'init depot' ' test_expect_success 'submit with no client dir' ' test_when_finished cleanup_git && - "$GITP4" clone --dest="$git" //depot && + git p4 clone --dest="$git" //depot && ( cd "$git" && echo file2 >file2 && @@ -27,24 +27,28 @@ test_expect_success 'submit with no client dir' ' git commit -m "git commit 2" && rm -rf "$cli" && git config git-p4.skipSubmitEdit true && - "$GITP4" submit + git p4 submit + ) && + ( + cd "$cli" && + test_path_is_file file1 && + test_path_is_file file2 ) ' # make two commits, but tell it to apply only from HEAD^ test_expect_success 'submit --origin' ' test_when_finished cleanup_git && - "$GITP4" clone --dest="$git" //depot && + git p4 clone --dest="$git" //depot && ( cd "$git" && test_commit "file3" && test_commit "file4" && git config git-p4.skipSubmitEdit true && - "$GITP4" submit --origin=HEAD^ + git p4 submit --origin=HEAD^ ) && ( cd "$cli" && - p4 sync && test_path_is_missing "file3.t" && test_path_is_file "file4.t" ) @@ -52,39 +56,287 @@ test_expect_success 'submit --origin' ' test_expect_success 'submit with allowSubmit' ' test_when_finished cleanup_git && - "$GITP4" clone --dest="$git" //depot && + git p4 clone --dest="$git" //depot && ( cd "$git" && test_commit "file5" && git config git-p4.skipSubmitEdit true && git config git-p4.allowSubmit "nobranch" && - test_must_fail "$GITP4" submit && + test_must_fail git p4 submit && git config git-p4.allowSubmit "nobranch,master" && - "$GITP4" submit + git p4 submit ) ' test_expect_success 'submit with master branch name from argv' ' test_when_finished cleanup_git && - "$GITP4" clone --dest="$git" //depot && + git p4 clone --dest="$git" //depot && ( cd "$git" && test_commit "file6" && git config git-p4.skipSubmitEdit true && - test_must_fail "$GITP4" submit nobranch && + test_must_fail git p4 submit nobranch && git branch otherbranch && git reset --hard HEAD^ && test_commit "file7" && - "$GITP4" submit otherbranch + git p4 submit otherbranch ) && ( cd "$cli" && - p4 sync && test_path_is_file "file6.t" && test_path_is_missing "file7.t" ) ' +# +# Basic submit tests, the five handled cases +# + +test_expect_success 'submit modify' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + echo line >>file1 && + git add file1 && + git commit -m file1 && + git p4 submit + ) && + ( + cd "$cli" && + test_path_is_file file1 && + test_line_count = 2 file1 + ) +' + +test_expect_success 'submit add' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + echo file13 >file13 && + git add file13 && + git commit -m file13 && + git p4 submit + ) && + ( + cd "$cli" && + test_path_is_file file13 + ) +' + +test_expect_success 'submit delete' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + git rm file4.t && + git commit -m "delete file4.t" && + git p4 submit + ) && + ( + cd "$cli" && + test_path_is_missing file4.t + ) +' + +test_expect_success 'submit copy' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + git config git-p4.detectCopies true && + git config git-p4.detectCopiesHarder true && + cp file5.t file5.ta && + git add file5.ta && + git commit -m "copy to file5.ta" && + git p4 submit + ) && + ( + cd "$cli" && + test_path_is_file file5.ta && + test ! -w file5.ta + ) +' + +test_expect_success 'submit rename' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + git config git-p4.detectRenames true && + git mv file6.t file6.ta && + git commit -m "rename file6.t to file6.ta" && + git p4 submit + ) && + ( + cd "$cli" && + test_path_is_missing file6.t && + test_path_is_file file6.ta && + test ! -w file6.ta + ) +' + +# +# Converting git commit message to p4 change description, including +# parsing out the optional Jobs: line. +# +test_expect_success 'simple one-line description' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo desc2 >desc2 && + git add desc2 && + cat >msg <<-EOF && + One-line description line for desc2. + EOF + git commit -F - <msg && + git config git-p4.skipSubmitEdit true && + git p4 submit && + change=$(p4 -G changes -m 1 //depot/... | \ + marshal_dump change) && + # marshal_dump always adds a newline + p4 -G describe $change | marshal_dump desc | sed \$d >pmsg && + test_cmp msg pmsg + ) +' + +test_expect_success 'description with odd formatting' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo desc3 >desc3 && + git add desc3 && + ( + printf "subject line\n\n\tExtra tab\nline.\n\n" && + printf "Description:\n\tBogus description marker\n\n" && + # git commit eats trailing newlines; only use one + printf "Files:\n\tBogus descs marker\n" + ) >msg && + git commit -F - <msg && + git config git-p4.skipSubmitEdit true && + git p4 submit && + change=$(p4 -G changes -m 1 //depot/... | \ + marshal_dump change) && + # marshal_dump always adds a newline + p4 -G describe $change | marshal_dump desc | sed \$d >pmsg && + test_cmp msg pmsg + ) +' + +make_job() { + name="$1" && + tab="$(printf \\t)" && + p4 job -o | \ + sed -e "/^Job:/s/.*/Job: $name/" \ + -e "/^Description/{ n; s/.*/$tab job text/; }" | \ + p4 job -i +} + +test_expect_success 'description with Jobs section at end' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo desc4 >desc4 && + git add desc4 && + echo 6060842 >jobname && + ( + printf "subject line\n\n\tExtra tab\nline.\n\n" && + printf "Files:\n\tBogus files marker\n" && + printf "Junk: 3164175\n" && + printf "Jobs: $(cat jobname)\n" + ) >msg && + git commit -F - <msg && + git config git-p4.skipSubmitEdit true && + # build a job + make_job $(cat jobname) && + git p4 submit && + change=$(p4 -G changes -m 1 //depot/... | \ + marshal_dump change) && + # marshal_dump always adds a newline + p4 -G describe $change | marshal_dump desc | sed \$d >pmsg && + # make sure Jobs line and all following is gone + sed "/^Jobs:/,\$d" msg >jmsg && + test_cmp jmsg pmsg && + # make sure p4 knows about job + p4 -G describe $change | marshal_dump job0 >job0 && + test_cmp jobname job0 + ) +' + +test_expect_success 'description with Jobs and values on separate lines' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo desc5 >desc5 && + git add desc5 && + echo PROJ-6060842 >jobname1 && + echo PROJ-6060847 >jobname2 && + ( + printf "subject line\n\n\tExtra tab\nline.\n\n" && + printf "Files:\n\tBogus files marker\n" && + printf "Junk: 3164175\n" && + printf "Jobs:\n" && + printf "\t$(cat jobname1)\n" && + printf "\t$(cat jobname2)\n" + ) >msg && + git commit -F - <msg && + git config git-p4.skipSubmitEdit true && + # build two jobs + make_job $(cat jobname1) && + make_job $(cat jobname2) && + git p4 submit && + change=$(p4 -G changes -m 1 //depot/... | \ + marshal_dump change) && + # marshal_dump always adds a newline + p4 -G describe $change | marshal_dump desc | sed \$d >pmsg && + # make sure Jobs line and all following is gone + sed "/^Jobs:/,\$d" msg >jmsg && + test_cmp jmsg pmsg && + # make sure p4 knows about the two jobs + p4 -G describe $change >change && + ( + marshal_dump job0 <change && + marshal_dump job1 <change + ) | sort >jobs && + cat jobname1 jobname2 | sort >expected && + test_cmp expected jobs + ) +' + +test_expect_success 'description with Jobs section and bogus following text' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo desc6 >desc6 && + git add desc6 && + echo 6060843 >jobname && + ( + printf "subject line\n\n\tExtra tab\nline.\n\n" && + printf "Files:\n\tBogus files marker\n" && + printf "Junk: 3164175\n" && + printf "Jobs: $(cat jobname)\n" && + printf "MoreJunk: 3711\n" + ) >msg && + git commit -F - <msg && + git config git-p4.skipSubmitEdit true && + # build a job + make_job $(cat jobname) && + test_must_fail git p4 submit 2>err && + test_i18ngrep "Unknown field name" err + ) +' + test_expect_success 'kill p4d' ' kill_p4d ' diff --git a/t/t9808-git-p4-chdir.sh b/t/t9808-git-p4-chdir.sh index f0022839c7..dc92e60cd6 100755 --- a/t/t9808-git-p4-chdir.sh +++ b/t/t9808-git-p4-chdir.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-p4 relative chdir' +test_description='git p4 relative chdir' . ./lib-git-p4.sh @@ -21,24 +21,24 @@ test_expect_success 'init depot' ' # environment variable is set test_expect_success 'P4CONFIG and absolute dir clone' ' printf "P4PORT=$P4PORT\nP4CLIENT=$P4CLIENT\n" >p4config && - test_when_finished "rm \"$TRASH_DIRECTORY/p4config\"" && + test_when_finished "rm p4config" && test_when_finished cleanup_git && ( P4CONFIG=p4config && export P4CONFIG && sane_unset P4PORT P4CLIENT && - "$GITP4" clone --verbose --dest="$git" //depot + git p4 clone --verbose --dest="$git" //depot ) ' # same thing, but with relative directory name, note missing $ on --dest test_expect_success 'P4CONFIG and relative dir clone' ' printf "P4PORT=$P4PORT\nP4CLIENT=$P4CLIENT\n" >p4config && - test_when_finished "rm \"$TRASH_DIRECTORY/p4config\"" && + test_when_finished "rm p4config" && test_when_finished cleanup_git && ( P4CONFIG=p4config && export P4CONFIG && sane_unset P4PORT P4CLIENT && - "$GITP4" clone --verbose --dest="git" //depot + git p4 clone --verbose --dest="git" //depot ) ' diff --git a/t/t9809-git-p4-client-view.sh b/t/t9809-git-p4-client-view.sh index b0c6d4391d..7d993ef80a 100755 --- a/t/t9809-git-p4-client-view.sh +++ b/t/t9809-git-p4-client-view.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-p4 client view' +test_description='git p4 client view' . ./lib-git-p4.sh @@ -96,19 +96,25 @@ test_expect_success 'init depot' ' test_expect_success 'unsupported view wildcard %%n' ' client_view "//depot/%%%%1/sub/... //client/sub/%%%%1/..." && test_when_finished cleanup_git && - test_must_fail "$GITP4" clone --use-client-spec --dest="$git" //depot + test_must_fail git p4 clone --use-client-spec --dest="$git" //depot ' test_expect_success 'unsupported view wildcard *' ' client_view "//depot/*/bar/... //client/*/bar/..." && test_when_finished cleanup_git && - test_must_fail "$GITP4" clone --use-client-spec --dest="$git" //depot + test_must_fail git p4 clone --use-client-spec --dest="$git" //depot ' -test_expect_success 'wildcard ... only supported at end of spec' ' +test_expect_success 'wildcard ... only supported at end of spec 1' ' client_view "//depot/.../file11 //client/.../file11" && test_when_finished cleanup_git && - test_must_fail "$GITP4" clone --use-client-spec --dest="$git" //depot + test_must_fail git p4 clone --use-client-spec --dest="$git" //depot +' + +test_expect_success 'wildcard ... only supported at end of spec 2' ' + client_view "//depot/.../a/... //client/.../a/..." && + test_when_finished cleanup_git && + test_must_fail git p4 clone --use-client-spec --dest="$git" //depot ' test_expect_success 'basic map' ' @@ -116,7 +122,7 @@ test_expect_success 'basic map' ' files="cli1/file11 cli1/file12" && client_verify $files && test_when_finished cleanup_git && - "$GITP4" clone --use-client-spec --dest="$git" //depot && + git p4 clone --use-client-spec --dest="$git" //depot && git_verify $files ' @@ -124,7 +130,7 @@ test_expect_success 'client view with no mappings' ' client_view && client_verify && test_when_finished cleanup_git && - "$GITP4" clone --use-client-spec --dest="$git" //depot && + git p4 clone --use-client-spec --dest="$git" //depot && git_verify ' @@ -133,7 +139,7 @@ test_expect_success 'single file map' ' files="file11" && client_verify $files && test_when_finished cleanup_git && - "$GITP4" clone --use-client-spec --dest="$git" //depot && + git p4 clone --use-client-spec --dest="$git" //depot && git_verify $files ' @@ -144,7 +150,7 @@ test_expect_success 'later mapping takes precedence (entire repo)' ' cli2/dir2/file21 cli2/dir2/file22" && client_verify $files && test_when_finished cleanup_git && - "$GITP4" clone --use-client-spec --dest="$git" //depot && + git p4 clone --use-client-spec --dest="$git" //depot && git_verify $files ' @@ -154,7 +160,7 @@ test_expect_success 'later mapping takes precedence (partial repo)' ' files="file21 file22" && client_verify $files && test_when_finished cleanup_git && - "$GITP4" clone --use-client-spec --dest="$git" //depot && + git p4 clone --use-client-spec --dest="$git" //depot && git_verify $files ' @@ -170,7 +176,7 @@ test_expect_success 'depot path matching rejected client path' ' files="cli12/file21 cli12/file22" && client_verify $files && test_when_finished cleanup_git && - "$GITP4" clone --use-client-spec --dest="$git" //depot && + git p4 clone --use-client-spec --dest="$git" //depot && git_verify $files ' @@ -181,7 +187,7 @@ test_expect_success 'exclusion wildcard, client rhs same (odd)' ' "-//depot/dir2/... //client/..." && client_verify && test_when_finished cleanup_git && - "$GITP4" clone --use-client-spec --dest="$git" //depot && + git p4 clone --use-client-spec --dest="$git" //depot && git_verify ' @@ -191,7 +197,7 @@ test_expect_success 'exclusion wildcard, client rhs different (normal)' ' files="dir1/file11 dir1/file12" && client_verify $files && test_when_finished cleanup_git && - "$GITP4" clone --use-client-spec --dest="$git" //depot && + git p4 clone --use-client-spec --dest="$git" //depot && git_verify $files ' @@ -201,7 +207,7 @@ test_expect_success 'exclusion single file' ' files="dir1/file11 dir1/file12 dir2/file21" && client_verify $files && test_when_finished cleanup_git && - "$GITP4" clone --use-client-spec --dest="$git" //depot && + git p4 clone --use-client-spec --dest="$git" //depot && git_verify $files ' @@ -211,7 +217,7 @@ test_expect_success 'overlay wildcard' ' files="cli/file11 cli/file12 cli/file21 cli/file22" && client_verify $files && test_when_finished cleanup_git && - "$GITP4" clone --use-client-spec --dest="$git" //depot && + git p4 clone --use-client-spec --dest="$git" //depot && git_verify $files ' @@ -221,7 +227,7 @@ test_expect_success 'overlay single file' ' files="cli/file11 cli/file12 cli/file21" && client_verify $files && test_when_finished cleanup_git && - "$GITP4" clone --use-client-spec --dest="$git" //depot && + git p4 clone --use-client-spec --dest="$git" //depot && git_verify $files ' @@ -232,7 +238,7 @@ test_expect_success 'exclusion with later inclusion' ' files="dir1/file11 dir1/file12 dir2incl/file21 dir2incl/file22" && client_verify $files && test_when_finished cleanup_git && - "$GITP4" clone --use-client-spec --dest="$git" //depot && + git p4 clone --use-client-spec --dest="$git" //depot && git_verify $files ' @@ -240,7 +246,7 @@ test_expect_success 'quotes on rhs only' ' client_view "//depot/dir1/... \"//client/cdir 1/...\"" && client_verify "cdir 1/file11" "cdir 1/file12" && test_when_finished cleanup_git && - "$GITP4" clone --use-client-spec --dest="$git" //depot && + git p4 clone --use-client-spec --dest="$git" //depot && git_verify "cdir 1/file11" "cdir 1/file12" ' @@ -252,7 +258,7 @@ test_expect_success 'quotes on rhs only' ' test_expect_success 'clone --use-client-spec sets useClientSpec' ' client_view "//depot/... //client/..." && test_when_finished cleanup_git && - "$GITP4" clone --use-client-spec --dest="$git" //depot && + git p4 clone --use-client-spec --dest="$git" //depot && ( cd "$git" && git config --bool git-p4.useClientSpec >actual && @@ -267,7 +273,7 @@ test_expect_success 'subdir clone' ' files="dir1/file11 dir1/file12 dir2/file21 dir2/file22" && client_verify $files && test_when_finished cleanup_git && - "$GITP4" clone --use-client-spec --dest="$git" //depot/dir1 && + git p4 clone --use-client-spec --dest="$git" //depot/dir1 && git_verify dir1/file11 dir1/file12 ' @@ -277,14 +283,14 @@ test_expect_success 'subdir clone' ' test_expect_success 'subdir clone, submit modify' ' client_view "//depot/... //client/..." && test_when_finished cleanup_git && - "$GITP4" clone --use-client-spec --dest="$git" //depot/dir1 && + git p4 clone --use-client-spec --dest="$git" //depot/dir1 && ( cd "$git" && git config git-p4.skipSubmitEdit true && echo line >>dir1/file12 && git add dir1/file12 && git commit -m dir1/file12 && - "$GITP4" submit + git p4 submit ) && ( cd "$cli" && @@ -296,14 +302,14 @@ test_expect_success 'subdir clone, submit modify' ' test_expect_success 'subdir clone, submit add' ' client_view "//depot/... //client/..." && test_when_finished cleanup_git && - "$GITP4" clone --use-client-spec --dest="$git" //depot/dir1 && + git p4 clone --use-client-spec --dest="$git" //depot/dir1 && ( cd "$git" && git config git-p4.skipSubmitEdit true && echo file13 >dir1/file13 && git add dir1/file13 && git commit -m dir1/file13 && - "$GITP4" submit + git p4 submit ) && ( cd "$cli" && @@ -314,13 +320,13 @@ test_expect_success 'subdir clone, submit add' ' test_expect_success 'subdir clone, submit delete' ' client_view "//depot/... //client/..." && test_when_finished cleanup_git && - "$GITP4" clone --use-client-spec --dest="$git" //depot/dir1 && + git p4 clone --use-client-spec --dest="$git" //depot/dir1 && ( cd "$git" && git config git-p4.skipSubmitEdit true && git rm dir1/file12 && git commit -m "delete dir1/file12" && - "$GITP4" submit + git p4 submit ) && ( cd "$cli" && @@ -331,7 +337,7 @@ test_expect_success 'subdir clone, submit delete' ' test_expect_success 'subdir clone, submit copy' ' client_view "//depot/... //client/..." && test_when_finished cleanup_git && - "$GITP4" clone --use-client-spec --dest="$git" //depot/dir1 && + git p4 clone --use-client-spec --dest="$git" //depot/dir1 && ( cd "$git" && git config git-p4.skipSubmitEdit true && @@ -339,37 +345,71 @@ test_expect_success 'subdir clone, submit copy' ' cp dir1/file11 dir1/file11a && git add dir1/file11a && git commit -m "copy to dir1/file11a" && - "$GITP4" submit + git p4 submit ) && ( cd "$cli" && - test_path_is_file dir1/file11a + test_path_is_file dir1/file11a && + test ! -w dir1/file11a ) ' test_expect_success 'subdir clone, submit rename' ' client_view "//depot/... //client/..." && test_when_finished cleanup_git && - "$GITP4" clone --use-client-spec --dest="$git" //depot/dir1 && + git p4 clone --use-client-spec --dest="$git" //depot/dir1 && ( cd "$git" && git config git-p4.skipSubmitEdit true && git config git-p4.detectRenames true && git mv dir1/file13 dir1/file13a && git commit -m "rename dir1/file13 to dir1/file13a" && - "$GITP4" submit + git p4 submit ) && ( cd "$cli" && test_path_is_missing dir1/file13 && - test_path_is_file dir1/file13a + test_path_is_file dir1/file13a && + test ! -w dir1/file13a + ) +' + +# see t9800 for the non-client-spec case, and the rest of the wildcard tests +test_expect_success 'wildcard files submit back to p4, client-spec case' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + git p4 clone --use-client-spec --dest="$git" //depot/dir1 && + ( + cd "$git" && + echo git-wild-hash >dir1/git-wild#hash && + echo git-wild-star >dir1/git-wild\*star && + echo git-wild-at >dir1/git-wild@at && + echo git-wild-percent >dir1/git-wild%percent && + git add dir1/git-wild* && + git commit -m "add some wildcard filenames" && + git config git-p4.skipSubmitEditCheck true && + git p4 submit + ) && + ( + cd "$cli" && + test_path_is_file dir1/git-wild#hash && + test_path_is_file dir1/git-wild\*star && + test_path_is_file dir1/git-wild@at && + test_path_is_file dir1/git-wild%percent + ) && + ( + # delete these carefully, cannot just do "p4 delete" + # on files with wildcards; but git-p4 knows how + cd "$git" && + git rm dir1/git-wild* && + git commit -m "clean up the wildcards" && + git p4 submit ) ' test_expect_success 'reinit depot' ' ( cd "$cli" && - p4 sync -f && rm files && p4 delete */* && p4 submit -d "delete all files" && @@ -378,6 +418,393 @@ test_expect_success 'reinit depot' ' ' # +# What happens when two files of the same name are overlayed together? +# The last-listed file should take preference. +# +# //depot +# - dir1 +# - file11 +# - file12 +# - filecollide +# - dir2 +# - file21 +# - file22 +# - filecollide +# +test_expect_success 'overlay collision setup' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + p4 sync && + echo dir1/filecollide >dir1/filecollide && + p4 add dir1/filecollide && + p4 submit -d dir1/filecollide && + echo dir2/filecollide >dir2/filecollide && + p4 add dir2/filecollide && + p4 submit -d dir2/filecollide + ) +' + +test_expect_success 'overlay collision 1 to 2' ' + client_view "//depot/dir1/... //client/..." \ + "+//depot/dir2/... //client/..." && + files="file11 file12 file21 file22 filecollide" && + echo dir2/filecollide >actual && + client_verify $files && + test_cmp actual "$cli"/filecollide && + test_when_finished cleanup_git && + git p4 clone --use-client-spec --dest="$git" //depot && + git_verify $files && + test_cmp actual "$git"/filecollide +' + +test_expect_failure 'overlay collision 2 to 1' ' + client_view "//depot/dir2/... //client/..." \ + "+//depot/dir1/... //client/..." && + files="file11 file12 file21 file22 filecollide" && + echo dir1/filecollide >actual && + client_verify $files && + test_cmp actual "$cli"/filecollide && + test_when_finished cleanup_git && + git p4 clone --use-client-spec --dest="$git" //depot && + git_verify $files && + test_cmp actual "$git"/filecollide +' + +test_expect_success 'overlay collision delete 2' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + p4 sync && + p4 delete dir2/filecollide && + p4 submit -d "remove dir2/filecollide" + ) +' + +# no filecollide, got deleted with dir2 +test_expect_failure 'overlay collision 1 to 2, but 2 deleted' ' + client_view "//depot/dir1/... //client/..." \ + "+//depot/dir2/... //client/..." && + files="file11 file12 file21 file22" && + client_verify $files && + test_when_finished cleanup_git && + git p4 clone --use-client-spec --dest="$git" //depot && + git_verify $files +' + +test_expect_success 'overlay collision update 1' ' + client_view "//depot/dir1/... //client/dir1/..." && + ( + cd "$cli" && + p4 sync && + p4 open dir1/filecollide && + echo dir1/filecollide update >dir1/filecollide && + p4 submit -d "update dir1/filecollide" + ) +' + +# still no filecollide, dir2 still wins with the deletion even though the +# change to dir1 is more recent +test_expect_failure 'overlay collision 1 to 2, but 2 deleted, then 1 updated' ' + client_view "//depot/dir1/... //client/..." \ + "+//depot/dir2/... //client/..." && + files="file11 file12 file21 file22" && + client_verify $files && + test_when_finished cleanup_git && + git p4 clone --use-client-spec --dest="$git" //depot && + git_verify $files +' + +test_expect_success 'overlay collision delete filecollides' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + p4 sync && + p4 delete dir1/filecollide dir2/filecollide && + p4 submit -d "remove filecollides" + ) +' + +# +# Overlays as part of sync, rather than initial checkout: +# 1. add a file in dir1 +# 2. sync to include it +# 3. add same file in dir2 +# 4. sync, make sure content switches as dir2 has priority +# 5. add another file in dir1 +# 6. sync +# 7. add/delete same file in dir2 +# 8. sync, make sure it disappears, again dir2 wins +# 9. cleanup +# +# //depot +# - dir1 +# - file11 +# - file12 +# - colA +# - colB +# - dir2 +# - file21 +# - file22 +# - colA +# - colB +# +test_expect_success 'overlay sync: add colA in dir1' ' + client_view "//depot/dir1/... //client/dir1/..." && + ( + cd "$cli" && + p4 sync && + echo dir1/colA >dir1/colA && + p4 add dir1/colA && + p4 submit -d dir1/colA + ) +' + +test_expect_success 'overlay sync: initial git checkout' ' + client_view "//depot/dir1/... //client/..." \ + "+//depot/dir2/... //client/..." && + files="file11 file12 file21 file22 colA" && + echo dir1/colA >actual && + client_verify $files && + test_cmp actual "$cli"/colA && + git p4 clone --use-client-spec --dest="$git" //depot && + git_verify $files && + test_cmp actual "$git"/colA +' + +test_expect_success 'overlay sync: add colA in dir2' ' + client_view "//depot/dir2/... //client/dir2/..." && + ( + cd "$cli" && + p4 sync && + echo dir2/colA >dir2/colA && + p4 add dir2/colA && + p4 submit -d dir2/colA + ) +' + +test_expect_success 'overlay sync: colA content switch' ' + client_view "//depot/dir1/... //client/..." \ + "+//depot/dir2/... //client/..." && + files="file11 file12 file21 file22 colA" && + echo dir2/colA >actual && + client_verify $files && + test_cmp actual "$cli"/colA && + ( + cd "$git" && + git p4 sync --use-client-spec && + git merge --ff-only p4/master + ) && + git_verify $files && + test_cmp actual "$git"/colA +' + +test_expect_success 'overlay sync: add colB in dir1' ' + client_view "//depot/dir1/... //client/dir1/..." && + ( + cd "$cli" && + p4 sync && + echo dir1/colB >dir1/colB && + p4 add dir1/colB && + p4 submit -d dir1/colB + ) +' + +test_expect_success 'overlay sync: colB appears' ' + client_view "//depot/dir1/... //client/..." \ + "+//depot/dir2/... //client/..." && + files="file11 file12 file21 file22 colA colB" && + echo dir1/colB >actual && + client_verify $files && + test_cmp actual "$cli"/colB && + ( + cd "$git" && + git p4 sync --use-client-spec && + git merge --ff-only p4/master + ) && + git_verify $files && + test_cmp actual "$git"/colB +' + +test_expect_success 'overlay sync: add/delete colB in dir2' ' + client_view "//depot/dir2/... //client/dir2/..." && + ( + cd "$cli" && + p4 sync && + echo dir2/colB >dir2/colB && + p4 add dir2/colB && + p4 submit -d dir2/colB && + p4 delete dir2/colB && + p4 submit -d "delete dir2/colB" + ) +' + +test_expect_success 'overlay sync: colB disappears' ' + client_view "//depot/dir1/... //client/..." \ + "+//depot/dir2/... //client/..." && + files="file11 file12 file21 file22 colA" && + client_verify $files && + test_when_finished cleanup_git && + ( + cd "$git" && + git p4 sync --use-client-spec && + git merge --ff-only p4/master + ) && + git_verify $files +' + +test_expect_success 'overlay sync: cleanup' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + p4 sync && + p4 delete dir1/colA dir2/colA dir1/colB && + p4 submit -d "remove overlay sync files" + ) +' + +# +# Overlay tests again, but swapped so dir1 has priority. +# 1. add a file in dir1 +# 2. sync to include it +# 3. add same file in dir2 +# 4. sync, make sure content does not switch +# 5. add another file in dir1 +# 6. sync +# 7. add/delete same file in dir2 +# 8. sync, make sure it is still there +# 9. cleanup +# +# //depot +# - dir1 +# - file11 +# - file12 +# - colA +# - colB +# - dir2 +# - file21 +# - file22 +# - colA +# - colB +# +test_expect_success 'overlay sync swap: add colA in dir1' ' + client_view "//depot/dir1/... //client/dir1/..." && + ( + cd "$cli" && + p4 sync && + echo dir1/colA >dir1/colA && + p4 add dir1/colA && + p4 submit -d dir1/colA + ) +' + +test_expect_success 'overlay sync swap: initial git checkout' ' + client_view "//depot/dir2/... //client/..." \ + "+//depot/dir1/... //client/..." && + files="file11 file12 file21 file22 colA" && + echo dir1/colA >actual && + client_verify $files && + test_cmp actual "$cli"/colA && + git p4 clone --use-client-spec --dest="$git" //depot && + git_verify $files && + test_cmp actual "$git"/colA +' + +test_expect_success 'overlay sync swap: add colA in dir2' ' + client_view "//depot/dir2/... //client/dir2/..." && + ( + cd "$cli" && + p4 sync && + echo dir2/colA >dir2/colA && + p4 add dir2/colA && + p4 submit -d dir2/colA + ) +' + +test_expect_failure 'overlay sync swap: colA no content switch' ' + client_view "//depot/dir2/... //client/..." \ + "+//depot/dir1/... //client/..." && + files="file11 file12 file21 file22 colA" && + echo dir1/colA >actual && + client_verify $files && + test_cmp actual "$cli"/colA && + ( + cd "$git" && + git p4 sync --use-client-spec && + git merge --ff-only p4/master + ) && + git_verify $files && + test_cmp actual "$git"/colA +' + +test_expect_success 'overlay sync swap: add colB in dir1' ' + client_view "//depot/dir1/... //client/dir1/..." && + ( + cd "$cli" && + p4 sync && + echo dir1/colB >dir1/colB && + p4 add dir1/colB && + p4 submit -d dir1/colB + ) +' + +test_expect_success 'overlay sync swap: colB appears' ' + client_view "//depot/dir2/... //client/..." \ + "+//depot/dir1/... //client/..." && + files="file11 file12 file21 file22 colA colB" && + echo dir1/colB >actual && + client_verify $files && + test_cmp actual "$cli"/colB && + ( + cd "$git" && + git p4 sync --use-client-spec && + git merge --ff-only p4/master + ) && + git_verify $files && + test_cmp actual "$git"/colB +' + +test_expect_success 'overlay sync swap: add/delete colB in dir2' ' + client_view "//depot/dir2/... //client/dir2/..." && + ( + cd "$cli" && + p4 sync && + echo dir2/colB >dir2/colB && + p4 add dir2/colB && + p4 submit -d dir2/colB && + p4 delete dir2/colB && + p4 submit -d "delete dir2/colB" + ) +' + +test_expect_failure 'overlay sync swap: colB no change' ' + client_view "//depot/dir2/... //client/..." \ + "+//depot/dir1/... //client/..." && + files="file11 file12 file21 file22 colA colB" && + echo dir1/colB >actual && + client_verify $files && + test_cmp actual "$cli"/colB && + test_when_finished cleanup_git && + ( + cd "$git" && + git p4 sync --use-client-spec && + git merge --ff-only p4/master + ) && + git_verify $files && + test_cmp actual "$cli"/colB +' + +test_expect_success 'overlay sync swap: cleanup' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + p4 sync && + p4 delete dir1/colA dir2/colA dir1/colB && + p4 submit -d "remove overlay sync files" + ) +' + +# # Rename directories to test quoting in depot-side mappings # //depot # - "dir 1" @@ -408,7 +835,7 @@ test_expect_success 'quotes on lhs only' ' files="cdir1/file11 cdir1/file12" && client_verify $files && test_when_finished cleanup_git && - "$GITP4" clone --use-client-spec --dest="$git" //depot && + git p4 clone --use-client-spec --dest="$git" //depot && client_verify $files ' @@ -416,7 +843,7 @@ test_expect_success 'quotes on both sides' ' client_view "\"//depot/dir 1/...\" \"//client/cdir 1/...\"" && client_verify "cdir 1/file11" "cdir 1/file12" && test_when_finished cleanup_git && - "$GITP4" clone --use-client-spec --dest="$git" //depot && + git p4 clone --use-client-spec --dest="$git" //depot && git_verify "cdir 1/file11" "cdir 1/file12" ' diff --git a/t/t9810-git-p4-rcs.sh b/t/t9810-git-p4-rcs.sh new file mode 100755 index 0000000000..e9daa9c4f6 --- /dev/null +++ b/t/t9810-git-p4-rcs.sh @@ -0,0 +1,388 @@ +#!/bin/sh + +test_description='git p4 rcs keywords' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +# +# Make one file with keyword lines at the top, and +# enough plain text to be able to test modifications +# far away from the keywords. +# +test_expect_success 'init depot' ' + ( + cd "$cli" && + cat <<-\EOF >filek && + $Id$ + /* $Revision$ */ + # $Change$ + line4 + line5 + line6 + line7 + line8 + EOF + cp filek fileko && + sed -i "s/Revision/Revision: do not scrub me/" fileko + cp fileko file_text && + sed -i "s/Id/Id: do not scrub me/" file_text + p4 add -t text+k filek && + p4 submit -d "filek" && + p4 add -t text+ko fileko && + p4 submit -d "fileko" && + p4 add -t text file_text && + p4 submit -d "file_text" + ) +' + +# +# Generate these in a function to make it easy to use single quote marks. +# +write_scrub_scripts () { + cat >"$TRASH_DIRECTORY/scrub_k.py" <<-\EOF && + import re, sys + sys.stdout.write(re.sub(r'(?i)\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\$', r'$\1$', sys.stdin.read())) + EOF + cat >"$TRASH_DIRECTORY/scrub_ko.py" <<-\EOF + import re, sys + sys.stdout.write(re.sub(r'(?i)\$(Id|Header):[^$]*\$', r'$\1$', sys.stdin.read())) + EOF +} + +test_expect_success 'scrub scripts' ' + write_scrub_scripts +' + +# +# Compare $cli/file to its scrubbed version, should be different. +# Compare scrubbed $cli/file to $git/file, should be same. +# +scrub_k_check () { + file="$1" && + scrub="$TRASH_DIRECTORY/$file" && + "$PYTHON_PATH" "$TRASH_DIRECTORY/scrub_k.py" <"$git/$file" >"$scrub" && + ! test_cmp "$cli/$file" "$scrub" && + test_cmp "$git/$file" "$scrub" && + rm "$scrub" +} +scrub_ko_check () { + file="$1" && + scrub="$TRASH_DIRECTORY/$file" && + "$PYTHON_PATH" "$TRASH_DIRECTORY/scrub_ko.py" <"$git/$file" >"$scrub" && + ! test_cmp "$cli/$file" "$scrub" && + test_cmp "$git/$file" "$scrub" && + rm "$scrub" +} + +# +# Modify far away from keywords. If no RCS lines show up +# in the diff, there is no conflict. +# +test_expect_success 'edit far away from RCS lines' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + sed -i "s/^line7/line7 edit/" filek && + git commit -m "filek line7 edit" filek && + git p4 submit && + scrub_k_check filek + ) +' + +# +# Modify near the keywords. This will require RCS scrubbing. +# +test_expect_success 'edit near RCS lines' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + git config git-p4.attemptRCSCleanup true && + sed -i "s/^line4/line4 edit/" filek && + git commit -m "filek line4 edit" filek && + git p4 submit && + scrub_k_check filek + ) +' + +# +# Modify the keywords themselves. This also will require RCS scrubbing. +# +test_expect_success 'edit keyword lines' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + git config git-p4.attemptRCSCleanup true && + sed -i "/Revision/d" filek && + git commit -m "filek remove Revision line" filek && + git p4 submit && + scrub_k_check filek + ) +' + +# +# Scrubbing text+ko files should not alter all keywords, just Id, Header. +# +test_expect_success 'scrub ko files differently' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + git config git-p4.attemptRCSCleanup true && + sed -i "s/^line4/line4 edit/" fileko && + git commit -m "fileko line4 edit" fileko && + git p4 submit && + scrub_ko_check fileko && + ! scrub_k_check fileko + ) +' + +# hack; git p4 submit should do it on its own +test_expect_success 'cleanup after failure' ' + ( + cd "$cli" && + p4 revert ... + ) +' + +# +# Do not scrub anything but +k or +ko files. Sneak a change into +# the cli file so that submit will get a conflict. Make sure that +# scrubbing doesn't make a mess of things. +# +# Assumes that git-p4 exits leaving the p4 file open, with the +# conflict-generating patch unapplied. +# +# This might happen only if the git repo is behind the p4 repo at +# submit time, and there is a conflict. +# +test_expect_success 'do not scrub plain text' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + git config git-p4.attemptRCSCleanup true && + sed -i "s/^line4/line4 edit/" file_text && + git commit -m "file_text line4 edit" file_text && + ( + cd "$cli" && + p4 open file_text && + sed -i "s/^line5/line5 p4 edit/" file_text && + p4 submit -d "file5 p4 edit" + ) && + ! git p4 submit && + ( + # exepct something like: + # file_text - file(s) not opened on this client + # but not copious diff output + cd "$cli" && + p4 diff file_text >wc && + test_line_count = 1 wc + ) + ) +' + +# hack; git p4 submit should do it on its own +test_expect_success 'cleanup after failure 2' ' + ( + cd "$cli" && + p4 revert ... + ) +' + +create_kw_file () { + cat <<\EOF >"$1" +/* A file + Id: $Id$ + Revision: $Revision$ + File: $File$ + */ +int main(int argc, const char **argv) { + return 0; +} +EOF +} + +test_expect_success 'add kwfile' ' + ( + cd "$cli" && + echo file1 >file1 && + p4 add file1 && + p4 submit -d "file 1" && + create_kw_file kwfile1.c && + p4 add kwfile1.c && + p4 submit -d "Add rcw kw file" kwfile1.c + ) +' + +p4_append_to_file () { + f="$1" && + p4 edit -t ktext "$f" && + echo "/* $(date) */" >>"$f" && + p4 submit -d "appending a line in p4" +} + +# Create some files with RCS keywords. If they get modified +# elsewhere then the version number gets bumped which then +# results in a merge conflict if we touch the RCS kw lines, +# even though the change itself would otherwise apply cleanly. +test_expect_success 'cope with rcs keyword expansion damage' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + git config git-p4.attemptRCSCleanup true && + (cd "$cli" && p4_append_to_file kwfile1.c) && + old_lines=$(wc -l <kwfile1.c) && + "$PERL_PATH" -n -i -e "print unless m/Revision:/" kwfile1.c && + new_lines=$(wc -l <kwfile1.c) && + test $new_lines = $(($old_lines - 1)) && + + git add kwfile1.c && + git commit -m "Zap an RCS kw line" && + git p4 submit && + git p4 rebase && + git diff p4/master && + git p4 commit && + echo "try modifying in both" && + cd "$cli" && + p4 edit kwfile1.c && + echo "line from p4" >>kwfile1.c && + p4 submit -d "add a line in p4" kwfile1.c && + cd "$git" && + echo "line from git at the top" | cat - kwfile1.c >kwfile1.c.new && + mv kwfile1.c.new kwfile1.c && + git commit -m "Add line in git at the top" kwfile1.c && + git p4 rebase && + git p4 submit + ) +' + +test_expect_success 'cope with rcs keyword file deletion' ' + test_when_finished cleanup_git && + ( + cd "$cli" && + echo "\$Revision\$" >kwdelfile.c && + p4 add -t ktext kwdelfile.c && + p4 submit -d "Add file to be deleted" && + cat kwdelfile.c && + grep 1 kwdelfile.c + ) && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + grep Revision kwdelfile.c && + git rm -f kwdelfile.c && + git commit -m "Delete a file containing RCS keywords" && + git config git-p4.skipSubmitEdit true && + git config git-p4.attemptRCSCleanup true && + git p4 submit + ) && + ( + cd "$cli" && + p4 sync && + ! test -f kwdelfile.c + ) +' + +# If you add keywords in git of the form $Header$ then everything should +# work fine without any special handling. +test_expect_success 'Add keywords in git which match the default p4 values' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo "NewKW: \$Revision\$" >>kwfile1.c && + git add kwfile1.c && + git commit -m "Adding RCS keywords in git" && + git config git-p4.skipSubmitEdit true && + git config git-p4.attemptRCSCleanup true && + git p4 submit + ) && + ( + cd "$cli" && + p4 sync && + test -f kwfile1.c && + grep "NewKW.*Revision.*[0-9]" kwfile1.c + + ) +' + +# If you add keywords in git of the form $Header:#1$ then things will fail +# unless git-p4 takes steps to scrub the *git* commit. +# +test_expect_failure 'Add keywords in git which do not match the default p4 values' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo "NewKW2: \$Revision:1\$" >>kwfile1.c && + git add kwfile1.c && + git commit -m "Adding RCS keywords in git" && + git config git-p4.skipSubmitEdit true && + git config git-p4.attemptRCSCleanup true && + git p4 submit + ) && + ( + cd "$cli" && + p4 sync && + grep "NewKW2.*Revision.*[0-9]" kwfile1.c + + ) +' + +# Check that the existing merge conflict handling still works. +# Modify kwfile1.c in git, and delete in p4. We should be able +# to skip the git commit. +# +test_expect_success 'merge conflict handling still works' ' + test_when_finished cleanup_git && + ( + cd "$cli" && + echo "Hello:\$Id\$" >merge2.c && + echo "World" >>merge2.c && + p4 add -t ktext merge2.c && + p4 submit -d "add merge test file" + ) && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + sed -e "/Hello/d" merge2.c >merge2.c.tmp && + mv merge2.c.tmp merge2.c && + git add merge2.c && + git commit -m "Modifying merge2.c" + ) && + ( + cd "$cli" && + p4 delete merge2.c && + p4 submit -d "remove merge test file" + ) && + ( + cd "$git" && + test -f merge2.c && + git config git-p4.skipSubmitEdit true && + git config git-p4.attemptRCSCleanup true && + !(echo "s" | git p4 submit) && + git rebase --skip && + ! test -f merge2.c + ) +' + + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9811-git-p4-label-import.sh b/t/t9811-git-p4-label-import.sh new file mode 100755 index 0000000000..095238fffe --- /dev/null +++ b/t/t9811-git-p4-label-import.sh @@ -0,0 +1,222 @@ +#!/bin/sh + +test_description='git p4 label tests' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +# Basic p4 label import tests. +# +test_expect_success 'basic p4 labels' ' + test_when_finished cleanup_git && + ( + cd "$cli" && + mkdir -p main && + + echo f1 >main/f1 && + p4 add main/f1 && + p4 submit -d "main/f1" && + + echo f2 >main/f2 && + p4 add main/f2 && + p4 submit -d "main/f2" && + + echo f3 >main/file_with_\$metachar && + p4 add main/file_with_\$metachar && + p4 submit -d "file with metachar" && + + p4 tag -l TAG_F1_ONLY main/f1 && + p4 tag -l TAG_WITH\$_SHELL_CHAR main/... && + p4 tag -l this_tag_will_be\ skipped main/... && + + echo f4 >main/f4 && + p4 add main/f4 && + p4 submit -d "main/f4" && + + p4 label -i <<-EOF && + Label: TAG_LONG_LABEL + Description: + A Label first line + A Label second line + View: //depot/... + EOF + + p4 tag -l TAG_LONG_LABEL ... && + + p4 labels ... && + + git p4 clone --dest="$git" //depot@all && + cd "$git" && + git config git-p4.labelImportRegexp ".*TAG.*" && + git p4 sync --import-labels --verbose && + + git tag && + git tag >taglist && + test_line_count = 3 taglist && + + cd main && + git checkout TAG_F1_ONLY && + ! test -f f2 && + git checkout TAG_WITH\$_SHELL_CHAR && + test -f f1 && test -f f2 && test -f file_with_\$metachar && + + git show TAG_LONG_LABEL | grep -q "A Label second line" + ) +' +# Test some label corner cases: +# +# - two tags on the same file; both should be available +# - a tag that is only on one file; this kind of tag +# cannot be imported (at least not easily). + +test_expect_success 'two labels on the same changelist' ' + test_when_finished cleanup_git && + ( + cd "$cli" && + mkdir -p main && + + p4 edit main/f1 main/f2 && + echo "hello world" >main/f1 && + echo "not in the tag" >main/f2 && + p4 submit -d "main/f[12]: testing two labels" && + + p4 tag -l TAG_F1_1 main/... && + p4 tag -l TAG_F1_2 main/... && + + p4 labels ... && + + git p4 clone --dest="$git" //depot@all && + cd "$git" && + git p4 sync --import-labels && + + git tag | grep TAG_F1 && + git tag | grep -q TAG_F1_1 && + git tag | grep -q TAG_F1_2 && + + cd main && + + git checkout TAG_F1_1 && + ls && + test -f f1 && + + git checkout TAG_F1_2 && + ls && + test -f f1 + ) +' + +# Export some git tags to p4 +test_expect_success 'export git tags to p4' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot@all && + ( + cd "$git" && + git tag -m "A tag created in git:xyzzy" GIT_TAG_1 && + echo "hello world" >main/f10 && + git add main/f10 && + git commit -m "Adding file for export test" && + git config git-p4.skipSubmitEdit true && + git p4 submit && + git tag -m "Another git tag" GIT_TAG_2 && + git tag LIGHTWEIGHT_TAG && + git p4 rebase --import-labels --verbose && + git p4 submit --export-labels --verbose + ) && + ( + cd "$cli" && + p4 sync ... && + p4 labels ... | grep GIT_TAG_1 && + p4 labels ... | grep GIT_TAG_2 && + p4 labels ... | grep LIGHTWEIGHT_TAG && + p4 label -o GIT_TAG_1 | grep "tag created in git:xyzzy" && + p4 sync ...@GIT_TAG_1 && + ! test -f main/f10 + p4 sync ...@GIT_TAG_2 && + test -f main/f10 + ) +' + +# Export a tag from git where an affected file is deleted later on +# Need to create git tags after rebase, since only then can the +# git commits be mapped to p4 changelists. +test_expect_success 'export git tags to p4 with deletion' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot@all && + ( + cd "$git" && + git p4 sync --import-labels && + echo "deleted file" >main/deleted_file && + git add main/deleted_file && + git commit -m "create deleted file" && + git rm main/deleted_file && + echo "new file" >main/f11 && + git add main/f11 && + git commit -m "delete the deleted file" && + git config git-p4.skipSubmitEdit true && + git p4 submit && + git p4 rebase --import-labels --verbose && + git tag -m "tag on deleted file" GIT_TAG_ON_DELETED HEAD~1 && + git tag -m "tag after deletion" GIT_TAG_AFTER_DELETION HEAD && + git p4 submit --export-labels --verbose + ) && + ( + cd "$cli" && + p4 sync ... && + p4 sync ...@GIT_TAG_ON_DELETED && + test -f main/deleted_file && + p4 sync ...@GIT_TAG_AFTER_DELETION && + ! test -f main/deleted_file && + echo "checking label contents" && + p4 label -o GIT_TAG_ON_DELETED | grep "tag on deleted file" + ) +' + +# Create a tag in git that cannot be exported to p4 +test_expect_success 'tag that cannot be exported' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot@all && + ( + cd "$git" && + git checkout -b a_branch && + echo "hello" >main/f12 && + git add main/f12 && + git commit -m "adding f12" && + git tag -m "tag on a_branch" GIT_TAG_ON_A_BRANCH && + git checkout master && + git p4 submit --export-labels + ) && + ( + cd "$cli" && + p4 sync ... && + !(p4 labels | grep GIT_TAG_ON_A_BRANCH) + ) +' + +test_expect_success 'use git config to enable import/export of tags' ' + git p4 clone --verbose --dest="$git" //depot@all && + ( + cd "$git" && + git config git-p4.exportLabels true && + git config git-p4.importLabels true && + git tag CFG_A_GIT_TAG && + git p4 rebase --verbose && + git p4 submit --verbose && + git tag && + git tag | grep TAG_F1_1 + ) && + ( + cd "$cli" && + p4 labels && + p4 labels | grep CFG_A_GIT_TAG + ) +' + + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9812-git-p4-wildcards.sh b/t/t9812-git-p4-wildcards.sh new file mode 100755 index 0000000000..143d413057 --- /dev/null +++ b/t/t9812-git-p4-wildcards.sh @@ -0,0 +1,147 @@ +#!/bin/sh + +test_description='git p4 wildcards' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'add p4 files with wildcards in the names' ' + ( + cd "$cli" && + printf "file2\nhas\nsome\nrandom\ntext\n" >file2 && + p4 add file2 && + echo file-wild-hash >file-wild#hash && + echo file-wild-star >file-wild\*star && + echo file-wild-at >file-wild@at && + echo file-wild-percent >file-wild%percent && + p4 add -f file-wild* && + p4 submit -d "file wildcards" + ) +' + +test_expect_success 'wildcard files git p4 clone' ' + git p4 clone --dest="$git" //depot && + test_when_finished cleanup_git && + ( + cd "$git" && + test -f file-wild#hash && + test -f file-wild\*star && + test -f file-wild@at && + test -f file-wild%percent + ) +' + +test_expect_success 'wildcard files submit back to p4, add' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo git-wild-hash >git-wild#hash && + echo git-wild-star >git-wild\*star && + echo git-wild-at >git-wild@at && + echo git-wild-percent >git-wild%percent && + git add git-wild* && + git commit -m "add some wildcard filenames" && + git config git-p4.skipSubmitEdit true && + git p4 submit + ) && + ( + cd "$cli" && + test_path_is_file git-wild#hash && + test_path_is_file git-wild\*star && + test_path_is_file git-wild@at && + test_path_is_file git-wild%percent + ) +' + +test_expect_success 'wildcard files submit back to p4, modify' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo new-line >>git-wild#hash && + echo new-line >>git-wild\*star && + echo new-line >>git-wild@at && + echo new-line >>git-wild%percent && + git add git-wild* && + git commit -m "modify the wildcard files" && + git config git-p4.skipSubmitEdit true && + git p4 submit + ) && + ( + cd "$cli" && + test_line_count = 2 git-wild#hash && + test_line_count = 2 git-wild\*star && + test_line_count = 2 git-wild@at && + test_line_count = 2 git-wild%percent + ) +' + +test_expect_success 'wildcard files submit back to p4, copy' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + cp file2 git-wild-cp#hash && + git add git-wild-cp#hash && + cp git-wild\*star file-wild-3 && + git add file-wild-3 && + git commit -m "wildcard copies" && + git config git-p4.detectCopies true && + git config git-p4.detectCopiesHarder true && + git config git-p4.skipSubmitEdit true && + git p4 submit + ) && + ( + cd "$cli" && + test_path_is_file git-wild-cp#hash && + test_path_is_file file-wild-3 + ) +' + +test_expect_success 'wildcard files submit back to p4, rename' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git mv git-wild@at file-wild-4 && + git mv file-wild-3 git-wild-cp%percent && + git commit -m "wildcard renames" && + git config git-p4.detectRenames true && + git config git-p4.skipSubmitEdit true && + git p4 submit + ) && + ( + cd "$cli" && + test_path_is_missing git-wild@at && + test_path_is_file git-wild-cp%percent + ) +' + +test_expect_success 'wildcard files submit back to p4, delete' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git rm git-wild* && + git commit -m "delete the wildcard files" && + git config git-p4.skipSubmitEdit true && + git p4 submit + ) && + ( + cd "$cli" && + test_path_is_missing git-wild#hash && + test_path_is_missing git-wild\*star && + test_path_is_missing git-wild@at && + test_path_is_missing git-wild%percent + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9813-git-p4-preserve-users.sh b/t/t9813-git-p4-preserve-users.sh new file mode 100755 index 0000000000..f2e85e518b --- /dev/null +++ b/t/t9813-git-p4-preserve-users.sh @@ -0,0 +1,153 @@ +#!/bin/sh + +test_description='git p4 preserve users' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'create files' ' + ( + cd "$cli" && + p4 client -o | sed "/LineEnd/s/:.*/:unix/" | p4 client -i && + echo file1 >file1 && + echo file2 >file2 && + p4 add file1 file2 && + p4 submit -d "add files" + ) +' + +p4_add_user() { + name=$1 fullname=$2 && + p4 user -f -i <<-EOF && + User: $name + Email: $name@localhost + FullName: $fullname + EOF + p4 passwd -P secret $name +} + +p4_grant_admin() { + name=$1 && + { + p4 protect -o && + echo " admin user $name * //depot/..." + } | p4 protect -i +} + +p4_check_commit_author() { + file=$1 user=$2 && + p4 changes -m 1 //depot/$file | grep -q $user +} + +make_change_by_user() { + file=$1 name=$2 email=$3 && + echo "username: a change by $name" >>"$file" && + git add "$file" && + git commit --author "$name <$email>" -m "a change by $name" +} + +# Test username support, submitting as user 'alice' +test_expect_success 'preserve users' ' + p4_add_user alice Alice && + p4_add_user bob Bob && + p4_grant_admin alice && + git p4 clone --dest="$git" //depot && + test_when_finished cleanup_git && + ( + cd "$git" && + echo "username: a change by alice" >>file1 && + echo "username: a change by bob" >>file2 && + git commit --author "Alice <alice@localhost>" -m "a change by alice" file1 && + git commit --author "Bob <bob@localhost>" -m "a change by bob" file2 && + git config git-p4.skipSubmitEditCheck true && + P4EDITOR=touch P4USER=alice P4PASSWD=secret git p4 commit --preserve-user && + p4_check_commit_author file1 alice && + p4_check_commit_author file2 bob + ) +' + +# Test username support, submitting as bob, who lacks admin rights. Should +# not submit change to p4 (git diff should show deltas). +test_expect_success 'refuse to preserve users without perms' ' + git p4 clone --dest="$git" //depot && + test_when_finished cleanup_git && + ( + cd "$git" && + git config git-p4.skipSubmitEditCheck true && + echo "username-noperms: a change by alice" >>file1 && + git commit --author "Alice <alice@localhost>" -m "perms: a change by alice" file1 && + P4EDITOR=touch P4USER=bob P4PASSWD=secret && + export P4EDITOR P4USER P4PASSWD && + test_must_fail git p4 commit --preserve-user && + ! git diff --exit-code HEAD..p4/master + ) +' + +# What happens with unknown author? Without allowMissingP4Users it should fail. +test_expect_success 'preserve user where author is unknown to p4' ' + git p4 clone --dest="$git" //depot && + test_when_finished cleanup_git && + ( + cd "$git" && + git config git-p4.skipSubmitEditCheck true && + echo "username-bob: a change by bob" >>file1 && + git commit --author "Bob <bob@localhost>" -m "preserve: a change by bob" file1 && + echo "username-unknown: a change by charlie" >>file1 && + git commit --author "Charlie <charlie@localhost>" -m "preserve: a change by charlie" file1 && + P4EDITOR=touch P4USER=alice P4PASSWD=secret && + export P4EDITOR P4USER P4PASSWD && + test_must_fail git p4 commit --preserve-user && + ! git diff --exit-code HEAD..p4/master && + + echo "$0: repeat with allowMissingP4Users enabled" && + git config git-p4.allowMissingP4Users true && + git config git-p4.preserveUser true && + git p4 commit && + git diff --exit-code HEAD..p4/master && + p4_check_commit_author file1 alice + ) +' + +# If we're *not* using --preserve-user, git-p4 should warn if we're submitting +# changes that are not all ours. +# Test: user in p4 and user unknown to p4. +# Test: warning disabled and user is the same. +test_expect_success 'not preserving user with mixed authorship' ' + git p4 clone --dest="$git" //depot && + test_when_finished cleanup_git && + ( + cd "$git" && + git config git-p4.skipSubmitEditCheck true && + p4_add_user derek Derek && + + make_change_by_user usernamefile3 Derek derek@localhost && + P4EDITOR=cat P4USER=alice P4PASSWD=secret && + export P4EDITOR P4USER P4PASSWD && + git p4 commit |\ + grep "git author derek@localhost does not match" && + + make_change_by_user usernamefile3 Charlie charlie@localhost && + git p4 commit |\ + grep "git author charlie@localhost does not match" && + + make_change_by_user usernamefile3 alice alice@localhost && + git p4 commit |\ + test_must_fail grep "git author.*does not match" && + + git config git-p4.skipUserNameCheck true && + make_change_by_user usernamefile3 Charlie charlie@localhost && + git p4 commit |\ + test_must_fail grep "git author.*does not match" && + + p4_check_commit_author usernamefile3 alice + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9814-git-p4-rename.sh b/t/t9814-git-p4-rename.sh new file mode 100755 index 0000000000..3bf1224ae0 --- /dev/null +++ b/t/t9814-git-p4-rename.sh @@ -0,0 +1,206 @@ +#!/bin/sh + +test_description='git p4 rename' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +# We rely on this behavior to detect for p4 move availability. +test_expect_success 'p4 help unknown returns 1' ' + ( + cd "$cli" && + ( + p4 help client >errs 2>&1 + echo $? >retval + ) + echo 0 >expected && + test_cmp expected retval && + rm retval && + ( + p4 help nosuchcommand >errs 2>&1 + echo $? >retval + ) + echo 1 >expected && + test_cmp expected retval && + rm retval + ) +' + +test_expect_success 'create files' ' + ( + cd "$cli" && + p4 client -o | sed "/LineEnd/s/:.*/:unix/" | p4 client -i && + cat >file1 <<-EOF && + A large block of text + in file1 that will generate + enough context so that rename + and copy detection will find + something interesting to do. + EOF + cat >file2 <<-EOF && + /* + * This blob looks a bit + * different. + */ + int main(int argc, char **argv) + { + char text[200]; + + strcpy(text, "copy/rename this"); + printf("text is %s\n", text); + return 0; + } + EOF + p4 add file1 file2 && + p4 submit -d "add files" + ) +' + +# Rename a file and confirm that rename is not detected in P4. +# Rename the new file again with detectRenames option enabled and confirm that +# this is detected in P4. +# Rename the new file again adding an extra line, configure a big threshold in +# detectRenames and confirm that rename is not detected in P4. +# Repeat, this time with a smaller threshold and confirm that the rename is +# detected in P4. +test_expect_success 'detect renames' ' + git p4 clone --dest="$git" //depot@all && + test_when_finished cleanup_git && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + + git mv file1 file4 && + git commit -a -m "Rename file1 to file4" && + git diff-tree -r -M HEAD && + git p4 submit && + p4 filelog //depot/file4 >filelog && + ! grep " from //depot" filelog && + + git mv file4 file5 && + git commit -a -m "Rename file4 to file5" && + git diff-tree -r -M HEAD && + git config git-p4.detectRenames true && + git p4 submit && + p4 filelog //depot/file5 >filelog && + grep " from //depot/file4" filelog && + + git mv file5 file6 && + echo update >>file6 && + git add file6 && + git commit -a -m "Rename file5 to file6 with changes" && + git diff-tree -r -M HEAD && + level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") && + test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 && + git config git-p4.detectRenames $(($level + 2)) && + git p4 submit && + p4 filelog //depot/file6 >filelog && + ! grep " from //depot" filelog && + + git mv file6 file7 && + echo update >>file7 && + git add file7 && + git commit -a -m "Rename file6 to file7 with changes" && + git diff-tree -r -M HEAD && + level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") && + test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 && + git config git-p4.detectRenames $(($level - 2)) && + git p4 submit && + p4 filelog //depot/file7 >filelog && + grep " from //depot/file6" filelog + ) +' + +# Copy a file and confirm that copy is not detected in P4. +# Copy a file with detectCopies option enabled and confirm that copy is not +# detected in P4. +# Modify and copy a file with detectCopies option enabled and confirm that copy +# is detected in P4. +# Copy a file with detectCopies and detectCopiesHarder options enabled and +# confirm that copy is detected in P4. +# Modify and copy a file, configure a bigger threshold in detectCopies and +# confirm that copy is not detected in P4. +# Modify and copy a file, configure a smaller threshold in detectCopies and +# confirm that copy is detected in P4. +test_expect_success 'detect copies' ' + git p4 clone --dest="$git" //depot@all && + test_when_finished cleanup_git && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + + cp file2 file8 && + git add file8 && + git commit -a -m "Copy file2 to file8" && + git diff-tree -r -C HEAD && + git p4 submit && + p4 filelog //depot/file8 && + p4 filelog //depot/file8 | test_must_fail grep -q "branch from" && + + cp file2 file9 && + git add file9 && + git commit -a -m "Copy file2 to file9" && + git diff-tree -r -C HEAD && + git config git-p4.detectCopies true && + git p4 submit && + p4 filelog //depot/file9 && + p4 filelog //depot/file9 | test_must_fail grep -q "branch from" && + + echo "file2" >>file2 && + cp file2 file10 && + git add file2 file10 && + git commit -a -m "Modify and copy file2 to file10" && + git diff-tree -r -C HEAD && + git p4 submit && + p4 filelog //depot/file10 && + p4 filelog //depot/file10 | grep -q "branch from //depot/file" && + + cp file2 file11 && + git add file11 && + git commit -a -m "Copy file2 to file11" && + git diff-tree -r -C --find-copies-harder HEAD && + src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && + test "$src" = file10 && + git config git-p4.detectCopiesHarder true && + git p4 submit && + p4 filelog //depot/file11 && + p4 filelog //depot/file11 | grep -q "branch from //depot/file" && + + cp file2 file12 && + echo "some text" >>file12 && + git add file12 && + git commit -a -m "Copy file2 to file12 with changes" && + git diff-tree -r -C --find-copies-harder HEAD && + level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") && + test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 && + src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && + test "$src" = file10 -o "$src" = file11 && + git config git-p4.detectCopies $(($level + 2)) && + git p4 submit && + p4 filelog //depot/file12 && + p4 filelog //depot/file12 | test_must_fail grep -q "branch from" && + + cp file2 file13 && + echo "different text" >>file13 && + git add file13 && + git commit -a -m "Copy file2 to file13 with changes" && + git diff-tree -r -C --find-copies-harder HEAD && + level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") && + test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 && + src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && + test "$src" = file10 -o "$src" = file11 -o "$src" = file12 && + git config git-p4.detectCopies $(($level - 2)) && + git p4 submit && + p4 filelog //depot/file13 && + p4 filelog //depot/file13 | grep -q "branch from //depot/file" + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh new file mode 100755 index 0000000000..92d7eb47c2 --- /dev/null +++ b/t/t9902-completion.sh @@ -0,0 +1,231 @@ +#!/bin/sh +# +# Copyright (c) 2012 Felipe Contreras +# + +test_description='test bash completion' + +. ./lib-bash.sh + +complete () +{ + # do nothing + return 0 +} + +. "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" + +# We don't need this function to actually join words or do anything special. +# Also, it's cleaner to avoid touching bash's internal completion variables. +# So let's override it with a minimal version for testing purposes. +_get_comp_words_by_ref () +{ + while [ $# -gt 0 ]; do + case "$1" in + cur) + cur=${_words[_cword]} + ;; + prev) + prev=${_words[_cword-1]} + ;; + words) + words=("${_words[@]}") + ;; + cword) + cword=$_cword + ;; + esac + shift + done +} + +print_comp () +{ + local IFS=$'\n' + echo "${COMPREPLY[*]}" > out +} + +run_completion () +{ + local -a COMPREPLY _words + local _cword + _words=( $1 ) + (( _cword = ${#_words[@]} - 1 )) + __git_wrap__git_main && print_comp +} + +test_completion () +{ + test $# -gt 1 && echo "$2" > expected + run_completion "$@" && + test_cmp expected out +} + +newline=$'\n' + +test_expect_success '__gitcomp - trailing space - options' ' + sed -e "s/Z$//" >expected <<-\EOF && + --reuse-message=Z + --reedit-message=Z + --reset-author Z + EOF + ( + local -a COMPREPLY && + cur="--re" && + __gitcomp "--dry-run --reuse-message= --reedit-message= + --reset-author" && + IFS="$newline" && + echo "${COMPREPLY[*]}" > out + ) && + test_cmp expected out +' + +test_expect_success '__gitcomp - trailing space - config keys' ' + sed -e "s/Z$//" >expected <<-\EOF && + branch.Z + branch.autosetupmerge Z + branch.autosetuprebase Z + browser.Z + EOF + ( + local -a COMPREPLY && + cur="br" && + __gitcomp "branch. branch.autosetupmerge + branch.autosetuprebase browser." && + IFS="$newline" && + echo "${COMPREPLY[*]}" > out + ) && + test_cmp expected out +' + +test_expect_success '__gitcomp - option parameter' ' + sed -e "s/Z$//" >expected <<-\EOF && + recursive Z + resolve Z + EOF + ( + local -a COMPREPLY && + cur="--strategy=re" && + __gitcomp "octopus ours recursive resolve subtree + " "" "re" && + IFS="$newline" && + echo "${COMPREPLY[*]}" > out + ) && + test_cmp expected out +' + +test_expect_success '__gitcomp - prefix' ' + sed -e "s/Z$//" >expected <<-\EOF && + branch.maint.merge Z + branch.maint.mergeoptions Z + EOF + ( + local -a COMPREPLY && + cur="branch.me" && + __gitcomp "remote merge mergeoptions rebase + " "branch.maint." "me" && + IFS="$newline" && + echo "${COMPREPLY[*]}" > out + ) && + test_cmp expected out +' + +test_expect_success '__gitcomp - suffix' ' + sed -e "s/Z$//" >expected <<-\EOF && + branch.master.Z + branch.maint.Z + EOF + ( + local -a COMPREPLY && + cur="branch.me" && + __gitcomp "master maint next pu + " "branch." "ma" "." && + IFS="$newline" && + echo "${COMPREPLY[*]}" > out + ) && + test_cmp expected out +' + +test_expect_success 'basic' ' + run_completion "git \"\"" && + # built-in + grep -q "^add \$" out && + # script + grep -q "^filter-branch \$" out && + # plumbing + ! grep -q "^ls-files \$" out && + + run_completion "git f" && + ! grep -q -v "^f" out +' + +test_expect_success 'double dash "git" itself' ' + sed -e "s/Z$//" >expected <<-\EOF && + --paginate Z + --no-pager Z + --git-dir= + --bare Z + --version Z + --exec-path Z + --exec-path= + --html-path Z + --info-path Z + --work-tree= + --namespace= + --no-replace-objects Z + --help Z + EOF + test_completion "git --" +' + +test_expect_success 'double dash "git checkout"' ' + sed -e "s/Z$//" >expected <<-\EOF && + --quiet Z + --ours Z + --theirs Z + --track Z + --no-track Z + --merge Z + --conflict= + --orphan Z + --patch Z + EOF + test_completion "git checkout --" +' + +test_expect_success 'general options' ' + test_completion "git --ver" "--version " && + test_completion "git --hel" "--help " && + sed -e "s/Z$//" >expected <<-\EOF && + --exec-path Z + --exec-path= + EOF + test_completion "git --exe" && + test_completion "git --htm" "--html-path " && + test_completion "git --pag" "--paginate " && + test_completion "git --no-p" "--no-pager " && + test_completion "git --git" "--git-dir=" && + test_completion "git --wor" "--work-tree=" && + test_completion "git --nam" "--namespace=" && + test_completion "git --bar" "--bare " && + test_completion "git --inf" "--info-path " && + test_completion "git --no-r" "--no-replace-objects " +' + +test_expect_success 'general options plus command' ' + test_completion "git --version check" "checkout " && + test_completion "git --paginate check" "checkout " && + test_completion "git --git-dir=foo check" "checkout " && + test_completion "git --bare check" "checkout " && + test_completion "git --help des" "describe " && + test_completion "git --exec-path=foo check" "checkout " && + test_completion "git --html-path check" "checkout " && + test_completion "git --no-pager check" "checkout " && + test_completion "git --work-tree=foo check" "checkout " && + test_completion "git --namespace=foo check" "checkout " && + test_completion "git --paginate check" "checkout " && + test_completion "git --info-path check" "checkout " && + test_completion "git --no-replace-objects check" "checkout " +' + +test_done diff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh new file mode 100755 index 0000000000..f17c1f8b85 --- /dev/null +++ b/t/t9903-bash-prompt.sh @@ -0,0 +1,456 @@ +#!/bin/sh +# +# Copyright (c) 2012 SZEDER Gábor +# + +test_description='test git-specific bash prompt functions' + +. ./lib-bash.sh + +. "$GIT_BUILD_DIR/contrib/completion/git-prompt.sh" + +actual="$TRASH_DIRECTORY/actual" + +test_expect_success 'setup for prompt tests' ' + mkdir -p subdir/subsubdir && + git init otherrepo && + echo 1 > file && + git add file && + test_tick && + git commit -m initial && + git tag -a -m msg1 t1 && + git checkout -b b1 && + echo 2 > file && + git commit -m "second b1" file && + echo 3 > file && + git commit -m "third b1" file && + git tag -a -m msg2 t2 && + git checkout -b b2 master && + echo 0 > file && + git commit -m "second b2" file && + git checkout master +' + +test_expect_success 'gitdir - from command line (through $__git_dir)' ' + echo "$TRASH_DIRECTORY/otherrepo/.git" > expected && + ( + __git_dir="$TRASH_DIRECTORY/otherrepo/.git" && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - repo as argument' ' + echo "otherrepo/.git" > expected && + __gitdir "otherrepo" > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - remote as argument' ' + echo "remote" > expected && + __gitdir "remote" > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - .git directory in cwd' ' + echo ".git" > expected && + __gitdir > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - .git directory in parent' ' + echo "$TRASH_DIRECTORY/.git" > expected && + ( + cd subdir/subsubdir && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - cwd is a .git directory' ' + echo "." > expected && + ( + cd .git && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - parent is a .git directory' ' + echo "$TRASH_DIRECTORY/.git" > expected && + ( + cd .git/refs/heads && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - $GIT_DIR set while .git directory in cwd' ' + echo "$TRASH_DIRECTORY/otherrepo/.git" > expected && + ( + GIT_DIR="$TRASH_DIRECTORY/otherrepo/.git" && + export GIT_DIR && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - $GIT_DIR set while .git directory in parent' ' + echo "$TRASH_DIRECTORY/otherrepo/.git" > expected && + ( + GIT_DIR="$TRASH_DIRECTORY/otherrepo/.git" && + export GIT_DIR && + cd subdir && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - non-existing $GIT_DIR' ' + ( + GIT_DIR="$TRASH_DIRECTORY/non-existing" && + export GIT_DIR && + test_must_fail __gitdir + ) +' + +test_expect_success 'gitdir - gitfile in cwd' ' + echo "$TRASH_DIRECTORY/otherrepo/.git" > expected && + echo "gitdir: $TRASH_DIRECTORY/otherrepo/.git" > subdir/.git && + test_when_finished "rm -f subdir/.git" && + ( + cd subdir && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - gitfile in parent' ' + echo "$TRASH_DIRECTORY/otherrepo/.git" > expected && + echo "gitdir: $TRASH_DIRECTORY/otherrepo/.git" > subdir/.git && + test_when_finished "rm -f subdir/.git" && + ( + cd subdir/subsubdir && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success SYMLINKS 'gitdir - resulting path avoids symlinks' ' + echo "$TRASH_DIRECTORY/otherrepo/.git" > expected && + mkdir otherrepo/dir && + test_when_finished "rm -rf otherrepo/dir" && + ln -s otherrepo/dir link && + test_when_finished "rm -f link" && + ( + cd link && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - not a git repository' ' + ( + cd subdir/subsubdir && + GIT_CEILING_DIRECTORIES="$TRASH_DIRECTORY" && + export GIT_CEILING_DIRECTORIES && + test_must_fail __gitdir + ) +' + +test_expect_success 'prompt - branch name' ' + printf " (master)" > expected && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - detached head' ' + printf " ((%s...))" $(git log -1 --format="%h" b1^) > expected && + git checkout b1^ && + test_when_finished "git checkout master" && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - describe detached head - contains' ' + printf " ((t2~1))" > expected && + git checkout b1^ && + test_when_finished "git checkout master" && + ( + GIT_PS1_DESCRIBE_STYLE=contains && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - describe detached head - branch' ' + printf " ((b1~1))" > expected && + git checkout b1^ && + test_when_finished "git checkout master" && + ( + GIT_PS1_DESCRIBE_STYLE=branch && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - describe detached head - describe' ' + printf " ((t1-1-g%s))" $(git log -1 --format="%h" b1^) > expected && + git checkout b1^ && + test_when_finished "git checkout master" && + ( + GIT_PS1_DESCRIBE_STYLE=describe && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - describe detached head - default' ' + printf " ((t2))" > expected && + git checkout --detach b1 && + test_when_finished "git checkout master" && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - inside .git directory' ' + printf " (GIT_DIR!)" > expected && + ( + cd .git && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - deep inside .git directory' ' + printf " (GIT_DIR!)" > expected && + ( + cd .git/refs/heads && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - inside bare repository' ' + printf " (BARE:master)" > expected && + git init --bare bare.git && + test_when_finished "rm -rf bare.git" && + ( + cd bare.git && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - interactive rebase' ' + printf " (b1|REBASE-i)" > expected + echo "#!$SHELL_PATH" >fake_editor.sh && + cat >>fake_editor.sh <<\EOF && +echo "edit $(git log -1 --format="%h")" > "$1" +EOF + test_when_finished "rm -f fake_editor.sh" && + chmod a+x fake_editor.sh && + test_set_editor "$TRASH_DIRECTORY/fake_editor.sh" && + git checkout b1 && + test_when_finished "git checkout master" && + git rebase -i HEAD^ && + test_when_finished "git rebase --abort" + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - rebase merge' ' + printf " (b2|REBASE-m)" > expected && + git checkout b2 && + test_when_finished "git checkout master" && + test_must_fail git rebase --merge b1 b2 && + test_when_finished "git rebase --abort" && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - rebase' ' + printf " ((t2)|REBASE)" > expected && + git checkout b2 && + test_when_finished "git checkout master" && + test_must_fail git rebase b1 b2 && + test_when_finished "git rebase --abort" && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - merge' ' + printf " (b1|MERGING)" > expected && + git checkout b1 && + test_when_finished "git checkout master" && + test_must_fail git merge b2 && + test_when_finished "git reset --hard" && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - cherry-pick' ' + printf " (master|CHERRY-PICKING)" > expected && + test_must_fail git cherry-pick b1 && + test_when_finished "git reset --hard" && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - bisect' ' + printf " (master|BISECTING)" > expected && + git bisect start && + test_when_finished "git bisect reset" && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - clean' ' + printf " (master)" > expected && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - dirty worktree' ' + printf " (master *)" > expected && + echo "dirty" > file && + test_when_finished "git reset --hard" && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - dirty index' ' + printf " (master +)" > expected && + echo "dirty" > file && + test_when_finished "git reset --hard" && + git add -u && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - dirty index and worktree' ' + printf " (master *+)" > expected && + echo "dirty index" > file && + test_when_finished "git reset --hard" && + git add -u && + echo "dirty worktree" > file && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - before root commit' ' + printf " (master #)" > expected && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + cd otherrepo && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - disabled by config' ' + printf " (master)" > expected && + echo "dirty" > file && + test_when_finished "git reset --hard" && + test_config bash.showDirtyState false && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - not shown inside .git directory' ' + printf " (GIT_DIR!)" > expected && + echo "dirty" > file && + test_when_finished "git reset --hard" && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + cd .git && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - stash status indicator - no stash' ' + printf " (master)" > expected && + ( + GIT_PS1_SHOWSTASHSTATE=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - stash status indicator - stash' ' + printf " (master $)" > expected && + echo 2 >file && + git stash && + test_when_finished "git stash drop" && + ( + GIT_PS1_SHOWSTASHSTATE=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - stash status indicator - not shown inside .git directory' ' + printf " (GIT_DIR!)" > expected && + echo 2 >file && + git stash && + test_when_finished "git stash drop" && + ( + GIT_PS1_SHOWSTASHSTATE=y && + cd .git && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - untracked files status indicator - no untracked files' ' + printf " (master)" > expected && + ( + GIT_PS1_SHOWUNTRACKEDFILES=y && + cd otherrepo && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - untracked files status indicator - untracked files' ' + printf " (master %%)" > expected && + ( + GIT_PS1_SHOWUNTRACKEDFILES=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - untracked files status indicator - not shown inside .git directory' ' + printf " (GIT_DIR!)" > expected && + ( + GIT_PS1_SHOWUNTRACKEDFILES=y && + cd .git && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - format string starting with dash' ' + printf -- "-master" > expected && + __git_ps1 "-%s" > "$actual" && + test_cmp expected "$actual" +' + +test_done diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh new file mode 100644 index 0000000000..9bc57d27e9 --- /dev/null +++ b/t/test-lib-functions.sh @@ -0,0 +1,637 @@ +#!/bin/sh +# +# Copyright (c) 2005 Junio C Hamano +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see http://www.gnu.org/licenses/ . + +# The semantics of the editor variables are that of invoking +# sh -c "$EDITOR \"$@\"" files ... +# +# If our trash directory contains shell metacharacters, they will be +# interpreted if we just set $EDITOR directly, so do a little dance with +# environment variables to work around this. +# +# In particular, quoting isn't enough, as the path may contain the same quote +# that we're using. +test_set_editor () { + FAKE_EDITOR="$1" + export FAKE_EDITOR + EDITOR='"$FAKE_EDITOR"' + export EDITOR +} + +test_decode_color () { + awk ' + function name(n) { + if (n == 0) return "RESET"; + if (n == 1) return "BOLD"; + if (n == 30) return "BLACK"; + if (n == 31) return "RED"; + if (n == 32) return "GREEN"; + if (n == 33) return "YELLOW"; + if (n == 34) return "BLUE"; + if (n == 35) return "MAGENTA"; + if (n == 36) return "CYAN"; + if (n == 37) return "WHITE"; + if (n == 40) return "BLACK"; + if (n == 41) return "BRED"; + if (n == 42) return "BGREEN"; + if (n == 43) return "BYELLOW"; + if (n == 44) return "BBLUE"; + if (n == 45) return "BMAGENTA"; + if (n == 46) return "BCYAN"; + if (n == 47) return "BWHITE"; + } + { + while (match($0, /\033\[[0-9;]*m/) != 0) { + printf "%s<", substr($0, 1, RSTART-1); + codes = substr($0, RSTART+2, RLENGTH-3); + if (length(codes) == 0) + printf "%s", name(0) + else { + n = split(codes, ary, ";"); + sep = ""; + for (i = 1; i <= n; i++) { + printf "%s%s", sep, name(ary[i]); + sep = ";" + } + } + printf ">"; + $0 = substr($0, RSTART + RLENGTH, length($0) - RSTART - RLENGTH + 1); + } + print + } + ' +} + +nul_to_q () { + "$PERL_PATH" -pe 'y/\000/Q/' +} + +q_to_nul () { + "$PERL_PATH" -pe 'y/Q/\000/' +} + +q_to_cr () { + tr Q '\015' +} + +q_to_tab () { + tr Q '\011' +} + +append_cr () { + sed -e 's/$/Q/' | tr Q '\015' +} + +remove_cr () { + tr '\015' Q | sed -e 's/Q$//' +} + +# In some bourne shell implementations, the "unset" builtin returns +# nonzero status when a variable to be unset was not set in the first +# place. +# +# Use sane_unset when that should not be considered an error. + +sane_unset () { + unset "$@" + return 0 +} + +test_tick () { + if test -z "${test_tick+set}" + then + test_tick=1112911993 + else + test_tick=$(($test_tick + 60)) + fi + GIT_COMMITTER_DATE="$test_tick -0700" + GIT_AUTHOR_DATE="$test_tick -0700" + export GIT_COMMITTER_DATE GIT_AUTHOR_DATE +} + +# Stop execution and start a shell. This is useful for debugging tests and +# only makes sense together with "-v". +# +# Be sure to remove all invocations of this command before submitting. + +test_pause () { + if test "$verbose" = t; then + "$SHELL_PATH" <&6 >&3 2>&4 + else + error >&5 "test_pause requires --verbose" + fi +} + +# Call test_commit with the arguments "<message> [<file> [<contents>]]" +# +# This will commit a file with the given contents and the given commit +# message. It will also add a tag with <message> as name. +# +# Both <file> and <contents> default to <message>. + +test_commit () { + notick= && + if test "z$1" = "z--notick" + then + notick=yes + shift + fi && + file=${2:-"$1.t"} && + echo "${3-$1}" > "$file" && + git add "$file" && + if test -z "$notick" + then + test_tick + fi && + git commit -m "$1" && + git tag "$1" +} + +# Call test_merge with the arguments "<message> <commit>", where <commit> +# can be a tag pointing to the commit-to-merge. + +test_merge () { + test_tick && + git merge -m "$1" "$2" && + git tag "$1" +} + +# This function helps systems where core.filemode=false is set. +# Use it instead of plain 'chmod +x' to set or unset the executable bit +# of a file in the working directory and add it to the index. + +test_chmod () { + chmod "$@" && + git update-index --add "--chmod=$@" +} + +# Unset a configuration variable, but don't fail if it doesn't exist. +test_unconfig () { + git config --unset-all "$@" + config_status=$? + case "$config_status" in + 5) # ok, nothing to unset + config_status=0 + ;; + esac + return $config_status +} + +# Set git config, automatically unsetting it after the test is over. +test_config () { + test_when_finished "test_unconfig '$1'" && + git config "$@" +} + +test_config_global () { + test_when_finished "test_unconfig --global '$1'" && + git config --global "$@" +} + +write_script () { + { + echo "#!${2-"$SHELL_PATH"}" && + cat + } >"$1" && + chmod +x "$1" +} + +# Use test_set_prereq to tell that a particular prerequisite is available. +# The prerequisite can later be checked for in two ways: +# +# - Explicitly using test_have_prereq. +# +# - Implicitly by specifying the prerequisite tag in the calls to +# test_expect_{success,failure,code}. +# +# The single parameter is the prerequisite tag (a simple word, in all +# capital letters by convention). + +test_set_prereq () { + satisfied_prereq="$satisfied_prereq$1 " +} +satisfied_prereq=" " +lazily_testable_prereq= lazily_tested_prereq= + +# Usage: test_lazy_prereq PREREQ 'script' +test_lazy_prereq () { + lazily_testable_prereq="$lazily_testable_prereq$1 " + eval test_prereq_lazily_$1=\$2 +} + +test_run_lazy_prereq_ () { + script=' +mkdir -p "$TRASH_DIRECTORY/prereq-test-dir" && +( + cd "$TRASH_DIRECTORY/prereq-test-dir" &&'"$2"' +)' + say >&3 "checking prerequisite: $1" + say >&3 "$script" + test_eval_ "$script" + eval_ret=$? + rm -rf "$TRASH_DIRECTORY/prereq-test-dir" + if test "$eval_ret" = 0; then + say >&3 "prerequisite $1 ok" + else + say >&3 "prerequisite $1 not satisfied" + fi + return $eval_ret +} + +test_have_prereq () { + # prerequisites can be concatenated with ',' + save_IFS=$IFS + IFS=, + set -- $* + IFS=$save_IFS + + total_prereq=0 + ok_prereq=0 + missing_prereq= + + for prerequisite + do + case " $lazily_tested_prereq " in + *" $prerequisite "*) + ;; + *) + case " $lazily_testable_prereq " in + *" $prerequisite "*) + eval "script=\$test_prereq_lazily_$prerequisite" && + if test_run_lazy_prereq_ "$prerequisite" "$script" + then + test_set_prereq $prerequisite + fi + lazily_tested_prereq="$lazily_tested_prereq$prerequisite " + esac + ;; + esac + + total_prereq=$(($total_prereq + 1)) + case "$satisfied_prereq" in + *" $prerequisite "*) + ok_prereq=$(($ok_prereq + 1)) + ;; + *) + # Keep a list of missing prerequisites + if test -z "$missing_prereq" + then + missing_prereq=$prerequisite + else + missing_prereq="$prerequisite,$missing_prereq" + fi + esac + done + + test $total_prereq = $ok_prereq +} + +test_declared_prereq () { + case ",$test_prereq," in + *,$1,*) + return 0 + ;; + esac + return 1 +} + +test_expect_failure () { + test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= + test "$#" = 2 || + error "bug in the test script: not 2 or 3 parameters to test-expect-failure" + export test_prereq + if ! test_skip "$@" + then + say >&3 "checking known breakage: $2" + if test_run_ "$2" expecting_failure + then + test_known_broken_ok_ "$1" + else + test_known_broken_failure_ "$1" + fi + fi + echo >&3 "" +} + +test_expect_success () { + test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= + test "$#" = 2 || + error "bug in the test script: not 2 or 3 parameters to test-expect-success" + export test_prereq + if ! test_skip "$@" + then + say >&3 "expecting success: $2" + if test_run_ "$2" + then + test_ok_ "$1" + else + test_failure_ "$@" + fi + fi + echo >&3 "" +} + +# test_external runs external test scripts that provide continuous +# test output about their progress, and succeeds/fails on +# zero/non-zero exit code. It outputs the test output on stdout even +# in non-verbose mode, and announces the external script with "# run +# <n>: ..." before running it. When providing relative paths, keep in +# mind that all scripts run in "trash directory". +# Usage: test_external description command arguments... +# Example: test_external 'Perl API' perl ../path/to/test.pl +test_external () { + test "$#" = 4 && { test_prereq=$1; shift; } || test_prereq= + test "$#" = 3 || + error >&5 "bug in the test script: not 3 or 4 parameters to test_external" + descr="$1" + shift + export test_prereq + if ! test_skip "$descr" "$@" + then + # Announce the script to reduce confusion about the + # test output that follows. + say_color "" "# run $test_count: $descr ($*)" + # Export TEST_DIRECTORY, TRASH_DIRECTORY and GIT_TEST_LONG + # to be able to use them in script + export TEST_DIRECTORY TRASH_DIRECTORY GIT_TEST_LONG + # Run command; redirect its stderr to &4 as in + # test_run_, but keep its stdout on our stdout even in + # non-verbose mode. + "$@" 2>&4 + if [ "$?" = 0 ] + then + if test $test_external_has_tap -eq 0; then + test_ok_ "$descr" + else + say_color "" "# test_external test $descr was ok" + test_success=$(($test_success + 1)) + fi + else + if test $test_external_has_tap -eq 0; then + test_failure_ "$descr" "$@" + else + say_color error "# test_external test $descr failed: $@" + test_failure=$(($test_failure + 1)) + fi + fi + fi +} + +# Like test_external, but in addition tests that the command generated +# no output on stderr. +test_external_without_stderr () { + # The temporary file has no (and must have no) security + # implications. + tmp=${TMPDIR:-/tmp} + stderr="$tmp/git-external-stderr.$$.tmp" + test_external "$@" 4> "$stderr" + [ -f "$stderr" ] || error "Internal error: $stderr disappeared." + descr="no stderr: $1" + shift + say >&3 "# expecting no stderr from previous command" + if [ ! -s "$stderr" ]; then + rm "$stderr" + + if test $test_external_has_tap -eq 0; then + test_ok_ "$descr" + else + say_color "" "# test_external_without_stderr test $descr was ok" + test_success=$(($test_success + 1)) + fi + else + if [ "$verbose" = t ]; then + output=`echo; echo "# Stderr is:"; cat "$stderr"` + else + output= + fi + # rm first in case test_failure exits. + rm "$stderr" + if test $test_external_has_tap -eq 0; then + test_failure_ "$descr" "$@" "$output" + else + say_color error "# test_external_without_stderr test $descr failed: $@: $output" + test_failure=$(($test_failure + 1)) + fi + fi +} + +# debugging-friendly alternatives to "test [-f|-d|-e]" +# The commands test the existence or non-existence of $1. $2 can be +# given to provide a more precise diagnosis. +test_path_is_file () { + if ! [ -f "$1" ] + then + echo "File $1 doesn't exist. $*" + false + fi +} + +test_path_is_dir () { + if ! [ -d "$1" ] + then + echo "Directory $1 doesn't exist. $*" + false + fi +} + +test_path_is_missing () { + if [ -e "$1" ] + then + echo "Path exists:" + ls -ld "$1" + if [ $# -ge 1 ]; then + echo "$*" + fi + false + fi +} + +# test_line_count checks that a file has the number of lines it +# ought to. For example: +# +# test_expect_success 'produce exactly one line of output' ' +# do something >output && +# test_line_count = 1 output +# ' +# +# is like "test $(wc -l <output) = 1" except that it passes the +# output through when the number of lines is wrong. + +test_line_count () { + if test $# != 3 + then + error "bug in the test script: not 3 parameters to test_line_count" + elif ! test $(wc -l <"$3") "$1" "$2" + then + echo "test_line_count: line count for $3 !$1 $2" + cat "$3" + return 1 + fi +} + +# This is not among top-level (test_expect_success | test_expect_failure) +# but is a prefix that can be used in the test script, like: +# +# test_expect_success 'complain and die' ' +# do something && +# do something else && +# test_must_fail git checkout ../outerspace +# ' +# +# Writing this as "! git checkout ../outerspace" is wrong, because +# the failure could be due to a segv. We want a controlled failure. + +test_must_fail () { + "$@" + exit_code=$? + if test $exit_code = 0; then + echo >&2 "test_must_fail: command succeeded: $*" + return 1 + elif test $exit_code -gt 129 -a $exit_code -le 192; then + echo >&2 "test_must_fail: died by signal: $*" + return 1 + elif test $exit_code = 127; then + echo >&2 "test_must_fail: command not found: $*" + return 1 + fi + return 0 +} + +# Similar to test_must_fail, but tolerates success, too. This is +# meant to be used in contexts like: +# +# test_expect_success 'some command works without configuration' ' +# test_might_fail git config --unset all.configuration && +# do something +# ' +# +# Writing "git config --unset all.configuration || :" would be wrong, +# because we want to notice if it fails due to segv. + +test_might_fail () { + "$@" + exit_code=$? + if test $exit_code -gt 129 -a $exit_code -le 192; then + echo >&2 "test_might_fail: died by signal: $*" + return 1 + elif test $exit_code = 127; then + echo >&2 "test_might_fail: command not found: $*" + return 1 + fi + return 0 +} + +# Similar to test_must_fail and test_might_fail, but check that a +# given command exited with a given exit code. Meant to be used as: +# +# test_expect_success 'Merge with d/f conflicts' ' +# test_expect_code 1 git merge "merge msg" B master +# ' + +test_expect_code () { + want_code=$1 + shift + "$@" + exit_code=$? + if test $exit_code = $want_code + then + return 0 + fi + + echo >&2 "test_expect_code: command exited with $exit_code, we wanted $want_code $*" + return 1 +} + +# test_cmp is a helper function to compare actual and expected output. +# You can use it like: +# +# test_expect_success 'foo works' ' +# echo expected >expected && +# foo >actual && +# test_cmp expected actual +# ' +# +# This could be written as either "cmp" or "diff -u", but: +# - cmp's output is not nearly as easy to read as diff -u +# - not all diff versions understand "-u" + +test_cmp() { + $GIT_TEST_CMP "$@" +} + +# Print a sequence of numbers or letters in increasing order. This is +# similar to GNU seq(1), but the latter might not be available +# everywhere (and does not do letters). It may be used like: +# +# for i in `test_seq 100`; do +# for j in `test_seq 10 20`; do +# for k in `test_seq a z`; do +# echo $i-$j-$k +# done +# done +# done + +test_seq () { + case $# in + 1) set 1 "$@" ;; + 2) ;; + *) error "bug in the test script: not 1 or 2 parameters to test_seq" ;; + esac + "$PERL_PATH" -le 'print for $ARGV[0]..$ARGV[1]' -- "$@" +} + +# This function can be used to schedule some commands to be run +# unconditionally at the end of the test to restore sanity: +# +# test_expect_success 'test core.capslock' ' +# git config core.capslock true && +# test_when_finished "git config --unset core.capslock" && +# hello world +# ' +# +# That would be roughly equivalent to +# +# test_expect_success 'test core.capslock' ' +# git config core.capslock true && +# hello world +# git config --unset core.capslock +# ' +# +# except that the greeting and config --unset must both succeed for +# the test to pass. +# +# Note that under --immediate mode, no clean-up is done to help diagnose +# what went wrong. + +test_when_finished () { + test_cleanup="{ $* + } && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup" +} + +# Most tests can use the created repository, but some may need to create more. +# Usage: test_create_repo <directory> +test_create_repo () { + test "$#" = 1 || + error "bug in the test script: not 1 parameter to test-create-repo" + repo="$1" + mkdir -p "$repo" + ( + cd "$repo" || error "Cannot setup test environment" + "$GIT_EXEC_PATH/git-init" "--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 || + error "cannot run git init -- have you built things yet?" + mv .git/hooks .git/hooks-disabled + ) || exit +} diff --git a/t/test-lib.sh b/t/test-lib.sh index c0d04c494a..78c428619e 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -34,6 +34,26 @@ esac # Keep the original TERM for say_color ORIGINAL_TERM=$TERM +# Test the binaries we have just built. The tests are kept in +# t/ subdirectory and are run in 'trash directory' subdirectory. +if test -z "$TEST_DIRECTORY" +then + # We allow tests to override this, in case they want to run tests + # outside of t/, e.g. for running tests on the test library + # itself. + TEST_DIRECTORY=$(pwd) +fi +if test -z "$TEST_OUTPUT_DIRECTORY" +then + # Similarly, override this to store the test-results subdir + # elsewhere + TEST_OUTPUT_DIRECTORY=$TEST_DIRECTORY +fi +GIT_BUILD_DIR="$TEST_DIRECTORY"/.. + +. "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS +export PERL_PATH SHELL_PATH + # For repeatability, reset the environment to known value. LANG=C LC_ALL=C @@ -46,7 +66,7 @@ EDITOR=: # /usr/xpg4/bin/sh and /bin/ksh to bail out. So keep the unsets # deriving from the command substitution clustered with the other # ones. -unset VISUAL EMAIL LANGUAGE $(perl -e ' +unset VISUAL EMAIL LANGUAGE COLUMNS $("$PERL_PATH" -e ' my @env = keys %ENV; my $ok = join("|", qw( TRACE @@ -56,16 +76,19 @@ unset VISUAL EMAIL LANGUAGE $(perl -e ' .*_TEST PROVE VALGRIND + PERF_AGGREGATING_LATER )); my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env); print join("\n", @vars); ') +unset XDG_CONFIG_HOME GIT_AUTHOR_EMAIL=author@example.com GIT_AUTHOR_NAME='A U Thor' GIT_COMMITTER_EMAIL=committer@example.com GIT_COMMITTER_NAME='C O Mitter' GIT_MERGE_VERBOSITY=5 -export GIT_MERGE_VERBOSITY +GIT_MERGE_AUTOEDIT=no +export GIT_MERGE_VERBOSITY GIT_MERGE_AUTOEDIT export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME export EDITOR @@ -98,6 +121,8 @@ _z40=0000000000000000000000000000000000000000 LF=' ' +export _x05 _x40 _z40 LF + # Each test should start with something like this, after copyright notices: # # test_description='Description of this test... @@ -223,235 +248,9 @@ die () { GIT_EXIT_OK= trap 'die' EXIT -# The semantics of the editor variables are that of invoking -# sh -c "$EDITOR \"$@\"" files ... -# -# If our trash directory contains shell metacharacters, they will be -# interpreted if we just set $EDITOR directly, so do a little dance with -# environment variables to work around this. -# -# In particular, quoting isn't enough, as the path may contain the same quote -# that we're using. -test_set_editor () { - FAKE_EDITOR="$1" - export FAKE_EDITOR - EDITOR='"$FAKE_EDITOR"' - export EDITOR -} - -test_decode_color () { - awk ' - function name(n) { - if (n == 0) return "RESET"; - if (n == 1) return "BOLD"; - if (n == 30) return "BLACK"; - if (n == 31) return "RED"; - if (n == 32) return "GREEN"; - if (n == 33) return "YELLOW"; - if (n == 34) return "BLUE"; - if (n == 35) return "MAGENTA"; - if (n == 36) return "CYAN"; - if (n == 37) return "WHITE"; - if (n == 40) return "BLACK"; - if (n == 41) return "BRED"; - if (n == 42) return "BGREEN"; - if (n == 43) return "BYELLOW"; - if (n == 44) return "BBLUE"; - if (n == 45) return "BMAGENTA"; - if (n == 46) return "BCYAN"; - if (n == 47) return "BWHITE"; - } - { - while (match($0, /\033\[[0-9;]*m/) != 0) { - printf "%s<", substr($0, 1, RSTART-1); - codes = substr($0, RSTART+2, RLENGTH-3); - if (length(codes) == 0) - printf "%s", name(0) - else { - n = split(codes, ary, ";"); - sep = ""; - for (i = 1; i <= n; i++) { - printf "%s%s", sep, name(ary[i]); - sep = ";" - } - } - printf ">"; - $0 = substr($0, RSTART + RLENGTH, length($0) - RSTART - RLENGTH + 1); - } - print - } - ' -} - -nul_to_q () { - perl -pe 'y/\000/Q/' -} - -q_to_nul () { - perl -pe 'y/Q/\000/' -} - -q_to_cr () { - tr Q '\015' -} - -q_to_tab () { - tr Q '\011' -} - -append_cr () { - sed -e 's/$/Q/' | tr Q '\015' -} - -remove_cr () { - tr '\015' Q | sed -e 's/Q$//' -} - -# In some bourne shell implementations, the "unset" builtin returns -# nonzero status when a variable to be unset was not set in the first -# place. -# -# Use sane_unset when that should not be considered an error. - -sane_unset () { - unset "$@" - return 0 -} - -test_tick () { - if test -z "${test_tick+set}" - then - test_tick=1112911993 - else - test_tick=$(($test_tick + 60)) - fi - GIT_COMMITTER_DATE="$test_tick -0700" - GIT_AUTHOR_DATE="$test_tick -0700" - export GIT_COMMITTER_DATE GIT_AUTHOR_DATE -} - -# Call test_commit with the arguments "<message> [<file> [<contents>]]" -# -# This will commit a file with the given contents and the given commit -# message. It will also add a tag with <message> as name. -# -# Both <file> and <contents> default to <message>. - -test_commit () { - file=${2:-"$1.t"} - echo "${3-$1}" > "$file" && - git add "$file" && - test_tick && - git commit -m "$1" && - git tag "$1" -} - -# Call test_merge with the arguments "<message> <commit>", where <commit> -# can be a tag pointing to the commit-to-merge. - -test_merge () { - test_tick && - git merge -m "$1" "$2" && - git tag "$1" -} - -# This function helps systems where core.filemode=false is set. -# Use it instead of plain 'chmod +x' to set or unset the executable bit -# of a file in the working directory and add it to the index. - -test_chmod () { - chmod "$@" && - git update-index --add "--chmod=$@" -} - -# Unset a configuration variable, but don't fail if it doesn't exist. -test_unconfig () { - git config --unset-all "$@" - config_status=$? - case "$config_status" in - 5) # ok, nothing to unset - config_status=0 - ;; - esac - return $config_status -} - -# Set git config, automatically unsetting it after the test is over. -test_config () { - test_when_finished "test_unconfig '$1'" && - git config "$@" -} - - -test_config_global () { - test_when_finished "test_unconfig --global '$1'" && - git config --global "$@" -} - -write_script () { - { - echo "#!${2-"$SHELL_PATH"}" && - cat - } >"$1" && - chmod +x "$1" -} - -# Use test_set_prereq to tell that a particular prerequisite is available. -# The prerequisite can later be checked for in two ways: -# -# - Explicitly using test_have_prereq. -# -# - Implicitly by specifying the prerequisite tag in the calls to -# test_expect_{success,failure,code}. -# -# The single parameter is the prerequisite tag (a simple word, in all -# capital letters by convention). - -test_set_prereq () { - satisfied="$satisfied$1 " -} -satisfied=" " - -test_have_prereq () { - # prerequisites can be concatenated with ',' - save_IFS=$IFS - IFS=, - set -- $* - IFS=$save_IFS - - total_prereq=0 - ok_prereq=0 - missing_prereq= - - for prerequisite - do - total_prereq=$(($total_prereq + 1)) - case $satisfied in - *" $prerequisite "*) - ok_prereq=$(($ok_prereq + 1)) - ;; - *) - # Keep a list of missing prerequisites - if test -z "$missing_prereq" - then - missing_prereq=$prerequisite - else - missing_prereq="$prerequisite,$missing_prereq" - fi - esac - done - - test $total_prereq = $ok_prereq -} - -test_declared_prereq () { - case ",$test_prereq," in - *,$1,*) - return 0 - ;; - esac - return 1 -} +# The user-facing functions are loaded from a separate file so that +# test_perf subshells can have them too +. "$TEST_DIRECTORY/test-lib-functions.sh" # You are not expected to call test_ok_ and test_failure_ directly, use # the text_expect_* functions instead. @@ -539,318 +338,16 @@ test_skip () { esac } -test_expect_failure () { - test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= - test "$#" = 2 || - error "bug in the test script: not 2 or 3 parameters to test-expect-failure" - export test_prereq - if ! test_skip "$@" - then - say >&3 "checking known breakage: $2" - if test_run_ "$2" expecting_failure - then - test_known_broken_ok_ "$1" - else - test_known_broken_failure_ "$1" - fi - fi - echo >&3 "" -} - -test_expect_success () { - test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= - test "$#" = 2 || - error "bug in the test script: not 2 or 3 parameters to test-expect-success" - export test_prereq - if ! test_skip "$@" - then - say >&3 "expecting success: $2" - if test_run_ "$2" - then - test_ok_ "$1" - else - test_failure_ "$@" - fi - fi - echo >&3 "" -} - -# test_external runs external test scripts that provide continuous -# test output about their progress, and succeeds/fails on -# zero/non-zero exit code. It outputs the test output on stdout even -# in non-verbose mode, and announces the external script with "# run -# <n>: ..." before running it. When providing relative paths, keep in -# mind that all scripts run in "trash directory". -# Usage: test_external description command arguments... -# Example: test_external 'Perl API' perl ../path/to/test.pl -test_external () { - test "$#" = 4 && { test_prereq=$1; shift; } || test_prereq= - test "$#" = 3 || - error >&5 "bug in the test script: not 3 or 4 parameters to test_external" - descr="$1" - shift - export test_prereq - if ! test_skip "$descr" "$@" - then - # Announce the script to reduce confusion about the - # test output that follows. - say_color "" "# run $test_count: $descr ($*)" - # Export TEST_DIRECTORY, TRASH_DIRECTORY and GIT_TEST_LONG - # to be able to use them in script - export TEST_DIRECTORY TRASH_DIRECTORY GIT_TEST_LONG - # Run command; redirect its stderr to &4 as in - # test_run_, but keep its stdout on our stdout even in - # non-verbose mode. - "$@" 2>&4 - if [ "$?" = 0 ] - then - if test $test_external_has_tap -eq 0; then - test_ok_ "$descr" - else - say_color "" "# test_external test $descr was ok" - test_success=$(($test_success + 1)) - fi - else - if test $test_external_has_tap -eq 0; then - test_failure_ "$descr" "$@" - else - say_color error "# test_external test $descr failed: $@" - test_failure=$(($test_failure + 1)) - fi - fi - fi -} - -# Like test_external, but in addition tests that the command generated -# no output on stderr. -test_external_without_stderr () { - # The temporary file has no (and must have no) security - # implications. - tmp=${TMPDIR:-/tmp} - stderr="$tmp/git-external-stderr.$$.tmp" - test_external "$@" 4> "$stderr" - [ -f "$stderr" ] || error "Internal error: $stderr disappeared." - descr="no stderr: $1" - shift - say >&3 "# expecting no stderr from previous command" - if [ ! -s "$stderr" ]; then - rm "$stderr" - - if test $test_external_has_tap -eq 0; then - test_ok_ "$descr" - else - say_color "" "# test_external_without_stderr test $descr was ok" - test_success=$(($test_success + 1)) - fi - else - if [ "$verbose" = t ]; then - output=`echo; echo "# Stderr is:"; cat "$stderr"` - else - output= - fi - # rm first in case test_failure exits. - rm "$stderr" - if test $test_external_has_tap -eq 0; then - test_failure_ "$descr" "$@" "$output" - else - say_color error "# test_external_without_stderr test $descr failed: $@: $output" - test_failure=$(($test_failure + 1)) - fi - fi -} - -# debugging-friendly alternatives to "test [-f|-d|-e]" -# The commands test the existence or non-existence of $1. $2 can be -# given to provide a more precise diagnosis. -test_path_is_file () { - if ! [ -f "$1" ] - then - echo "File $1 doesn't exist. $*" - false - fi -} - -test_path_is_dir () { - if ! [ -d "$1" ] - then - echo "Directory $1 doesn't exist. $*" - false - fi -} - -test_path_is_missing () { - if [ -e "$1" ] - then - echo "Path exists:" - ls -ld "$1" - if [ $# -ge 1 ]; then - echo "$*" - fi - false - fi -} - -# test_line_count checks that a file has the number of lines it -# ought to. For example: -# -# test_expect_success 'produce exactly one line of output' ' -# do something >output && -# test_line_count = 1 output -# ' -# -# is like "test $(wc -l <output) = 1" except that it passes the -# output through when the number of lines is wrong. - -test_line_count () { - if test $# != 3 - then - error "bug in the test script: not 3 parameters to test_line_count" - elif ! test $(wc -l <"$3") "$1" "$2" - then - echo "test_line_count: line count for $3 !$1 $2" - cat "$3" - return 1 - fi -} - -# This is not among top-level (test_expect_success | test_expect_failure) -# but is a prefix that can be used in the test script, like: -# -# test_expect_success 'complain and die' ' -# do something && -# do something else && -# test_must_fail git checkout ../outerspace -# ' -# -# Writing this as "! git checkout ../outerspace" is wrong, because -# the failure could be due to a segv. We want a controlled failure. - -test_must_fail () { - "$@" - exit_code=$? - if test $exit_code = 0; then - echo >&2 "test_must_fail: command succeeded: $*" - return 1 - elif test $exit_code -gt 129 -a $exit_code -le 192; then - echo >&2 "test_must_fail: died by signal: $*" - return 1 - elif test $exit_code = 127; then - echo >&2 "test_must_fail: command not found: $*" - return 1 - fi - return 0 -} - -# Similar to test_must_fail, but tolerates success, too. This is -# meant to be used in contexts like: -# -# test_expect_success 'some command works without configuration' ' -# test_might_fail git config --unset all.configuration && -# do something -# ' -# -# Writing "git config --unset all.configuration || :" would be wrong, -# because we want to notice if it fails due to segv. - -test_might_fail () { - "$@" - exit_code=$? - if test $exit_code -gt 129 -a $exit_code -le 192; then - echo >&2 "test_might_fail: died by signal: $*" - return 1 - elif test $exit_code = 127; then - echo >&2 "test_might_fail: command not found: $*" - return 1 - fi - return 0 -} - -# Similar to test_must_fail and test_might_fail, but check that a -# given command exited with a given exit code. Meant to be used as: -# -# test_expect_success 'Merge with d/f conflicts' ' -# test_expect_code 1 git merge "merge msg" B master -# ' - -test_expect_code () { - want_code=$1 - shift - "$@" - exit_code=$? - if test $exit_code = $want_code - then - return 0 - fi - - echo >&2 "test_expect_code: command exited with $exit_code, we wanted $want_code $*" - return 1 -} - -# test_cmp is a helper function to compare actual and expected output. -# You can use it like: -# -# test_expect_success 'foo works' ' -# echo expected >expected && -# foo >actual && -# test_cmp expected actual -# ' -# -# This could be written as either "cmp" or "diff -u", but: -# - cmp's output is not nearly as easy to read as diff -u -# - not all diff versions understand "-u" - -test_cmp() { - $GIT_TEST_CMP "$@" -} - -# This function can be used to schedule some commands to be run -# unconditionally at the end of the test to restore sanity: -# -# test_expect_success 'test core.capslock' ' -# git config core.capslock true && -# test_when_finished "git config --unset core.capslock" && -# hello world -# ' -# -# That would be roughly equivalent to -# -# test_expect_success 'test core.capslock' ' -# git config core.capslock true && -# hello world -# git config --unset core.capslock -# ' -# -# except that the greeting and config --unset must both succeed for -# the test to pass. -# -# Note that under --immediate mode, no clean-up is done to help diagnose -# what went wrong. - -test_when_finished () { - test_cleanup="{ $* - } && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup" -} - -# Most tests can use the created repository, but some may need to create more. -# Usage: test_create_repo <directory> -test_create_repo () { - test "$#" = 1 || - error "bug in the test script: not 1 parameter to test-create-repo" - repo="$1" - mkdir -p "$repo" - ( - cd "$repo" || error "Cannot setup test environment" - "$GIT_EXEC_PATH/git-init" "--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 || - error "cannot run git init -- have you built things yet?" - mv .git/hooks .git/hooks-disabled - ) || exit +# stub; perf-lib overrides it +test_at_end_hook_ () { + : } test_done () { GIT_EXIT_OK=t if test -z "$HARNESS_ACTIVE"; then - test_results_dir="$TEST_DIRECTORY/test-results" + test_results_dir="$TEST_OUTPUT_DIRECTORY/test-results" mkdir -p "$test_results_dir" test_results_path="$test_results_dir/${0%.sh}-$$.counts" @@ -889,6 +386,8 @@ test_done () { cd "$(dirname "$remove_trash")" && rm -rf "$(basename "$remove_trash")" + test_at_end_hook_ + exit 0 ;; *) @@ -902,17 +401,6 @@ test_done () { esac } -# Test the binaries we have just built. The tests are kept in -# t/ subdirectory and are run in 'trash directory' subdirectory. -if test -z "$TEST_DIRECTORY" -then - # We allow tests to override this, in case they want to run tests - # outside of t/, e.g. for running tests on the test library - # itself. - TEST_DIRECTORY=$(pwd) -fi -GIT_BUILD_DIR="$TEST_DIRECTORY"/.. - if test -n "$valgrind" then make_symlink () { @@ -1008,8 +496,6 @@ GIT_CONFIG_NOSYSTEM=1 GIT_ATTR_NOSYSTEM=1 export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_ATTR_NOSYSTEM -. "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS - if test -z "$GIT_TEST_CMP" then if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT" @@ -1046,7 +532,7 @@ test="trash directory.$(basename "$0" .sh)" test -n "$root" && test="$root/$test" case "$test" in /*) TRASH_DIRECTORY="$test" ;; - *) TRASH_DIRECTORY="$TEST_DIRECTORY/$test" ;; + *) TRASH_DIRECTORY="$TEST_OUTPUT_DIRECTORY/$test" ;; esac test ! -z "$debug" || remove_trash=$TRASH_DIRECTORY rm -fr "$test" || { @@ -1058,7 +544,11 @@ rm -fr "$test" || { HOME="$TRASH_DIRECTORY" export HOME -test_create_repo "$test" +if test -z "$TEST_NO_CREATE_REPO"; then + test_create_repo "$test" +else + mkdir -p "$test" +fi # Use -P to resolve symlinks in our working directory so that the cwd # in subprocesses like git equals our $PWD (for pathname comparisons). cd -P "$test" || exit 1 @@ -1127,6 +617,7 @@ case $(uname -s) in ;; esac +( COLUMNS=1 && test $COLUMNS = 1 ) && test_set_prereq COLUMNS_CAN_BE_1 test -z "$NO_PERL" && test_set_prereq PERL test -z "$NO_PYTHON" && test_set_prereq PYTHON test -n "$USE_LIBPCRE" && test_set_prereq LIBPCRE @@ -1168,9 +659,29 @@ test_i18ngrep () { fi } -# test whether the filesystem supports symbolic links -ln -s x y 2>/dev/null && test -h y 2>/dev/null && test_set_prereq SYMLINKS -rm -f y +test_lazy_prereq SYMLINKS ' + # test whether the filesystem supports symbolic links + ln -s x y && test -h y +' + +test_lazy_prereq CASE_INSENSITIVE_FS ' + echo good >CamelCase && + echo bad >camelcase && + test "$(cat CamelCase)" != good +' + +test_lazy_prereq UTF8_NFD_TO_NFC ' + # check whether FS converts nfd unicode to nfc + auml=$(printf "\303\244") + aumlcdiar=$(printf "\141\314\210") + >"$auml" && + case "$(echo *)" in + "$aumlcdiar") + true ;; + *) + false ;; + esac +' # When the tests are run as root, permission tests will report that # things are writable when they shouldn't be. |