diff options
Diffstat (limited to 't')
279 files changed, 18996 insertions, 4094 deletions
diff --git a/t/Makefile b/t/Makefile index 88e289fc8b..2373a04f7a 100644 --- a/t/Makefile +++ b/t/Makefile @@ -6,16 +6,25 @@ -include ../config.mak.autogen -include ../config.mak -#GIT_TEST_OPTS=--verbose --debug +#GIT_TEST_OPTS = --verbose --debug SHELL_PATH ?= $(SHELL) PERL_PATH ?= /usr/bin/perl TAR ?= $(TAR) RM ?= rm -f PROVE ?= prove DEFAULT_TEST_TARGET ?= test +TEST_LINT ?= test-lint-duplicates test-lint-executable + +ifdef TEST_OUTPUT_DIRECTORY +TEST_RESULTS_DIRECTORY = $(TEST_OUTPUT_DIRECTORY)/test-results +else +TEST_RESULTS_DIRECTORY = test-results +endif # Shell quote; SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) +PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) +TEST_RESULTS_DIRECTORY_SQ = $(subst ','\'',$(TEST_RESULTS_DIRECTORY)) T = $(sort $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)) TSVN = $(sort $(wildcard t91[0-9][0-9]-*.sh)) @@ -34,16 +43,16 @@ $(T): @echo "*** $@ ***"; GIT_CONFIG=.git/config '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS) pre-clean: - $(RM) -r test-results + $(RM) -r '$(TEST_RESULTS_DIRECTORY_SQ)' clean-except-prove-cache: - $(RM) -r 'trash directory'.* test-results + $(RM) -r 'trash directory'.* '$(TEST_RESULTS_DIRECTORY_SQ)' $(RM) -r valgrind/bin clean: clean-except-prove-cache $(RM) .prove -test-lint: test-lint-duplicates test-lint-executable +test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax test-lint-duplicates: @dups=`echo $(T) | tr ' ' '\n' | sed 's/-.*//' | sort | uniq -d` && \ @@ -55,12 +64,15 @@ test-lint-executable: test -z "$$bad" || { \ echo >&2 "non-executable tests:" $$bad; exit 1; } +test-lint-shell-syntax: + @'$(PERL_PATH_SQ)' check-non-portable-shell.pl $(T) + aggregate-results-and-cleanup: $(T) $(MAKE) aggregate-results $(MAKE) clean aggregate-results: - for f in test-results/t*-*.counts; do \ + for f in '$(TEST_RESULTS_DIRECTORY_SQ)'/t*-*.counts; do \ echo "$$f"; \ done | '$(SHELL_PATH_SQ)' ./aggregate-results.sh @@ -78,42 +90,4 @@ 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 @@ -76,6 +76,11 @@ appropriately before running "make". command being run and their output if any are also output. +--verbose-only=<pattern>:: + Like --verbose, but the effect is limited to tests with + numbers matching <pattern>. The number matched against is + simply the running count of the test within the file. + --debug:: This may help the person who is developing a new test. It causes the command defined with test_debug to run. @@ -86,29 +91,46 @@ appropriately before running "make". --immediate:: This causes the test to immediately exit upon the first - failed test. + failed test. Cleanup commands requested with + test_when_finished are not executed if the test failed, + in order to keep the state for inspection by the tester + to diagnose the bug. --long-tests:: This causes additional long-running tests to be run (where available), for more exhaustive testing. ---valgrind:: - Execute all Git binaries with valgrind and exit with status - 126 on errors (just like regular tests, this will only stop - the test script when running under -i). Valgrind errors - go to stderr, so you might want to pass the -v option, too. +--valgrind=<tool>:: + Execute all Git binaries under valgrind tool <tool> and exit + with status 126 on errors (just like regular tests, this will + only stop the test script when running under -i). Since it makes no sense to run the tests with --valgrind and not see any output, this option implies --verbose. For convenience, it also implies --tee. - Note that valgrind is run with the option --leak-check=no, + <tool> defaults to 'memcheck', just like valgrind itself. + Other particularly useful choices include 'helgrind' and + 'drd', but you may use any tool recognized by your valgrind + installation. + + As a special case, <tool> can be 'memcheck-fast', which uses + memcheck but disables --track-origins. Use this if you are + running tests in bulk, to see if there are _any_ memory + issues. + + Note that memcheck is run with the option --leak-check=no, as the git process is short-lived and some errors are not interesting. In order to run a single command under the same conditions manually, you should set GIT_VALGRIND to point to the 't/valgrind/' directory and use the commands under 't/valgrind/bin/'. +--valgrind-only=<pattern>:: + Like --valgrind, but the effect is limited to tests with + numbers matching <pattern>. The number matched against is + simply the running count of the test within the file. + --tee:: In addition to printing the test output to the terminal, write it to files named 't/test-results/$TEST_NAME.out'. @@ -312,6 +334,9 @@ Don't: use 'test_must_fail git cmd'. This will signal a failure if git dies in an unexpected way (e.g. segfault). + On the other hand, don't use test_must_fail for running regular + platform commands; just use '! cmd'. + - 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 @@ -580,6 +605,20 @@ library for your script to use. test_cmp expected actual ' + - test_ln_s_add <path1> <path2> + + This function helps systems whose filesystem does not support symbolic + links. Use it to add a symbolic link entry to the index when it is not + important that the file system entry is a symbolic link, i.e., instead + of the sequence + + ln -s foo bar && + git add bar + + Sometimes it is possible to split a test in a part that does not need + the symbolic link in the file system and a part that does; then only + the latter part need be protected by a SYMLINKS prerequisite (see below). + Prerequisites ------------- @@ -610,6 +649,11 @@ use these, and "test_set_prereq" for how to define your own. The process retains the same pid across exec(2). See fb9a2bea for details. + - PIPE + + The filesystem we're on supports creation of FIFOs (named pipes) + via mkfifo(1). + - SYMLINKS The filesystem we're on supports symbolic links. E.g. a FAT diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index c56a77d237..0bfee001b4 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -2,11 +2,21 @@ # sourced from t8001-annotate.sh and t8002-blame.sh. check_count () { - head= - case "$1" in -h) head="$2"; shift; shift ;; esac - echo "$PROG file $head" >&4 - $PROG file $head >.result || return 1 - cat .result | perl -e ' + head= && + file='file' && + options= && + while : + do + case "$1" in + -h) head="$2"; shift; shift ;; + -f) file="$2"; shift; shift ;; + -*) options="$options $1"; shift ;; + *) break ;; + esac + done && + echo "$PROG $options $file $head" >&4 && + $PROG $options $file $head >actual && + perl -e ' my %expect = (@ARGV); my %count = map { $_ => 0 } keys %expect; while (<STDIN>) { @@ -31,107 +41,246 @@ check_count () { print STDERR "Author $author (expected $value, attributed $count) $ok\n"; } exit($bad); - ' "$@" + ' "$@" <actual } -test_expect_success \ - 'prepare reference tree' \ - 'echo "1A quick brown fox jumps over the" >file && - echo "lazy dog" >>file && - git add file && - GIT_AUTHOR_NAME="A" GIT_AUTHOR_EMAIL="A@test.git" git commit -a -m "Initial."' - -test_expect_success \ - 'check all lines blamed on A' \ - 'check_count A 2' - -test_expect_success \ - 'Setup new lines blamed on B' \ - 'echo "2A quick brown fox jumps over the" >>file && - echo "lazy dog" >> file && - GIT_AUTHOR_NAME="B" GIT_AUTHOR_EMAIL="B@test.git" git commit -a -m "Second."' - -test_expect_success \ - 'Two lines blamed on A, two on B' \ - 'check_count A 2 B 2' - -test_expect_success \ - 'merge-setup part 1' \ - 'git checkout -b branch1 master && - echo "3A slow green fox jumps into the" >> file && - echo "well." >> file && - GIT_AUTHOR_NAME="B1" GIT_AUTHOR_EMAIL="B1@test.git" git commit -a -m "Branch1-1"' - -test_expect_success \ - 'Two lines blamed on A, two on B, two on B1' \ - 'check_count A 2 B 2 B1 2' - -test_expect_success \ - 'merge-setup part 2' \ - 'git checkout -b branch2 master && - sed -e "s/2A quick brown/4A quick brown lazy dog/" < file > file.new && - mv file.new file && - GIT_AUTHOR_NAME="B2" GIT_AUTHOR_EMAIL="B2@test.git" git commit -a -m "Branch2-1"' - -test_expect_success \ - 'Two lines blamed on A, one on B, one on B2' \ - 'check_count A 2 B 1 B2 1' - -test_expect_success \ - 'merge-setup part 3' \ - 'git pull . branch1' - -test_expect_success \ - 'Two lines blamed on A, one on B, two on B1, one on B2' \ - 'check_count A 2 B 1 B1 2 B2 1' - -test_expect_success \ - 'Annotating an old revision works' \ - 'check_count -h master A 2 B 2' - -test_expect_success \ - 'Annotating an old revision works' \ - 'check_count -h master^ A 2' - -test_expect_success \ - 'merge-setup part 4' \ - 'echo "evil merge." >>file && - git commit -a --amend' - -test_expect_success \ - 'Two lines blamed on A, one on B, two on B1, one on B2, one on A U Thor' \ - 'check_count A 2 B 1 B1 2 B2 1 "A U Thor" 1' - -test_expect_success \ - 'an incomplete line added' \ - 'echo "incomplete" | tr -d "\\012" >>file && - GIT_AUTHOR_NAME="C" GIT_AUTHOR_EMAIL="C@test.git" git commit -a -m "Incomplete"' - -test_expect_success \ - 'With incomplete lines.' \ - 'check_count A 2 B 1 B1 2 B2 1 "A U Thor" 1 C 1' - -test_expect_success \ - 'some edit' \ - 'mv file file.orig && - { - cat file.orig && - echo - } | sed -e "s/^3A/99/" -e "/^1A/d" -e "/^incomplete/d" > file && - echo "incomplete" | tr -d "\\012" >>file && - GIT_AUTHOR_NAME="D" GIT_AUTHOR_EMAIL="D@test.git" git commit -a -m "edit"' - -test_expect_success \ - 'some edit' \ - 'check_count A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1' - -test_expect_success \ - 'an obfuscated email added' \ - 'echo "No robots allowed" > file.new && - cat file >> file.new && - mv file.new file && - GIT_AUTHOR_NAME="E" GIT_AUTHOR_EMAIL="E at test dot git" git commit -a -m "norobots"' - -test_expect_success \ - 'obfuscated email parsed' \ - 'check_count A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1 E 1' +test_expect_success 'setup A lines' ' + echo "1A quick brown fox jumps over the" >file && + echo "lazy dog" >>file && + git add file && + GIT_AUTHOR_NAME="A" GIT_AUTHOR_EMAIL="A@test.git" \ + git commit -a -m "Initial." +' + +test_expect_success 'blame 1 author' ' + check_count A 2 +' + +test_expect_success 'setup B lines' ' + echo "2A quick brown fox jumps over the" >>file && + echo "lazy dog" >>file && + GIT_AUTHOR_NAME="B" GIT_AUTHOR_EMAIL="B@test.git" \ + git commit -a -m "Second." +' + +test_expect_success 'blame 2 authors' ' + check_count A 2 B 2 +' + +test_expect_success 'setup B1 lines (branch1)' ' + git checkout -b branch1 master && + echo "3A slow green fox jumps into the" >>file && + echo "well." >>file && + GIT_AUTHOR_NAME="B1" GIT_AUTHOR_EMAIL="B1@test.git" \ + git commit -a -m "Branch1-1" +' + +test_expect_success 'blame 2 authors + 1 branch1 author' ' + check_count A 2 B 2 B1 2 +' + +test_expect_success 'setup B2 lines (branch2)' ' + git checkout -b branch2 master && + sed -e "s/2A quick brown/4A quick brown lazy dog/" <file >file.new && + mv file.new file && + GIT_AUTHOR_NAME="B2" GIT_AUTHOR_EMAIL="B2@test.git" \ + git commit -a -m "Branch2-1" +' + +test_expect_success 'blame 2 authors + 1 branch2 author' ' + check_count A 2 B 1 B2 1 +' + +test_expect_success 'merge branch1 & branch2' ' + git pull . branch1 +' + +test_expect_success 'blame 2 authors + 2 merged-in authors' ' + check_count A 2 B 1 B1 2 B2 1 +' + +test_expect_success 'blame ancestor' ' + check_count -h master A 2 B 2 +' + +test_expect_success 'blame great-ancestor' ' + check_count -h master^ A 2 +' + +test_expect_success 'setup evil merge' ' + echo "evil merge." >>file && + git commit -a --amend +' + +test_expect_success 'blame evil merge' ' + check_count A 2 B 1 B1 2 B2 1 "A U Thor" 1 +' + +test_expect_success 'setup incomplete line' ' + echo "incomplete" | tr -d "\\012" >>file && + GIT_AUTHOR_NAME="C" GIT_AUTHOR_EMAIL="C@test.git" \ + git commit -a -m "Incomplete" +' + +test_expect_success 'blame incomplete line' ' + check_count A 2 B 1 B1 2 B2 1 "A U Thor" 1 C 1 +' + +test_expect_success 'setup edits' ' + mv file file.orig && + { + cat file.orig && + echo + } | sed -e "s/^3A/99/" -e "/^1A/d" -e "/^incomplete/d" >file && + echo "incomplete" | tr -d "\\012" >>file && + GIT_AUTHOR_NAME="D" GIT_AUTHOR_EMAIL="D@test.git" \ + git commit -a -m "edit" +' + +test_expect_success 'blame edits' ' + check_count A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1 +' + +test_expect_success 'setup obfuscated email' ' + echo "No robots allowed" >file.new && + cat file >>file.new && + mv file.new file && + GIT_AUTHOR_NAME="E" GIT_AUTHOR_EMAIL="E at test dot git" \ + git commit -a -m "norobots" +' + +test_expect_success 'blame obfuscated email' ' + check_count A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1 E 1 +' + +test_expect_success 'blame -L 1 (all)' ' + check_count -L1 A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1 E 1 +' + +test_expect_success 'blame -L , (all)' ' + check_count -L, A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1 E 1 +' + +test_expect_success 'blame -L X (X to end)' ' + check_count -L5 B1 1 C 1 D 1 "A U Thor" 1 +' + +test_expect_success 'blame -L X, (X to end)' ' + check_count -L5, B1 1 C 1 D 1 "A U Thor" 1 +' + +test_expect_success 'blame -L ,Y (up to Y)' ' + check_count -L,3 A 1 B2 1 E 1 +' + +test_expect_success 'blame -L X,X' ' + check_count -L3,3 B2 1 +' + +test_expect_success 'blame -L X,Y' ' + check_count -L3,6 B 1 B1 1 B2 1 D 1 +' + +test_expect_success 'blame -L Y,X (undocumented)' ' + check_count -L6,3 B 1 B1 1 B2 1 D 1 +' + +test_expect_success 'blame -L X,+1' ' + check_count -L3,+1 B2 1 +' + +test_expect_success 'blame -L X,+N' ' + check_count -L3,+4 B 1 B1 1 B2 1 D 1 +' + +test_expect_success 'blame -L X,-1' ' + check_count -L3,-1 B2 1 +' + +test_expect_success 'blame -L X,-N' ' + check_count -L6,-4 B 1 B1 1 B2 1 D 1 +' + +test_expect_success 'blame -L /RE/ (RE to end)' ' + check_count -L/evil/ C 1 "A U Thor" 1 +' + +test_expect_success 'blame -L /RE/,/RE2/' ' + check_count -L/robot/,/green/ A 1 B 1 B2 1 D 1 E 1 +' + +test_expect_success 'blame -L X,/RE/' ' + check_count -L5,/evil/ B1 1 D 1 "A U Thor" 1 +' + +test_expect_success 'blame -L /RE/,Y' ' + check_count -L/99/,7 B1 1 D 1 "A U Thor" 1 +' + +test_expect_success 'blame -L /RE/,+N' ' + check_count -L/99/,+3 B1 1 D 1 "A U Thor" 1 +' + +test_expect_success 'blame -L /RE/,-N' ' + check_count -L/99/,-3 B 1 B2 1 D 1 +' + +test_expect_success 'blame -L X (X > nlines)' ' + test_must_fail $PROG -L12345 file +' + +test_expect_success 'blame -L ,Y (Y > nlines)' ' + test_must_fail $PROG -L,12345 file +' + +test_expect_success 'setup -L :regex' ' + tr Q "\\t" >hello.c <<-\EOF && + int main(int argc, const char *argv[]) + { + Qputs("hello"); + } + EOF + git add hello.c && + GIT_AUTHOR_NAME="F" GIT_AUTHOR_EMAIL="F@test.git" \ + git commit -m "hello" && + + mv hello.c hello.orig && + sed -e "/}/i\\ + Qputs(\"goodbye\");" <hello.orig | tr Q "\\t" >hello.c && + GIT_AUTHOR_NAME="G" GIT_AUTHOR_EMAIL="G@test.git" \ + git commit -a -m "goodbye" && + + mv hello.c hello.orig && + echo "#include <stdio.h>" >hello.c && + cat hello.orig >>hello.c && + tr Q "\\t" >>hello.c <<-\EOF + void mail() + { + Qputs("mail"); + } + EOF + GIT_AUTHOR_NAME="H" GIT_AUTHOR_EMAIL="H@test.git" \ + git commit -a -m "mail" +' + +test_expect_success 'blame -L :literal' ' + check_count -f hello.c -L:main F 4 G 1 +' + +test_expect_success 'blame -L :regex' ' + check_count -f hello.c "-L:m[a-z][a-z]l" H 4 +' + +test_expect_success 'blame -L :nomatch' ' + test_must_fail $PROG -L:nomatch hello.c +' + +test_expect_success 'blame -L bogus' ' + test_must_fail $PROG -L file && + test_must_fail $PROG -L1,+ file && + test_must_fail $PROG -L1,- file && + test_must_fail $PROG -LX file && + test_must_fail $PROG -L1,X file && + test_must_fail $PROG -L1,+N file && + test_must_fail $PROG -L1,-N file +' diff --git a/t/check-non-portable-shell.pl b/t/check-non-portable-shell.pl new file mode 100755 index 0000000000..45971f43b7 --- /dev/null +++ b/t/check-non-portable-shell.pl @@ -0,0 +1,28 @@ +#!/usr/bin/perl + +# Test t0000..t9999.sh for non portable shell scripts +# This script can be called with one or more filenames as parameters + +use strict; +use warnings; + +my $exit_code=0; + +sub err { + my $msg = shift; + print "$ARGV:$.: error: $msg: $_\n"; + $exit_code = 1; +} + +while (<>) { + chomp; + /^\s*sed\s+-i/ and err 'sed -i is not portable'; + /^\s*echo\s+-n/ and err 'echo -n is not portable (please use printf)'; + /^\s*declare\s+/ and err 'arrays/declare not portable'; + /^\s*[^#]\s*which\s/ and err 'which is not portable (please use type)'; + /test\s+[^=]*==/ and err '"test a == b" is not portable (please use =)'; + /^\s*export\s+[^=]*=/ and err '"export FOO=bar" is not portable (please use FOO=bar && export FOO)'; + # this resets our $. for each file + close ARGV if eof; +} +exit $exit_code; diff --git a/t/lib-gettext.sh b/t/lib-gettext.sh index 0f76f6cdc0..ae8883a075 100644 --- a/t/lib-gettext.sh +++ b/t/lib-gettext.sh @@ -14,12 +14,14 @@ export GIT_TEXTDOMAINDIR GIT_PO_PATH if test_have_prereq GETTEXT && ! test_have_prereq GETTEXT_POISON then # is_IS.UTF-8 on Solaris and FreeBSD, is_IS.utf8 on Debian - is_IS_locale=$(locale -a | sed -n '/^is_IS\.[uU][tT][fF]-*8$/{ + is_IS_locale=$(locale -a 2>/dev/null | + sed -n '/^is_IS\.[uU][tT][fF]-*8$/{ p q }') # is_IS.ISO8859-1 on Solaris and FreeBSD, is_IS.iso88591 on Debian - is_IS_iso_locale=$(locale -a | sed -n '/^is_IS\.[iI][sS][oO]8859-*1$/{ + is_IS_iso_locale=$(locale -a 2>/dev/null | + sed -n '/^is_IS\.[iI][sS][oO]8859-*1$/{ p q }') diff --git a/t/lib-git-p4.sh b/t/lib-git-p4.sh index 7061dce7e5..2098b9ba05 100644 --- a/t/lib-git-p4.sh +++ b/t/lib-git-p4.sh @@ -8,7 +8,8 @@ TEST_NO_CREATE_REPO=NoThanks . ./test-lib.sh -if ! test_have_prereq PYTHON; then +if ! test_have_prereq PYTHON +then skip_all='skipping git p4 tests; python not available' test_done fi @@ -17,6 +18,24 @@ fi test_done } +# On cygwin, the NT version of Perforce can be used. When giving +# it paths, either on the command-line or in client specifications, +# be sure to use the native windows form. +# +# Older versions of perforce were available compiled natively for +# cygwin. Those do not accept native windows paths, so make sure +# not to convert for them. +native_path() { + path="$1" && + if test_have_prereq CYGWIN && ! p4 -V | grep -q CYGWIN + then + path=$(cygpath --windows "$path") + else + path=$(test-path-utils real_path "$path") + fi && + echo "$path" +} + # Try to pick a unique port: guess a large number, then hope # no more than one of each test is running. # @@ -32,7 +51,7 @@ P4EDITOR=: export P4PORT P4CLIENT P4EDITOR db="$TRASH_DIRECTORY/db" -cli=$(test-path-utils real_path "$TRASH_DIRECTORY/cli") +cli="$TRASH_DIRECTORY/cli" git="$TRASH_DIRECTORY/git" pidfile="$TRASH_DIRECTORY/p4d.pid" @@ -40,8 +59,11 @@ start_p4d() { mkdir -p "$db" "$cli" "$git" && rm -f "$pidfile" && ( - p4d -q -r "$db" -p $P4DPORT & - echo $! >"$pidfile" + cd "$db" && + { + p4d -q -p $P4DPORT & + echo $! >"$pidfile" + } ) && # This gives p4d a long time to start up, as it can be @@ -74,15 +96,8 @@ start_p4d() { fi # build a client - ( - cd "$cli" && - p4 client -i <<-EOF - Client: client - Description: client - Root: $cli - View: //depot/... //client/... - EOF - ) + client_view "//depot/... //client/..." && + return 0 } @@ -123,13 +138,26 @@ marshal_dump() { client_view() { ( cat <<-EOF && - Client: client - Description: client + Client: $P4CLIENT + Description: $P4CLIENT Root: $cli + AltRoots: $(native_path "$cli") + LineEnd: unix View: EOF - for arg ; do - printf "\t$arg\n" - done + printf "\t%s\n" "$@" ) | p4 client -i } + +is_cli_file_writeable() { + # cygwin version of p4 does not set read-only attr, + # will be marked 444 but -w is true + file="$1" && + if test_have_prereq CYGWIN && p4 -V | grep -q CYGWIN + then + stat=$(stat --format=%a "$file") && + test $stat = 644 + else + test -w "$file" + fi +} diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh index 199f22c231..c5e55b190b 100644 --- a/t/lib-git-svn.sh +++ b/t/lib-git-svn.sh @@ -148,7 +148,7 @@ stop_httpd () { convert_to_rev_db () { "$PERL_PATH" -w -- - "$@" <<\EOF use strict; -@ARGV == 2 or die "Usage: convert_to_rev_db <input> <output>"; +@ARGV == 2 or die "usage: convert_to_rev_db <input> <output>"; open my $wr, '+>', $ARGV[1] or die "$!: couldn't open: $ARGV[1]"; open my $rd, '<', $ARGV[0] or die "$!: couldn't open: $ARGV[0]"; my $size = (stat($rd))[7]; diff --git a/t/lib-gpg/pubring.gpg b/t/lib-gpg/pubring.gpg Binary files differindex 83855fa4e1..1a3c2d487c 100644 --- a/t/lib-gpg/pubring.gpg +++ b/t/lib-gpg/pubring.gpg diff --git a/t/lib-gpg/random_seed b/t/lib-gpg/random_seed Binary files differindex 8fed1339ed..95d249f15f 100644 --- a/t/lib-gpg/random_seed +++ b/t/lib-gpg/random_seed diff --git a/t/lib-gpg/secring.gpg b/t/lib-gpg/secring.gpg Binary files differindex d831cd9eb3..82dca8f80b 100644 --- a/t/lib-gpg/secring.gpg +++ b/t/lib-gpg/secring.gpg diff --git a/t/lib-gpg/trustdb.gpg b/t/lib-gpg/trustdb.gpg Binary files differindex abace962b8..4879ae9a84 100644 --- a/t/lib-gpg/trustdb.gpg +++ b/t/lib-gpg/trustdb.gpg diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh index 02f442bfad..895b9258b0 100644 --- a/t/lib-httpd.sh +++ b/t/lib-httpd.sh @@ -80,6 +80,7 @@ fi prepare_httpd() { mkdir -p "$HTTPD_DOCUMENT_ROOT_PATH" cp "$TEST_PATH"/passwd "$HTTPD_ROOT_PATH" + cp "$TEST_PATH"/broken-smart-http.sh "$HTTPD_ROOT_PATH" ln -s "$LIB_HTTPD_MODULE_PATH" "$HTTPD_ROOT_PATH/modules" diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf index 49d5d877ce..dd17e3a09d 100644 --- a/t/lib-httpd/apache.conf +++ b/t/lib-httpd/apache.conf @@ -1,5 +1,4 @@ ServerName dummy -LockFile accept.lock PidFile httpd.pid DocumentRoot www LogFormat "%h %l %u %t \"%r\" %>s %b" common @@ -24,6 +23,10 @@ ErrorLog error.log LoadModule version_module modules/mod_version.so </IfModule> +<IfVersion < 2.4> +LockFile accept.lock +</IfVersion> + <IfVersion < 2.1> <IfModule !mod_auth.c> LoadModule auth_module modules/mod_auth.so @@ -40,6 +43,24 @@ ErrorLog error.log <IfModule !mod_authz_user.c> LoadModule authz_user_module modules/mod_authz_user.so </IfModule> +<IfModule !mod_authz_host.c> + LoadModule authz_host_module modules/mod_authz_host.so +</IfModule> +</IfVersion> + +<IfVersion >= 2.4> +<IfModule !mod_authn_core.c> + LoadModule authn_core_module modules/mod_authn_core.so +</IfModule> +<IfModule !mod_authz_core.c> + LoadModule authz_core_module modules/mod_authz_core.so +</IfModule> +<IfModule !mod_access_compat.c> + LoadModule access_compat_module modules/mod_access_compat.so +</IfModule> +<IfModule !mod_mpm_prefork.c> + LoadModule mpm_prefork_module modules/mod_mpm_prefork.so +</IfModule> </IfVersion> PassEnv GIT_VALGRIND @@ -61,10 +82,19 @@ Alias /auth/dumb/ www/auth/dumb/ SetEnv GIT_COMMITTER_NAME "Custom User" SetEnv GIT_COMMITTER_EMAIL custom@example.com </LocationMatch> +<LocationMatch /smart_namespace/> + SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH} + SetEnv GIT_HTTP_EXPORT_ALL + SetEnv GIT_NAMESPACE ns +</LocationMatch> ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1 +ScriptAlias /broken_smart/ broken-smart-http.sh/ <Directory ${GIT_EXEC_PATH}> Options FollowSymlinks </Directory> +<Files broken-smart-http.sh> + Options ExecCGI +</Files> <Files ${GIT_EXEC_PATH}/git-http-backend> Options ExecCGI </Files> @@ -99,6 +129,28 @@ SSLEngine On Require valid-user </LocationMatch> +<LocationMatch "^/auth-fetch/.*/git-upload-pack$"> + AuthType Basic + AuthName "git-auth" + AuthUserFile passwd + Require valid-user +</LocationMatch> + +RewriteCond %{QUERY_STRING} service=git-receive-pack [OR] +RewriteCond %{REQUEST_URI} /git-receive-pack$ +RewriteRule ^/half-auth-complete/ - [E=AUTHREQUIRED:yes] + +<Location /half-auth-complete/> + Order Deny,Allow + Deny from env=AUTHREQUIRED + + AuthType Basic + AuthName "Git Access" + AuthUserFile passwd + Require valid-user + Satisfy Any +</Location> + <IfDefine DAV> LoadModule dav_module modules/mod_dav.so LoadModule dav_fs_module modules/mod_dav_fs.so diff --git a/t/lib-httpd/broken-smart-http.sh b/t/lib-httpd/broken-smart-http.sh new file mode 100755 index 0000000000..f7ebfffa80 --- /dev/null +++ b/t/lib-httpd/broken-smart-http.sh @@ -0,0 +1,11 @@ +#!/bin/sh +printf "Content-Type: text/%s\n" "html" +echo +printf "%s\n" "001e# service=git-upload-pack" +printf "%s" "0000" +printf "%s%c%s%s\n" \ + "00a58681d9f286a48b08f37b3a095330da16689e3693 HEAD" \ + 0 \ + " include-tag multi_ack_detailed multi_ack ofs-delta" \ + " side-band side-band-64k thin-pack no-progress shallow no-done " +printf "%s" "0000" diff --git a/t/lib-rebase.sh b/t/lib-rebase.sh index 6ccf797091..8ff87fb3f9 100644 --- a/t/lib-rebase.sh +++ b/t/lib-rebase.sh @@ -17,51 +17,98 @@ # ("squash", "fixup", "edit", or "reword") and the SHA1 taken # from the specified line. # +# "exec_cmd_with_args" -- add an "exec cmd with args" line. +# # "#" -- Add a comment line. # # ">" -- Add a blank line. set_fake_editor () { - echo "#!$SHELL_PATH" >fake-editor.sh - cat >> fake-editor.sh <<\EOF -case "$1" in -*/COMMIT_EDITMSG) - test -z "$EXPECT_HEADER_COUNT" || - test "$EXPECT_HEADER_COUNT" = "$(sed -n '1s/^# This is a combination of \(.*\) commits\./\1/p' < "$1")" || + write_script fake-editor.sh <<-\EOF + case "$1" in + */COMMIT_EDITMSG) + test -z "$EXPECT_HEADER_COUNT" || + test "$EXPECT_HEADER_COUNT" = "$(sed -n '1s/^# This is a combination of \(.*\) commits\./\1/p' < "$1")" || + exit + test -z "$FAKE_COMMIT_MESSAGE" || echo "$FAKE_COMMIT_MESSAGE" > "$1" + test -z "$FAKE_COMMIT_AMEND" || echo "$FAKE_COMMIT_AMEND" >> "$1" exit - test -z "$FAKE_COMMIT_MESSAGE" || echo "$FAKE_COMMIT_MESSAGE" > "$1" - test -z "$FAKE_COMMIT_AMEND" || echo "$FAKE_COMMIT_AMEND" >> "$1" - exit - ;; -esac -test -z "$EXPECT_COUNT" || - test "$EXPECT_COUNT" = $(sed -e '/^#/d' -e '/^$/d' < "$1" | wc -l) || - exit -test -z "$FAKE_LINES" && exit -grep -v '^#' < "$1" > "$1".tmp -rm -f "$1" -echo 'rebase -i script before editing:' -cat "$1".tmp -action=pick -for line in $FAKE_LINES; do - case $line in - squash|fixup|edit|reword) - action="$line";; - exec*) - echo "$line" | sed 's/_/ /g' >> "$1";; - "#") - echo '# comment' >> "$1";; - ">") - echo >> "$1";; - *) - sed -n "${line}s/^pick/$action/p" < "$1".tmp >> "$1" - action=pick;; + ;; esac -done -echo 'rebase -i script after editing:' -cat "$1" -EOF + test -z "$EXPECT_COUNT" || + test "$EXPECT_COUNT" = $(sed -e '/^#/d' -e '/^$/d' < "$1" | wc -l) || + exit + test -z "$FAKE_LINES" && exit + grep -v '^#' < "$1" > "$1".tmp + rm -f "$1" + echo 'rebase -i script before editing:' + cat "$1".tmp + action=pick + for line in $FAKE_LINES; do + case $line in + squash|fixup|edit|reword) + action="$line";; + exec*) + echo "$line" | sed 's/_/ /g' >> "$1";; + "#") + echo '# comment' >> "$1";; + ">") + echo >> "$1";; + *) + sed -n "${line}s/^pick/$action/p" < "$1".tmp >> "$1" + action=pick;; + esac + done + echo 'rebase -i script after editing:' + cat "$1" + EOF + + test_set_editor "$(pwd)/fake-editor.sh" +} + +# After set_cat_todo_editor, rebase -i will write the todo list (ignoring +# blank lines and comments) to stdout, and exit failure (so you should run +# it with test_must_fail). This can be used to verify the expected user +# experience, for todo list changes that do not affect the outcome of +# rebase; or as an extra check in addition to checking the outcome. +set_cat_todo_editor () { + write_script fake-editor.sh <<-\EOF + grep "^[^#]" "$1" + exit 1 + EOF test_set_editor "$(pwd)/fake-editor.sh" - chmod a+x fake-editor.sh +} + +# checks that the revisions in "$2" represent a linear range with the +# subjects in "$1" +test_linear_range () { + revlist_merges=$(git rev-list --merges "$2") && + test -z "$revlist_merges" && + expected=$1 + set -- $(git log --reverse --format=%s "$2") + test "$expected" = "$*" +} + +reset_rebase () { + test_might_fail git rebase --abort && + git reset --hard && + git clean -f +} + +cherry_pick () { + git cherry-pick -n "$2" && + git commit -m "$1" && + git tag "$1" +} + +revert () { + git revert -n "$2" && + git commit -m "$1" && + git tag "$1" +} + +make_empty () { + git commit --allow-empty -m "$1" && + git tag "$1" } diff --git a/t/lib-t6000.sh b/t/lib-t6000.sh index ea25dd89e5..4ffd90127e 100644 --- a/t/lib-t6000.sh +++ b/t/lib-t6000.sh @@ -1,55 +1,50 @@ : included from 6002 and others -[ -d .git/refs/tags ] || mkdir -p .git/refs/tags +mkdir -p .git/refs/tags -:> sed.script +>sed.script -# Answer the sha1 has associated with the tag. The tag must exist in .git or .git/refs/tags -tag() -{ +# Answer the sha1 has associated with the tag. The tag must exist in .git/refs/tags +tag () { _tag=$1 - [ -f .git/refs/tags/$_tag ] || error "tag: \"$_tag\" does not exist" - cat .git/refs/tags/$_tag + test -f ".git/refs/tags/$_tag" || error "tag: \"$_tag\" does not exist" + cat ".git/refs/tags/$_tag" } # Generate a commit using the text specified to make it unique and the tree # named by the tag specified. -unique_commit() -{ +unique_commit () { _text=$1 - _tree=$2 + _tree=$2 shift 2 - echo $_text | git commit-tree $(tag $_tree) "$@" + echo "$_text" | git commit-tree $(tag "$_tree") "$@" } # Save the output of a command into the tag specified. Prepend # a substitution script for the tag onto the front of sed.script -save_tag() -{ +save_tag () { _tag=$1 - [ -n "$_tag" ] || error "usage: save_tag tag commit-args ..." + test -n "$_tag" || error "usage: save_tag tag commit-args ..." shift 1 - "$@" >.git/refs/tags/$_tag + "$@" >".git/refs/tags/$_tag" - echo "s/$(tag $_tag)/$_tag/g" > sed.script.tmp - cat sed.script >> sed.script.tmp + echo "s/$(tag $_tag)/$_tag/g" >sed.script.tmp + cat sed.script >>sed.script.tmp rm sed.script mv sed.script.tmp sed.script } # Replace unhelpful sha1 hashses with their symbolic equivalents -entag() -{ +entag () { sed -f sed.script } # Execute a command after first saving, then setting the GIT_AUTHOR_EMAIL # tag to a specified value. Restore the original value on return. -as_author() -{ +as_author () { _author=$1 shift 1 - _save=$GIT_AUTHOR_EMAIL + _save=$GIT_AUTHOR_EMAIL GIT_AUTHOR_EMAIL="$_author" export GIT_AUTHOR_EMAIL @@ -63,45 +58,58 @@ as_author() fi } -commit_date() -{ - _commit=$1 - git cat-file commit $_commit | sed -n "s/^committer .*> \([0-9]*\) .*/\1/p" +commit_date () { + _commit=$1 + git cat-file commit $_commit | + sed -n "s/^committer .*> \([0-9]*\) .*/\1/p" } -on_committer_date() -{ - _date=$1 - shift 1 - GIT_COMMITTER_DATE="$_date" - export GIT_COMMITTER_DATE - "$@" - unset GIT_COMMITTER_DATE +# Assign the value of fake date to a variable, but +# allow fairly common "1971-08-16 00:00" to be omittd +assign_fake_date () { + case "$2" in + ??:??:??) eval "$1='1971-08-16 $2'" ;; + ??:??) eval "$1='1971-08-16 00:$2'" ;; + ??) eval "$1='1971-08-16 00:00:$2'" ;; + *) eval "$1='$2'" ;; + esac +} + +on_committer_date () { + assign_fake_date GIT_COMMITTER_DATE "$1" + export GIT_COMMITTER_DATE + shift 1 + "$@" +} + +on_dates () { + assign_fake_date GIT_COMMITTER_DATE "$1" + assign_fake_date GIT_AUTHOR_DATE "$2" + export GIT_COMMITTER_DATE GIT_AUTHOR_DATE + shift 2 + "$@" } # Execute a command and suppress any error output. -hide_error() -{ +hide_error () { "$@" 2>/dev/null } -check_output() -{ +check_output () { _name=$1 shift 1 - if eval "$*" | entag > $_name.actual + if eval "$*" | entag >"$_name.actual" then - test_cmp $_name.expected $_name.actual + test_cmp "$_name.expected" "$_name.actual" else - return 1; + return 1 fi } # Turn a reasonable test description into a reasonable test name. # All alphanums translated into -'s which are then compressed and stripped # from front and back. -name_from_description() -{ +name_from_description () { perl -pe ' s/[^A-Za-z0-9.]/-/g; s/-+/-/g; @@ -119,9 +127,11 @@ name_from_description() test_output_expect_success() { _description=$1 - _test=$2 - [ $# -eq 2 ] || error "usage: test_output_expect_success description test <<EOF ... EOF" - _name=$(echo $_description | name_from_description) - cat > $_name.expected + _test=$2 + test $# -eq 2 || + error "usage: test_output_expect_success description test <<EOF ... EOF" + + _name=$(echo $_description | name_from_description) + cat >"$_name.expected" test_expect_success "$_description" "check_output $_name \"$_test\"" } diff --git a/t/perf/README b/t/perf/README index b2dbad4d50..8848c14619 100644 --- a/t/perf/README +++ b/t/perf/README @@ -56,7 +56,7 @@ 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. + measurements. Defaults to 3. GIT_PERF_MAKE_OPTS Options to use when automatically building a git tree for @@ -66,7 +66,7 @@ You can set the following variables (also in your config.mak): 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. + probably be about linux.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 diff --git a/t/perf/p0002-read-cache.sh b/t/perf/p0002-read-cache.sh new file mode 100755 index 0000000000..9180ae9343 --- /dev/null +++ b/t/perf/p0002-read-cache.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +test_description="Tests performance of reading the index" + +. ./perf-lib.sh + +test_perf_default_repo + +count=1000 +test_perf "read_cache/discard_cache $count times" " + test-read-cache $count +" + +test_done diff --git a/t/perf/p4211-line-log.sh b/t/perf/p4211-line-log.sh new file mode 100755 index 0000000000..3d074b0e41 --- /dev/null +++ b/t/perf/p4211-line-log.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +test_description='Tests log -L performance' +. ./perf-lib.sh + +test_perf_default_repo + +# Pick a file to log pseudo-randomly. The sort key is the blob hash, +# so it is stable. +test_expect_success 'select a file' ' + git ls-tree HEAD | grep ^100644 | + sort -k 3 | head -1 | cut -f 2 >filelist +' + +file=$(cat filelist) +export file + +test_perf 'git rev-list --topo-order (baseline)' ' + git rev-list --topo-order HEAD >/dev/null +' + +test_perf 'git log --follow (baseline for -M)' ' + git log --oneline --follow -- "$file" >/dev/null +' + +test_perf 'git log -L' ' + git log -L 1:"$file" >/dev/null +' + +test_perf 'git log -M -L' ' + git log -M -L 1:"$file" >/dev/null +' + +test_done diff --git a/t/perf/perf-lib.sh b/t/perf/perf-lib.sh index a816fbcb76..c61d5351e1 100644 --- a/t/perf/perf-lib.sh +++ b/t/perf/perf-lib.sh @@ -150,6 +150,7 @@ exit $ret' >&3 2>&4 test_perf () { + test_start_ 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" @@ -187,7 +188,7 @@ test_perf () { 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 "" + test_finish_ } # We extend test_done to print timings at the end (./run disables this diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 08677df10e..10be52beed 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -45,39 +45,236 @@ test_expect_failure 'pretend we have a known breakage' ' 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 +run_sub_test_lib_test () { + name="$1" descr="$2" # stdin is the body of the test code + shift 2 + mkdir "$name" && + ( + # Pretend we're a test harness. This prevents + # test-lib from writing the counts to a file that will + # later be summarized, showing spurious "failed" tests + HARNESS_ACTIVE=t && + export HARNESS_ACTIVE && + cd "$name" && + cat >"$name.sh" <<-EOF && + #!$SHELL_PATH + + test_description='$descr (run in sub test-lib) + + 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-lib.sh + EOF + cat >>"$name.sh" && + chmod +x "$name.sh" && + export TEST_DIRECTORY && + ./"$name.sh" "$@" >out 2>err + ) +} - This is run in a sub test-lib so that we do not get incorrect - passing metrics - ' +check_sub_test_lib_test () { + name="$1" # stdin is the expected output from the test + ( + cd "$name" && + ! test -s err && + sed -e 's/^> //' -e 's/Z$//' >expect && + test_cmp expect out + ) +} + +test_expect_success 'pretend we have a fully passing test suite' " + run_sub_test_lib_test full-pass '3 passing tests' <<-\\EOF && + for i in 1 2 3 + do + test_expect_success \"passing test #\$i\" 'true' + done + test_done + EOF + check_sub_test_lib_test full-pass <<-\\EOF + > ok 1 - passing test #1 + > ok 2 - passing test #2 + > ok 3 - passing test #3 + > # passed all 3 test(s) + > 1..3 + EOF +" - # 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 'pretend we have a partially passing test suite' " + test_must_fail run_sub_test_lib_test \ + partial-pass '2/3 tests passing' <<-\\EOF && + test_expect_success 'passing test #1' 'true' + test_expect_success 'failing test #2' 'false' + test_expect_success 'passing test #3' 'true' + test_done + EOF + check_sub_test_lib_test partial-pass <<-\\EOF + > ok 1 - passing test #1 + > not ok 2 - failing test #2 + # false + > ok 3 - passing test #3 + > # failed 1 among 3 test(s) + > 1..3 + EOF +" - test_expect_failure 'pretend we have fixed a known breakage' ' - : - ' +test_expect_success 'pretend we have a known breakage' " + run_sub_test_lib_test failing-todo 'A failing TODO test' <<-\\EOF && + test_expect_success 'passing test' 'true' + test_expect_failure 'pretend we have a known breakage' 'false' + test_done + EOF + check_sub_test_lib_test failing-todo <<-\\EOF + > ok 1 - passing test + > not ok 2 - pretend we have a known breakage # TODO known breakage + > # still have 1 known breakage(s) + > # passed all remaining 1 test(s) + > 1..2 + EOF +" +test_expect_success 'pretend we have fixed a known breakage' " + run_sub_test_lib_test passing-todo 'A passing TODO test' <<-\\EOF && + test_expect_failure 'pretend we have fixed a known breakage' 'true' 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) + check_sub_test_lib_test passing-todo <<-\\EOF + > ok 1 - pretend we have fixed a known breakage # TODO known breakage vanished + > # 1 known breakage(s) vanished; please update test(s) > 1..1 EOF - test_cmp expect out) " + +test_expect_success 'pretend we have fixed one of two known breakages (run in sub test-lib)' " + run_sub_test_lib_test partially-passing-todos \ + '2 TODO tests, one passing' <<-\\EOF && + test_expect_failure 'pretend we have a known breakage' 'false' + test_expect_success 'pretend we have a passing test' 'true' + test_expect_failure 'pretend we have fixed another known breakage' 'true' + test_done + EOF + check_sub_test_lib_test partially-passing-todos <<-\\EOF + > not ok 1 - pretend we have a known breakage # TODO known breakage + > ok 2 - pretend we have a passing test + > ok 3 - pretend we have fixed another known breakage # TODO known breakage vanished + > # 1 known breakage(s) vanished; please update test(s) + > # still have 1 known breakage(s) + > # passed all remaining 1 test(s) + > 1..3 + EOF +" + +test_expect_success 'pretend we have a pass, fail, and known breakage' " + test_must_fail run_sub_test_lib_test \ + mixed-results1 'mixed results #1' <<-\\EOF && + test_expect_success 'passing test' 'true' + test_expect_success 'failing test' 'false' + test_expect_failure 'pretend we have a known breakage' 'false' + test_done + EOF + check_sub_test_lib_test mixed-results1 <<-\\EOF + > ok 1 - passing test + > not ok 2 - failing test + > # false + > not ok 3 - pretend we have a known breakage # TODO known breakage + > # still have 1 known breakage(s) + > # failed 1 among remaining 2 test(s) + > 1..3 + EOF +" + +test_expect_success 'pretend we have a mix of all possible results' " + test_must_fail run_sub_test_lib_test \ + mixed-results2 'mixed results #2' <<-\\EOF && + test_expect_success 'passing test' 'true' + test_expect_success 'passing test' 'true' + test_expect_success 'passing test' 'true' + test_expect_success 'passing test' 'true' + test_expect_success 'failing test' 'false' + test_expect_success 'failing test' 'false' + test_expect_success 'failing test' 'false' + test_expect_failure 'pretend we have a known breakage' 'false' + test_expect_failure 'pretend we have a known breakage' 'false' + test_expect_failure 'pretend we have fixed a known breakage' 'true' + test_done + EOF + check_sub_test_lib_test mixed-results2 <<-\\EOF + > ok 1 - passing test + > ok 2 - passing test + > ok 3 - passing test + > ok 4 - passing test + > not ok 5 - failing test + > # false + > not ok 6 - failing test + > # false + > not ok 7 - failing test + > # false + > not ok 8 - pretend we have a known breakage # TODO known breakage + > not ok 9 - pretend we have a known breakage # TODO known breakage + > ok 10 - pretend we have fixed a known breakage # TODO known breakage vanished + > # 1 known breakage(s) vanished; please update test(s) + > # still have 2 known breakage(s) + > # failed 3 among remaining 7 test(s) + > 1..10 + EOF +" + +test_expect_success 'test --verbose' ' + test_must_fail run_sub_test_lib_test \ + test-verbose "test verbose" --verbose <<-\EOF && + test_expect_success "passing test" true + test_expect_success "test with output" "echo foo" + test_expect_success "failing test" false + test_done + EOF + mv test-verbose/out test-verbose/out+ + grep -v "^Initialized empty" test-verbose/out+ >test-verbose/out && + check_sub_test_lib_test test-verbose <<-\EOF + > expecting success: true + > Z + > ok 1 - passing test + > Z + > expecting success: echo foo + > foo + > Z + > ok 2 - test with output + > Z + > expecting success: false + > Z + > not ok 3 - failing test + > # false + > Z + > # failed 1 among 3 test(s) + > 1..3 + EOF +' + +test_expect_success 'test --verbose-only' ' + test_must_fail run_sub_test_lib_test \ + test-verbose-only-2 "test verbose-only=2" \ + --verbose-only=2 <<-\EOF && + test_expect_success "passing test" true + test_expect_success "test with output" "echo foo" + test_expect_success "failing test" false + test_done + EOF + check_sub_test_lib_test test-verbose-only-2 <<-\EOF + > ok 1 - passing test + > Z + > expecting success: echo foo + > foo + > Z + > ok 2 - test with output + > Z + > not ok 3 - failing test + > # false + > # failed 1 among 3 test(s) + > 1..3 + EOF +' + test_set_prereq HAVEIT haveit=no test_expect_success HAVEIT 'test runs if prerequisite is satisfied' ' @@ -115,6 +312,38 @@ then exit 1 fi +test_lazy_prereq LAZY_TRUE true +havetrue=no +test_expect_success LAZY_TRUE 'test runs if lazy prereq is satisfied' ' + havetrue=yes +' +donthavetrue=yes +test_expect_success !LAZY_TRUE 'missing lazy prereqs skip tests' ' + donthavetrue=no +' + +if test "$havetrue$donthavetrue" != yesyes +then + say 'bug in test framework: lazy prerequisites do not work' + exit 1 +fi + +test_lazy_prereq LAZY_FALSE false +nothavefalse=no +test_expect_success !LAZY_FALSE 'negative lazy prereqs checked' ' + nothavefalse=yes +' +havefalse=yes +test_expect_success LAZY_FALSE 'missing negative lazy prereqs will skip' ' + havefalse=no +' + +if test "$nothavefalse$havefalse" != yesyes +then + say 'bug in test framework: negative lazy prerequisites do not work' + exit 1 +fi + clean=no test_expect_success 'tests clean up after themselves' ' test_when_finished clean=yes @@ -127,19 +356,8 @@ 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_must_fail run_sub_test_lib_test \ + failing-cleanup 'Failing tests with cleanup commands' <<-\\EOF && test_expect_success 'tests clean up even after a failure' ' touch clean-after-failure && test_when_finished rm clean-after-failure && @@ -149,29 +367,21 @@ test_expect_success 'tests clean up even on failures' " 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 + check_sub_test_lib_test failing-cleanup <<-\\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 + > 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 - ) " ################################################################ @@ -217,22 +427,6 @@ test_expect_success 'validate object ID of a known tree' ' # Various types of objects -# Some filesystems do not support symblic links; on such systems -# some expected values are different -if test_have_prereq SYMLINKS -then - expectfilter=cat - expectedtree=087704a96baf1c2d1c869a8b084481e121c88b5b - expectedptree1=21ae8269cacbe57ae09138dcc3a2887f904d02b3 - expectedptree2=3c5e5399f3a333eddecce7a9b9465b63f65f51e2 -else - expectfilter='grep -v sym' - expectedtree=8e18edf7d7edcf4371a3ac6ae5f07c2641db7c46 - expectedptree1=cfb8591b2f65de8b8cc1020cd7d9e67e7793b325 - expectedptree2=ce580448f0148b985a513b693fdf7d802cacb44f -fi - - 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" && @@ -240,10 +434,7 @@ test_expect_success 'adding various types of objects with git update-index --add 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 + test_ln_s_add "hello $p" ${p}sym || exit 1 done ) && find path* ! -type d -print | xargs git update-index --add @@ -255,7 +446,7 @@ test_expect_success 'showing stage with git ls-files --stage' ' ' test_expect_success 'validate git ls-files output for a known tree' ' - $expectfilter >expected <<-\EOF && + cat >expected <<-\EOF && 100644 f87290f8eb2cbbea7857214459a0739927eab154 0 path0 120000 15a98433ae33114b085f3eb3bb03b832b3180a01 0 path0sym 100644 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 0 path2/file2 @@ -273,14 +464,14 @@ test_expect_success 'writing tree out with git write-tree' ' ' test_expect_success 'validate object ID for a known tree' ' - test "$tree" = "$expectedtree" + test "$tree" = 087704a96baf1c2d1c869a8b084481e121c88b5b ' 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' ' +test_expect_success 'git ls-tree output for a known tree' ' cat >expected <<-\EOF && 100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0 120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym @@ -297,7 +488,7 @@ test_expect_success 'showing tree with git ls-tree -r' ' ' test_expect_success 'git ls-tree -r output for a known tree' ' - $expectfilter >expected <<-\EOF && + cat >expected <<-\EOF && 100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0 120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym 100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2 @@ -315,7 +506,7 @@ test_expect_success 'showing tree with git ls-tree -r -t' ' git ls-tree -r -t $tree >current ' -test_expect_success SYMLINKS 'git ls-tree -r output for a known tree' ' +test_expect_success 'git ls-tree -r output for a known tree' ' cat >expected <<-\EOF && 100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0 120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym @@ -337,7 +528,7 @@ test_expect_success 'writing partial tree out with git write-tree --prefix' ' ' test_expect_success 'validate object ID for a known tree' ' - test "$ptree" = "$expectedptree1" + test "$ptree" = 21ae8269cacbe57ae09138dcc3a2887f904d02b3 ' test_expect_success 'writing partial tree out with git write-tree --prefix' ' @@ -345,7 +536,7 @@ test_expect_success 'writing partial tree out with git write-tree --prefix' ' ' test_expect_success 'validate object ID for a known tree' ' - test "$ptree" = "$expectedptree2" + test "$ptree" = 3c5e5399f3a333eddecce7a9b9465b63f65f51e2 ' test_expect_success 'put invalid objects into the index' ' @@ -379,7 +570,7 @@ test_expect_success 'git read-tree followed by write-tree should be idempotent' ' test_expect_success 'validate git diff-files output for a know cache/work tree state' ' - $expectfilter >expected <<\EOF && + cat >expected <<\EOF && :100644 100644 f87290f8eb2cbbea7857214459a0739927eab154 0000000000000000000000000000000000000000 M path0 :120000 120000 15a98433ae33114b085f3eb3bb03b832b3180a01 0000000000000000000000000000000000000000 M path0sym :100644 100644 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 0000000000000000000000000000000000000000 M path2/file2 @@ -403,7 +594,7 @@ test_expect_success 'no diff after checkout and git update-index --refresh' ' ' ################################################################ -P=$expectedtree +P=087704a96baf1c2d1c869a8b084481e121c88b5b test_expect_success 'git commit-tree records the correct tree in a commit' ' commit0=$(echo NO | git commit-tree $P) && diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh index febc45c9cc..0b98b6f8d0 100755 --- a/t/t0003-attributes.sh +++ b/t/t0003-attributes.sh @@ -196,6 +196,54 @@ test_expect_success 'root subdir attribute test' ' attr_check subdir/a/i unspecified ' +test_expect_success 'negative patterns' ' + echo "!f test=bar" >.gitattributes && + git check-attr test -- '"'"'!f'"'"' 2>errors && + test_i18ngrep "Negative patterns are ignored" errors +' + +test_expect_success 'patterns starting with exclamation' ' + echo "\!f test=foo" >.gitattributes && + attr_check "!f" foo +' + +test_expect_success '"**" test' ' + echo "**/f foo=bar" >.gitattributes && + cat <<\EOF >expect && +f: foo: bar +a/f: foo: bar +a/b/f: foo: bar +a/b/c/f: foo: bar +EOF + git check-attr foo -- "f" >actual 2>err && + git check-attr foo -- "a/f" >>actual 2>>err && + git check-attr foo -- "a/b/f" >>actual 2>>err && + git check-attr foo -- "a/b/c/f" >>actual 2>>err && + test_cmp expect actual && + test_line_count = 0 err +' + +test_expect_success '"**" with no slashes test' ' + echo "a**f foo=bar" >.gitattributes && + git check-attr foo -- "f" >actual && + cat <<\EOF >expect && +f: foo: unspecified +af: foo: bar +axf: foo: bar +a/f: foo: unspecified +a/b/f: foo: unspecified +a/b/c/f: foo: unspecified +EOF + git check-attr foo -- "f" >actual 2>err && + git check-attr foo -- "af" >>actual 2>err && + git check-attr foo -- "axf" >>actual 2>err && + git check-attr foo -- "a/f" >>actual 2>>err && + git check-attr foo -- "a/b/f" >>actual 2>>err && + git check-attr foo -- "a/b/c/f" >>actual 2>>err && + test_cmp expect actual && + test_line_count = 0 err +' + test_expect_success 'setup bare' ' git clone --bare . bare.git && cd bare.git diff --git a/t/t0005-signals.sh b/t/t0005-signals.sh index 93e58c00e8..981437b3a8 100755 --- a/t/t0005-signals.sh +++ b/t/t0005-signals.sh @@ -20,4 +20,11 @@ test_expect_success 'sigchain works' ' test_cmp expect actual ' +test_expect_success !MINGW 'signals are propagated using shell convention' ' + # we use exec here to avoid any sub-shell interpretation + # of the exit code + git config alias.sigterm "!exec test-sigchain" && + test_expect_code 143 git sigterm +' + test_done diff --git a/t/t0007-git-var.sh b/t/t0007-git-var.sh new file mode 100755 index 0000000000..5868a87352 --- /dev/null +++ b/t/t0007-git-var.sh @@ -0,0 +1,49 @@ +#!/bin/sh + +test_description='basic sanity checks for git var' +. ./test-lib.sh + +test_expect_success 'get GIT_AUTHOR_IDENT' ' + test_tick && + echo "$GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE" >expect && + git var GIT_AUTHOR_IDENT >actual && + test_cmp expect actual +' + +test_expect_success 'get GIT_COMMITTER_IDENT' ' + test_tick && + echo "$GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE" >expect && + git var GIT_COMMITTER_IDENT >actual && + test_cmp expect actual +' + +test_expect_success !AUTOIDENT 'requested identites are strict' ' + ( + sane_unset GIT_COMMITTER_NAME && + sane_unset GIT_COMMITTER_EMAIL && + test_must_fail git var GIT_COMMITTER_IDENT + ) +' + +# For git var -l, we check only a representative variable; +# testing the whole output would make our test too brittle with +# respect to unrelated changes in the test suite's environment. +test_expect_success 'git var -l lists variables' ' + git var -l >actual && + echo "$GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE" >expect && + sed -n s/GIT_AUTHOR_IDENT=//p <actual >actual.author && + test_cmp expect actual.author +' + +test_expect_success 'git var -l lists config' ' + git var -l >actual && + echo false >expect && + sed -n s/core\\.bare=//p <actual >actual.bare && + test_cmp expect actual.bare +' + +test_expect_success 'listing and asking for variables are exclusive' ' + test_must_fail git var -l GIT_COMMITTER_IDENT +' + +test_done diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh new file mode 100755 index 0000000000..c29342d6bc --- /dev/null +++ b/t/t0008-ignores.sh @@ -0,0 +1,718 @@ +#!/bin/sh + +test_description=check-ignore + +. ./test-lib.sh + +init_vars () { + global_excludes="$(pwd)/global-excludes" +} + +enable_global_excludes () { + init_vars && + git config core.excludesfile "$global_excludes" +} + +expect_in () { + dest="$HOME/expected-$1" text="$2" + if test -z "$text" + then + >"$dest" # avoid newline + else + echo "$text" >"$dest" + fi +} + +expect () { + expect_in stdout "$1" +} + +expect_from_stdin () { + cat >"$HOME/expected-stdout" +} + +test_stderr () { + expected="$1" + expect_in stderr "$1" && + test_cmp "$HOME/expected-stderr" "$HOME/stderr" +} + +stderr_contains () { + regexp="$1" + if grep "$regexp" "$HOME/stderr" + then + return 0 + else + echo "didn't find /$regexp/ in $HOME/stderr" + cat "$HOME/stderr" + return 1 + fi +} + +stderr_empty_on_success () { + expect_code="$1" + if test $expect_code = 0 + then + test_stderr "" + else + # If we expect failure then stderr might or might not be empty + # due to --quiet - the caller can check its contents + return 0 + fi +} + +test_check_ignore () { + args="$1" expect_code="${2:-0}" global_args="$3" + + init_vars && + rm -f "$HOME/stdout" "$HOME/stderr" "$HOME/cmd" && + echo git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $args \ + >"$HOME/cmd" && + echo "$expect_code" >"$HOME/expected-exit-code" && + test_expect_code "$expect_code" \ + git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $args \ + >"$HOME/stdout" 2>"$HOME/stderr" && + test_cmp "$HOME/expected-stdout" "$HOME/stdout" && + stderr_empty_on_success "$expect_code" +} + +# Runs the same code with 4 different levels of output verbosity: +# +# 1. with -q / --quiet +# 2. with default verbosity +# 3. with -v / --verbose +# 4. with -v / --verbose, *and* -n / --non-matching +# +# expecting success each time. Takes advantage of the fact that +# check-ignore --verbose output is the same as normal output except +# for the extra first column. +# +# Arguments: +# - (optional) prereqs for this test, e.g. 'SYMLINKS' +# - test name +# - output to expect from the fourth verbosity mode (the output +# from the other verbosity modes is automatically inferred +# from this value) +# - code to run (should invoke test_check_ignore) +test_expect_success_multi () { + prereq= + if test $# -eq 4 + then + prereq=$1 + shift + fi + testname="$1" expect_all="$2" code="$3" + + expect_verbose=$( echo "$expect_all" | grep -v '^:: ' ) + expect=$( echo "$expect_verbose" | sed -e 's/.* //' ) + + test_expect_success $prereq "$testname" ' + expect "$expect" && + eval "$code" + ' + + # --quiet is only valid when a single pattern is passed + if test $( echo "$expect_all" | wc -l ) = 1 + then + for quiet_opt in '-q' '--quiet' + do + test_expect_success $prereq "$testname${quiet_opt:+ with $quiet_opt}" " + expect '' && + $code + " + done + quiet_opt= + fi + + for verbose_opt in '-v' '--verbose' + do + for non_matching_opt in '' ' -n' ' --non-matching' + do + if test -n "$non_matching_opt" + then + my_expect="$expect_all" + else + my_expect="$expect_verbose" + fi + + test_code=" + expect '$my_expect' && + $code + " + opts="$verbose_opt$non_matching_opt" + test_expect_success $prereq "$testname${opts:+ with $opts}" "$test_code" + done + done + verbose_opt= + non_matching_opt= +} + +test_expect_success 'setup' ' + init_vars && + mkdir -p a/b/ignored-dir a/submodule b && + if test_have_prereq SYMLINKS + then + ln -s b a/symlink + fi && + ( + cd a/submodule && + git init && + echo a >a && + git add a && + git commit -m"commit in submodule" + ) && + git add a/submodule && + cat <<-\EOF >.gitignore && + one + ignored-* + top-level-dir/ + EOF + for dir in . a + do + : >$dir/not-ignored && + : >$dir/ignored-and-untracked && + : >$dir/ignored-but-in-index + done && + git add -f ignored-but-in-index a/ignored-but-in-index && + cat <<-\EOF >a/.gitignore && + two* + *three + EOF + cat <<-\EOF >a/b/.gitignore && + four + five + # this comment should affect the line numbers + six + ignored-dir/ + # and so should this blank line: + + !on* + !two + EOF + echo "seven" >a/b/ignored-dir/.gitignore && + test -n "$HOME" && + cat <<-\EOF >"$global_excludes" && + globalone + !globaltwo + globalthree + EOF + cat <<-\EOF >>.git/info/exclude + per-repo + EOF +' + +############################################################################ +# +# test invalid inputs + +test_expect_success_multi '. corner-case' ':: .' ' + test_check_ignore . 1 +' + +test_expect_success_multi 'empty command line' '' ' + test_check_ignore "" 128 && + stderr_contains "fatal: no path specified" +' + +test_expect_success_multi '--stdin with empty STDIN' '' ' + test_check_ignore "--stdin" 1 </dev/null && + test_stderr "" +' + +test_expect_success '-q with multiple args' ' + expect "" && + test_check_ignore "-q one two" 128 && + stderr_contains "fatal: --quiet is only valid with a single pathname" +' + +test_expect_success '--quiet with multiple args' ' + expect "" && + test_check_ignore "--quiet one two" 128 && + stderr_contains "fatal: --quiet is only valid with a single pathname" +' + +for verbose_opt in '-v' '--verbose' +do + for quiet_opt in '-q' '--quiet' + do + test_expect_success "$quiet_opt $verbose_opt" " + expect '' && + test_check_ignore '$quiet_opt $verbose_opt foo' 128 && + stderr_contains 'fatal: cannot have both --quiet and --verbose' + " + done +done + +test_expect_success '--quiet with multiple args' ' + expect "" && + test_check_ignore "--quiet one two" 128 && + stderr_contains "fatal: --quiet is only valid with a single pathname" +' + +test_expect_success_multi 'erroneous use of --' '' ' + test_check_ignore "--" 128 && + stderr_contains "fatal: no path specified" +' + +test_expect_success_multi '--stdin with superfluous arg' '' ' + test_check_ignore "--stdin foo" 128 && + stderr_contains "fatal: cannot specify pathnames with --stdin" +' + +test_expect_success_multi '--stdin -z with superfluous arg' '' ' + test_check_ignore "--stdin -z foo" 128 && + stderr_contains "fatal: cannot specify pathnames with --stdin" +' + +test_expect_success_multi '-z without --stdin' '' ' + test_check_ignore "-z" 128 && + stderr_contains "fatal: -z only makes sense with --stdin" +' + +test_expect_success_multi '-z without --stdin and superfluous arg' '' ' + test_check_ignore "-z foo" 128 && + stderr_contains "fatal: -z only makes sense with --stdin" +' + +test_expect_success_multi 'needs work tree' '' ' + ( + cd .git && + test_check_ignore "foo" 128 + ) && + stderr_contains "fatal: This operation must be run in a work tree" +' + +############################################################################ +# +# test standard ignores + +# First make sure that the presence of a file in the working tree +# does not impact results, but that the presence of a file in the +# index does. + +for subdir in '' 'a/' +do + if test -z "$subdir" + then + where="at top-level" + else + where="in subdir $subdir" + fi + + test_expect_success_multi "non-existent file $where not ignored" \ + ":: ${subdir}non-existent" \ + "test_check_ignore '${subdir}non-existent' 1" + + test_expect_success_multi "non-existent file $where ignored" \ + ".gitignore:1:one ${subdir}one" \ + "test_check_ignore '${subdir}one'" + + test_expect_success_multi "existing untracked file $where not ignored" \ + ":: ${subdir}not-ignored" \ + "test_check_ignore '${subdir}not-ignored' 1" + + test_expect_success_multi "existing tracked file $where not ignored" \ + ":: ${subdir}ignored-but-in-index" \ + "test_check_ignore '${subdir}ignored-but-in-index' 1" + + test_expect_success_multi "existing untracked file $where ignored" \ + ".gitignore:2:ignored-* ${subdir}ignored-and-untracked" \ + "test_check_ignore '${subdir}ignored-and-untracked'" + + test_expect_success_multi "mix of file types $where" \ +":: ${subdir}non-existent +.gitignore:1:one ${subdir}one +:: ${subdir}not-ignored +:: ${subdir}ignored-but-in-index +.gitignore:2:ignored-* ${subdir}ignored-and-untracked" \ + "test_check_ignore ' + ${subdir}non-existent + ${subdir}one + ${subdir}not-ignored + ${subdir}ignored-but-in-index + ${subdir}ignored-and-untracked' + " +done + +# Having established the above, from now on we mostly test against +# files which do not exist in the working tree or index. + +test_expect_success 'sub-directory local ignore' ' + expect "a/3-three" && + test_check_ignore "a/3-three a/three-not-this-one" +' + +test_expect_success 'sub-directory local ignore with --verbose' ' + expect "a/.gitignore:2:*three a/3-three" && + test_check_ignore "--verbose a/3-three a/three-not-this-one" +' + +test_expect_success 'local ignore inside a sub-directory' ' + expect "3-three" && + ( + cd a && + test_check_ignore "3-three three-not-this-one" + ) +' +test_expect_success 'local ignore inside a sub-directory with --verbose' ' + expect "a/.gitignore:2:*three 3-three" && + ( + cd a && + test_check_ignore "--verbose 3-three three-not-this-one" + ) +' + +test_expect_success_multi 'nested include' \ + 'a/b/.gitignore:8:!on* a/b/one' ' + test_check_ignore "a/b/one" +' + +############################################################################ +# +# test ignored sub-directories + +test_expect_success_multi 'ignored sub-directory' \ + 'a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir' ' + test_check_ignore "a/b/ignored-dir" +' + +test_expect_success 'multiple files inside ignored sub-directory' ' + expect_from_stdin <<-\EOF && + a/b/ignored-dir/foo + a/b/ignored-dir/twoooo + a/b/ignored-dir/seven + EOF + test_check_ignore "a/b/ignored-dir/foo a/b/ignored-dir/twoooo a/b/ignored-dir/seven" +' + +test_expect_success 'multiple files inside ignored sub-directory with -v' ' + expect_from_stdin <<-\EOF && + a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir/foo + a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir/twoooo + a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir/seven + EOF + test_check_ignore "-v a/b/ignored-dir/foo a/b/ignored-dir/twoooo a/b/ignored-dir/seven" +' + +test_expect_success 'cd to ignored sub-directory' ' + expect_from_stdin <<-\EOF && + foo + twoooo + ../one + seven + ../../one + EOF + ( + cd a/b/ignored-dir && + test_check_ignore "foo twoooo ../one seven ../../one" + ) +' + +test_expect_success 'cd to ignored sub-directory with -v' ' + expect_from_stdin <<-\EOF && + a/b/.gitignore:5:ignored-dir/ foo + a/b/.gitignore:5:ignored-dir/ twoooo + a/b/.gitignore:8:!on* ../one + a/b/.gitignore:5:ignored-dir/ seven + .gitignore:1:one ../../one + EOF + ( + cd a/b/ignored-dir && + test_check_ignore "-v foo twoooo ../one seven ../../one" + ) +' + +############################################################################ +# +# test handling of symlinks + +test_expect_success_multi SYMLINKS 'symlink' ':: a/symlink' ' + test_check_ignore "a/symlink" 1 +' + +test_expect_success_multi SYMLINKS 'beyond a symlink' '' ' + test_check_ignore "a/symlink/foo" 128 && + test_stderr "fatal: '\''a/symlink/foo'\'' is beyond a symbolic link" +' + +test_expect_success_multi SYMLINKS 'beyond a symlink from subdirectory' '' ' + ( + cd a && + test_check_ignore "symlink/foo" 128 + ) && + test_stderr "fatal: '\''symlink/foo'\'' is beyond a symbolic link" +' + +############################################################################ +# +# test handling of submodules + +test_expect_success_multi 'submodule' '' ' + test_check_ignore "a/submodule/one" 128 && + test_stderr "fatal: Path '\''a/submodule/one'\'' is in submodule '\''a/submodule'\''" +' + +test_expect_success_multi 'submodule from subdirectory' '' ' + ( + cd a && + test_check_ignore "submodule/one" 128 + ) && + test_stderr "fatal: Path '\''a/submodule/one'\'' is in submodule '\''a/submodule'\''" +' + +############################################################################ +# +# test handling of global ignore files + +test_expect_success 'global ignore not yet enabled' ' + expect_from_stdin <<-\EOF && + .git/info/exclude:7:per-repo per-repo + a/.gitignore:2:*three a/globalthree + .git/info/exclude:7:per-repo a/per-repo + EOF + test_check_ignore "-v globalone per-repo a/globalthree a/per-repo not-ignored a/globaltwo" +' + +test_expect_success 'global ignore' ' + enable_global_excludes && + expect_from_stdin <<-\EOF && + globalone + per-repo + globalthree + a/globalthree + a/per-repo + globaltwo + EOF + test_check_ignore "globalone per-repo globalthree a/globalthree a/per-repo not-ignored globaltwo" +' + +test_expect_success 'global ignore with -v' ' + enable_global_excludes && + expect_from_stdin <<-EOF && + $global_excludes:1:globalone globalone + .git/info/exclude:7:per-repo per-repo + $global_excludes:3:globalthree globalthree + a/.gitignore:2:*three a/globalthree + .git/info/exclude:7:per-repo a/per-repo + $global_excludes:2:!globaltwo globaltwo + EOF + test_check_ignore "-v globalone per-repo globalthree a/globalthree a/per-repo not-ignored globaltwo" +' + +############################################################################ +# +# test --stdin + +cat <<-\EOF >stdin + one + not-ignored + a/one + a/not-ignored + a/b/on + a/b/one + a/b/one one + "a/b/one two" + "a/b/one\"three" + a/b/not-ignored + a/b/two + a/b/twooo + globaltwo + a/globaltwo + a/b/globaltwo + b/globaltwo +EOF +cat <<-\EOF >expected-default + one + a/one + a/b/on + a/b/one + a/b/one one + a/b/one two + "a/b/one\"three" + a/b/two + a/b/twooo + globaltwo + a/globaltwo + a/b/globaltwo + b/globaltwo +EOF +cat <<-EOF >expected-verbose + .gitignore:1:one one + .gitignore:1:one a/one + a/b/.gitignore:8:!on* a/b/on + a/b/.gitignore:8:!on* a/b/one + a/b/.gitignore:8:!on* a/b/one one + a/b/.gitignore:8:!on* a/b/one two + a/b/.gitignore:8:!on* "a/b/one\"three" + a/b/.gitignore:9:!two a/b/two + a/.gitignore:1:two* a/b/twooo + $global_excludes:2:!globaltwo globaltwo + $global_excludes:2:!globaltwo a/globaltwo + $global_excludes:2:!globaltwo a/b/globaltwo + $global_excludes:2:!globaltwo b/globaltwo +EOF + +sed -e 's/^"//' -e 's/\\//' -e 's/"$//' stdin | \ + tr "\n" "\0" >stdin0 +sed -e 's/^"//' -e 's/\\//' -e 's/"$//' expected-default | \ + tr "\n" "\0" >expected-default0 +sed -e 's/ "/ /' -e 's/\\//' -e 's/"$//' expected-verbose | \ + tr ":\t\n" "\0" >expected-verbose0 + +test_expect_success '--stdin' ' + expect_from_stdin <expected-default && + test_check_ignore "--stdin" <stdin +' + +test_expect_success '--stdin -q' ' + expect "" && + test_check_ignore "-q --stdin" <stdin +' + +test_expect_success '--stdin -v' ' + expect_from_stdin <expected-verbose && + test_check_ignore "-v --stdin" <stdin +' + +for opts in '--stdin -z' '-z --stdin' +do + test_expect_success "$opts" " + expect_from_stdin <expected-default0 && + test_check_ignore '$opts' <stdin0 + " + + test_expect_success "$opts -q" " + expect "" && + test_check_ignore '-q $opts' <stdin0 + " + + test_expect_success "$opts -v" " + expect_from_stdin <expected-verbose0 && + test_check_ignore '-v $opts' <stdin0 + " +done + +cat <<-\EOF >stdin + ../one + ../not-ignored + one + not-ignored + b/on + b/one + b/one one + "b/one two" + "b/one\"three" + b/two + b/not-ignored + b/twooo + ../globaltwo + globaltwo + b/globaltwo + ../b/globaltwo + c/not-ignored +EOF +# N.B. we deliberately end STDIN with a non-matching pattern in order +# to test that the exit code indicates that one or more of the +# provided paths is ignored - in other words, that it represents an +# aggregation of all the results, not just the final result. + +cat <<-EOF >expected-all + .gitignore:1:one ../one + :: ../not-ignored + .gitignore:1:one one + :: not-ignored + a/b/.gitignore:8:!on* b/on + a/b/.gitignore:8:!on* b/one + a/b/.gitignore:8:!on* b/one one + a/b/.gitignore:8:!on* b/one two + a/b/.gitignore:8:!on* "b/one\"three" + a/b/.gitignore:9:!two b/two + :: b/not-ignored + a/.gitignore:1:two* b/twooo + $global_excludes:2:!globaltwo ../globaltwo + $global_excludes:2:!globaltwo globaltwo + $global_excludes:2:!globaltwo b/globaltwo + $global_excludes:2:!globaltwo ../b/globaltwo + :: c/not-ignored +EOF +grep -v '^:: ' expected-all >expected-verbose +sed -e 's/.* //' expected-verbose >expected-default + +sed -e 's/^"//' -e 's/\\//' -e 's/"$//' stdin | \ + tr "\n" "\0" >stdin0 +sed -e 's/^"//' -e 's/\\//' -e 's/"$//' expected-default | \ + tr "\n" "\0" >expected-default0 +sed -e 's/ "/ /' -e 's/\\//' -e 's/"$//' expected-verbose | \ + tr ":\t\n" "\0" >expected-verbose0 + +test_expect_success '--stdin from subdirectory' ' + expect_from_stdin <expected-default && + ( + cd a && + test_check_ignore "--stdin" <../stdin + ) +' + +test_expect_success '--stdin from subdirectory with -v' ' + expect_from_stdin <expected-verbose && + ( + cd a && + test_check_ignore "--stdin -v" <../stdin + ) +' + +test_expect_success '--stdin from subdirectory with -v -n' ' + expect_from_stdin <expected-all && + ( + cd a && + test_check_ignore "--stdin -v -n" <../stdin + ) +' + +for opts in '--stdin -z' '-z --stdin' +do + test_expect_success "$opts from subdirectory" ' + expect_from_stdin <expected-default0 && + ( + cd a && + test_check_ignore "'"$opts"'" <../stdin0 + ) + ' + + test_expect_success "$opts from subdirectory with -v" ' + expect_from_stdin <expected-verbose0 && + ( + cd a && + test_check_ignore "'"$opts"' -v" <../stdin0 + ) + ' +done + +test_expect_success PIPE 'streaming support for --stdin' ' + mkfifo in out && + (git check-ignore -n -v --stdin <in >out &) && + + # We cannot just "echo >in" because check-ignore would get EOF + # after echo exited; instead we open the descriptor in our + # shell, and then echo to the fd. We make sure to close it at + # the end, so that the subprocess does get EOF and dies + # properly. + # + # Similarly, we must keep "out" open so that check-ignore does + # not ever get SIGPIPE trying to write to us. Not only would that + # produce incorrect results, but then there would be no writer on the + # other end of the pipe, and we would potentially block forever trying + # to open it. + exec 9>in && + exec 8<out && + test_when_finished "exec 9>&-" && + test_when_finished "exec 8<&-" && + echo >&9 one && + read response <&8 && + echo "$response" | grep "^\.gitignore:1:one one" && + echo >&9 two && + read response <&8 && + echo "$response" | grep "^:: two" +' + +test_done diff --git a/t/t0009-prio-queue.sh b/t/t0009-prio-queue.sh new file mode 100755 index 0000000000..94045c3fad --- /dev/null +++ b/t/t0009-prio-queue.sh @@ -0,0 +1,50 @@ +#!/bin/sh + +test_description='basic tests for priority queue implementation' +. ./test-lib.sh + +cat >expect <<'EOF' +1 +2 +3 +4 +5 +5 +6 +7 +8 +9 +10 +EOF +test_expect_success 'basic ordering' ' + test-prio-queue 2 6 3 10 9 5 7 4 5 8 1 dump >actual && + test_cmp expect actual +' + +cat >expect <<'EOF' +2 +3 +4 +1 +5 +6 +EOF +test_expect_success 'mixed put and get' ' + test-prio-queue 6 2 4 get 5 3 get get 1 dump >actual && + test_cmp expect actual +' + +cat >expect <<'EOF' +1 +2 +NULL +1 +2 +NULL +EOF +test_expect_success 'notice empty queue' ' + test-prio-queue 1 2 get get get 1 2 get get get >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t0020-crlf.sh b/t/t0020-crlf.sh index 1a8f44c44c..e526184a0b 100755 --- a/t/t0020-crlf.sh +++ b/t/t0020-crlf.sh @@ -81,6 +81,14 @@ test_expect_success 'safecrlf: print warning only once' ' test $(git add doublewarn 2>&1 | grep "CRLF will be replaced by LF" | wc -l) = 1 ' + +test_expect_success 'safecrlf: git diff demotes safecrlf=true to warn' ' + git config core.autocrlf input && + git config core.safecrlf true && + git diff HEAD +' + + test_expect_success 'switch off autocrlf, safecrlf, reset HEAD' ' git config core.autocrlf false && git config core.safecrlf false && diff --git a/t/t0024-crlf-archive.sh b/t/t0024-crlf-archive.sh index ec6c1b3f8a..4e9fa3cd68 100755 --- a/t/t0024-crlf-archive.sh +++ b/t/t0024-crlf-archive.sh @@ -3,7 +3,6 @@ test_description='respect crlf in git archive' . ./test-lib.sh -UNZIP=${UNZIP:-unzip} test_expect_success setup ' @@ -26,18 +25,11 @@ test_expect_success 'tar archive' ' ' -"$UNZIP" -v >/dev/null 2>&1 -if [ $? -eq 127 ]; then - say "Skipping ZIP test, because unzip was not found" -else - test_set_prereq UNZIP -fi - test_expect_success UNZIP 'zip archive' ' git archive --format=zip HEAD >test.zip && - ( mkdir unzipped && cd unzipped && unzip ../test.zip ) && + ( mkdir unzipped && cd unzipped && "$GIT_UNZIP" ../test.zip ) && test_cmp sample unzipped/sample diff --git a/t/t0030-stripspace.sh b/t/t0030-stripspace.sh index ccb0a3cb61..a8e84d8546 100755 --- a/t/t0030-stripspace.sh +++ b/t/t0030-stripspace.sh @@ -397,4 +397,39 @@ test_expect_success 'strip comments, too' ' test -z "$(echo "# comment" | git stripspace -s)" ' +test_expect_success 'strip comments with changed comment char' ' + test ! -z "$(echo "; comment" | git -c core.commentchar=";" stripspace)" && + test -z "$(echo "; comment" | git -c core.commentchar=";" stripspace -s)" +' + +test_expect_success '-c with single line' ' + printf "# foo\n" >expect && + printf "foo" | git stripspace -c >actual && + test_cmp expect actual +' + +test_expect_success '-c with single line followed by empty line' ' + printf "# foo\n#\n" >expect && + printf "foo\n\n" | git stripspace -c >actual && + test_cmp expect actual +' + +test_expect_success '-c with newline only' ' + printf "#\n" >expect && + printf "\n" | git stripspace -c >actual && + test_cmp expect actual +' + +test_expect_success '--comment-lines with single line' ' + printf "# foo\n" >expect && + printf "foo" | git stripspace -c >actual && + test_cmp expect actual +' + +test_expect_success '-c with changed comment char' ' + printf "; foo\n" >expect && + printf "foo" | git -c core.commentchar=";" stripspace -c >actual && + test_cmp expect actual +' + test_done diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index 244a43c920..65606df3ed 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -50,7 +50,7 @@ EOF test_expect_success 'test help' ' test_must_fail test-parse-options -h > output 2> output.err && - test ! -s output.err && + test_must_be_empty output.err && test_i18ncmp expect output ' @@ -75,7 +75,7 @@ check() { shift && sed "s/^$what .*/$what $expect/" <expect.template >expect && test-parse-options $* >output 2>output.err && - test ! -s output.err && + test_must_be_empty output.err && test_cmp expect output } @@ -86,7 +86,7 @@ check_i18n() { shift && sed "s/^$what .*/$what $expect/" <expect.template >expect && test-parse-options $* >output 2>output.err && - test ! -s output.err && + test_must_be_empty output.err && test_i18ncmp expect output } @@ -99,7 +99,7 @@ check_unknown() { esac && cat expect.err >>expect && test_must_fail test-parse-options $* >output 2>output.err && - test ! -s output && + test_must_be_empty output && test_cmp expect output.err } @@ -112,7 +112,7 @@ check_unknown_i18n() { esac && cat expect.err >>expect && test_must_fail test-parse-options $* >output 2>output.err && - test ! -s output && + test_must_be_empty output && test_i18ncmp expect output.err } @@ -149,7 +149,7 @@ test_expect_success 'short options' ' test-parse-options -s123 -b -i 1729 -b -vv -n -F my.file \ > output 2> output.err && test_cmp expect output && - test ! -s output.err + test_must_be_empty output.err ' cat > expect << EOF @@ -168,7 +168,7 @@ test_expect_success 'long options' ' test-parse-options --boolean --integer 1729 --boolean --string2=321 \ --verbose --verbose --no-dry-run --abbrev=10 --file fi.le\ --obsolete > output 2> output.err && - test ! -s output.err && + test_must_be_empty output.err && test_cmp expect output ' @@ -199,7 +199,7 @@ EOF test_expect_success 'intermingled arguments' ' test-parse-options a1 --string 123 b1 --boolean -j 13 -- --boolean \ > output 2> output.err && - test ! -s output.err && + test_must_be_empty output.err && test_cmp expect output ' @@ -217,13 +217,13 @@ EOF test_expect_success 'unambiguously abbreviated option' ' test-parse-options --int 2 --boolean --no-bo > output 2> output.err && - test ! -s output.err && + test_must_be_empty output.err && test_cmp expect output ' test_expect_success 'unambiguously abbreviated option with "="' ' test-parse-options --int=2 > output 2> output.err && - test ! -s output.err && + test_must_be_empty output.err && test_cmp expect output ' @@ -246,7 +246,7 @@ EOF test_expect_success 'non ambiguous option (after two options it abbreviates)' ' test-parse-options --st 123 > output 2> output.err && - test ! -s output.err && + test_must_be_empty output.err && test_cmp expect output ' @@ -256,7 +256,7 @@ EOF test_expect_success 'detect possible typos' ' test_must_fail test-parse-options -boolean > output 2> output.err && - test ! -s output && + test_must_be_empty output && test_cmp typo.err output.err ' @@ -266,7 +266,7 @@ EOF test_expect_success 'detect possible typos' ' test_must_fail test-parse-options -ambiguous > output 2> output.err && - test ! -s output && + test_must_be_empty output && test_cmp typo.err output.err ' @@ -285,7 +285,7 @@ EOF test_expect_success 'keep some options as arguments' ' test-parse-options --quux > output 2> output.err && - test ! -s output.err && + test_must_be_empty output.err && test_cmp expect output ' @@ -305,7 +305,7 @@ EOF test_expect_success 'OPT_DATE() and OPT_SET_PTR() work' ' test-parse-options -t "1970-01-01 00:00:01 +0000" --default-string \ foo -q > output 2> output.err && - test ! -s output.err && + test_must_be_empty output.err && test_cmp expect output ' @@ -324,7 +324,7 @@ EOF test_expect_success 'OPT_CALLBACK() and OPT_BIT() work' ' test-parse-options --length=four -b -4 > output 2> output.err && - test ! -s output.err && + test_must_be_empty output.err && test_cmp expect output ' @@ -352,13 +352,13 @@ EOF test_expect_success 'OPT_BIT() and OPT_SET_INT() work' ' test-parse-options --set23 -bbbbb --no-or4 > output 2> output.err && - test ! -s output.err && + test_must_be_empty output.err && test_cmp expect output ' test_expect_success 'OPT_NEGBIT() and OPT_SET_INT() work' ' test-parse-options --set23 -bbbbb --neg-or4 > output 2> output.err && - test ! -s output.err && + test_must_be_empty output.err && test_cmp expect output ' @@ -376,19 +376,19 @@ EOF test_expect_success 'OPT_BIT() works' ' test-parse-options -bb --or4 > output 2> output.err && - test ! -s output.err && + test_must_be_empty output.err && test_cmp expect output ' test_expect_success 'OPT_NEGBIT() works' ' test-parse-options -bb --no-neg-or4 > output 2> output.err && - test ! -s output.err && + test_must_be_empty output.err && test_cmp expect output ' test_expect_success 'OPT_COUNTUP() with PARSE_OPT_NODASH works' ' test-parse-options + + + + + + > output 2> output.err && - test ! -s output.err && + test_must_be_empty output.err && test_cmp expect output ' @@ -406,7 +406,7 @@ EOF test_expect_success 'OPT_NUMBER_CALLBACK() works' ' test-parse-options -12345 > output 2> output.err && - test ! -s output.err && + test_must_be_empty output.err && test_cmp expect output ' @@ -424,7 +424,7 @@ EOF test_expect_success 'negation of OPT_NONEG flags is not ambiguous' ' test-parse-options --no-ambig >output 2>output.err && - test ! -s output.err && + test_must_be_empty output.err && test_cmp expect output ' diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh index 78816d9d93..05d78d22a6 100755 --- a/t/t0050-filesystem.sh +++ b/t/t0050-filesystem.sh @@ -29,12 +29,10 @@ test_have_prereq SYMLINKS || if test_have_prereq CASE_INSENSITIVE_FS then test_expect_success "detection of case insensitive filesystem during repo init" ' - test $(git config --bool core.ignorecase) = true ' else test_expect_success "detection of case insensitive filesystem during repo init" ' - test_must_fail git config --bool core.ignorecase >/dev/null || test $(git config --bool core.ignorecase) = false ' @@ -43,20 +41,17 @@ fi if test_have_prereq SYMLINKS then 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 ' else test_expect_success "detection of filesystem w/o symlink support during repo init" ' - v=$(git config --bool core.symlinks) && test "$v" = false ' fi test_expect_success "setup case tests" ' - git config core.ignorecase true && touch camelcase && git add camelcase && @@ -67,29 +62,23 @@ test_expect_success "setup case tests" ' git mv tmp CamelCase && git commit -m "rename" && git checkout -f master - ' $test_case 'rename (case change)' ' - git mv camelcase CamelCase && git commit -m "rename" - ' -$test_case 'merge (case change)' ' - +test_expect_success 'merge (case change)' ' rm -f CamelCase && rm -f camelcase && git reset --hard initial && git merge topic - ' -test_expect_failure 'add (with different case)' ' - +test_expect_failure CASE_INSENSITIVE_FS 'add (with different case)' ' git reset --hard initial && rm camelcase && echo 1 >CamelCase && @@ -97,37 +86,30 @@ test_expect_failure 'add (with different case)' ' camel=$(git ls-files | grep -i camelcase) && test $(echo "$camel" | wc -l) = 1 && test "z$(git cat-file blob :$camel)" = z1 - ' test_expect_success "setup unicode normalization tests" ' - - test_create_repo unicode && - cd unicode && - touch "$aumlcdiar" && - git add "$aumlcdiar" && - git commit -m initial && - git tag initial && - git checkout -b topic && - git mv $aumlcdiar tmp && - git mv tmp "$auml" && - git commit -m rename && - git checkout -f master - + test_create_repo unicode && + cd unicode && + touch "$aumlcdiar" && + git add "$aumlcdiar" && + git commit -m initial && + git tag initial && + git checkout -b topic && + git mv $aumlcdiar tmp && + git mv tmp "$auml" && + git commit -m rename && + git checkout -f master ' $test_unicode 'rename (silent unicode normalization)' ' - - git mv "$aumlcdiar" "$auml" && - git commit -m rename - + git mv "$aumlcdiar" "$auml" && + git commit -m rename ' $test_unicode 'merge (silent unicode normalization)' ' - - git reset --hard initial && - git merge topic - + git reset --hard initial && + git merge topic ' test_done diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh index 4ef2345982..3a48de20d8 100755 --- a/t/t0060-path-utils.sh +++ b/t/t0060-path-utils.sh @@ -8,8 +8,15 @@ test_description='Test various path utilities' . ./test-lib.sh norm_path() { + expected=$(test-path-utils mingw_path "$2") test_expect_success $3 "normalize path: $1 => $2" \ - "test \"\$(test-path-utils normalize_path_copy '$1')\" = '$2'" + "test \"\$(test-path-utils normalize_path_copy '$1')\" = '$expected'" +} + +relative_path() { + expected=$(test-path-utils mingw_path "$3") + test_expect_success $4 "relative path: $1 $2 => $3" \ + "test \"\$(test-path-utils relative_path '$1' '$2')\" = '$expected'" } # On Windows, we are using MSYS's bash, which mangles the paths. @@ -34,8 +41,8 @@ ancestor() { test \"\$actual\" = '$expected'" } -# Absolute path tests must be skipped on Windows because due to path mangling -# the test program never sees a POSIX-style absolute path +# Some absolute path tests should be skipped on Windows due to path mangling +# on POSIX-style absolute paths case $(uname -s) in *MINGW*) ;; @@ -68,72 +75,57 @@ norm_path d1/s1//../s2/../../d2 d2 norm_path d1/.../d2 d1/.../d2 norm_path d1/..././../d2 d1/d2 -norm_path / / POSIX +norm_path / / norm_path // / POSIX norm_path /// / POSIX -norm_path /. / POSIX +norm_path /. / norm_path /./ / POSIX norm_path /./.. ++failed++ POSIX -norm_path /../. ++failed++ POSIX +norm_path /../. ++failed++ norm_path /./../.// ++failed++ POSIX norm_path /dir/.. / POSIX norm_path /dir/sub/../.. / POSIX norm_path /dir/sub/../../.. ++failed++ POSIX -norm_path /dir /dir POSIX -norm_path /dir// /dir/ POSIX -norm_path /./dir /dir POSIX -norm_path /dir/. /dir/ POSIX -norm_path /dir///./ /dir/ POSIX -norm_path /dir//sub/.. /dir/ POSIX -norm_path /dir/sub/../ /dir/ POSIX +norm_path /dir /dir +norm_path /dir// /dir/ +norm_path /./dir /dir +norm_path /dir/. /dir/ +norm_path /dir///./ /dir/ +norm_path /dir//sub/.. /dir/ +norm_path /dir/sub/../ /dir/ norm_path //dir/sub/../. /dir/ POSIX -norm_path /dir/s1/../s2/ /dir/s2/ POSIX -norm_path /d1/s1///s2/..//../s3/ /d1/s3/ POSIX -norm_path /d1/s1//../s2/../../d2 /d2 POSIX -norm_path /d1/.../d2 /d1/.../d2 POSIX -norm_path /d1/..././../d2 /d1/d2 POSIX +norm_path /dir/s1/../s2/ /dir/s2/ +norm_path /d1/s1///s2/..//../s3/ /d1/s3/ +norm_path /d1/s1//../s2/../../d2 /d2 +norm_path /d1/.../d2 /d1/.../d2 +norm_path /d1/..././../d2 /d1/d2 -ancestor / "" -1 ancestor / / -1 -ancestor /foo "" -1 -ancestor /foo : -1 -ancestor /foo ::. -1 -ancestor /foo ::..:: -1 ancestor /foo / 0 ancestor /foo /fo -1 ancestor /foo /foo -1 -ancestor /foo /foo/ -1 ancestor /foo /bar -1 -ancestor /foo /bar/ -1 ancestor /foo /foo/bar -1 -ancestor /foo /foo:/bar/ -1 -ancestor /foo /foo/:/bar/ -1 -ancestor /foo /foo::/bar/ -1 -ancestor /foo /:/foo:/bar/ 0 -ancestor /foo /foo:/:/bar/ 0 -ancestor /foo /:/bar/:/foo 0 -ancestor /foo/bar "" -1 +ancestor /foo /foo:/bar -1 +ancestor /foo /:/foo:/bar 0 +ancestor /foo /foo:/:/bar 0 +ancestor /foo /:/bar:/foo 0 ancestor /foo/bar / 0 ancestor /foo/bar /fo -1 -ancestor /foo/bar foo -1 ancestor /foo/bar /foo 4 -ancestor /foo/bar /foo/ 4 ancestor /foo/bar /foo/ba -1 ancestor /foo/bar /:/fo 0 ancestor /foo/bar /foo:/foo/ba 4 ancestor /foo/bar /bar -1 -ancestor /foo/bar /bar/ -1 -ancestor /foo/bar /fo: -1 -ancestor /foo/bar :/fo -1 -ancestor /foo/bar /foo:/bar/ 4 -ancestor /foo/bar /:/foo:/bar/ 4 -ancestor /foo/bar /foo:/:/bar/ 4 -ancestor /foo/bar /:/bar/:/fo 0 -ancestor /foo/bar /:/bar/ 0 -ancestor /foo/bar .:/foo/. 4 -ancestor /foo/bar .:/foo/.:.: 4 -ancestor /foo/bar /foo/./:.:/bar 4 -ancestor /foo/bar .:/bar -1 +ancestor /foo/bar /fo -1 +ancestor /foo/bar /foo:/bar 4 +ancestor /foo/bar /:/foo:/bar 4 +ancestor /foo/bar /foo:/:/bar 4 +ancestor /foo/bar /:/bar:/fo 0 +ancestor /foo/bar /:/bar 0 +ancestor /foo/bar /foo 4 +ancestor /foo/bar /foo:/bar 4 +ancestor /foo/bar /bar -1 test_expect_success 'strip_path_suffix' ' test c:/msysgit = $(test-path-utils strip_path_suffix \ @@ -198,4 +190,33 @@ test_expect_success SYMLINKS 'real path works on symlinks' ' test "$sym" = "$(test-path-utils real_path "$dir2/syml")" ' +relative_path /a/b/c/ /a/b/ c/ +relative_path /a/b/c/ /a/b c/ +relative_path /a//b//c/ //a/b// c/ POSIX +relative_path /a/b /a/b ./ +relative_path /a/b/ /a/b ./ +relative_path /a /a/b ../ +relative_path / /a/b/ ../../ +relative_path /a/c /a/b/ ../c +relative_path /a/c /a/b ../c +relative_path /x/y /a/b/ ../../x/y +relative_path /a/b "<empty>" /a/b +relative_path /a/b "<null>" /a/b +relative_path a/b/c/ a/b/ c/ +relative_path a/b/c/ a/b c/ +relative_path a/b//c a//b c +relative_path a/b/ a/b/ ./ +relative_path a/b/ a/b ./ +relative_path a a/b ../ +relative_path x/y a/b ../../x/y +relative_path a/c a/b ../c +relative_path a/b "<empty>" a/b +relative_path a/b "<null>" a/b +relative_path "<empty>" /a/b ./ +relative_path "<empty>" "<empty>" ./ +relative_path "<empty>" "<null>" ./ +relative_path "<null>" "<empty>" ./ +relative_path "<null>" "<null>" ./ +relative_path "<null>" /a/b ./ + test_done diff --git a/t/t0063-string-list.sh b/t/t0063-string-list.sh index 41c8826a74..dbfc05ebdc 100755 --- a/t/t0063-string-list.sh +++ b/t/t0063-string-list.sh @@ -17,14 +17,6 @@ test_split () { " } -test_longest_prefix () { - test "$(test-string-list longest_prefix "$1" "$2")" = "$3" -} - -test_no_longest_prefix () { - test_must_fail test-string-list longest_prefix "$1" "$2" -} - test_split "foo:bar:baz" ":" "-1" <<EOF 3 [0]: "foo" @@ -96,26 +88,4 @@ test_expect_success "test remove_duplicates" ' test a:b:c = "$(test-string-list remove_duplicates a:a:a:b:b:b:c:c:c)" ' -test_expect_success "test longest_prefix" ' - test_no_longest_prefix - '' && - test_no_longest_prefix - x && - test_longest_prefix "" x "" && - test_longest_prefix x x x && - test_longest_prefix "" foo "" && - test_longest_prefix : foo "" && - test_longest_prefix f foo f && - test_longest_prefix foo foobar foo && - test_longest_prefix foo foo foo && - test_no_longest_prefix bar foo && - test_no_longest_prefix bar:bar foo && - test_no_longest_prefix foobar foo && - test_longest_prefix foo:bar foo foo && - test_longest_prefix foo:bar bar bar && - test_longest_prefix foo::bar foo foo && - test_longest_prefix foo:foobar foo foo && - test_longest_prefix foobar:foo foo foo && - test_longest_prefix foo: bar "" && - test_longest_prefix :foo bar "" -' - test_done diff --git a/t/t0070-fundamental.sh b/t/t0070-fundamental.sh index da2c504e53..986b2a8f26 100755 --- a/t/t0070-fundamental.sh +++ b/t/t0070-fundamental.sh @@ -17,7 +17,7 @@ test_expect_success 'mktemp to nonexistent directory prints filename' ' grep "doesnotexist/test" err ' -test_expect_success POSIXPERM 'mktemp to unwritable directory prints filename' ' +test_expect_success POSIXPERM,SANITY 'mktemp to unwritable directory prints filename' ' mkdir cannotwrite && chmod -w cannotwrite && test_when_finished "chmod +w cannotwrite" && diff --git a/t/t0100-previous.sh b/t/t0100-previous.sh index 315b9b3f10..e0a6940232 100755 --- a/t/t0100-previous.sh +++ b/t/t0100-previous.sh @@ -27,6 +27,7 @@ test_expect_success 'merge @{-1}' ' test_commit B && git checkout A && test_commit C && + test_commit D && git branch -f master B && git branch -f other && git checkout other && @@ -35,14 +36,24 @@ test_expect_success 'merge @{-1}' ' git cat-file commit HEAD | grep "Merge branch '\''other'\''" ' -test_expect_success 'merge @{-1} when there is not enough switches yet' ' +test_expect_success 'merge @{-1}~1' ' + git checkout master && + git reset --hard B && + git checkout other && + git checkout master && + git merge @{-1}~1 && + git cat-file commit HEAD >actual && + grep "Merge branch '\''other'\''" actual +' + +test_expect_success 'merge @{-100} before checking out that many branches yet' ' git reflog expire --expire=now && git checkout -f master && git reset --hard B && git branch -f other C && git checkout other && git checkout master && - test_must_fail git merge @{-12} + test_must_fail git merge @{-100} ' test_done diff --git a/t/t1004-read-tree-m-u-wf.sh b/t/t1004-read-tree-m-u-wf.sh index b3ae7d52c6..3e72aff470 100755 --- a/t/t1004-read-tree-m-u-wf.sh +++ b/t/t1004-read-tree-m-u-wf.sh @@ -158,7 +158,7 @@ test_expect_success '3-way not overwriting local changes (their side)' ' ' -test_expect_success SYMLINKS 'funny symlink in work tree' ' +test_expect_success 'funny symlink in work tree' ' git reset --hard && git checkout -b sym-b side-b && @@ -170,15 +170,14 @@ test_expect_success SYMLINKS 'funny symlink in work tree' ' rm -fr a && git checkout -b sym-a side-a && mkdir -p a && - ln -s ../b a/b && - git add a/b && + test_ln_s_add ../b a/b && git commit -m "we add a/b" && read_tree_u_must_succeed -m -u sym-a sym-a sym-b ' -test_expect_success SYMLINKS,SANITY 'funny symlink in work tree, un-unlink-able' ' +test_expect_success SANITY 'funny symlink in work tree, un-unlink-able' ' rm -fr a b && git reset --hard && diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh index d8b7f2ffbc..d499d02a29 100755 --- a/t/t1006-cat-file.sh +++ b/t/t1006-cat-file.sh @@ -36,66 +36,54 @@ $content" ' test_expect_success "Type of $type is correct" ' - test $type = "$(git cat-file -t $sha1)" + echo $type >expect && + git cat-file -t $sha1 >actual && + test_cmp expect actual ' test_expect_success "Size of $type is correct" ' - test $size = "$(git cat-file -s $sha1)" + echo $size >expect && + git cat-file -s $sha1 >actual && + test_cmp expect actual ' test -z "$content" || test_expect_success "Content of $type is correct" ' - expect="$(maybe_remove_timestamp "$content" $no_ts)" - actual="$(maybe_remove_timestamp "$(git cat-file $type $sha1)" $no_ts)" - - if test "z$expect" = "z$actual" - then - : happy - else - echo "Oops: expected $expect" - echo "but got $actual" - false - fi + maybe_remove_timestamp "$content" $no_ts >expect && + maybe_remove_timestamp "$(git cat-file $type $sha1)" $no_ts >actual && + test_cmp expect actual ' test_expect_success "Pretty content of $type is correct" ' - expect="$(maybe_remove_timestamp "$pretty_content" $no_ts)" - actual="$(maybe_remove_timestamp "$(git cat-file -p $sha1)" $no_ts)" - if test "z$expect" = "z$actual" - then - : happy - else - echo "Oops: expected $expect" - echo "but got $actual" - false - fi + maybe_remove_timestamp "$pretty_content" $no_ts >expect && + maybe_remove_timestamp "$(git cat-file -p $sha1)" $no_ts >actual && + test_cmp expect actual ' test -z "$content" || test_expect_success "--batch output of $type is correct" ' - expect="$(maybe_remove_timestamp "$batch_output" $no_ts)" - actual="$(maybe_remove_timestamp "$(echo $sha1 | git cat-file --batch)" $no_ts)" - if test "z$expect" = "z$actual" - then - : happy - else - echo "Oops: expected $expect" - echo "but got $actual" - false - fi + maybe_remove_timestamp "$batch_output" $no_ts >expect && + maybe_remove_timestamp "$(echo $sha1 | git cat-file --batch)" $no_ts >actual && + test_cmp expect actual ' test_expect_success "--batch-check output of $type is correct" ' - expect="$sha1 $type $size" - actual="$(echo_without_newline $sha1 | git cat-file --batch-check)" - if test "z$expect" = "z$actual" - then - : happy - else - echo "Oops: expected $expect" - echo "but got $actual" - false - fi + echo "$sha1 $type $size" >expect && + echo_without_newline $sha1 | git cat-file --batch-check >actual && + test_cmp expect actual + ' + + test_expect_success "custom --batch-check format" ' + echo "$type $sha1" >expect && + echo $sha1 | git cat-file --batch-check="%(objecttype) %(objectname)" >actual && + test_cmp expect actual + ' + + test_expect_success '--batch-check with %(rest)' ' + echo "$type this is some extra content" >expect && + echo "$sha1 this is some extra content" | + git cat-file --batch-check="%(objecttype) %(rest)" >actual && + test_cmp expect actual ' } @@ -116,9 +104,9 @@ tree_pretty_content="100644 blob $hello_sha1 hello" run_tests 'tree' $tree_sha1 $tree_size "" "$tree_pretty_content" -commit_message="Intial commit" +commit_message="Initial commit" commit_sha1=$(echo_without_newline "$commit_message" | git commit-tree $tree_sha1) -commit_size=176 +commit_size=177 commit_content="tree $tree_sha1 author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> 0000000000 +0000 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 0000000000 +0000 @@ -135,14 +123,11 @@ tag_description="This is a tag" tag_content="$tag_header_without_timestamp 0000000000 +0000 $tag_description" -tag_pretty_content="$tag_header_without_timestamp Thu Jan 1 00:00:00 1970 +0000 - -$tag_description" tag_sha1=$(echo_without_newline "$tag_content" | git mktag) tag_size=$(strlen "$tag_content") -run_tests 'tag' $tag_sha1 $tag_size "$tag_content" "$tag_pretty_content" 1 +run_tests 'tag' $tag_sha1 $tag_size "$tag_content" "$tag_content" 1 test_expect_success \ "Reach a blob from a tag pointing to it" \ diff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh index 5c0053a20b..0c74beedd2 100755 --- a/t/t1011-read-tree-sparse-checkout.sh +++ b/t/t1011-read-tree-sparse-checkout.sh @@ -250,4 +250,28 @@ EOF test_cmp expected actual ' +test_expect_success 'checkout without --ignore-skip-worktree-bits' ' + echo "*" >.git/info/sparse-checkout && + git checkout -f top && + test_path_is_file init.t && + echo sub >.git/info/sparse-checkout && + git checkout && + echo modified >> sub/added && + git checkout . && + test_path_is_missing init.t && + git diff --exit-code HEAD +' + +test_expect_success 'checkout with --ignore-skip-worktree-bits' ' + echo "*" >.git/info/sparse-checkout && + git checkout -f top && + test_path_is_file init.t && + echo sub >.git/info/sparse-checkout && + git checkout && + echo modified >> sub/added && + git checkout --ignore-skip-worktree-bits . && + test_path_is_file init.t && + git diff --exit-code HEAD +' + test_done diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh index e23ac0e69d..1e2945ec7e 100755 --- a/t/t1020-subdirectory.sh +++ b/t/t1020-subdirectory.sh @@ -111,19 +111,19 @@ test_expect_success 'read-tree' ' test_expect_success 'alias expansion' ' ( - git config alias.ss status && + git config alias.test-status-alias status && cd dir && git status && - git ss + git test-status-alias ) ' test_expect_success NOT_MINGW '!alias expansion' ' pwd >expect && ( - git config alias.test !pwd && + git config alias.test-alias-directory !pwd && cd dir && - git test >../actual + git test-alias-directory >../actual ) && test_cmp expect actual ' @@ -131,9 +131,9 @@ test_expect_success NOT_MINGW '!alias expansion' ' test_expect_success 'GIT_PREFIX for !alias' ' printf "dir/" >expect && ( - git config alias.test "!sh -c \"printf \$GIT_PREFIX\"" && + git config alias.test-alias-directory "!sh -c \"printf \$GIT_PREFIX\"" && cd dir && - git test >../actual + git test-alias-directory >../actual ) && test_cmp expect actual ' diff --git a/t/t1060-object-corruption.sh b/t/t1060-object-corruption.sh new file mode 100755 index 0000000000..3f8705139d --- /dev/null +++ b/t/t1060-object-corruption.sh @@ -0,0 +1,104 @@ +#!/bin/sh + +test_description='see how we handle various forms of corruption' +. ./test-lib.sh + +# convert "1234abcd" to ".git/objects/12/34abcd" +obj_to_file() { + echo "$(git rev-parse --git-dir)/objects/$(git rev-parse "$1" | sed 's,..,&/,')" +} + +# Convert byte at offset "$2" of object "$1" into '\0' +corrupt_byte() { + obj_file=$(obj_to_file "$1") && + chmod +w "$obj_file" && + printf '\0' | dd of="$obj_file" bs=1 seek="$2" conv=notrunc +} + +test_expect_success 'setup corrupt repo' ' + git init bit-error && + ( + cd bit-error && + test_commit content && + corrupt_byte HEAD:content.t 10 + ) +' + +test_expect_success 'setup repo with missing object' ' + git init missing && + ( + cd missing && + test_commit content && + rm -f "$(obj_to_file HEAD:content.t)" + ) +' + +test_expect_success 'setup repo with misnamed object' ' + git init misnamed && + ( + cd misnamed && + test_commit content && + good=$(obj_to_file HEAD:content.t) && + blob=$(echo corrupt | git hash-object -w --stdin) && + bad=$(obj_to_file $blob) && + rm -f "$good" && + mv "$bad" "$good" + ) +' + +test_expect_success 'streaming a corrupt blob fails' ' + ( + cd bit-error && + test_must_fail git cat-file blob HEAD:content.t + ) +' + +test_expect_success 'read-tree -u detects bit-errors in blobs' ' + ( + cd bit-error && + rm -f content.t && + test_must_fail git read-tree --reset -u HEAD + ) +' + +test_expect_success 'read-tree -u detects missing objects' ' + ( + cd missing && + rm -f content.t && + test_must_fail git read-tree --reset -u HEAD + ) +' + +# We use --bare to make sure that the transport detects it, not the checkout +# phase. +test_expect_success 'clone --no-local --bare detects corruption' ' + test_must_fail git clone --no-local --bare bit-error corrupt-transport +' + +test_expect_success 'clone --no-local --bare detects missing object' ' + test_must_fail git clone --no-local --bare missing missing-transport +' + +test_expect_success 'clone --no-local --bare detects misnamed object' ' + test_must_fail git clone --no-local --bare misnamed misnamed-transport +' + +# We do not expect --local to detect corruption at the transport layer, +# so we are really checking the checkout() code path. +test_expect_success 'clone --local detects corruption' ' + test_must_fail git clone --local bit-error corrupt-checkout +' + +test_expect_success 'error detected during checkout leaves repo intact' ' + test_path_is_dir corrupt-checkout/.git +' + +test_expect_success 'clone --local detects missing objects' ' + test_must_fail git clone --local missing missing-checkout +' + +test_expect_failure 'clone --local detects misnamed objects' ' + test_must_fail git clone --local misnamed misnamed-checkout +' + +test_done diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 7c4c372e37..c4a7d84f46 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -55,11 +55,13 @@ test_expect_success 'uppercase section' ' test_cmp expect .git/config ' -test_expect_success 'replace with non-match' \ - 'git config core.penguin kingpin !blue' +test_expect_success 'replace with non-match' ' + git config core.penguin kingpin !blue +' -test_expect_success 'replace with non-match (actually matching)' \ - 'git config core.penguin "very blue" !kingpin' +test_expect_success 'replace with non-match (actually matching)' ' + git config core.penguin "very blue" !kingpin +' cat > expect << EOF [core] @@ -108,8 +110,9 @@ baz = multiple \ lines EOF -test_expect_success 'unset with cont. lines' \ - 'git config --unset beta.baz' +test_expect_success 'unset with cont. lines' ' + git config --unset beta.baz +' cat > expect <<\EOF [alpha] @@ -133,8 +136,9 @@ EOF cp .git/config .git/config2 -test_expect_success 'multiple unset' \ - 'git config --unset-all beta.haha' +test_expect_success 'multiple unset' ' + git config --unset-all beta.haha +' cat > expect << EOF [beta] ; silly comment # another comment @@ -145,7 +149,9 @@ noIndent= sillyValue ; 'nother silly comment [nextSection] noNewline = ouch EOF -test_expect_success 'multiple unset is correct' 'test_cmp expect .git/config' +test_expect_success 'multiple unset is correct' ' + test_cmp expect .git/config +' cp .git/config2 .git/config @@ -156,8 +162,9 @@ test_expect_success '--replace-all missing value' ' rm .git/config2 -test_expect_success '--replace-all' \ - 'git config --replace-all beta.haha gamma' +test_expect_success '--replace-all' ' + git config --replace-all beta.haha gamma +' cat > expect << EOF [beta] ; silly comment # another comment @@ -169,7 +176,9 @@ noIndent= sillyValue ; 'nother silly comment [nextSection] noNewline = ouch EOF -test_expect_success 'all replaced' 'test_cmp expect .git/config' +test_expect_success 'all replaced' ' + test_cmp expect .git/config +' cat > expect << EOF [beta] ; silly comment # another comment @@ -200,7 +209,11 @@ test_expect_success 'really really mean test' ' test_cmp expect .git/config ' -test_expect_success 'get value' 'test alpha = $(git config beta.haha)' +test_expect_success 'get value' ' + echo alpha >expect && + git config beta.haha >actual && + test_cmp expect actual +' cat > expect << EOF [beta] ; silly comment # another comment @@ -231,18 +244,30 @@ test_expect_success 'multivar' ' test_cmp expect .git/config ' -test_expect_success 'non-match' \ - 'git config --get nextsection.nonewline !for' +test_expect_success 'non-match' ' + git config --get nextsection.nonewline !for +' -test_expect_success 'non-match value' \ - 'test wow = $(git config --get nextsection.nonewline !for)' +test_expect_success 'non-match value' ' + echo wow >expect && + git config --get nextsection.nonewline !for >actual && + test_cmp expect actual +' -test_expect_success 'ambiguous get' ' - test_must_fail git config --get nextsection.nonewline +test_expect_success 'multi-valued get returns final one' ' + echo "wow2 for me" >expect && + git config --get nextsection.nonewline >actual && + test_cmp expect actual ' -test_expect_success 'get multivar' \ - 'git config --get-all nextsection.nonewline' +test_expect_success 'multi-valued get-all returns all' ' + cat >expect <<-\EOF && + wow + wow2 for me + EOF + git config --get-all nextsection.nonewline >actual && + test_cmp expect actual +' cat > expect << EOF [beta] ; silly comment # another comment @@ -259,10 +284,6 @@ test_expect_success 'multivar replace' ' test_cmp expect .git/config ' -test_expect_success 'ambiguous value' ' - test_must_fail git config nextsection.nonewline -' - test_expect_success 'ambiguous unset' ' test_must_fail git config --unset nextsection.nonewline ' @@ -290,8 +311,9 @@ test_expect_success 'invalid key' 'test_must_fail git config inval.2key blabla' test_expect_success 'correct key' 'git config 123456.a123 987' -test_expect_success 'hierarchical section' \ - 'git config Version.1.2.3eX.Alpha beta' +test_expect_success 'hierarchical section' ' + git config Version.1.2.3eX.Alpha beta +' cat > expect << EOF [beta] ; silly comment # another comment @@ -307,7 +329,9 @@ noIndent= sillyValue ; 'nother silly comment Alpha = beta EOF -test_expect_success 'hierarchical section value' 'test_cmp expect .git/config' +test_expect_success 'hierarchical section value' ' + test_cmp expect .git/config +' cat > expect << EOF beta.noindent=sillyValue @@ -316,9 +340,10 @@ nextsection.nonewline=wow2 for me version.1.2.3eX.alpha=beta EOF -test_expect_success 'working --list' \ - 'git config --list > output && cmp output expect' - +test_expect_success 'working --list' ' + git config --list > output && + test_cmp expect output +' cat > expect << EOF EOF @@ -332,8 +357,10 @@ beta.noindent sillyValue nextsection.nonewline wow2 for me EOF -test_expect_success '--get-regexp' \ - 'git config --get-regexp in > output && cmp output expect' +test_expect_success '--get-regexp' ' + git config --get-regexp in >output && + test_cmp expect output +' cat > expect << EOF wow2 for me @@ -353,41 +380,48 @@ cat > .git/config << EOF variable = EOF -test_expect_success 'get variable with no value' \ - 'git config --get novalue.variable ^$' +test_expect_success 'get variable with no value' ' + git config --get novalue.variable ^$ +' -test_expect_success 'get variable with empty value' \ - 'git config --get emptyvalue.variable ^$' +test_expect_success 'get variable with empty value' ' + git config --get emptyvalue.variable ^$ +' echo novalue.variable > expect -test_expect_success 'get-regexp variable with no value' \ - 'git config --get-regexp novalue > output && - cmp output expect' +test_expect_success 'get-regexp variable with no value' ' + git config --get-regexp novalue > output && + test_cmp expect output +' echo 'novalue.variable true' > expect -test_expect_success 'get-regexp --bool variable with no value' \ - 'git config --bool --get-regexp novalue > output && - cmp output expect' +test_expect_success 'get-regexp --bool variable with no value' ' + git config --bool --get-regexp novalue > output && + test_cmp expect output +' echo 'emptyvalue.variable ' > expect -test_expect_success 'get-regexp variable with empty value' \ - 'git config --get-regexp emptyvalue > output && - cmp output expect' +test_expect_success 'get-regexp variable with empty value' ' + git config --get-regexp emptyvalue > output && + test_cmp expect output +' echo true > expect -test_expect_success 'get bool variable with no value' \ - 'git config --bool novalue.variable > output && - cmp output expect' +test_expect_success 'get bool variable with no value' ' + git config --bool novalue.variable > output && + test_cmp expect output +' echo false > expect -test_expect_success 'get bool variable with empty value' \ - 'git config --bool emptyvalue.variable > output && - cmp output expect' +test_expect_success 'get bool variable with empty value' ' + git config --bool emptyvalue.variable > output && + test_cmp expect output +' test_expect_success 'no arguments, but no crash' ' test_must_fail git config >output 2>&1 && @@ -427,8 +461,9 @@ test_expect_success 'new variable inserts into proper section' ' test_cmp expect .git/config ' -test_expect_success 'alternative GIT_CONFIG (non-existing file should fail)' \ - 'test_must_fail git config --file non-existing-config -l' +test_expect_success 'alternative GIT_CONFIG (non-existing file should fail)' ' + test_must_fail git config --file non-existing-config -l +' cat > other-config << EOF [ein] @@ -444,8 +479,10 @@ test_expect_success 'alternative GIT_CONFIG' ' test_cmp expect output ' -test_expect_success 'alternative GIT_CONFIG (--file)' \ - 'git config --file other-config -l > output && cmp output expect' +test_expect_success 'alternative GIT_CONFIG (--file)' ' + git config --file other-config -l > output && + test_cmp expect output +' test_expect_success 'refer config from subdirectory' ' mkdir x && @@ -489,8 +526,9 @@ cat > .git/config << EOF weird EOF -test_expect_success "rename section" \ - "git config --rename-section branch.eins branch.zwei" +test_expect_success 'rename section' ' + git config --rename-section branch.eins branch.zwei +' cat > expect << EOF # Hallo @@ -503,17 +541,22 @@ cat > expect << EOF weird EOF -test_expect_success "rename succeeded" "test_cmp expect .git/config" +test_expect_success 'rename succeeded' ' + test_cmp expect .git/config +' -test_expect_success "rename non-existing section" ' +test_expect_success 'rename non-existing section' ' test_must_fail git config --rename-section \ branch."world domination" branch.drei ' -test_expect_success "rename succeeded" "test_cmp expect .git/config" +test_expect_success 'rename succeeded' ' + test_cmp expect .git/config +' -test_expect_success "rename another section" \ - 'git config --rename-section branch."1 234 blabl/a" branch.drei' +test_expect_success 'rename another section' ' + git config --rename-section branch."1 234 blabl/a" branch.drei +' cat > expect << EOF # Hallo @@ -526,14 +569,17 @@ cat > expect << EOF weird EOF -test_expect_success "rename succeeded" "test_cmp expect .git/config" +test_expect_success 'rename succeeded' ' + test_cmp expect .git/config +' cat >> .git/config << EOF [branch "vier"] z = 1 EOF -test_expect_success "rename a section with a var on the same line" \ - 'git config --rename-section branch.vier branch.zwei' +test_expect_success 'rename a section with a var on the same line' ' + git config --rename-section branch.vier branch.zwei +' cat > expect << EOF # Hallo @@ -548,7 +594,9 @@ weird z = 1 EOF -test_expect_success "rename succeeded" "test_cmp expect .git/config" +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 "" @@ -562,7 +610,9 @@ cat >> .git/config << EOF [branch "zwei"] a = 1 [branch "vier"] EOF -test_expect_success "remove section" "git config --remove-section branch.zwei" +test_expect_success 'remove section' ' + git config --remove-section branch.zwei +' cat > expect << EOF # Hallo @@ -571,8 +621,9 @@ cat > expect << EOF weird EOF -test_expect_success "section was removed properly" \ - "test_cmp expect .git/config" +test_expect_success 'section was removed properly' ' + test_cmp expect .git/config +' cat > expect << EOF [gitcvs] @@ -583,7 +634,6 @@ cat > expect << EOF EOF test_expect_success 'section ending' ' - rm -f .git/config && git config gitcvs.enabled true && git config gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite && @@ -593,30 +643,25 @@ test_expect_success 'section ending' ' ' test_expect_success numbers ' - git config kilo.gram 1k && git config mega.ton 1m && - k=$(git config --int --get kilo.gram) && - test z1024 = "z$k" && - m=$(git config --int --get mega.ton) && - test z1048576 = "z$m" + echo 1024 >expect && + echo 1048576 >>expect && + git config --int --get kilo.gram >actual && + git config --int --get mega.ton >>actual && + test_cmp expect actual ' -cat > expect <<EOF -fatal: bad config value for 'aninvalid.unit' in .git/config -EOF - test_expect_success 'invalid unit' ' - git config aninvalid.unit "1auto" && - s=$(git config aninvalid.unit) && - test "z1auto" = "z$s" && - if git config --int --get aninvalid.unit 2>actual - then - echo config should have failed - false - fi && - cmp actual expect + echo 1auto >expect && + git config aninvalid.unit >actual && + test_cmp expect actual && + cat > expect <<-\EOF + fatal: bad config value for '\''aninvalid.unit'\'' in .git/config + EOF + test_must_fail git config --int --get aninvalid.unit 2>actual && + test_cmp actual expect ' cat > expect << EOF @@ -646,7 +691,7 @@ test_expect_success bool ' git config --bool --get bool.true$i >>result git config --bool --get bool.false$i >>result done && - cmp expect result' + test_cmp expect result' test_expect_success 'invalid bool (--get)' ' @@ -680,7 +725,7 @@ test_expect_success 'set --bool' ' git config --bool bool.false2 "" && git config --bool bool.false3 nO && git config --bool bool.false4 FALSE && - cmp expect .git/config' + test_cmp expect .git/config' cat > expect <<\EOF [int] @@ -695,39 +740,37 @@ test_expect_success 'set --int' ' git config --int int.val1 01 && git config --int int.val2 -1 && git config --int int.val3 5m && - cmp expect .git/config' + test_cmp expect .git/config +' -cat >expect <<\EOF -[bool] - true1 = true +test_expect_success 'get --bool-or-int' ' + cat >.git/config <<-\EOF && + [bool] + true1 true2 = true - false1 = false - false2 = false -[int] + false = false + [int] int1 = 0 int2 = 1 int3 = -1 -EOF - -test_expect_success 'get --bool-or-int' ' - rm -f .git/config && - ( - echo "[bool]" - echo true1 - echo true2 = true - echo false = false - echo "[int]" - echo int1 = 0 - echo int2 = 1 - echo int3 = -1 - ) >>.git/config && - test $(git config --bool-or-int bool.true1) = true && - test $(git config --bool-or-int bool.true2) = true && - test $(git config --bool-or-int bool.false) = false && - test $(git config --bool-or-int int.int1) = 0 && - test $(git config --bool-or-int int.int2) = 1 && - test $(git config --bool-or-int int.int3) = -1 - + EOF + cat >expect <<-\EOF && + true + true + false + 0 + 1 + -1 + EOF + { + git config --bool-or-int bool.true1 && + git config --bool-or-int bool.true2 && + git config --bool-or-int bool.false && + git config --bool-or-int int.int1 && + git config --bool-or-int int.int2 && + git config --bool-or-int int.int3 + } >actual && + test_cmp expect actual ' cat >expect <<\EOF @@ -849,7 +892,7 @@ EOF test_expect_success 'value continued on next line' ' git config --list > result && - cmp result expect + test_cmp result expect ' cat > .git/config <<\EOF @@ -885,11 +928,12 @@ test_expect_success '--null --get-regexp' ' test_expect_success 'inner whitespace kept verbatim' ' git config section.val "foo bar" && - test "z$(git config section.val)" = "zfoo bar" + echo "foo bar" >expect && + git config section.val >actual && + test_cmp expect actual ' test_expect_success SYMLINKS 'symlinked configuration' ' - ln -s notyet myconfig && GIT_CONFIG=myconfig git config test.frotz nitfol && test -h myconfig && @@ -898,9 +942,15 @@ test_expect_success SYMLINKS 'symlinked configuration' ' GIT_CONFIG=myconfig git config test.xyzzy rezrov && test -h myconfig && test -f notyet && - test "z$(GIT_CONFIG=notyet git config test.frotz)" = znitfol && - test "z$(GIT_CONFIG=notyet git config test.xyzzy)" = zrezrov - + cat >expect <<-\EOF && + nitfol + rezrov + EOF + { + GIT_CONFIG=notyet git config test.frotz && + GIT_CONFIG=notyet git config test.xyzzy + } >actual && + test_cmp expect actual ' test_expect_success 'nonexistent configuration' ' @@ -932,12 +982,20 @@ test_expect_success 'check split_cmdline return' " git commit -m 'initial commit' && git config branch.master.mergeoptions 'echo \"' && test_must_fail git merge master - " +" test_expect_success 'git -c "key=value" support' ' - test "z$(git -c core.name=value config core.name)" = zvalue && - test "z$(git -c foo.CamelCase=value config foo.camelcase)" = zvalue && - test "z$(git -c foo.flag config --bool foo.flag)" = ztrue && + cat >expect <<-\EOF && + value + value + true + EOF + { + git -c core.name=value config core.name && + git -c foo.CamelCase=value config foo.camelcase && + git -c foo.flag config --bool foo.flag + } >actual && + test_cmp expect actual && test_must_fail git -c name=value config core.name ' @@ -1029,4 +1087,39 @@ test_expect_success 'barf on incomplete string' ' grep " line 3 " error ' +# good section hygiene +test_expect_failure 'unsetting the last key in a section removes header' ' + cat >.git/config <<-\EOF && + # some generic comment on the configuration file itself + # a comment specific to this "section" section. + [section] + # some intervening lines + # that should also be dropped + + key = value + # please be careful when you update the above variable + EOF + + cat >expect <<-\EOF && + # some generic comment on the configuration file itself + EOF + + git config --unset section.key && + test_cmp expect .git/config +' + +test_expect_failure 'adding a key into an empty section reuses header' ' + cat >.git/config <<-\EOF && + [section] + EOF + + q_to_tab >expect <<-\EOF && + [section] + Qkey = value + EOF + + git config section.key value + test_cmp expect .git/config +' + test_done diff --git a/t/t1307-config-blob.sh b/t/t1307-config-blob.sh new file mode 100755 index 0000000000..fdc257e66f --- /dev/null +++ b/t/t1307-config-blob.sh @@ -0,0 +1,70 @@ +#!/bin/sh + +test_description='support for reading config from a blob' +. ./test-lib.sh + +test_expect_success 'create config blob' ' + cat >config <<-\EOF && + [some] + value = 1 + EOF + git add config && + git commit -m foo +' + +test_expect_success 'list config blob contents' ' + echo some.value=1 >expect && + git config --blob=HEAD:config --list >actual && + test_cmp expect actual +' + +test_expect_success 'fetch value from blob' ' + echo true >expect && + git config --blob=HEAD:config --bool some.value >actual && + test_cmp expect actual +' + +test_expect_success 'reading non-existing value from blob is an error' ' + test_must_fail git config --blob=HEAD:config non.existing +' + +test_expect_success 'reading from blob and file is an error' ' + test_must_fail git config --blob=HEAD:config --system --list +' + +test_expect_success 'reading from missing ref is an error' ' + test_must_fail git config --blob=HEAD:doesnotexist --list +' + +test_expect_success 'reading from non-blob is an error' ' + test_must_fail git config --blob=HEAD --list +' + +test_expect_success 'setting a value in a blob is an error' ' + test_must_fail git config --blob=HEAD:config some.value foo +' + +test_expect_success 'deleting a value in a blob is an error' ' + test_must_fail git config --blob=HEAD:config --unset some.value +' + +test_expect_success 'editing a blob is an error' ' + test_must_fail git config --blob=HEAD:config --edit +' + +test_expect_success 'parse errors in blobs are properly attributed' ' + cat >config <<-\EOF && + [some] + value = " + EOF + git add config && + git commit -m broken && + + test_must_fail git config --blob=HEAD:config some.value 2>err && + + # just grep for our token as the exact error message is likely to + # change or be internationalized + grep "HEAD:config" err +' + +test_done diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh index 2c96551ed0..36378b0e3f 100755 --- a/t/t1401-symbolic-ref.sh +++ b/t/t1401-symbolic-ref.sh @@ -33,4 +33,34 @@ test_expect_success 'symbolic-ref refuses bare sha1' ' ' reset_to_sane +test_expect_success 'symbolic-ref deletes HEAD' ' + git symbolic-ref -d HEAD && + test_path_is_file .git/refs/heads/foo && + test_path_is_missing .git/HEAD +' +reset_to_sane + +test_expect_success 'symbolic-ref deletes dangling HEAD' ' + git symbolic-ref HEAD refs/heads/missing && + git symbolic-ref -d HEAD && + test_path_is_missing .git/refs/heads/missing && + test_path_is_missing .git/HEAD +' +reset_to_sane + +test_expect_success 'symbolic-ref fails to delete missing FOO' ' + echo "fatal: Cannot delete FOO, not a symbolic ref" >expect && + test_must_fail git symbolic-ref -d FOO >actual 2>&1 && + test_cmp expect actual +' +reset_to_sane + +test_expect_success 'symbolic-ref fails to delete real ref' ' + echo "fatal: Cannot delete refs/heads/foo, not a symbolic ref" >expect && + test_must_fail git symbolic-ref -d refs/heads/foo >actual 2>&1 && + test_path_is_file .git/refs/heads/foo && + test_cmp expect actual +' +reset_to_sane + test_done diff --git a/t/t1402-check-ref-format.sh b/t/t1402-check-ref-format.sh index 1ae4d87c92..1a5a5f39fd 100755 --- a/t/t1402-check-ref-format.sh +++ b/t/t1402-check-ref-format.sh @@ -11,7 +11,8 @@ valid_ref() { prereq=$1 shift esac - test_expect_success $prereq "ref name '$1' is valid${2:+ with options $2}" " + desc="ref name '$1' is valid${2:+ with options $2}" + test_expect_success $prereq "$desc" " git check-ref-format $2 '$1' " } @@ -22,7 +23,8 @@ invalid_ref() { prereq=$1 shift esac - test_expect_success $prereq "ref name '$1' is invalid${2:+ with options $2}" " + desc="ref name '$1' is invalid${2:+ with options $2}" + test_expect_success $prereq "$desc" " test_must_fail git check-ref-format $2 '$1' " } diff --git a/t/t1403-show-ref.sh b/t/t1403-show-ref.sh new file mode 100755 index 0000000000..3e500ed7da --- /dev/null +++ b/t/t1403-show-ref.sh @@ -0,0 +1,167 @@ +#!/bin/sh + +test_description='show-ref' +. ./test-lib.sh + +test_expect_success setup ' + test_commit A && + git tag -f -a -m "annotated A" A && + git checkout -b side && + test_commit B && + git tag -f -a -m "annotated B" B && + git checkout master && + test_commit C && + git branch B A^0 +' + +test_expect_success 'show-ref' ' + echo $(git rev-parse refs/tags/A) refs/tags/A >expect && + + git show-ref A >actual && + test_cmp expect actual && + + git show-ref tags/A >actual && + test_cmp expect actual && + + git show-ref refs/tags/A >actual && + test_cmp expect actual && + + >expect && + + test_must_fail git show-ref D >actual + test_cmp expect actual +' + +test_expect_success 'show-ref -q' ' + >expect && + + git show-ref -q A >actual && + test_cmp expect actual && + + git show-ref -q tags/A >actual && + test_cmp expect actual && + + git show-ref -q refs/tags/A >actual && + test_cmp expect actual && + + test_must_fail git show-ref -q D >actual && + test_cmp expect actual +' + +test_expect_success 'show-ref --verify' ' + echo $(git rev-parse refs/tags/A) refs/tags/A >expect && + + git show-ref --verify refs/tags/A >actual && + test_cmp expect actual && + + >expect && + + test_must_fail git show-ref --verify A >actual && + test_cmp expect actual && + + test_must_fail git show-ref --verify tags/A >actual && + test_cmp expect actual && + + test_must_fail git show-ref --verify D >actual + test_cmp expect actual +' + +test_expect_success 'show-ref --verify -q' ' + >expect && + + git show-ref --verify -q refs/tags/A >actual && + test_cmp expect actual && + + test_must_fail git show-ref --verify -q A >actual && + test_cmp expect actual && + + test_must_fail git show-ref --verify -q tags/A >actual && + test_cmp expect actual && + + test_must_fail git show-ref --verify -q D >actual + test_cmp expect actual +' + +test_expect_success 'show-ref -d' ' + { + echo $(git rev-parse refs/tags/A) refs/tags/A && + echo $(git rev-parse refs/tags/A^0) "refs/tags/A^{}" + echo $(git rev-parse refs/tags/C) refs/tags/C + } >expect && + git show-ref -d A C >actual && + test_cmp expect actual && + + git show-ref -d tags/A tags/C >actual && + test_cmp expect actual && + + git show-ref -d refs/tags/A refs/tags/C >actual && + test_cmp expect actual && + + echo $(git rev-parse refs/heads/master) refs/heads/master >expect && + git show-ref -d master >actual && + test_cmp expect actual && + + git show-ref -d heads/master >actual && + test_cmp expect actual && + + git show-ref -d refs/heads/master >actual && + test_cmp expect actual + + git show-ref -d --verify refs/heads/master >actual && + test_cmp expect actual + + >expect && + + test_must_fail git show-ref -d --verify master >actual && + test_cmp expect actual && + + test_must_fail git show-ref -d --verify heads/master >actual && + test_cmp expect actual + +' + +test_expect_success 'show-ref --heads, --tags, --head, pattern' ' + for branch in B master side + do + echo $(git rev-parse refs/heads/$branch) refs/heads/$branch + done >expect.heads && + git show-ref --heads >actual && + test_cmp expect.heads actual && + + for tag in A B C + do + echo $(git rev-parse refs/tags/$tag) refs/tags/$tag + done >expect.tags && + git show-ref --tags >actual && + test_cmp expect.tags actual && + + cat expect.heads expect.tags >expect && + git show-ref --heads --tags >actual && + test_cmp expect actual && + + { + echo $(git rev-parse HEAD) HEAD && + cat expect.heads expect.tags + } >expect && + git show-ref --heads --tags --head >actual && + test_cmp expect actual && + + { + echo $(git rev-parse HEAD) HEAD && + echo $(git rev-parse refs/heads/B) refs/heads/B + echo $(git rev-parse refs/tags/B) refs/tags/B + } >expect && + git show-ref --head B >actual && + test_cmp expect actual && + + { + echo $(git rev-parse HEAD) HEAD && + echo $(git rev-parse refs/heads/B) refs/heads/B + echo $(git rev-parse refs/tags/B) refs/tags/B + echo $(git rev-parse refs/tags/B^0) "refs/tags/B^{}" + } >expect && + git show-ref --head -d B >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh index 08aa24ca15..d730734fde 100755 --- a/t/t1450-fsck.sh +++ b/t/t1450-fsck.sh @@ -237,4 +237,35 @@ test_expect_success 'fsck notices submodule entry pointing to null sha1' ' ) ' +test_expect_success 'fsck notices "." and ".." in trees' ' + ( + git init dots && + cd dots && + blob=$(echo foo | git hash-object -w --stdin) && + tab=$(printf "\\t") && + git mktree <<-EOF && + 100644 blob $blob$tab. + 100644 blob $blob$tab.. + EOF + git fsck 2>out && + cat out && + grep "warning.*\\." out + ) +' + +test_expect_success 'fsck notices ".git" in trees' ' + ( + git init dotgit && + cd dotgit && + blob=$(echo foo | git hash-object -w --stdin) && + tab=$(printf "\\t") && + git mktree <<-EOF && + 100644 blob $blob$tab.git + EOF + git fsck 2>out && + cat out && + grep "warning.*\\.git" out + ) +' + test_done diff --git a/t/t1504-ceiling-dirs.sh b/t/t1504-ceiling-dirs.sh index cce87a5ab5..3d51615e42 100755 --- a/t/t1504-ceiling-dirs.sh +++ b/t/t1504-ceiling-dirs.sh @@ -44,6 +44,10 @@ test_prefix ceil_at_sub "" GIT_CEILING_DIRECTORIES="$TRASH_ROOT/sub/" test_prefix ceil_at_sub_slash "" +if test_have_prereq SYMLINKS +then + ln -s sub top +fi mkdir -p sub/dir || exit 1 cd sub/dir || exit 1 @@ -68,6 +72,19 @@ test_fail subdir_ceil_at_sub GIT_CEILING_DIRECTORIES="$TRASH_ROOT/sub/" test_fail subdir_ceil_at_sub_slash +if test_have_prereq SYMLINKS +then + GIT_CEILING_DIRECTORIES="$TRASH_ROOT/top" + test_fail subdir_ceil_at_top + GIT_CEILING_DIRECTORIES="$TRASH_ROOT/top/" + test_fail subdir_ceil_at_top_slash + + GIT_CEILING_DIRECTORIES=":$TRASH_ROOT/top" + test_prefix subdir_ceil_at_top_no_resolve "sub/dir/" + GIT_CEILING_DIRECTORIES=":$TRASH_ROOT/top/" + test_prefix subdir_ceil_at_top_slash_no_resolve "sub/dir/" +fi + GIT_CEILING_DIRECTORIES="$TRASH_ROOT/sub/dir" test_prefix subdir_ceil_at_subdir "sub/dir/" diff --git a/t/t1505-rev-parse-last.sh b/t/t1505-rev-parse-last.sh index d709ecf8df..4969edb314 100755 --- a/t/t1505-rev-parse-last.sh +++ b/t/t1505-rev-parse-last.sh @@ -32,32 +32,24 @@ test_expect_success 'setup' ' # # and 'side' should be the last branch -test_rev_equivalent () { - - git rev-parse "$1" > expect && - git rev-parse "$2" > output && - test_cmp expect output - -} - test_expect_success '@{-1} works' ' - test_rev_equivalent side @{-1} + test_cmp_rev side @{-1} ' test_expect_success '@{-1}~2 works' ' - test_rev_equivalent side~2 @{-1}~2 + test_cmp_rev side~2 @{-1}~2 ' test_expect_success '@{-1}^2 works' ' - test_rev_equivalent side^2 @{-1}^2 + test_cmp_rev side^2 @{-1}^2 ' test_expect_success '@{-1}@{1} works' ' - test_rev_equivalent side@{1} @{-1}@{1} + test_cmp_rev side@{1} @{-1}@{1} ' test_expect_success '@{-2} works' ' - test_rev_equivalent master @{-2} + test_cmp_rev master @{-2} ' test_expect_success '@{-3} fails' ' diff --git a/t/t1507-rev-parse-upstream.sh b/t/t1507-rev-parse-upstream.sh index d6e576192f..2a19e797eb 100755 --- a/t/t1507-rev-parse-upstream.sh +++ b/t/t1507-rev-parse-upstream.sh @@ -54,6 +54,10 @@ test_expect_success 'my-side@{upstream} resolves to correct full name' ' test refs/remotes/origin/side = "$(full_name my-side@{u})" ' +test_expect_success 'refs/heads/my-side@{upstream} does not resolve to my-side{upstream}' ' + test_must_fail full_name refs/heads/my-side@{upstream} +' + test_expect_success 'my-side@{u} resolves to correct commit' ' git checkout side && test_commit 5 && @@ -125,8 +129,7 @@ test_expect_success 'branch@{u} works when tracking a local branch' ' 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 + fatal: No upstream configured for branch ${sq}non-tracking${sq} EOF error_message non-tracking@{u} 2>actual && test_i18ncmp expect actual @@ -134,8 +137,7 @@ test_expect_success 'branch@{u} error message when no upstream' ' 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 + fatal: No upstream configured for branch ${sq}master${sq} EOF test_must_fail git rev-parse --verify @{u} 2>actual && test_i18ncmp expect actual @@ -143,8 +145,7 @@ test_expect_success '@{u} error message when no upstream' ' 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 + fatal: No such branch: ${sq}no-such-branch${sq} EOF error_message no-such-branch@{u} 2>actual && test_i18ncmp expect actual @@ -152,8 +153,7 @@ test_expect_success 'branch@{u} error message with misspelt branch' ' 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 + fatal: HEAD does not point to a branch EOF git checkout HEAD^0 && test_must_fail git rev-parse --verify @{u} 2>actual && @@ -162,8 +162,7 @@ test_expect_success '@{u} error message when not on a branch' ' 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 + fatal: Upstream branch ${sq}refs/heads/side${sq} not stored as a remote-tracking branch EOF error_message bad-upstream@{u} 2>actual && test_i18ncmp expect actual diff --git a/t/t1508-at-combinations.sh b/t/t1508-at-combinations.sh index d5d6244178..4db1613f8a 100755 --- a/t/t1508-at-combinations.sh +++ b/t/t1508-at-combinations.sh @@ -4,17 +4,24 @@ test_description='test various @{X} syntax combinations together' . ./test-lib.sh check() { -test_expect_${3:-success} "$1 = $2" " - echo '$2' >expect && - git log -1 --format=%s '$1' >actual && - test_cmp expect actual -" + test_expect_${4:-success} "$1 = $3" " + echo '$3' >expect && + if test '$2' = 'commit' + then + git log -1 --format=%s '$1' >actual + else + git rev-parse --symbolic-full-name '$1' >actual + fi && + test_cmp expect actual + " } + nonsense() { -test_expect_${2:-success} "$1 is nonsensical" " - test_must_fail git log -1 '$1' -" + test_expect_${2:-success} "$1 is nonsensical" " + test_must_fail git rev-parse --verify '$1' + " } + fail() { "$@" failure } @@ -31,21 +38,42 @@ test_expect_success 'setup' ' git checkout -b new-branch && test_commit new-one && test_commit new-two && - git config branch.old-branch.remote . && - git config branch.old-branch.merge refs/heads/master && - git config branch.new-branch.remote . && - git config branch.new-branch.merge refs/heads/upstream-branch + git branch -u master old-branch && + git branch -u upstream-branch new-branch ' -check HEAD new-two -check "@{1}" new-one -check "@{-1}" old-two -check "@{-1}@{1}" old-one -check "@{u}" upstream-two -check "@{u}@{1}" upstream-one -check "@{-1}@{u}" master-two -check "@{-1}@{u}@{1}" master-one +check HEAD ref refs/heads/new-branch +check "@{1}" commit new-one +check "HEAD@{1}" commit new-one +check "@{now}" commit new-two +check "HEAD@{now}" commit new-two +check "@{-1}" ref refs/heads/old-branch +check "@{-1}@{0}" commit old-two +check "@{-1}@{1}" commit old-one +check "@{u}" ref refs/heads/upstream-branch +check "HEAD@{u}" ref refs/heads/upstream-branch +check "@{u}@{1}" commit upstream-one +check "@{-1}@{u}" ref refs/heads/master +check "@{-1}@{u}@{1}" commit master-one +check "@" commit new-two +check "@@{u}" ref refs/heads/upstream-branch nonsense "@{u}@{-1}" +nonsense "@{0}@{0}" nonsense "@{1}@{u}" +nonsense "HEAD@{-1}" +nonsense "@{-1}@{-1}" + +# @{N} versus HEAD@{N} + +check "HEAD@{3}" commit old-two +nonsense "@{3}" + +test_expect_success 'switch to old-branch' ' + git checkout old-branch +' + +check HEAD ref refs/heads/old-branch +check "HEAD@{1}" commit new-two +check "@{1}" commit old-one test_done diff --git a/t/t1509/prepare-chroot.sh b/t/t1509/prepare-chroot.sh index c5334a8fa4..62691172e3 100755 --- a/t/t1509/prepare-chroot.sh +++ b/t/t1509/prepare-chroot.sh @@ -14,7 +14,7 @@ xmkdir() { R="$1" -[ -n "$R" ] || die "Usage: prepare-chroot.sh <root>" +[ -n "$R" ] || die "usage: prepare-chroot.sh <root>" [ -x git ] || die "This script needs to be executed at git source code's top directory" [ -x /bin/busybox ] || die "You need busybox" diff --git a/t/t1510-repo-setup.sh b/t/t1510-repo-setup.sh index 80aedfca8c..cf2ee7885a 100755 --- a/t/t1510-repo-setup.sh +++ b/t/t1510-repo-setup.sh @@ -517,6 +517,25 @@ test_expect_success '#16c: bare .git has no worktree' ' "$here/16c/.git" "(null)" "$here/16c/sub" "(null)" ' +test_expect_success '#16d: bareness preserved across alias' ' + setup_repo 16d unset "" unset && + ( + cd 16d/.git && + test_must_fail git status && + git config alias.st status && + test_must_fail git st + ) +' + +test_expect_success '#16e: bareness preserved by --bare' ' + setup_repo 16e unset "" unset && + ( + cd 16e/.git && + test_must_fail git status && + test_must_fail git --bare status + ) +' + test_expect_success '#17: GIT_WORK_TREE without explicit GIT_DIR is accepted (bare case)' ' # Just like #16. setup_repo 17a unset "" true && diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh index 6b3d797cea..4a155c8d09 100755 --- a/t/t1512-rev-parse-disambiguation.sh +++ b/t/t1512-rev-parse-disambiguation.sh @@ -77,6 +77,7 @@ test_expect_success 'disambiguate blob' ' test_expect_success 'disambiguate tree' ' commit=$(echo "d7xm" | git commit-tree 000000000) && + # this commit is fffff2e and not ambiguous with the 00000* objects test $(git rev-parse $commit^{tree}) = $(git rev-parse 0000000000cdc) ' @@ -99,10 +100,14 @@ test_expect_success 'disambiguate commit-ish' ' test_expect_success 'disambiguate commit' ' commit=$(echo "hoaxj" | git commit-tree 0000000000cdc -p 000000000) && + # this commit is ffffffd8 and not ambiguous with the 00000* objects test $(git rev-parse $commit^) = $(git rev-parse 0000000000e4f) ' test_expect_success 'log name1..name2 takes only commit-ishes on both ends' ' + # These are underspecified from the prefix-length point of view + # to disambiguate the commit with other objects, but there is only + # one commit that has 00000* prefix at this point. git log 000000000..000000000 && git log ..000000000 && git log 000000000.. && @@ -112,16 +117,19 @@ test_expect_success 'log name1..name2 takes only commit-ishes on both ends' ' ' test_expect_success 'rev-parse name1..name2 takes only commit-ishes on both ends' ' + # Likewise. git rev-parse 000000000..000000000 && git rev-parse ..000000000 && git rev-parse 000000000.. ' test_expect_success 'git log takes only commit-ish' ' + # Likewise. git log 000000000 ' test_expect_success 'git reset takes only commit-ish' ' + # Likewise. git reset 000000000 ' @@ -131,26 +139,30 @@ test_expect_success 'first tag' ' ' test_expect_failure 'two semi-ambiguous commit-ish' ' + # At this point, we have a tag 0000000000f8f that points + # at a commit 0000000000e4f, and a tree and a blob that + # share 0000000000 prefix with these tag and commit. + # # Once the parser becomes ultra-smart, it could notice that - # 110282 before ^{commit} name many different objects, but + # 0000000000 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} && + git rev-parse --verify 0000000000^{commit} && # likewise - git log 000000000..000000000 && - git log ..000000000 && - git log 000000000.. && - git log 000000000...000000000 && - git log ...000000000 && - git log 000000000... + git log 0000000000..0000000000 && + git log ..0000000000 && + git log 0000000000.. && + git log 0000000000...0000000000 && + git log ...0000000000 && + git log 0000000000... ' 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} + git rev-parse --verify 0000000000^{tree} ' test_expect_success 'parse describe name' ' @@ -241,7 +253,7 @@ 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} && + test_must_fail git rev-parse --verify 00000000^{commit} && # likewise test_must_fail git log 000000000..000000000 && @@ -261,4 +273,22 @@ test_expect_success 'rev-parse --disambiguate' ' test "$(sed -e "s/^\(.........\).*/\1/" actual | sort -u)" = 000000000 ' +test_expect_success 'ambiguous 40-hex ref' ' + TREE=$(git mktree </dev/null) && + REF=`git rev-parse HEAD` && + VAL=$(git commit-tree $TREE </dev/null) && + git update-ref refs/heads/$REF $VAL && + test `git rev-parse $REF 2>err` = $REF && + grep "refname.*${REF}.*ambiguous" err +' + +test_expect_success 'ambiguous short sha1 ref' ' + TREE=$(git mktree </dev/null) && + REF=`git rev-parse --short HEAD` && + VAL=$(git commit-tree $TREE </dev/null) && + git update-ref refs/heads/$REF $VAL && + test `git rev-parse $REF 2>err` = $VAL && + grep "refname.*${REF}.*ambiguous" err +' + test_done diff --git a/t/t1513-rev-parse-prefix.sh b/t/t1513-rev-parse-prefix.sh new file mode 100755 index 0000000000..87ec3ae714 --- /dev/null +++ b/t/t1513-rev-parse-prefix.sh @@ -0,0 +1,96 @@ +#!/bin/sh + +test_description='Tests for rev-parse --prefix' + +. ./test-lib.sh + +test_expect_success 'setup' ' + mkdir -p sub1/sub2 && + echo top >top && + echo file1 >sub1/file1 && + echo file2 >sub1/sub2/file2 && + git add top sub1/file1 sub1/sub2/file2 && + git commit -m commit +' + +test_expect_success 'empty prefix -- file' ' + git rev-parse --prefix "" -- top sub1/file1 >actual && + cat <<-\EOF >expected && + -- + top + sub1/file1 + EOF + test_cmp expected actual +' + +test_expect_success 'valid prefix -- file' ' + git rev-parse --prefix sub1/ -- file1 sub2/file2 >actual && + cat <<-\EOF >expected && + -- + sub1/file1 + sub1/sub2/file2 + EOF + test_cmp expected actual +' + +test_expect_success 'valid prefix -- ../file' ' + git rev-parse --prefix sub1/ -- ../top sub2/file2 >actual && + cat <<-\EOF >expected && + -- + sub1/../top + sub1/sub2/file2 + EOF + test_cmp expected actual +' + +test_expect_success 'empty prefix HEAD:./path' ' + git rev-parse --prefix "" HEAD:./top >actual && + git rev-parse HEAD:top >expected && + test_cmp expected actual +' + +test_expect_success 'valid prefix HEAD:./path' ' + git rev-parse --prefix sub1/ HEAD:./file1 >actual && + git rev-parse HEAD:sub1/file1 >expected && + test_cmp expected actual +' + +test_expect_success 'valid prefix HEAD:../path' ' + git rev-parse --prefix sub1/ HEAD:../top >actual && + git rev-parse HEAD:top >expected && + test_cmp expected actual +' + +test_expect_success 'prefix ignored with HEAD:top' ' + git rev-parse --prefix sub1/ HEAD:top >actual && + git rev-parse HEAD:top >expected && + test_cmp expected actual +' + +test_expect_success 'disambiguate path with valid prefix' ' + git rev-parse --prefix sub1/ file1 >actual && + cat <<-\EOF >expected && + sub1/file1 + EOF + test_cmp expected actual +' + +test_expect_success 'file and refs with prefix' ' + git rev-parse --prefix sub1/ master file1 >actual && + cat <<-EOF >expected && + $(git rev-parse master) + sub1/file1 + EOF + test_cmp expected actual +' + +test_expect_success 'two-levels deep' ' + git rev-parse --prefix sub1/sub2/ -- file2 >actual && + cat <<-\EOF >expected && + -- + sub1/sub2/file2 + EOF + test_cmp expected actual +' + +test_done diff --git a/t/t2001-checkout-cache-clash.sh b/t/t2001-checkout-cache-clash.sh index 98aa73e823..1fc8e634b7 100755 --- a/t/t2001-checkout-cache-clash.sh +++ b/t/t2001-checkout-cache-clash.sh @@ -59,10 +59,9 @@ test_expect_success \ 'git read-tree -m $tree1 && git checkout-index -f -a' test_debug 'show_files $tree1' -test_expect_success SYMLINKS \ - 'git update-index --add a symlink.' \ - 'ln -s path0 path1 && - git update-index --add path1' +test_expect_success \ + 'add a symlink' \ + 'test_ln_s_add path0 path1' test_expect_success \ 'writing tree out with git write-tree' \ 'tree3=$(git write-tree)' diff --git a/t/t2003-checkout-cache-mkdir.sh b/t/t2003-checkout-cache-mkdir.sh index 02a4fc5d36..ff163cf675 100755 --- a/t/t2003-checkout-cache-mkdir.sh +++ b/t/t2003-checkout-cache-mkdir.sh @@ -12,85 +12,108 @@ the GIT controlled paths. . ./test-lib.sh -test_expect_success \ - 'setup' \ - 'mkdir path1 && - echo frotz >path0 && - echo rezrov >path1/file1 && - git update-index --add path0 path1/file1' +test_expect_success 'setup' ' + mkdir path1 && + echo frotz >path0 && + echo rezrov >path1/file1 && + git update-index --add path0 path1/file1 +' + +test_expect_success SYMLINKS 'have symlink in place where dir is expected.' ' + rm -fr path0 path1 && + mkdir path2 && + ln -s path2 path1 && + git checkout-index -f -a && + test ! -h path1 && test -d path1 && + test -f path1/file1 && test ! -f path2/file1 +' -test_expect_success SYMLINKS \ - 'have symlink in place where dir is expected.' \ - 'rm -fr path0 path1 && - mkdir path2 && - ln -s path2 path1 && - git checkout-index -f -a && - test ! -h path1 && test -d path1 && - test -f path1/file1 && test ! -f path2/file1' +test_expect_success 'use --prefix=path2/' ' + rm -fr path0 path1 path2 && + mkdir path2 && + git checkout-index --prefix=path2/ -f -a && + test -f path2/path0 && + test -f path2/path1/file1 && + test ! -f path0 && + test ! -f path1/file1 +' + +test_expect_success 'use --prefix=tmp-' ' + rm -fr path0 path1 path2 tmp* && + git checkout-index --prefix=tmp- -f -a && + test -f tmp-path0 && + test -f tmp-path1/file1 && + test ! -f path0 && + test ! -f path1/file1 +' -test_expect_success \ - 'use --prefix=path2/' \ - 'rm -fr path0 path1 path2 && - mkdir path2 && - git checkout-index --prefix=path2/ -f -a && - test -f path2/path0 && - test -f path2/path1/file1 && - test ! -f path0 && - test ! -f path1/file1' +test_expect_success 'use --prefix=tmp- but with a conflicting file and dir' ' + rm -fr path0 path1 path2 tmp* && + echo nitfol >tmp-path1 && + mkdir tmp-path0 && + git checkout-index --prefix=tmp- -f -a && + test -f tmp-path0 && + test -f tmp-path1/file1 && + test ! -f path0 && + test ! -f path1/file1 +' -test_expect_success \ - 'use --prefix=tmp-' \ - 'rm -fr path0 path1 path2 tmp* && - git checkout-index --prefix=tmp- -f -a && - test -f tmp-path0 && - test -f tmp-path1/file1 && - test ! -f path0 && - test ! -f path1/file1' +test_expect_success SYMLINKS 'use --prefix=tmp/orary/ where tmp is a symlink' ' + rm -fr path0 path1 path2 tmp* && + mkdir tmp1 tmp1/orary && + ln -s tmp1 tmp && + git checkout-index --prefix=tmp/orary/ -f -a && + test -d tmp1/orary && + test -f tmp1/orary/path0 && + test -f tmp1/orary/path1/file1 && + test -h tmp +' -test_expect_success \ - 'use --prefix=tmp- but with a conflicting file and dir' \ - 'rm -fr path0 path1 path2 tmp* && - echo nitfol >tmp-path1 && - mkdir tmp-path0 && - git checkout-index --prefix=tmp- -f -a && - test -f tmp-path0 && - test -f tmp-path1/file1 && - test ! -f path0 && - test ! -f path1/file1' +test_expect_success SYMLINKS 'use --prefix=tmp/orary- where tmp is a symlink' ' + rm -fr path0 path1 path2 tmp* && + mkdir tmp1 && + ln -s tmp1 tmp && + git checkout-index --prefix=tmp/orary- -f -a && + test -f tmp1/orary-path0 && + test -f tmp1/orary-path1/file1 && + test -h tmp +' -# Linus fix #1 -test_expect_success SYMLINKS \ - 'use --prefix=tmp/orary/ where tmp is a symlink' \ - 'rm -fr path0 path1 path2 tmp* && - mkdir tmp1 tmp1/orary && - ln -s tmp1 tmp && - git checkout-index --prefix=tmp/orary/ -f -a && - test -d tmp1/orary && - test -f tmp1/orary/path0 && - test -f tmp1/orary/path1/file1 && - test -h tmp' +test_expect_success SYMLINKS 'use --prefix=tmp- where tmp-path1 is a symlink' ' + rm -fr path0 path1 path2 tmp* && + mkdir tmp1 && + ln -s tmp1 tmp-path1 && + git checkout-index --prefix=tmp- -f -a && + test -f tmp-path0 && + test ! -h tmp-path1 && + test -d tmp-path1 && + test -f tmp-path1/file1 +' -# Linus fix #2 -test_expect_success SYMLINKS \ - 'use --prefix=tmp/orary- where tmp is a symlink' \ - 'rm -fr path0 path1 path2 tmp* && - mkdir tmp1 && - ln -s tmp1 tmp && - git checkout-index --prefix=tmp/orary- -f -a && - test -f tmp1/orary-path0 && - test -f tmp1/orary-path1/file1 && - test -h tmp' +test_expect_success 'apply filter from working tree .gitattributes with --prefix' ' + rm -fr path0 path1 path2 tmp* && + mkdir path1 && + mkdir tmp && + git config filter.replace-all.smudge "sed -e s/./,/g" && + git config filter.replace-all.clean cat && + git config filter.replace-all.required true && + echo "file1 filter=replace-all" >path1/.gitattributes && + git checkout-index --prefix=tmp/ -f -a && + echo frotz >expected && + test_cmp expected tmp/path0 && + echo ,,,,,, >expected && + test_cmp expected tmp/path1/file1 +' -# Linus fix #3 -test_expect_success SYMLINKS \ - 'use --prefix=tmp- where tmp-path1 is a symlink' \ - 'rm -fr path0 path1 path2 tmp* && - mkdir tmp1 && - ln -s tmp1 tmp-path1 && - git checkout-index --prefix=tmp- -f -a && - test -f tmp-path0 && - test ! -h tmp-path1 && - test -d tmp-path1 && - test -f tmp-path1/file1' +test_expect_success 'apply CRLF filter from working tree .gitattributes with --prefix' ' + rm -fr path0 path1 path2 tmp* && + mkdir path1 && + mkdir tmp && + echo "file1 eol=crlf" >path1/.gitattributes && + git checkout-index --prefix=tmp/ -f -a && + echo rezrovQ >expected && + tr \\015 Q <tmp/path1/file1 >actual && + test_cmp expected actual +' test_done diff --git a/t/t2004-checkout-cache-temp.sh b/t/t2004-checkout-cache-temp.sh index 0f4b2896af..f171a5578b 100755 --- a/t/t2004-checkout-cache-temp.sh +++ b/t/t2004-checkout-cache-temp.sh @@ -194,11 +194,10 @@ test_expect_success \ test $(cat ../$s1) = tree1asubdir/path5) )' -test_expect_success SYMLINKS \ +test_expect_success \ 'checkout --temp symlink' ' rm -f path* .merge_* out .git/index && -ln -s b a && -git update-index --add a && +test_ln_s_add b a && t4=$(git write-tree) && rm -f .git/index && git read-tree $t4 && diff --git a/t/t2007-checkout-symlink.sh b/t/t2007-checkout-symlink.sh index e6f59f1914..fc9aad530e 100755 --- a/t/t2007-checkout-symlink.sh +++ b/t/t2007-checkout-symlink.sh @@ -6,7 +6,7 @@ test_description='git checkout to switch between branches with symlink<->dir' . ./test-lib.sh -test_expect_success SYMLINKS setup ' +test_expect_success setup ' mkdir frotz && echo hello >frotz/filfre && @@ -25,25 +25,25 @@ test_expect_success SYMLINKS setup ' git rm --cached frotz/filfre && mv frotz xyzzy && - ln -s xyzzy frotz && - git add xyzzy/filfre frotz && + test_ln_s_add xyzzy frotz && + git add xyzzy/filfre && test_tick && git commit -m "side moves frotz/ to xyzzy/ and adds frotz->xyzzy/" ' -test_expect_success SYMLINKS 'switch from symlink to dir' ' +test_expect_success 'switch from symlink to dir' ' git checkout master ' -test_expect_success SYMLINKS 'Remove temporary directories & switch to master' ' +test_expect_success 'Remove temporary directories & switch to master' ' rm -fr frotz xyzzy nitfol && git checkout -f master ' -test_expect_success SYMLINKS 'switch from dir to symlink' ' +test_expect_success 'switch from dir to symlink' ' git checkout side diff --git a/t/t2012-checkout-last.sh b/t/t2012-checkout-last.sh index b44de9dc62..e7ba8c505f 100755 --- a/t/t2012-checkout-last.sh +++ b/t/t2012-checkout-last.sh @@ -116,4 +116,38 @@ test_expect_success 'master...' ' test "z$(git rev-parse --verify HEAD)" = "z$(git rev-parse --verify master^)" ' +test_expect_success '"checkout -" works after a rebase A' ' + git checkout master && + git checkout other && + git rebase master && + git checkout - && + test "z$(git symbolic-ref HEAD)" = "zrefs/heads/master" +' + +test_expect_success '"checkout -" works after a rebase A B' ' + git branch moodle master~1 && + git checkout master && + git checkout other && + git rebase master moodle && + git checkout - && + test "z$(git symbolic-ref HEAD)" = "zrefs/heads/master" +' + +test_expect_success '"checkout -" works after a rebase -i A' ' + git checkout master && + git checkout other && + git rebase -i master && + git checkout - && + test "z$(git symbolic-ref HEAD)" = "zrefs/heads/master" +' + +test_expect_success '"checkout -" works after a rebase -i A B' ' + git branch foodle master~1 && + git checkout master && + git checkout other && + git rebase master foodle && + git checkout - && + test "z$(git symbolic-ref HEAD)" = "zrefs/heads/master" +' + test_done diff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh index 70edbb33e2..06b18f8bc1 100755 --- a/t/t2013-checkout-submodule.sh +++ b/t/t2013-checkout-submodule.sh @@ -23,7 +23,7 @@ test_expect_success '"reset <submodule>" updates the index' ' git update-index --refresh && git diff-files --quiet && git diff-index --quiet --cached HEAD && - test_must_fail git reset HEAD^ submodule && + git reset HEAD^ submodule && test_must_fail git diff-files --quiet && git reset submodule && git diff-files --quiet diff --git a/t/t2020-checkout-detach.sh b/t/t2020-checkout-detach.sh index 81005373d7..5d68729d7a 100755 --- a/t/t2020-checkout-detach.sh +++ b/t/t2020-checkout-detach.sh @@ -151,6 +151,7 @@ test_expect_success 'checkout does not warn leaving reachable commit' ' cat >expect <<'EOF' Your branch is behind 'master' by 1 commit, and can be fast-forwarded. + (use "git pull" to update your local branch) EOF test_expect_success 'tracking count is accurate after orphan check' ' reset && diff --git a/t/t2021-checkout-overwrite.sh b/t/t2021-checkout-overwrite.sh index 5da63e9fa2..c2ada7de37 100755 --- a/t/t2021-checkout-overwrite.sh +++ b/t/t2021-checkout-overwrite.sh @@ -29,21 +29,25 @@ test_expect_success 'checkout commit with dir must not remove untracked a/b' ' test -f a/b ' -test_expect_success SYMLINKS 'create a commit where dir a/b changed to symlink' ' +test_expect_success 'create a commit where dir a/b changed to symlink' ' rm -rf a/b && # cleanup if previous test failed git checkout -f -b symlink start && rm -rf a/b && - ln -s foo a/b && git add -A && + test_ln_s_add foo a/b && git commit -m "dir to symlink" ' -test_expect_success SYMLINKS 'checkout commit with dir must not remove untracked a/b' ' +test_expect_success 'checkout commit with dir must not remove untracked a/b' ' git rm --cached a/b && git commit -m "un-track the symlink" && - test_must_fail git checkout start && + test_must_fail git checkout start +' + +test_expect_success SYMLINKS 'the symlink remained' ' + test -h a/b ' diff --git a/t/t2022-checkout-paths.sh b/t/t2022-checkout-paths.sh index 56090d2eba..8e3545d868 100755 --- a/t/t2022-checkout-paths.sh +++ b/t/t2022-checkout-paths.sh @@ -39,4 +39,26 @@ test_expect_success 'checking out paths out of a tree does not clobber unrelated test_cmp expect.next2 dir/next2 ' +test_expect_success 'do not touch unmerged entries matching $path but not in $tree' ' + git checkout next && + git reset --hard && + + cat dir/common >expect.common && + EMPTY_SHA1=$(git hash-object -w --stdin </dev/null) && + git rm dir/next0 && + cat >expect.next0 <<-EOF && + 100644 $EMPTY_SHA1 1 dir/next0 + 100644 $EMPTY_SHA1 2 dir/next0 + EOF + git update-index --index-info <expect.next0 && + + git checkout master dir && + + test_cmp expect.common dir/common && + test_path_is_file dir/master && + git diff --exit-code master dir/master && + git ls-files -s dir/next0 >actual.next0 && + test_cmp expect.next0 actual.next0 +' + test_done diff --git a/t/t2024-checkout-dwim.sh b/t/t2024-checkout-dwim.sh new file mode 100755 index 0000000000..dee55e428f --- /dev/null +++ b/t/t2024-checkout-dwim.sh @@ -0,0 +1,167 @@ +#!/bin/sh + +test_description='checkout <branch> + +Ensures that checkout on an unborn branch does what the user expects' + +. ./test-lib.sh + +# Is the current branch "refs/heads/$1"? +test_branch () { + printf "%s\n" "refs/heads/$1" >expect.HEAD && + git symbolic-ref HEAD >actual.HEAD && + test_cmp expect.HEAD actual.HEAD +} + +# Is branch "refs/heads/$1" set to pull from "$2/$3"? +test_branch_upstream () { + printf "%s\n" "$2" "refs/heads/$3" >expect.upstream && + { + git config "branch.$1.remote" && + git config "branch.$1.merge" + } >actual.upstream && + test_cmp expect.upstream actual.upstream +} + +test_expect_success 'setup' ' + test_commit my_master && + git init repo_a && + ( + cd repo_a && + test_commit a_master && + git checkout -b foo && + test_commit a_foo && + git checkout -b bar && + test_commit a_bar + ) && + git init repo_b && + ( + cd repo_b && + test_commit b_master && + git checkout -b foo && + test_commit b_foo && + git checkout -b baz && + test_commit b_baz + ) && + git remote add repo_a repo_a && + git remote add repo_b repo_b && + git config remote.repo_b.fetch \ + "+refs/heads/*:refs/remotes/other_b/*" && + git fetch --all +' + +test_expect_success 'checkout of non-existing branch fails' ' + git checkout -B master && + test_might_fail git branch -D xyzzy && + + test_must_fail git checkout xyzzy && + test_must_fail git rev-parse --verify refs/heads/xyzzy && + test_branch master +' + +test_expect_success 'checkout of branch from multiple remotes fails #1' ' + git checkout -B master && + test_might_fail git branch -D foo && + + test_must_fail git checkout foo && + test_must_fail git rev-parse --verify refs/heads/foo && + test_branch master +' + +test_expect_success 'checkout of branch from a single remote succeeds #1' ' + git checkout -B master && + test_might_fail git branch -D bar && + + git checkout bar && + test_branch bar && + test_cmp_rev remotes/repo_a/bar HEAD && + test_branch_upstream bar repo_a bar +' + +test_expect_success 'checkout of branch from a single remote succeeds #2' ' + git checkout -B master && + test_might_fail git branch -D baz && + + git checkout baz && + test_branch baz && + test_cmp_rev remotes/other_b/baz HEAD && + test_branch_upstream baz repo_b baz +' + +test_expect_success '--no-guess suppresses branch auto-vivification' ' + git checkout -B master && + test_might_fail git branch -D bar && + + test_must_fail git checkout --no-guess bar && + test_must_fail git rev-parse --verify refs/heads/bar && + test_branch master +' + +test_expect_success 'setup more remotes with unconventional refspecs' ' + git checkout -B master && + git init repo_c && + ( + cd repo_c && + test_commit c_master && + git checkout -b bar && + test_commit c_bar + git checkout -b spam && + test_commit c_spam + ) && + git init repo_d && + ( + cd repo_d && + test_commit d_master && + git checkout -b baz && + test_commit f_baz + git checkout -b eggs && + test_commit c_eggs + ) && + git remote add repo_c repo_c && + git config remote.repo_c.fetch \ + "+refs/heads/*:refs/remotes/extra_dir/repo_c/extra_dir/*" && + git remote add repo_d repo_d && + git config remote.repo_d.fetch \ + "+refs/heads/*:refs/repo_d/*" && + git fetch --all +' + +test_expect_success 'checkout of branch from multiple remotes fails #2' ' + git checkout -B master && + test_might_fail git branch -D bar && + + test_must_fail git checkout bar && + test_must_fail git rev-parse --verify refs/heads/bar && + test_branch master +' + +test_expect_success 'checkout of branch from multiple remotes fails #3' ' + git checkout -B master && + test_might_fail git branch -D baz && + + test_must_fail git checkout baz && + test_must_fail git rev-parse --verify refs/heads/baz && + test_branch master +' + +test_expect_success 'checkout of branch from a single remote succeeds #3' ' + git checkout -B master && + test_might_fail git branch -D spam && + + git checkout spam && + test_branch spam && + test_cmp_rev refs/remotes/extra_dir/repo_c/extra_dir/spam HEAD && + test_branch_upstream spam repo_c spam +' + +test_expect_success 'checkout of branch from a single remote succeeds #4' ' + git checkout -B master && + test_might_fail git branch -D eggs && + + git checkout eggs && + test_branch eggs && + test_cmp_rev refs/repo_d/eggs HEAD && + test_branch_upstream eggs repo_d eggs +' + +test_done diff --git a/t/t2030-unresolve-info.sh b/t/t2030-unresolve-info.sh index f2620650ce..309199bca2 100755 --- a/t/t2030-unresolve-info.sh +++ b/t/t2030-unresolve-info.sh @@ -44,14 +44,21 @@ prime_resolve_undo () { test_expect_success setup ' mkdir fi && + printf "a\0a" >binary && + git add binary && test_commit initial fi/le first && git branch side && git branch another && + printf "a\0b" >binary && + git add binary && test_commit second fi/le second && git checkout side && test_commit third fi/le third && + git branch add-add && git checkout another && test_commit fourth fi/le fourth && + git checkout add-add && + test_commit fifth add-differently && git checkout master ' @@ -167,4 +174,22 @@ test_expect_success 'rerere and rerere forget (subdirectory)' ' test_cmp expect actual ' +test_expect_success 'rerere forget (binary)' ' + git checkout -f side && + printf "a\0c" >binary && + git commit -a -m binary && + test_must_fail git merge second && + git rerere forget binary +' + +test_expect_success 'rerere forget (add-add conflict)' ' + git checkout -f master && + echo master >add-differently && + git add add-differently && + git commit -m "add differently" && + test_must_fail git merge fifth && + git rerere forget add-differently 2>actual && + test_i18ngrep "no remembered" actual +' + test_done diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh index 4cdebda6a5..9bf2bdffd2 100755 --- a/t/t2200-add-update.sh +++ b/t/t2200-add-update.sh @@ -80,11 +80,26 @@ test_expect_success 'change gets noticed' ' ' -test_expect_success SYMLINKS 'replace a file with a symlink' ' +# Note that this is scheduled to change in Git 2.0, when +# "git add -u" will become full-tree by default. +test_expect_success 'non-limited update in subdir leaves root alone' ' + ( + cd dir1 && + echo even more >>sub2 && + git add -u + ) && + cat >expect <<-\EOF && + check + top + EOF + git diff-files --name-only >actual && + test_cmp expect actual +' + +test_expect_success 'replace a file with a symlink' ' rm foo && - ln -s top foo && - git add -u -- foo + test_ln_s_add top foo ' @@ -150,9 +165,9 @@ test_expect_success 'add -u resolves unmerged paths' ' echo 2 >path3 && echo 2 >path5 && - # Explicit resolving by adding removed paths should fail - test_must_fail git add path4 && - test_must_fail git add path6 && + # Fail to explicitly resolve removed paths with "git add" + test_must_fail git add --no-all path4 && + test_must_fail git add --no-all path6 && # "add -u" should notice removals no matter what stages # the index entries are in. diff --git a/t/t2202-add-addremove.sh b/t/t2202-add-addremove.sh index 6a8151064c..fc8b59e7f7 100755 --- a/t/t2202-add-addremove.sh +++ b/t/t2202-add-addremove.sh @@ -41,4 +41,14 @@ test_expect_success 'git add --all' ' test_cmp expect actual ' +test_expect_success 'Just "git add" is a no-op' ' + git reset --hard && + echo >will-remove && + >will-not-be-added && + git add && + git diff-index --name-status --cached HEAD >actual && + >expect && + test_cmp expect actual +' + test_done diff --git a/t/t2203-add-intent.sh b/t/t2203-add-intent.sh index ec35409f9c..2a4a749b4f 100755 --- a/t/t2203-add-intent.sh +++ b/t/t2203-add-intent.sh @@ -62,5 +62,25 @@ test_expect_success 'can "commit -a" with an i-t-a entry' ' git commit -a -m all ' +test_expect_success 'cache-tree invalidates i-t-a paths' ' + git reset --hard && + mkdir dir && + : >dir/foo && + git add dir/foo && + git commit -m foo && + + : >dir/bar && + git add -N dir/bar && + git diff --cached --name-only >actual && + echo dir/bar >expect && + test_cmp expect actual && + + git write-tree >/dev/null && + + git diff --cached --name-only >actual && + echo dir/bar >expect && + test_cmp expect actual +' + test_done diff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh index c8fe978267..f0421c09c7 100755 --- a/t/t3001-ls-files-others-exclude.sh +++ b/t/t3001-ls-files-others-exclude.sh @@ -103,7 +103,7 @@ test_expect_success \ test_cmp expect output' test_expect_success 'restore gitignore' ' - git checkout $allignores && + git checkout --ignore-skip-worktree-bits $allignores && rm .git/index ' @@ -175,6 +175,24 @@ test_expect_success 'negated exclude matches can override previous ones' ' grep "^a.1" output ' +test_expect_success 'excluded directory overrides content patterns' ' + + git ls-files --others --exclude="one" --exclude="!one/a.1" >output && + if grep "^one/a.1" output + then + false + fi +' + +test_expect_success 'negated directory doesn'\''t affect content patterns' ' + + git ls-files --others --exclude="!one" --exclude="one/a.1" >output && + if grep "^one/a.1" output + then + false + fi +' + test_expect_success 'subdirectory ignore (setup)' ' mkdir -p top/l1/l2 && ( @@ -214,4 +232,77 @@ test_expect_success 'subdirectory ignore (l1)' ' test_cmp expect actual ' +test_expect_success 'show/hide empty ignored directory (setup)' ' + rm top/l1/l2/l1 && + rm top/l1/.gitignore +' + +test_expect_success 'show empty ignored directory with --directory' ' + ( + cd top && + git ls-files -o -i --exclude l1 --directory + ) >actual && + echo l1/ >expect && + test_cmp expect actual +' + +test_expect_success 'hide empty ignored directory with --no-empty-directory' ' + ( + cd top && + git ls-files -o -i --exclude l1 --directory --no-empty-directory + ) >actual && + >expect && + test_cmp expect actual +' + +test_expect_success 'show/hide empty ignored sub-directory (setup)' ' + > top/l1/tracked && + ( + cd top && + git add -f l1/tracked + ) +' + +test_expect_success 'show empty ignored sub-directory with --directory' ' + ( + cd top && + git ls-files -o -i --exclude l1 --directory + ) >actual && + echo l1/l2/ >expect && + test_cmp expect actual +' + +test_expect_success 'hide empty ignored sub-directory with --no-empty-directory' ' + ( + cd top && + git ls-files -o -i --exclude l1 --directory --no-empty-directory + ) >actual && + >expect && + test_cmp expect actual +' + +test_expect_success 'pattern matches prefix completely' ' + : >expect && + git ls-files -i -o --exclude "/three/a.3[abc]" >actual && + test_cmp expect actual +' + +test_expect_success 'ls-files with "**" patterns' ' + cat <<\EOF >expect && +a.1 +one/a.1 +one/two/a.1 +three/a.1 +EOF + git ls-files -o -i --exclude "**/a.1" >actual + test_cmp expect actual +' + + +test_expect_success 'ls-files with "**" patterns and no slashes' ' + : >expect && + git ls-files -o -i --exclude "one**a.1" >actual && + test_cmp expect actual +' + test_done diff --git a/t/t3010-ls-files-killed-modified.sh b/t/t3010-ls-files-killed-modified.sh index 95671c2053..f611d799b6 100755 --- a/t/t3010-ls-files-killed-modified.sh +++ b/t/t3010-ls-files-killed-modified.sh @@ -11,6 +11,8 @@ This test prepares the following in the cache: path1 - a symlink path2/file2 - a file in a directory path3/file3 - a file in a directory + submod1/ - a submodule + submod2/ - another submodule and the following on the filesystem: @@ -21,9 +23,11 @@ and the following on the filesystem: path4 - a file path5 - a symlink path6/file6 - a file in a directory + submod1/ - a submodule (modified from the cache) + submod2/ - a submodule (matches the cache) -git ls-files -k should report that existing filesystem -objects except path4, path5 and path6/file6 to be killed. +git ls-files -k should report that existing filesystem objects +path0/*, path1/*, path2 and path3 to be killed. Also for modification test, the cache and working tree have: @@ -33,75 +37,82 @@ Also for modification test, the cache and working tree have: path10 - a non-empty file, cache dirtied. We should report path0, path1, path2/file2, path3/file3, path7 and path8 -modified without reporting path9 and path10. +modified without reporting path9 and path10. submod1 is also modified. ' . ./test-lib.sh -date >path0 -if test_have_prereq SYMLINKS -then - ln -s xyzzy path1 -else - date > path1 -fi -mkdir path2 path3 -date >path2/file2 -date >path3/file3 -: >path7 -date >path8 -: >path9 -date >path10 -test_expect_success \ - 'git update-index --add to add various paths.' \ - "git update-index --add -- path0 path1 path?/file? path7 path8 path9 path10" - -rm -fr path? ;# leave path10 alone -date >path2 -if test_have_prereq SYMLINKS -then - ln -s frotz path3 - ln -s nitfol path5 -else - date > path3 - date > path5 -fi -mkdir path0 path1 path6 -date >path0/file0 -date >path1/file1 -date >path6/file6 -date >path7 -: >path8 -: >path9 -touch path10 +test_expect_success 'git update-index --add to add various paths.' ' + date >path0 && + test_ln_s_add xyzzy path1 && + mkdir path2 path3 && + date >path2/file2 && + date >path3/file3 && + : >path7 && + date >path8 && + : >path9 && + date >path10 && + git update-index --add -- path0 path?/file? path7 path8 path9 path10 && + for i in 1 2 + do + git init submod$i && + ( + cd submod$i && git commit --allow-empty -m "empty $i" + ) || break + done && + git update-index --add submod[12] + ( + cd submod1 && + git commit --allow-empty -m "empty 1 (updated)" + ) && + rm -fr path? # leave path10 alone +' -test_expect_success \ - 'git ls-files -k to show killed files.' \ - 'git ls-files -k >.output' -cat >.expected <<EOF -path0/file0 -path1/file1 -path2 -path3 -EOF +test_expect_success 'git ls-files -k to show killed files.' ' + date >path2 && + if test_have_prereq SYMLINKS + then + ln -s frotz path3 && + ln -s nitfol path5 + else + date >path3 && + date >path5 + fi && + mkdir path0 path1 path6 && + date >path0/file0 && + date >path1/file1 && + date >path6/file6 && + date >path7 && + : >path8 && + : >path9 && + touch path10 && + git ls-files -k >.output +' -test_expect_success \ - 'validate git ls-files -k output.' \ - 'test_cmp .expected .output' +test_expect_success 'validate git ls-files -k output.' ' + cat >.expected <<-\EOF && + path0/file0 + path1/file1 + path2 + path3 + EOF + test_cmp .expected .output +' -test_expect_success \ - 'git ls-files -m to show modified files.' \ - 'git ls-files -m >.output' -cat >.expected <<EOF -path0 -path1 -path2/file2 -path3/file3 -path7 -path8 -EOF +test_expect_success 'git ls-files -m to show modified files.' ' + git ls-files -m >.output +' -test_expect_success \ - 'validate git ls-files -m output.' \ - 'test_cmp .expected .output' +test_expect_success 'validate git ls-files -m output.' ' + cat >.expected <<-\EOF && + path0 + path1 + path2/file2 + path3/file3 + path7 + path8 + submod1 + EOF + test_cmp .expected .output +' test_done diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh index a5e3da7e41..2f96100a5f 100755 --- a/t/t3030-merge-recursive.sh +++ b/t/t3030-merge-recursive.sh @@ -25,10 +25,7 @@ test_expect_success 'setup 1' ' git branch submod && git branch copy && git branch rename && - if test_have_prereq SYMLINKS - then - git branch rename-ln - fi && + git branch rename-ln && echo hello >>a && cp a d/e && @@ -260,16 +257,12 @@ test_expect_success 'setup 8' ' git add e && test_tick && git commit -m "rename a->e" && - if test_have_prereq SYMLINKS - then - git checkout rename-ln && - git mv a e && - ln -s e a && - git add a e && - test_tick && - git commit -m "rename a->e, symlink a->e" && - oln=`printf e | git hash-object --stdin` - fi + git checkout rename-ln && + git mv a e && + test_ln_s_add e a && + test_tick && + git commit -m "rename a->e, symlink a->e" && + oln=`printf e | git hash-object --stdin` ' test_expect_success 'setup 9' ' @@ -569,28 +562,25 @@ test_expect_success 'merge-recursive copy vs. rename' ' test_cmp expected actual ' -if test_have_prereq SYMLINKS -then - test_expect_failure 'merge-recursive rename vs. rename/symlink' ' - - git checkout -f rename && - git merge rename-ln && - ( git ls-tree -r HEAD ; git ls-files -s ) >actual && - ( - echo "120000 blob $oln a" - echo "100644 blob $o0 b" - echo "100644 blob $o0 c" - echo "100644 blob $o0 d/e" - echo "100644 blob $o0 e" - echo "120000 $oln 0 a" - echo "100644 $o0 0 b" - echo "100644 $o0 0 c" - echo "100644 $o0 0 d/e" - echo "100644 $o0 0 e" - ) >expected && - test_cmp expected actual - ' -fi +test_expect_failure 'merge-recursive rename vs. rename/symlink' ' + + git checkout -f rename && + git merge rename-ln && + ( git ls-tree -r HEAD ; git ls-files -s ) >actual && + ( + echo "120000 blob $oln a" + echo "100644 blob $o0 b" + echo "100644 blob $o0 c" + echo "100644 blob $o0 d/e" + echo "100644 blob $o0 e" + echo "120000 $oln 0 a" + echo "100644 $o0 0 b" + echo "100644 $o0 0 c" + echo "100644 $o0 0 d/e" + echo "100644 $o0 0 e" + ) >expected && + test_cmp expected actual +' test_done diff --git a/t/t3032-merge-recursive-options.sh b/t/t3032-merge-recursive-options.sh index 2b17311cb0..5fd7bbb652 100755 --- a/t/t3032-merge-recursive-options.sh +++ b/t/t3032-merge-recursive-options.sh @@ -14,7 +14,7 @@ test_description='merge-recursive options . ./test-lib.sh test_have_prereq SED_STRIPS_CR && SED_OPTIONS=-b -test_have_prereq MINGW && export GREP_OPTIONS=-U +test_have_prereq GREP_STRIPS_CR && export GREP_OPTIONS=-U test_expect_success 'setup' ' conflict_hunks () { diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh new file mode 100755 index 0000000000..38446a0e87 --- /dev/null +++ b/t/t3070-wildmatch.sh @@ -0,0 +1,281 @@ +#!/bin/sh + +test_description='wildmatch tests' + +. ./test-lib.sh + +match() { + if [ $1 = 1 ]; then + test_expect_success "wildmatch: match '$3' '$4'" " + test-wildmatch wildmatch '$3' '$4' + " + else + test_expect_success "wildmatch: no match '$3' '$4'" " + ! test-wildmatch wildmatch '$3' '$4' + " + fi + if [ $2 = 1 ]; then + test_expect_success "fnmatch: match '$3' '$4'" " + test-wildmatch fnmatch '$3' '$4' + " + elif [ $2 = 0 ]; then + test_expect_success "fnmatch: no match '$3' '$4'" " + ! test-wildmatch fnmatch '$3' '$4' + " +# else +# test_expect_success BROKEN_FNMATCH "fnmatch: '$3' '$4'" " +# ! test-wildmatch fnmatch '$3' '$4' +# " + fi +} + +imatch() { + if [ $1 = 1 ]; then + test_expect_success "iwildmatch: match '$2' '$3'" " + test-wildmatch iwildmatch '$2' '$3' + " + else + test_expect_success "iwildmatch: no match '$2' '$3'" " + ! test-wildmatch iwildmatch '$2' '$3' + " + fi +} + +pathmatch() { + if [ $1 = 1 ]; then + test_expect_success "pathmatch: match '$2' '$3'" " + test-wildmatch pathmatch '$2' '$3' + " + else + test_expect_success "pathmatch: no match '$2' '$3'" " + ! test-wildmatch pathmatch '$2' '$3' + " + fi +} + +# Basic wildmat features +match 1 1 foo foo +match 0 0 foo bar +match 1 1 '' "" +match 1 1 foo '???' +match 0 0 foo '??' +match 1 1 foo '*' +match 1 1 foo 'f*' +match 0 0 foo '*f' +match 1 1 foo '*foo*' +match 1 1 foobar '*ob*a*r*' +match 1 1 aaaaaaabababab '*ab' +match 1 1 'foo*' 'foo\*' +match 0 0 foobar 'foo\*bar' +match 1 1 'f\oo' 'f\\oo' +match 1 1 ball '*[al]?' +match 0 0 ten '[ten]' +match 0 1 ten '**[!te]' +match 0 0 ten '**[!ten]' +match 1 1 ten 't[a-g]n' +match 0 0 ten 't[!a-g]n' +match 1 1 ton 't[!a-g]n' +match 1 1 ton 't[^a-g]n' +match 1 x 'a]b' 'a[]]b' +match 1 x a-b 'a[]-]b' +match 1 x 'a]b' 'a[]-]b' +match 0 x aab 'a[]-]b' +match 1 x aab 'a[]a-]b' +match 1 1 ']' ']' + +# Extended slash-matching features +match 0 0 'foo/baz/bar' 'foo*bar' +match 0 0 'foo/baz/bar' 'foo**bar' +match 0 1 'foobazbar' 'foo**bar' +match 1 1 'foo/baz/bar' 'foo/**/bar' +match 1 0 'foo/baz/bar' 'foo/**/**/bar' +match 1 0 'foo/b/a/z/bar' 'foo/**/bar' +match 1 0 'foo/b/a/z/bar' 'foo/**/**/bar' +match 1 0 'foo/bar' 'foo/**/bar' +match 1 0 'foo/bar' 'foo/**/**/bar' +match 0 0 'foo/bar' 'foo?bar' +match 0 0 'foo/bar' 'foo[/]bar' +match 0 0 'foo/bar' 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r' +match 1 1 'foo-bar' 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r' +match 1 0 'foo' '**/foo' +match 1 x 'XXX/foo' '**/foo' +match 1 0 'bar/baz/foo' '**/foo' +match 0 0 'bar/baz/foo' '*/foo' +match 0 0 'foo/bar/baz' '**/bar*' +match 1 0 'deep/foo/bar/baz' '**/bar/*' +match 0 0 'deep/foo/bar/baz/' '**/bar/*' +match 1 0 'deep/foo/bar/baz/' '**/bar/**' +match 0 0 'deep/foo/bar' '**/bar/*' +match 1 0 'deep/foo/bar/' '**/bar/**' +match 0 0 'foo/bar/baz' '**/bar**' +match 1 0 'foo/bar/baz/x' '*/bar/**' +match 0 0 'deep/foo/bar/baz/x' '*/bar/**' +match 1 0 'deep/foo/bar/baz/x' '**/bar/*/*' + +# Various additional tests +match 0 0 'acrt' 'a[c-c]st' +match 1 1 'acrt' 'a[c-c]rt' +match 0 0 ']' '[!]-]' +match 1 x 'a' '[!]-]' +match 0 0 '' '\' +match 0 x '\' '\' +match 0 x 'XXX/\' '*/\' +match 1 x 'XXX/\' '*/\\' +match 1 1 'foo' 'foo' +match 1 1 '@foo' '@foo' +match 0 0 'foo' '@foo' +match 1 1 '[ab]' '\[ab]' +match 1 1 '[ab]' '[[]ab]' +match 1 x '[ab]' '[[:]ab]' +match 0 x '[ab]' '[[::]ab]' +match 1 x '[ab]' '[[:digit]ab]' +match 1 x '[ab]' '[\[:]ab]' +match 1 1 '?a?b' '\??\?b' +match 1 1 'abc' '\a\b\c' +match 0 0 'foo' '' +match 1 0 'foo/bar/baz/to' '**/t[o]' + +# Character class tests +match 1 x 'a1B' '[[:alpha:]][[:digit:]][[:upper:]]' +match 0 x 'a' '[[:digit:][:upper:][:space:]]' +match 1 x 'A' '[[:digit:][:upper:][:space:]]' +match 1 x '1' '[[:digit:][:upper:][:space:]]' +match 0 x '1' '[[:digit:][:upper:][:spaci:]]' +match 1 x ' ' '[[:digit:][:upper:][:space:]]' +match 0 x '.' '[[:digit:][:upper:][:space:]]' +match 1 x '.' '[[:digit:][:punct:][:space:]]' +match 1 x '5' '[[:xdigit:]]' +match 1 x 'f' '[[:xdigit:]]' +match 1 x 'D' '[[:xdigit:]]' +match 1 x '_' '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]' +match 1 x '_' '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]' +match 1 x '.' '[^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]' +match 1 x '5' '[a-c[:digit:]x-z]' +match 1 x 'b' '[a-c[:digit:]x-z]' +match 1 x 'y' '[a-c[:digit:]x-z]' +match 0 x 'q' '[a-c[:digit:]x-z]' + +# Additional tests, including some malformed wildmats +match 1 x ']' '[\\-^]' +match 0 0 '[' '[\\-^]' +match 1 x '-' '[\-_]' +match 1 x ']' '[\]]' +match 0 0 '\]' '[\]]' +match 0 0 '\' '[\]]' +match 0 0 'ab' 'a[]b' +match 0 x 'a[]b' 'a[]b' +match 0 x 'ab[' 'ab[' +match 0 0 'ab' '[!' +match 0 0 'ab' '[-' +match 1 1 '-' '[-]' +match 0 0 '-' '[a-' +match 0 0 '-' '[!a-' +match 1 x '-' '[--A]' +match 1 x '5' '[--A]' +match 1 1 ' ' '[ --]' +match 1 1 '$' '[ --]' +match 1 1 '-' '[ --]' +match 0 0 '0' '[ --]' +match 1 x '-' '[---]' +match 1 x '-' '[------]' +match 0 0 'j' '[a-e-n]' +match 1 x '-' '[a-e-n]' +match 1 x 'a' '[!------]' +match 0 0 '[' '[]-a]' +match 1 x '^' '[]-a]' +match 0 0 '^' '[!]-a]' +match 1 x '[' '[!]-a]' +match 1 1 '^' '[a^bc]' +match 1 x '-b]' '[a-]b]' +match 0 0 '\' '[\]' +match 1 1 '\' '[\\]' +match 0 0 '\' '[!\\]' +match 1 1 'G' '[A-\\]' +match 0 0 'aaabbb' 'b*a' +match 0 0 'aabcaa' '*ba*' +match 1 1 ',' '[,]' +match 1 1 ',' '[\\,]' +match 1 1 '\' '[\\,]' +match 1 1 '-' '[,-.]' +match 0 0 '+' '[,-.]' +match 0 0 '-.]' '[,-.]' +match 1 1 '2' '[\1-\3]' +match 1 1 '3' '[\1-\3]' +match 0 0 '4' '[\1-\3]' +match 1 1 '\' '[[-\]]' +match 1 1 '[' '[[-\]]' +match 1 1 ']' '[[-\]]' +match 0 0 '-' '[[-\]]' + +# Test recursion and the abort code (use "wildtest -i" to see iteration counts) +match 1 1 '-adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1' '-*-*-*-*-*-*-12-*-*-*-m-*-*-*' +match 0 0 '-adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1' '-*-*-*-*-*-*-12-*-*-*-m-*-*-*' +match 0 0 '-adobe-courier-bold-o-normal--12-120-75-75-/-70-iso8859-1' '-*-*-*-*-*-*-12-*-*-*-m-*-*-*' +match 1 1 'XXX/adobe/courier/bold/o/normal//12/120/75/75/m/70/iso8859/1' 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*' +match 0 0 'XXX/adobe/courier/bold/o/normal//12/120/75/75/X/70/iso8859/1' 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*' +match 1 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt' '**/*a*b*g*n*t' +match 0 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz' '**/*a*b*g*n*t' +match 0 x foo '*/*/*' +match 0 x foo/bar '*/*/*' +match 1 x foo/bba/arr '*/*/*' +match 0 x foo/bb/aa/rr '*/*/*' +match 1 x foo/bb/aa/rr '**/**/**' +match 1 x abcXdefXghi '*X*i' +match 0 x ab/cXd/efXg/hi '*X*i' +match 1 x ab/cXd/efXg/hi '*/*X*/*/*i' +match 1 x ab/cXd/efXg/hi '**/*X*/**/*i' + +pathmatch 1 foo foo +pathmatch 0 foo fo +pathmatch 1 foo/bar foo/bar +pathmatch 1 foo/bar 'foo/*' +pathmatch 1 foo/bba/arr 'foo/*' +pathmatch 1 foo/bba/arr 'foo/**' +pathmatch 1 foo/bba/arr 'foo*' +pathmatch 1 foo/bba/arr 'foo**' +pathmatch 1 foo/bba/arr 'foo/*arr' +pathmatch 1 foo/bba/arr 'foo/**arr' +pathmatch 0 foo/bba/arr 'foo/*z' +pathmatch 0 foo/bba/arr 'foo/**z' +pathmatch 1 foo/bar 'foo?bar' +pathmatch 1 foo/bar 'foo[/]bar' +pathmatch 0 foo '*/*/*' +pathmatch 0 foo/bar '*/*/*' +pathmatch 1 foo/bba/arr '*/*/*' +pathmatch 1 foo/bb/aa/rr '*/*/*' +pathmatch 1 abcXdefXghi '*X*i' +pathmatch 1 ab/cXd/efXg/hi '*/*X*/*/*i' +pathmatch 1 ab/cXd/efXg/hi '*Xg*i' + +# Case-sensitivy features +match 0 x 'a' '[A-Z]' +match 1 x 'A' '[A-Z]' +match 0 x 'A' '[a-z]' +match 1 x 'a' '[a-z]' +match 0 x 'a' '[[:upper:]]' +match 1 x 'A' '[[:upper:]]' +match 0 x 'A' '[[:lower:]]' +match 1 x 'a' '[[:lower:]]' +match 0 x 'A' '[B-Za]' +match 1 x 'a' '[B-Za]' +match 0 x 'A' '[B-a]' +match 1 x 'a' '[B-a]' +match 0 x 'z' '[Z-y]' +match 1 x 'Z' '[Z-y]' + +imatch 1 'a' '[A-Z]' +imatch 1 'A' '[A-Z]' +imatch 1 'A' '[a-z]' +imatch 1 'a' '[a-z]' +imatch 1 'a' '[[:upper:]]' +imatch 1 'A' '[[:upper:]]' +imatch 1 'A' '[[:lower:]]' +imatch 1 'a' '[[:lower:]]' +imatch 1 'A' '[B-Za]' +imatch 1 'a' '[B-Za]' +imatch 1 'A' '[B-a]' +imatch 1 'a' '[B-a]' +imatch 1 'z' '[Z-y]' +imatch 1 'Z' '[Z-y]' + +test_done diff --git a/t/t3100-ls-tree-restrict.sh b/t/t3100-ls-tree-restrict.sh index 81d90b66c5..eb73c06a4e 100755 --- a/t/t3100-ls-tree-restrict.sh +++ b/t/t3100-ls-tree-restrict.sh @@ -22,20 +22,8 @@ test_expect_success \ 'setup' \ 'mkdir path2 path2/baz && echo Hi >path0 && - if test_have_prereq SYMLINKS - then - ln -s path0 path1 && - ln -s ../path1 path2/bazbo - make_expected () { - cat >expected - } - else - printf path0 > path1 && - printf ../path1 > path2/bazbo - make_expected () { - sed -e "s/120000 /100644 /" >expected - } - fi && + test_ln_s_add path0 path1 && + test_ln_s_add ../path1 path2/bazbo && echo Lo >path2/foo && echo Mi >path2/baz/b && find path? \( -type f -o -type l \) -print | @@ -51,7 +39,7 @@ test_output () { test_expect_success \ 'ls-tree plain' \ 'git ls-tree $tree >current && - make_expected <<\EOF && + cat >expected <<\EOF && 100644 blob X path0 120000 blob X path1 040000 tree X path2 @@ -61,7 +49,7 @@ EOF test_expect_success \ 'ls-tree recursive' \ 'git ls-tree -r $tree >current && - make_expected <<\EOF && + cat >expected <<\EOF && 100644 blob X path0 120000 blob X path1 100644 blob X path2/baz/b @@ -73,7 +61,7 @@ EOF test_expect_success \ 'ls-tree recursive with -t' \ 'git ls-tree -r -t $tree >current && - make_expected <<\EOF && + cat >expected <<\EOF && 100644 blob X path0 120000 blob X path1 040000 tree X path2 @@ -87,7 +75,7 @@ EOF test_expect_success \ 'ls-tree recursive with -d' \ 'git ls-tree -r -d $tree >current && - make_expected <<\EOF && + cat >expected <<\EOF && 040000 tree X path2 040000 tree X path2/baz EOF @@ -96,7 +84,7 @@ EOF test_expect_success \ 'ls-tree filtered with path' \ 'git ls-tree $tree path >current && - make_expected <<\EOF && + cat >expected <<\EOF && EOF test_output' @@ -106,7 +94,7 @@ EOF test_expect_success \ 'ls-tree filtered with path1 path0' \ 'git ls-tree $tree path1 path0 >current && - make_expected <<\EOF && + cat >expected <<\EOF && 100644 blob X path0 120000 blob X path1 EOF @@ -115,7 +103,7 @@ EOF test_expect_success \ 'ls-tree filtered with path0/' \ 'git ls-tree $tree path0/ >current && - make_expected <<\EOF && + cat >expected <<\EOF && EOF test_output' @@ -124,7 +112,7 @@ EOF test_expect_success \ 'ls-tree filtered with path2' \ 'git ls-tree $tree path2 >current && - make_expected <<\EOF && + cat >expected <<\EOF && 040000 tree X path2 EOF test_output' @@ -133,7 +121,7 @@ EOF test_expect_success \ 'ls-tree filtered with path2/' \ 'git ls-tree $tree path2/ >current && - make_expected <<\EOF && + cat >expected <<\EOF && 040000 tree X path2/baz 120000 blob X path2/bazbo 100644 blob X path2/foo @@ -145,7 +133,7 @@ EOF test_expect_success \ 'ls-tree filtered with path2/baz' \ 'git ls-tree $tree path2/baz >current && - make_expected <<\EOF && + cat >expected <<\EOF && 040000 tree X path2/baz EOF test_output' @@ -153,14 +141,14 @@ EOF test_expect_success \ 'ls-tree filtered with path2/bak' \ 'git ls-tree $tree path2/bak >current && - make_expected <<\EOF && + cat >expected <<\EOF && EOF test_output' test_expect_success \ 'ls-tree -t filtered with path2/bak' \ 'git ls-tree -t $tree path2/bak >current && - make_expected <<\EOF && + cat >expected <<\EOF && 040000 tree X path2 EOF test_output' @@ -168,7 +156,7 @@ EOF test_expect_success \ 'ls-tree with one path a prefix of the other' \ 'git ls-tree $tree path2/baz path2/bazbo >current && - make_expected <<\EOF && + cat >expected <<\EOF && 040000 tree X path2/baz 120000 blob X path2/bazbo EOF diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index 80e6be39d7..44ec6a45f4 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -7,20 +7,18 @@ test_description='git branch assorted tests' . ./test-lib.sh -test_expect_success \ - 'prepare a trivial repository' \ - 'echo Hello > A && - git update-index --add A && - git commit -m "Initial commit." && - echo World >> A && - git update-index --add A && - git commit -m "Second commit." && - HEAD=$(git rev-parse --verify HEAD)' - -test_expect_success \ - 'git branch --help should not have created a bogus branch' ' - test_might_fail git branch --help </dev/null >/dev/null 2>/dev/null && - test_path_is_missing .git/refs/heads/--help +test_expect_success 'prepare a trivial repository' ' + echo Hello >A && + git update-index --add A && + git commit -m "Initial commit." && + echo World >>A && + git update-index --add A && + git commit -m "Second commit." && + HEAD=$(git rev-parse --verify HEAD)' + +test_expect_success 'git branch --help should not have created a bogus branch' ' + test_might_fail git branch --help </dev/null >/dev/null 2>/dev/null && + test_path_is_missing .git/refs/heads/--help ' test_expect_success 'branch -h in broken repository' ' @@ -34,63 +32,67 @@ test_expect_success 'branch -h in broken repository' ' test_i18ngrep "[Uu]sage" broken/usage ' -test_expect_success \ - 'git branch abc should create a branch' \ - 'git branch abc && test_path_is_file .git/refs/heads/abc' +test_expect_success 'git branch abc should create a branch' ' + git branch abc && test_path_is_file .git/refs/heads/abc +' -test_expect_success \ - 'git branch a/b/c should create a branch' \ - 'git branch a/b/c && test_path_is_file .git/refs/heads/a/b/c' +test_expect_success 'git branch a/b/c should create a branch' ' + git branch a/b/c && test_path_is_file .git/refs/heads/a/b/c +' + +test_expect_success 'git branch HEAD should fail' ' + test_must_fail git branch HEAD +' cat >expect <<EOF $_z40 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master EOF -test_expect_success \ - 'git branch -l d/e/f should create a branch and a log' \ - 'GIT_COMMITTER_DATE="2005-05-26 23:30" \ - git branch -l d/e/f && - test_path_is_file .git/refs/heads/d/e/f && - test_path_is_file .git/logs/refs/heads/d/e/f && - test_cmp expect .git/logs/refs/heads/d/e/f' - -test_expect_success \ - 'git branch -d d/e/f should delete a branch and a log' \ - 'git branch -d d/e/f && - test_path_is_missing .git/refs/heads/d/e/f && - test_path_is_missing .git/logs/refs/heads/d/e/f' - -test_expect_success \ - 'git branch j/k should work after branch j has been deleted' \ - 'git branch j && - git branch -d j && - git branch j/k' - -test_expect_success \ - 'git branch l should work after branch l/m has been deleted' \ - 'git branch l/m && - git branch -d l/m && - git branch l' - -test_expect_success \ - 'git branch -m dumps usage' \ - 'test_expect_code 129 git branch -m 2>err && - test_i18ngrep "[Uu]sage: git branch" err' - -test_expect_success \ - 'git branch -m m m/m should work' \ - 'git branch -l m && - git branch -m m m/m && - test_path_is_file .git/logs/refs/heads/m/m' - -test_expect_success \ - 'git branch -m n/n n should work' \ - 'git branch -l n/n && +test_expect_success 'git branch -l d/e/f should create a branch and a log' ' + GIT_COMMITTER_DATE="2005-05-26 23:30" \ + git branch -l d/e/f && + test_path_is_file .git/refs/heads/d/e/f && + test_path_is_file .git/logs/refs/heads/d/e/f && + test_cmp expect .git/logs/refs/heads/d/e/f +' + +test_expect_success 'git branch -d d/e/f should delete a branch and a log' ' + git branch -d d/e/f && + test_path_is_missing .git/refs/heads/d/e/f && + test_path_is_missing .git/logs/refs/heads/d/e/f +' + +test_expect_success 'git branch j/k should work after branch j has been deleted' ' + git branch j && + git branch -d j && + git branch j/k +' + +test_expect_success 'git branch l should work after branch l/m has been deleted' ' + git branch l/m && + git branch -d l/m && + git branch l +' + +test_expect_success 'git branch -m dumps usage' ' + test_expect_code 128 git branch -m 2>err && + test_i18ngrep "branch name required" err +' + +test_expect_success 'git branch -m m m/m should work' ' + git branch -l m && + git branch -m m m/m && + test_path_is_file .git/logs/refs/heads/m/m +' + +test_expect_success 'git branch -m n/n n should work' ' + git branch -l n/n && git branch -m n/n n && - test_path_is_file .git/logs/refs/heads/n' + test_path_is_file .git/logs/refs/heads/n +' test_expect_success 'git branch -m o/o o should fail when o/p exists' ' git branch o/o && - git branch o/p && + git branch o/p && test_must_fail git branch -m o/o o ' @@ -248,19 +250,20 @@ mv .git/config-saved .git/config git config branch.s/s.dummy Hello -test_expect_success \ - 'git branch -m s/s s should work when s/t is deleted' \ - 'git branch -l s/s && +test_expect_success 'git branch -m s/s s should work when s/t is deleted' ' + git branch -l s/s && test_path_is_file .git/logs/refs/heads/s/s && - git branch -l s/t && + git branch -l s/t && test_path_is_file .git/logs/refs/heads/s/t && - git branch -d s/t && - git branch -m s/s s && - test_path_is_file .git/logs/refs/heads/s' + git branch -d s/t && + git branch -m s/s s && + test_path_is_file .git/logs/refs/heads/s +' -test_expect_success 'config information was renamed, too' \ - "test $(git config branch.s.dummy) = Hello && - test_must_fail git config branch.s/s/dummy" +test_expect_success 'config information was renamed, too' ' + test $(git config branch.s.dummy) = Hello && + test_must_fail git config branch.s/s/dummy +' test_expect_success 'deleting a symref' ' git branch target && @@ -281,8 +284,7 @@ test_expect_success 'deleting a dangling symref' ' test_i18ncmp expect actual ' -test_expect_success 'renaming a symref is not allowed' \ -' +test_expect_success 'renaming a symref is not allowed' ' git symbolic-ref refs/heads/master2 refs/heads/master && test_must_fail git branch -m master2 master3 && git symbolic-ref refs/heads/master2 && @@ -290,146 +292,191 @@ test_expect_success 'renaming a symref is not allowed' \ test_path_is_missing .git/refs/heads/master3 ' -test_expect_success SYMLINKS \ - 'git branch -m u v should fail when the reflog for u is a symlink' ' - git branch -l u && - mv .git/logs/refs/heads/u real-u && - ln -s real-u .git/logs/refs/heads/u && - test_must_fail git branch -m u v -' - -test_expect_success 'test tracking setup via --track' \ - 'git config remote.local.url . && - git config remote.local.fetch refs/heads/*:refs/remotes/local/* && - (git show-ref -q refs/remotes/local/master || git fetch local) && - git branch --track my1 local/master && - test $(git config branch.my1.remote) = local && - test $(git config branch.my1.merge) = refs/heads/master' - -test_expect_success 'test tracking setup (non-wildcard, matching)' \ - 'git config remote.local.url . && - git config remote.local.fetch refs/heads/master:refs/remotes/local/master && - (git show-ref -q refs/remotes/local/master || git fetch local) && - git branch --track my4 local/master && - test $(git config branch.my4.remote) = local && - test $(git config branch.my4.merge) = refs/heads/master' - -test_expect_success 'test tracking setup (non-wildcard, not matching)' \ - 'git config remote.local.url . && - git config remote.local.fetch refs/heads/s:refs/remotes/local/s && - (git show-ref -q refs/remotes/local/master || git fetch local) && - git branch --track my5 local/master && - ! test "$(git config branch.my5.remote)" = local && - ! test "$(git config branch.my5.merge)" = refs/heads/master' - -test_expect_success 'test tracking setup via config' \ - 'git config branch.autosetupmerge true && - git config remote.local.url . && - git config remote.local.fetch refs/heads/*:refs/remotes/local/* && - (git show-ref -q refs/remotes/local/master || git fetch local) && - git branch my3 local/master && - test $(git config branch.my3.remote) = local && - test $(git config branch.my3.merge) = refs/heads/master' - -test_expect_success 'test overriding tracking setup via --no-track' \ - 'git config branch.autosetupmerge true && - git config remote.local.url . && - git config remote.local.fetch refs/heads/*:refs/remotes/local/* && - (git show-ref -q refs/remotes/local/master || git fetch local) && - git branch --no-track my2 local/master && - git config branch.autosetupmerge false && - ! test "$(git config branch.my2.remote)" = local && - ! test "$(git config branch.my2.merge)" = refs/heads/master' - -test_expect_success 'no tracking without .fetch entries' \ - 'git config branch.autosetupmerge true && - git branch my6 s && - git config branch.automsetupmerge false && - test -z "$(git config branch.my6.remote)" && - test -z "$(git config branch.my6.merge)"' - -test_expect_success 'test tracking setup via --track but deeper' \ - 'git config remote.local.url . && - git config remote.local.fetch refs/heads/*:refs/remotes/local/* && - (git show-ref -q refs/remotes/local/o/o || git fetch local) && - git branch --track my7 local/o/o && - test "$(git config branch.my7.remote)" = local && - test "$(git config branch.my7.merge)" = refs/heads/o/o' - -test_expect_success 'test deleting branch deletes branch config' \ - 'git branch -d my7 && - test -z "$(git config branch.my7.remote)" && - test -z "$(git config branch.my7.merge)"' - -test_expect_success 'test deleting branch without config' \ - 'git branch my7 s && - sha1=$(git rev-parse my7 | cut -c 1-7) && - echo "Deleted branch my7 (was $sha1)." >expect && - git branch -d my7 >actual 2>&1 && - test_i18ncmp expect actual' - -test_expect_success 'test --track without .fetch entries' \ - 'git branch --track my8 && - test "$(git config branch.my8.remote)" && - test "$(git config branch.my8.merge)"' - -test_expect_success \ - 'branch from non-branch HEAD w/autosetupmerge=always' \ - 'git config branch.autosetupmerge always && - git branch my9 HEAD^ && - git config branch.autosetupmerge false' - -test_expect_success \ - 'branch from non-branch HEAD w/--track causes failure' \ - 'test_must_fail git branch --track my10 HEAD^' - -test_expect_success \ - 'branch from tag w/--track causes failure' \ - 'git tag foobar && - test_must_fail git branch --track my11 foobar' - -test_expect_success 'use --set-upstream-to modify HEAD' \ - 'test_config branch.master.remote foo && - test_config branch.master.merge foo && - git branch my12 - git branch --set-upstream-to my12 && - test "$(git config branch.master.remote)" = "." && - test "$(git config branch.master.merge)" = "refs/heads/my12"' - -test_expect_success 'use --set-upstream-to modify a particular branch' \ - 'git branch my13 - git branch --set-upstream-to master my13 && - test "$(git config branch.my13.remote)" = "." && - test "$(git config branch.my13.merge)" = "refs/heads/master"' - -test_expect_success '--unset-upstream should fail if given a non-existent branch' \ - 'test_must_fail git branch --unset-upstream i-dont-exist' - -test_expect_success 'test --unset-upstream on HEAD' \ - 'git branch my14 - test_config branch.master.remote foo && - test_config branch.master.merge foo && - git branch --set-upstream-to my14 && - git branch --unset-upstream && - test_must_fail git config branch.master.remote && - test_must_fail git config branch.master.merge && - # fail for a branch without upstream set - test_must_fail git branch --unset-upstream -' - -test_expect_success 'test --unset-upstream on a particular branch' \ - 'git branch my15 - git branch --set-upstream-to master my14 && - git branch --unset-upstream my14 && - test_must_fail git config branch.my14.remote && - test_must_fail git config branch.my14.merge' - -test_expect_success '--set-upstream shows message when creating a new branch that exists as remote-tracking' \ - 'git update-ref refs/remotes/origin/master HEAD && - git branch --set-upstream origin/master 2>actual && - test_when_finished git update-ref -d refs/remotes/origin/master && - test_when_finished git branch -d origin/master && - cat >expected <<EOF && +test_expect_success SYMLINKS 'git branch -m u v should fail when the reflog for u is a symlink' ' + git branch -l u && + mv .git/logs/refs/heads/u real-u && + ln -s real-u .git/logs/refs/heads/u && + test_must_fail git branch -m u v +' + +test_expect_success 'test tracking setup via --track' ' + git config remote.local.url . && + git config remote.local.fetch refs/heads/*:refs/remotes/local/* && + (git show-ref -q refs/remotes/local/master || git fetch local) && + git branch --track my1 local/master && + test $(git config branch.my1.remote) = local && + test $(git config branch.my1.merge) = refs/heads/master +' + +test_expect_success 'test tracking setup (non-wildcard, matching)' ' + git config remote.local.url . && + git config remote.local.fetch refs/heads/master:refs/remotes/local/master && + (git show-ref -q refs/remotes/local/master || git fetch local) && + git branch --track my4 local/master && + test $(git config branch.my4.remote) = local && + test $(git config branch.my4.merge) = refs/heads/master +' + +test_expect_success 'tracking setup fails on non-matching refspec' ' + git config remote.local.url . && + git config remote.local.fetch refs/heads/s:refs/remotes/local/s && + (git show-ref -q refs/remotes/local/master || git fetch local) && + test_must_fail git branch --track my5 local/master && + test_must_fail git config branch.my5.remote && + test_must_fail git config branch.my5.merge +' + +test_expect_success 'test tracking setup via config' ' + git config branch.autosetupmerge true && + git config remote.local.url . && + git config remote.local.fetch refs/heads/*:refs/remotes/local/* && + (git show-ref -q refs/remotes/local/master || git fetch local) && + git branch my3 local/master && + test $(git config branch.my3.remote) = local && + test $(git config branch.my3.merge) = refs/heads/master +' + +test_expect_success 'test overriding tracking setup via --no-track' ' + git config branch.autosetupmerge true && + git config remote.local.url . && + git config remote.local.fetch refs/heads/*:refs/remotes/local/* && + (git show-ref -q refs/remotes/local/master || git fetch local) && + git branch --no-track my2 local/master && + git config branch.autosetupmerge false && + ! test "$(git config branch.my2.remote)" = local && + ! test "$(git config branch.my2.merge)" = refs/heads/master +' + +test_expect_success 'no tracking without .fetch entries' ' + git config branch.autosetupmerge true && + git branch my6 s && + git config branch.automsetupmerge false && + test -z "$(git config branch.my6.remote)" && + test -z "$(git config branch.my6.merge)" +' + +test_expect_success 'test tracking setup via --track but deeper' ' + git config remote.local.url . && + git config remote.local.fetch refs/heads/*:refs/remotes/local/* && + (git show-ref -q refs/remotes/local/o/o || git fetch local) && + git branch --track my7 local/o/o && + test "$(git config branch.my7.remote)" = local && + test "$(git config branch.my7.merge)" = refs/heads/o/o +' + +test_expect_success 'test deleting branch deletes branch config' ' + git branch -d my7 && + test -z "$(git config branch.my7.remote)" && + test -z "$(git config branch.my7.merge)" +' + +test_expect_success 'test deleting branch without config' ' + git branch my7 s && + sha1=$(git rev-parse my7 | cut -c 1-7) && + echo "Deleted branch my7 (was $sha1)." >expect && + git branch -d my7 >actual 2>&1 && + test_i18ncmp expect actual +' + +test_expect_success 'test --track without .fetch entries' ' + git branch --track my8 && + test "$(git config branch.my8.remote)" && + test "$(git config branch.my8.merge)" +' + +test_expect_success 'branch from non-branch HEAD w/autosetupmerge=always' ' + git config branch.autosetupmerge always && + git branch my9 HEAD^ && + git config branch.autosetupmerge false +' + +test_expect_success 'branch from non-branch HEAD w/--track causes failure' ' + test_must_fail git branch --track my10 HEAD^ +' + +test_expect_success 'branch from tag w/--track causes failure' ' + git tag foobar && + test_must_fail git branch --track my11 foobar +' + +test_expect_success '--set-upstream-to fails on multiple branches' ' + test_must_fail git branch --set-upstream-to master a b c +' + +test_expect_success '--set-upstream-to fails on detached HEAD' ' + git checkout HEAD^{} && + test_must_fail git branch --set-upstream-to master && + git checkout - +' + +test_expect_success '--set-upstream-to fails on a missing dst branch' ' + test_must_fail git branch --set-upstream-to master does-not-exist +' + +test_expect_success '--set-upstream-to fails on a missing src branch' ' + test_must_fail git branch --set-upstream-to does-not-exist master +' + +test_expect_success '--set-upstream-to fails on a non-ref' ' + test_must_fail git branch --set-upstream-to HEAD^{} +' + +test_expect_success 'use --set-upstream-to modify HEAD' ' + test_config branch.master.remote foo && + test_config branch.master.merge foo && + git branch my12 + git branch --set-upstream-to my12 && + test "$(git config branch.master.remote)" = "." && + test "$(git config branch.master.merge)" = "refs/heads/my12" +' + +test_expect_success 'use --set-upstream-to modify a particular branch' ' + git branch my13 + git branch --set-upstream-to master my13 && + test "$(git config branch.my13.remote)" = "." && + test "$(git config branch.my13.merge)" = "refs/heads/master" +' + +test_expect_success '--unset-upstream should fail if given a non-existent branch' ' + test_must_fail git branch --unset-upstream i-dont-exist +' + +test_expect_success 'test --unset-upstream on HEAD' ' + git branch my14 + test_config branch.master.remote foo && + test_config branch.master.merge foo && + git branch --set-upstream-to my14 && + git branch --unset-upstream && + test_must_fail git config branch.master.remote && + test_must_fail git config branch.master.merge && + # fail for a branch without upstream set + test_must_fail git branch --unset-upstream +' + +test_expect_success '--unset-upstream should fail on multiple branches' ' + test_must_fail git branch --unset-upstream a b c +' + +test_expect_success '--unset-upstream should fail on detached HEAD' ' + git checkout HEAD^{} && + test_must_fail git branch --unset-upstream && + git checkout - +' + +test_expect_success 'test --unset-upstream on a particular branch' ' + git branch my15 + git branch --set-upstream-to master my14 && + git branch --unset-upstream my14 && + test_must_fail git config branch.my14.remote && + test_must_fail git config branch.my14.merge +' + +test_expect_success '--set-upstream shows message when creating a new branch that exists as remote-tracking' ' + git update-ref refs/remotes/origin/master HEAD && + git branch --set-upstream origin/master 2>actual && + test_when_finished git update-ref -d refs/remotes/origin/master && + test_when_finished git branch -d origin/master && + cat >expected <<EOF && The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to If you wanted to make '"'master'"' track '"'origin/master'"', do this: @@ -437,38 +484,38 @@ If you wanted to make '"'master'"' track '"'origin/master'"', do this: git branch -d origin/master git branch --set-upstream-to origin/master EOF - test_cmp expected actual + test_cmp expected actual ' -test_expect_success '--set-upstream with two args only shows the deprecation message' \ - 'git branch --set-upstream master my13 2>actual && - test_when_finished git branch --unset-upstream master && - cat >expected <<EOF && +test_expect_success '--set-upstream with two args only shows the deprecation message' ' + git branch --set-upstream master my13 2>actual && + test_when_finished git branch --unset-upstream master && + cat >expected <<EOF && The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to EOF - test_cmp expected actual + test_cmp expected actual ' -test_expect_success '--set-upstream with one arg only shows the deprecation message if the branch existed' \ - 'git branch --set-upstream my13 2>actual && - test_when_finished git branch --unset-upstream my13 && - cat >expected <<EOF && +test_expect_success '--set-upstream with one arg only shows the deprecation message if the branch existed' ' + git branch --set-upstream my13 2>actual && + test_when_finished git branch --unset-upstream my13 && + cat >expected <<EOF && The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to EOF - test_cmp expected actual + test_cmp expected actual ' # Keep this test last, as it changes the current branch cat >expect <<EOF $_z40 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master EOF -test_expect_success \ - 'git checkout -b g/h/i -l should create a branch and a log' \ - 'GIT_COMMITTER_DATE="2005-05-26 23:30" \ - git checkout -b g/h/i -l master && - test_path_is_file .git/refs/heads/g/h/i && - test_path_is_file .git/logs/refs/heads/g/h/i && - test_cmp expect .git/logs/refs/heads/g/h/i' +test_expect_success 'git checkout -b g/h/i -l should create a branch and a log' ' + GIT_COMMITTER_DATE="2005-05-26 23:30" \ + git checkout -b g/h/i -l master && + test_path_is_file .git/refs/heads/g/h/i && + test_path_is_file .git/logs/refs/heads/g/h/i && + test_cmp expect .git/logs/refs/heads/g/h/i +' test_expect_success 'checkout -b makes reflog by default' ' git checkout master && @@ -739,7 +786,7 @@ test_expect_success 'detect misconfigured autosetuprebase (bad value)' ' test_expect_success 'detect misconfigured autosetuprebase (no value)' ' git config --unset branch.autosetuprebase && - echo "[branch] autosetuprebase" >> .git/config && + echo "[branch] autosetuprebase" >>.git/config && test_must_fail git branch && git config --unset branch.autosetuprebase ' diff --git a/t/t3201-branch-contains.sh b/t/t3201-branch-contains.sh index f86f4bc5eb..141b0611ea 100755 --- a/t/t3201-branch-contains.sh +++ b/t/t3201-branch-contains.sh @@ -55,6 +55,16 @@ test_expect_success 'branch --contains=side' ' ' +test_expect_success 'branch --contains with pattern implies --list' ' + + git branch --contains=master master >actual && + { + echo " master" + } >expect && + test_cmp expect actual + +' + test_expect_success 'side: branch --merged' ' git branch --merged >actual && @@ -66,6 +76,16 @@ test_expect_success 'side: branch --merged' ' ' +test_expect_success 'branch --merged with pattern implies --list' ' + + git branch --merged=side master >actual && + { + echo " master" + } >expect && + test_cmp expect actual + +' + test_expect_success 'side: branch --no-merged' ' git branch --no-merged >actual && @@ -95,4 +115,19 @@ test_expect_success 'master: branch --no-merged' ' ' +test_expect_success 'branch --no-merged with pattern implies --list' ' + + git branch --no-merged=master master >actual && + >expect && + test_cmp expect actual + +' + +test_expect_success 'implicit --list conflicts with modification options' ' + + test_must_fail git branch --contains=master -d && + test_must_fail git branch --contains=master -m foo + +' + test_done diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh index 76fe7e0060..ba4f98e800 100755 --- a/t/t3203-branch-output.sh +++ b/t/t3203-branch-output.sh @@ -94,13 +94,13 @@ test_expect_success 'git branch -v pattern does not show branch summaries' ' test_must_fail git branch -v branch* ' -cat >expect <<'EOF' -* (no branch) +test_expect_success 'git branch shows detached HEAD properly' ' + cat >expect <<EOF && +* (detached from $(git rev-parse --short HEAD^0)) branch-one branch-two master EOF -test_expect_success 'git branch shows detached HEAD properly' ' git checkout HEAD^0 && git branch >actual && test_i18ncmp expect actual diff --git a/t/t3210-pack-refs.sh b/t/t3210-pack-refs.sh index cd04361df8..1a2080e3dc 100755 --- a/t/t3210-pack-refs.sh +++ b/t/t3210-pack-refs.sh @@ -118,4 +118,37 @@ test_expect_success 'pack, prune and repack' ' test_cmp all-of-them again ' +test_expect_success 'explicit pack-refs with dangling packed reference' ' + git commit --allow-empty -m "soon to be garbage-collected" && + git pack-refs --all && + git reset --hard HEAD^ && + git reflog expire --expire=all --all && + git prune --expire=all && + git pack-refs --all 2>result && + test_cmp /dev/null result +' + +test_expect_success 'delete ref with dangling packed version' ' + git checkout -b lamb && + git commit --allow-empty -m "future garbage" && + git pack-refs --all && + git reset --hard HEAD^ && + git checkout master && + git reflog expire --expire=all --all && + git prune --expire=all && + git branch -d lamb 2>result && + test_cmp /dev/null result +' + +test_expect_success 'delete ref while another dangling packed ref' ' + git branch lamb && + git commit --allow-empty -m "future garbage" && + git pack-refs --all && + git reset --hard HEAD^ && + git reflog expire --expire=all --all && + git prune --expire=all && + git branch -d lamb 2>result && + test_cmp /dev/null result +' + test_done diff --git a/t/t3211-peel-ref.sh b/t/t3211-peel-ref.sh new file mode 100755 index 0000000000..3b7caca421 --- /dev/null +++ b/t/t3211-peel-ref.sh @@ -0,0 +1,73 @@ +#!/bin/sh + +test_description='tests for the peel_ref optimization of packed-refs' +. ./test-lib.sh + +test_expect_success 'create annotated tag in refs/tags' ' + test_commit base && + git tag -m annotated foo +' + +test_expect_success 'create annotated tag outside of refs/tags' ' + git update-ref refs/outside/foo refs/tags/foo +' + +# This matches show-ref's output +print_ref() { + echo "$(git rev-parse "$1") $1" +} + +test_expect_success 'set up expected show-ref output' ' + { + print_ref "refs/heads/master" && + print_ref "refs/outside/foo" && + print_ref "refs/outside/foo^{}" && + print_ref "refs/tags/base" && + print_ref "refs/tags/foo" && + print_ref "refs/tags/foo^{}" + } >expect +' + +test_expect_success 'refs are peeled outside of refs/tags (loose)' ' + git show-ref -d >actual && + test_cmp expect actual +' + +test_expect_success 'refs are peeled outside of refs/tags (packed)' ' + git pack-refs --all && + git show-ref -d >actual && + test_cmp expect actual +' + +test_expect_success 'create old-style pack-refs without fully-peeled' ' + # Git no longer writes without fully-peeled, so we just write our own + # from scratch; we could also munge the existing file to remove the + # fully-peeled bits, but that seems even more prone to failure, + # especially if the format ever changes again. At least this way we + # know we are emulating exactly what an older git would have written. + { + echo "# pack-refs with: peeled " && + print_ref "refs/heads/master" && + print_ref "refs/outside/foo" && + print_ref "refs/tags/base" && + print_ref "refs/tags/foo" && + echo "^$(git rev-parse "refs/tags/foo^{}")" + } >tmp && + mv tmp .git/packed-refs +' + +test_expect_success 'refs are peeled outside of refs/tags (old packed)' ' + git show-ref -d >actual && + test_cmp expect actual +' + +test_expect_success 'peeled refs survive deletion of packed ref' ' + git pack-refs --all && + cp .git/packed-refs fully-peeled && + git branch yadda && + git pack-refs --all && + git branch -d yadda && + test_cmp fully-peeled .git/packed-refs +' + +test_done diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index 1de0ebda25..ebf93b0695 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -40,13 +40,6 @@ test_expect_success 'prepare repository with topic branches' ' echo Side >>C && git add C && git commit -m "Add C" && - git checkout -b nonlinear my-topic-branch && - echo Edit >>B && - git add B && - git commit -m "Modify B" && - git merge side && - git checkout -b upstream-merged-nonlinear && - git merge master && git checkout -f my-topic-branch && git tag topic ' @@ -66,26 +59,15 @@ test_expect_success 'rebase against master' ' git rebase master ' -test_expect_success 'rebase against master twice' ' - git rebase master >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 && - 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 && - 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 && - test_i18ngrep "Fast-forwarded HEAD to my-topic-branch" out +test_expect_success 'rebase, with <onto> and <upstream> specified as :/quuxery' ' + test_when_finished "git branch -D torebase" && + git checkout -b torebase my-topic-branch^ && + upstream=$(git rev-parse ":/Add B") && + onto=$(git rev-parse ":/Add A") && + git rebase --onto $onto $upstream && + git reset --hard my-topic-branch^ && + git rebase --onto ":/Add A" ":/Add B" && + git checkout my-topic-branch ' test_expect_success 'the rebase operation should not have destroyed author information' ' @@ -101,29 +83,14 @@ test_expect_success 'HEAD was detached during rebase' ' test $(git rev-parse HEAD@{1}) != $(git rev-parse my-topic-branch@{1}) ' -test_expect_success 'rebase after merge master' ' - git reset --hard topic && - git merge master && - git rebase master && - ! (git show | grep "^Merge:") -' - -test_expect_success 'rebase of history with merges is linearized' ' - git checkout nonlinear && - test 4 = $(git rev-list master.. | wc -l) && - git rebase master && - test 3 = $(git rev-list master.. | wc -l) -' - -test_expect_success 'rebase of history with merges after upstream merge is linearized' ' - git checkout upstream-merged-nonlinear && - test 5 = $(git rev-list master.. | wc -l) && - git rebase master && - test 3 = $(git rev-list master.. | wc -l) +test_expect_success 'rebase from ambiguous branch name' ' + git checkout -b topic side && + git rebase master ' test_expect_success 'rebase a single mode change' ' git checkout master && + git branch -D topic && echo 1 >X && git add X && test_tick && @@ -138,8 +105,7 @@ test_expect_success 'rebase a single mode change' ' ' test_expect_success 'rebase is not broken by diff.renames' ' - git config diff.renames copies && - test_when_finished "git config --unset diff.renames" && + test_config diff.renames copies && git checkout filemove && GIT_TRACE=1 git rebase force-3way ' @@ -179,7 +145,7 @@ test_expect_success 'default to @{upstream} when upstream arg is missing' ' test_expect_success 'rebase -q is quiet' ' git checkout -b quiet topic && git rebase -q master >output.out 2>&1 && - test ! -s output.out + test_must_be_empty output.out ' test_expect_success 'Rebase a commit that sprinkles CRs in' ' diff --git a/t/t3401-rebase-partial.sh b/t/t3401-rebase-partial.sh deleted file mode 100755 index 58f4823783..0000000000 --- a/t/t3401-rebase-partial.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2006 Yann Dirson, based on t3400 by Amos Waterland -# - -test_description='git rebase should detect patches integrated upstream - -This test cherry-picks one local change of two into master branch, and -checks that git rebase succeeds with only the second patch in the -local branch. -' -. ./test-lib.sh - -test_expect_success 'prepare repository with topic branch' ' - test_commit A && - git checkout -b my-topic-branch && - test_commit B && - test_commit C && - git checkout -f master && - test_commit A2 A.t -' - -test_expect_success 'pick top patch from topic branch into master' ' - git cherry-pick C && - git checkout -f my-topic-branch -' - -test_debug ' - git cherry master && - git format-patch -k --stdout --full-index master >/dev/null && - gitk --all & sleep 1 -' - -test_expect_success 'rebase topic branch against new master and check git am did not get halted' ' - git rebase master && - test_path_is_missing .git/rebase-apply -' - -test_expect_success 'rebase --merge topic branch that was partially merged upstream' ' - git reset --hard C && - git rebase --merge master && - 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_expect_success 'rebase --keep-empty' ' - git reset --hard D && - git rebase --keep-empty C && - test "$(git log --format=%s C..)" = "D -empty" -' - -test_expect_success 'rebase --keep-empty keeps empty even if already in upstream' ' - git reset --hard A && - git commit --allow-empty -m also-empty && - git rebase --keep-empty D && - test "$(git log --format=%s A..)" = "also-empty -D -empty" -' - -test_done diff --git a/t/t3403-rebase-skip.sh b/t/t3403-rebase-skip.sh index 826500bd18..3968020e64 100755 --- a/t/t3403-rebase-skip.sh +++ b/t/t3403-rebase-skip.sh @@ -64,10 +64,11 @@ test_expect_success 'rebase with --merge' ' test_expect_success 'rebase --skip with --merge' ' git rebase --skip - ' +' -test_expect_success 'merge and reference trees equal' \ - 'test -z "`git diff-tree skip-merge skip-reference`"' +test_expect_success 'merge and reference trees equal' ' + test -z "`git diff-tree skip-merge skip-reference`" +' test_expect_success 'moved back to branch correctly' ' test refs/heads/skip-merge = $(git symbolic-ref HEAD) diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 32fdc9938e..49ccb38f88 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -29,12 +29,6 @@ Initial setup: . "$TEST_DIRECTORY"/lib-rebase.sh -test_cmp_rev () { - git rev-parse --verify "$1" >expect.rev && - git rev-parse --verify "$2" >actual.rev && - test_cmp expect.rev actual.rev -} - set_fake_editor # WARNING: Modifications to the initial repository can change the SHA ID used @@ -483,19 +477,11 @@ test_expect_success 'interrupted squash works as expected (case 2)' ' test $one = $(git rev-parse HEAD~2) ' -test_expect_success 'ignore patch if in upstream' ' - HEAD=$(git rev-parse HEAD) && - git checkout -b has-cherry-picked HEAD^ && +test_expect_success '--continue tries to commit, even for "edit"' ' echo unrelated > file7 && git add file7 && test_tick && git commit -m "unrelated change" && - git cherry-pick $HEAD && - EXPECT_COUNT=1 git rebase -i $HEAD && - test $HEAD = $(git rev-parse HEAD^) -' - -test_expect_success '--continue tries to commit, even for "edit"' ' parent=$(git rev-parse HEAD^) && test_tick && FAKE_LINES="edit 1" git rebase -i HEAD^ && @@ -698,7 +684,7 @@ test_expect_success 'rebase -i can copy notes' ' test_commit n2 && test_commit n3 && git notes add -m"a note" n3 && - git rebase --onto n1 n2 && + git rebase -i --onto n1 n2 && test "a note" = "$(git notes show HEAD)" ' @@ -940,4 +926,54 @@ test_expect_success 'rebase --edit-todo can be used to modify todo' ' test L = $(git cat-file commit HEAD | sed -ne \$p) ' +test_expect_success 'rebase -i produces readable reflog' ' + git reset --hard && + git branch -f branch-reflog-test H && + git rebase -i --onto I F branch-reflog-test && + cat >expect <<-\EOF && + rebase -i (start): checkout I + rebase -i (pick): G + rebase -i (pick): H + rebase -i (finish): returning to refs/heads/branch-reflog-test + EOF + tail -n 4 .git/logs/HEAD | + sed -e "s/.* //" >actual && + test_cmp expect actual +' + +test_expect_success 'rebase -i respects core.commentchar' ' + git reset --hard && + git checkout E^0 && + test_config core.commentchar "\\" && + write_script remove-all-but-first.sh <<-\EOF && + sed -e "2,\$s/^/\\\\/" "$1" >"$1.tmp" && + mv "$1.tmp" "$1" + EOF + test_set_editor "$(pwd)/remove-all-but-first.sh" && + git rebase -i B && + test B = $(git cat-file commit HEAD^ | sed -ne \$p) +' + +test_expect_success 'rebase -i, with <onto> and <upstream> specified as :/quuxery' ' + test_when_finished "git branch -D torebase" && + git checkout -b torebase branch1 && + upstream=$(git rev-parse ":/J") && + onto=$(git rev-parse ":/A") && + git rebase --onto $onto $upstream && + git reset --hard branch1 && + git rebase --onto ":/A" ":/J" && + git checkout branch1 +' + +test_expect_success 'rebase -i with --strategy and -X' ' + git checkout -b conflict-merge-use-theirs conflict-branch && + git reset --hard HEAD^ && + echo five >conflict && + echo Z >file1 && + git commit -a -m "one file conflict" && + EDITOR=true git rebase -i --strategy=recursive -Xours conflict-branch && + test $(git show conflict-branch:conflict) = $(cat conflict) && + test $(cat file1) = Z +' + test_done diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh index e6a9a0d436..0392e36d23 100755 --- a/t/t3406-rebase-message.sh +++ b/t/t3406-rebase-message.sh @@ -4,27 +4,17 @@ test_description='messages from rebase operation' . ./test-lib.sh -quick_one () { - echo "$1" >"file$1" && - git add "file$1" && - test_tick && - git commit -m "$1" -} +test_expect_success 'setup' ' + test_commit O fileO && + test_commit X fileX && + test_commit A fileA && + test_commit B fileB && + test_commit Y fileY && -test_expect_success setup ' - quick_one O && - git branch topic && - quick_one X && - quick_one A && - quick_one B && - quick_one Y && - - git checkout topic && - quick_one A && - quick_one B && - quick_one Z && + git checkout -b topic O && + git cherry-pick A B && + test_commit Z fileZ && git tag start - ' cat >expect <<\EOF @@ -34,12 +24,32 @@ Committed: 0003 Z EOF test_expect_success 'rebase -m' ' - git rebase -m master >report && sed -n -e "/^Already applied: /p" \ -e "/^Committed: /p" report >actual && test_cmp expect actual +' + +test_expect_success 'rebase against master twice' ' + git rebase master >out && + test_i18ngrep "Current branch topic is up to date" out +' + +test_expect_success 'rebase against master twice with --force' ' + git rebase --force-rebase master >out && + test_i18ngrep "Current branch topic is up to date, rebase forced" out +' + +test_expect_success 'rebase against master twice from another branch' ' + git checkout topic^ && + git rebase master topic >out && + test_i18ngrep "Current branch topic is up to date" out +' +test_expect_success 'rebase fast-forward to master' ' + git checkout topic^ && + git rebase topic >out && + test_i18ngrep "Fast-forwarded HEAD to topic" out ' test_expect_success 'rebase --stat' ' diff --git a/t/t3409-rebase-preserve-merges.sh b/t/t3409-rebase-preserve-merges.sh index 6de4e2263f..2e0c36415f 100755 --- a/t/t3409-rebase-preserve-merges.sh +++ b/t/t3409-rebase-preserve-merges.sh @@ -11,14 +11,6 @@ Run "git rebase -p" and check that merges are properly carried along GIT_AUTHOR_EMAIL=bogus_email_address export GIT_AUTHOR_EMAIL -# Clone 1 (trivial merge): -# -# A1--A2 <-- origin/master -# \ \ -# B1--M <-- topic -# \ -# B2 <-- origin/topic -# # Clone 2 (conflicting merge): # # A1--A2--B3 <-- origin/master @@ -36,16 +28,6 @@ export GIT_AUTHOR_EMAIL # \--A3 <-- topic2 # \ # B2 <-- origin/topic -# -# Clone 4 (merge using second parent as base): -# -# A1--A2--B3 <-- origin/master -# \ -# B1--A3--M <-- topic -# \ / -# \--A4 <-- topic2 -# \ -# B2 <-- origin/topic test_expect_success 'setup for merge-preserving rebase' \ 'echo First > A && @@ -58,20 +40,6 @@ test_expect_success 'setup for merge-preserving rebase' \ git checkout -f master && echo Third >> A && git commit -a -m "Modify A2" && - - git clone ./. clone1 && - (cd clone1 && - git checkout -b topic origin/topic && - git merge origin/master - ) && - - git clone ./. clone4 && - ( - cd clone4 && - git checkout -b topic origin/topic && - git merge origin/master - ) && - echo Fifth > B && git add B && git commit -m "Add different B" && @@ -101,16 +69,6 @@ test_expect_success 'setup for merge-preserving rebase' \ git commit -a -m "Modify B2" ' -test_expect_success 'rebase -p fakes interactive rebase' ' - ( - cd clone1 && - git fetch && - git rebase -p origin/topic && - test 1 = $(git rev-list --all --pretty=oneline | grep "Modify A" | wc -l) && - test 1 = $(git rev-list --all --pretty=oneline | grep "Merge remote-tracking branch " | wc -l) - ) -' - test_expect_success '--continue works after a conflict' ' ( cd clone2 && @@ -138,15 +96,4 @@ test_expect_success 'rebase -p preserves no-ff merges' ' ) ' -test_expect_success 'rebase -p works when base inside second parent' ' - ( - cd clone4 && - git fetch && - git rebase -p HEAD^2 && - test 1 = $(git rev-list --all --pretty=oneline | grep "Modify A" | wc -l) && - test 1 = $(git rev-list --all --pretty=oneline | grep "Modify B" | wc -l) && - test 1 = $(git rev-list --all --pretty=oneline | grep "Merge remote-tracking branch " | wc -l) - ) -' - test_done diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh index a1e86c4097..41370ab998 100755 --- a/t/t3415-rebase-autosquash.sh +++ b/t/t3415-rebase-autosquash.sh @@ -4,6 +4,8 @@ test_description='auto squash' . ./test-lib.sh +. "$TEST_DIRECTORY"/lib-rebase.sh + test_expect_success setup ' echo 0 >file0 && git add . && @@ -193,4 +195,59 @@ test_expect_success 'use commit --squash' ' test_auto_commit_flags squash 2 ' +test_auto_fixup_fixup () { + git reset --hard base && + echo 1 >file1 && + git add -u && + test_tick && + git commit -m "$1! first" && + echo 2 >file1 && + git add -u && + test_tick && + git commit -m "$1! $2! first" && + git tag "final-$1-$2" && + test_tick && + ( + set_cat_todo_editor && + test_must_fail git rebase --autosquash -i HEAD^^^^ >actual && + cat >expected <<-EOF && + pick $(git rev-parse --short HEAD^^^) first commit + $1 $(git rev-parse --short HEAD^) $1! first + $1 $(git rev-parse --short HEAD) $1! $2! first + pick $(git rev-parse --short HEAD^^) second commit + EOF + test_cmp expected actual + ) && + git rebase --autosquash -i HEAD^^^^ && + git log --oneline >actual && + test_line_count = 3 actual + git diff --exit-code "final-$1-$2" && + test 2 = "$(git cat-file blob HEAD^:file1)" && + if test "$1" = "fixup" + then + test 1 = $(git cat-file commit HEAD^ | grep first | wc -l) + elif test "$1" = "squash" + then + test 3 = $(git cat-file commit HEAD^ | grep first | wc -l) + else + false + fi +} + +test_expect_success 'fixup! fixup!' ' + test_auto_fixup_fixup fixup fixup +' + +test_expect_success 'fixup! squash!' ' + test_auto_fixup_fixup fixup squash +' + +test_expect_success 'squash! squash!' ' + test_auto_fixup_fixup squash squash +' + +test_expect_success 'squash! fixup!' ' + test_auto_fixup_fixup squash fixup +' + test_done diff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh new file mode 100755 index 0000000000..90eb26493c --- /dev/null +++ b/t/t3420-rebase-autostash.sh @@ -0,0 +1,170 @@ +#!/bin/sh +# +# Copyright (c) 2013 Ramkumar Ramachandra +# + +test_description='git rebase --autostash tests' +. ./test-lib.sh + +test_expect_success setup ' + echo hello-world >file0 && + git add . && + test_tick && + git commit -m "initial commit" && + git checkout -b feature-branch && + echo another-hello >file1 && + echo goodbye >file2 && + git add . && + test_tick && + git commit -m "second commit" && + echo final-goodbye >file3 && + git add . && + test_tick && + git commit -m "third commit" && + git checkout -b unrelated-onto-branch master && + echo unrelated >file4 && + git add . && + test_tick && + git commit -m "unrelated commit" && + git checkout -b related-onto-branch master && + echo conflicting-change >file2 && + git add . && + test_tick && + git commit -m "related commit" +' + +testrebase() { + type=$1 + dotest=$2 + + test_expect_success "rebase$type: dirty worktree, non-conflicting rebase" ' + test_config rebase.autostash true && + git reset --hard && + git checkout -b rebased-feature-branch feature-branch && + test_when_finished git branch -D rebased-feature-branch && + echo dirty >>file3 && + git rebase$type unrelated-onto-branch && + grep unrelated file4 && + grep dirty file3 && + git checkout feature-branch + ' + + test_expect_success "rebase$type: dirty index, non-conflicting rebase" ' + test_config rebase.autostash true && + git reset --hard && + git checkout -b rebased-feature-branch feature-branch && + test_when_finished git branch -D rebased-feature-branch && + echo dirty >>file3 && + git add file3 && + git rebase$type unrelated-onto-branch && + grep unrelated file4 && + grep dirty file3 && + git checkout feature-branch + ' + + test_expect_success "rebase$type: conflicting rebase" ' + test_config rebase.autostash true && + git reset --hard && + git checkout -b rebased-feature-branch feature-branch && + test_when_finished git branch -D rebased-feature-branch && + echo dirty >>file3 && + test_must_fail git rebase$type related-onto-branch && + test_path_is_file $dotest/autostash && + ! grep dirty file3 && + rm -rf $dotest && + git reset --hard && + git checkout feature-branch + ' + + test_expect_success "rebase$type: --continue" ' + test_config rebase.autostash true && + git reset --hard && + git checkout -b rebased-feature-branch feature-branch && + test_when_finished git branch -D rebased-feature-branch && + echo dirty >>file3 && + test_must_fail git rebase$type related-onto-branch && + test_path_is_file $dotest/autostash && + ! grep dirty file3 && + echo "conflicting-plus-goodbye" >file2 && + git add file2 && + git rebase --continue && + test_path_is_missing $dotest/autostash && + grep dirty file3 && + git checkout feature-branch + ' + + test_expect_success "rebase$type: --skip" ' + test_config rebase.autostash true && + git reset --hard && + git checkout -b rebased-feature-branch feature-branch && + test_when_finished git branch -D rebased-feature-branch && + echo dirty >>file3 && + test_must_fail git rebase$type related-onto-branch && + test_path_is_file $dotest/autostash && + ! grep dirty file3 && + git rebase --skip && + test_path_is_missing $dotest/autostash && + grep dirty file3 && + git checkout feature-branch + ' + + test_expect_success "rebase$type: --abort" ' + test_config rebase.autostash true && + git reset --hard && + git checkout -b rebased-feature-branch feature-branch && + test_when_finished git branch -D rebased-feature-branch && + echo dirty >>file3 && + test_must_fail git rebase$type related-onto-branch && + test_path_is_file $dotest/autostash && + ! grep dirty file3 && + git rebase --abort && + test_path_is_missing $dotest/autostash && + grep dirty file3 && + git checkout feature-branch + ' + + test_expect_success "rebase$type: non-conflicting rebase, conflicting stash" ' + test_config rebase.autostash true && + git reset --hard && + git checkout -b rebased-feature-branch feature-branch && + test_when_finished git branch -D rebased-feature-branch && + echo dirty >file4 && + git add file4 && + git rebase$type unrelated-onto-branch && + test_path_is_missing $dotest && + git reset --hard && + grep unrelated file4 && + ! grep dirty file4 && + git checkout feature-branch && + git stash pop && + grep dirty file4 + ' +} + +test_expect_success "rebase: fast-forward rebase" ' + test_config rebase.autostash true && + git reset --hard && + git checkout -b behind-feature-branch feature-branch~1 && + test_when_finished git branch -D behind-feature-branch && + echo dirty >>file1 && + git rebase feature-branch && + grep dirty file1 && + git checkout feature-branch +' + +test_expect_success "rebase: noop rebase" ' + test_config rebase.autostash true && + git reset --hard && + git checkout -b same-feature-branch feature-branch && + test_when_finished git branch -D same-feature-branch && + echo dirty >>file1 && + git rebase feature-branch && + grep dirty file1 && + git checkout feature-branch +' + +testrebase "" .git/rebase-apply +testrebase " --merge" .git/rebase-merge +testrebase " --interactive" .git/rebase-merge + +test_done diff --git a/t/t3421-rebase-topology-linear.sh b/t/t3421-rebase-topology-linear.sh new file mode 100755 index 0000000000..9c55cba198 --- /dev/null +++ b/t/t3421-rebase-topology-linear.sh @@ -0,0 +1,350 @@ +#!/bin/sh + +test_description='basic rebase topology tests' +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-rebase.sh + +# a---b---c +# \ +# d---e +test_expect_success 'setup' ' + test_commit a && + test_commit b && + test_commit c && + git checkout b && + test_commit d && + test_commit e +' + +test_run_rebase () { + result=$1 + shift + test_expect_$result "simple rebase $*" " + reset_rebase && + git rebase $* c e && + test_cmp_rev c HEAD~2 && + test_linear_range 'd e' c.. + " +} +test_run_rebase success '' +test_run_rebase success -m +test_run_rebase success -i +test_run_rebase success -p + +test_run_rebase () { + result=$1 + shift + test_expect_$result "rebase $* is no-op if upstream is an ancestor" " + reset_rebase && + git rebase $* b e && + test_cmp_rev e HEAD + " +} +test_run_rebase success '' +test_run_rebase success -m +test_run_rebase success -i +test_run_rebase success -p + +test_run_rebase () { + result=$1 + shift + test_expect_$result "rebase $* -f rewrites even if upstream is an ancestor" " + reset_rebase && + git rebase $* -f b e && + ! test_cmp_rev e HEAD && + test_cmp_rev b HEAD~2 && + test_linear_range 'd e' b.. + " +} +test_run_rebase success '' +test_run_rebase success -m +test_run_rebase success -i +test_run_rebase failure -p + +test_run_rebase () { + result=$1 + shift + test_expect_$result "rebase $* fast-forwards from ancestor of upstream" " + reset_rebase && + git rebase $* e b && + test_cmp_rev e HEAD + " +} +test_run_rebase success '' +test_run_rebase success -m +test_run_rebase success -i +test_run_rebase success -p + +# f +# / +# a---b---c---g---h +# \ +# d---gp--i +# +# gp = cherry-picked g +# h = reverted g +# +# Reverted patches are there for tests to be able to check if a commit +# that introduced the same change as another commit is +# dropped. Without reverted commits, we could get false positives +# because applying the patch succeeds, but simply results in no +# changes. +test_expect_success 'setup of linear history for range selection tests' ' + git checkout c && + test_commit g && + revert h g && + git checkout d && + cherry_pick gp g && + test_commit i && + git checkout b && + test_commit f +' + +test_run_rebase () { + result=$1 + shift + test_expect_$result "rebase $* drops patches in upstream" " + reset_rebase && + git rebase $* h i && + test_cmp_rev h HEAD~2 && + test_linear_range 'd i' h.. + " +} +test_run_rebase success '' +test_run_rebase failure -m +test_run_rebase success -i +test_run_rebase success -p + +test_run_rebase () { + result=$1 + shift + test_expect_$result "rebase $* can drop last patch if in upstream" " + reset_rebase && + git rebase $* h gp && + test_cmp_rev h HEAD^ && + test_linear_range 'd' h.. + " +} +test_run_rebase success '' +test_run_rebase failure -m +test_run_rebase success -i +test_run_rebase success -p + +test_run_rebase () { + result=$1 + shift + test_expect_$result "rebase $* --onto drops patches in upstream" " + reset_rebase && + git rebase $* --onto f h i && + test_cmp_rev f HEAD~2 && + test_linear_range 'd i' f.. + " +} +test_run_rebase success '' +test_run_rebase failure -m +test_run_rebase success -i +test_run_rebase success -p + +test_run_rebase () { + result=$1 + shift + test_expect_$result "rebase $* --onto does not drop patches in onto" " + reset_rebase && + git rebase $* --onto h f i && + test_cmp_rev h HEAD~3 && + test_linear_range 'd gp i' h.. + " +} +test_run_rebase success '' +test_run_rebase success -m +test_run_rebase success -i +test_run_rebase success -p + +# a---b---c---j! +# \ +# d---k!--l +# +# ! = empty +test_expect_success 'setup of linear history for empty commit tests' ' + git checkout c && + make_empty j && + git checkout d && + make_empty k && + test_commit l +' + +test_run_rebase () { + result=$1 + shift + test_expect_$result "rebase $* drops empty commit" " + reset_rebase && + git rebase $* c l && + test_cmp_rev c HEAD~2 && + test_linear_range 'd l' c.. + " +} +test_run_rebase success '' +test_run_rebase success -m +test_run_rebase success -i +test_run_rebase success -p + +test_run_rebase () { + result=$1 + shift + test_expect_$result "rebase $* --keep-empty" " + reset_rebase && + git rebase $* --keep-empty c l && + test_cmp_rev c HEAD~3 && + test_linear_range 'd k l' c.. + " +} +test_run_rebase success '' +test_run_rebase failure -m +test_run_rebase success -i +test_run_rebase failure -p + +test_run_rebase () { + result=$1 + shift + test_expect_$result "rebase $* --keep-empty keeps empty even if already in upstream" " + reset_rebase && + git rebase $* --keep-empty j l && + test_cmp_rev j HEAD~3 && + test_linear_range 'd k l' j.. + " +} +test_run_rebase success '' +test_run_rebase failure -m +test_run_rebase failure -i +test_run_rebase failure -p + +# m +# / +# a---b---c---g +# +# x---y---bp +# +# bp = cherry-picked b +# m = reverted b +# +# Reverted patches are there for tests to be able to check if a commit +# that introduced the same change as another commit is +# dropped. Without reverted commits, we could get false positives +# because applying the patch succeeds, but simply results in no +# changes. +test_expect_success 'setup of linear history for test involving root' ' + git checkout b && + revert m b && + git checkout --orphan disjoint && + git rm -rf . && + test_commit x && + test_commit y && + cherry_pick bp b +' + +test_run_rebase () { + result=$1 + shift + test_expect_$result "rebase $* --onto --root" " + reset_rebase && + git rebase $* --onto c --root y && + test_cmp_rev c HEAD~2 && + test_linear_range 'x y' c.. + " +} +test_run_rebase success '' +test_run_rebase failure -m +test_run_rebase success -i +test_run_rebase success -p + +test_run_rebase () { + result=$1 + shift + test_expect_$result "rebase $* without --onto --root with disjoint history" " + reset_rebase && + git rebase $* c y && + test_cmp_rev c HEAD~2 && + test_linear_range 'x y' c.. + " +} +test_run_rebase success '' +test_run_rebase failure -m +test_run_rebase success -i +test_run_rebase failure -p + +test_run_rebase () { + result=$1 + shift + test_expect_$result "rebase $* --onto --root drops patch in onto" " + reset_rebase && + git rebase $* --onto m --root bp && + test_cmp_rev m HEAD~2 && + test_linear_range 'x y' m.. + " +} +test_run_rebase success '' +test_run_rebase failure -m +test_run_rebase success -i +test_run_rebase success -p + +test_run_rebase () { + result=$1 + shift + test_expect_$result "rebase $* --onto --root with merge-base does not go to root" " + reset_rebase && + git rebase $* --onto m --root g && + test_cmp_rev m HEAD~2 && + test_linear_range 'c g' m.. + " +} + +test_run_rebase success '' +test_run_rebase success -m +test_run_rebase success -i +test_run_rebase failure -p + +test_run_rebase () { + result=$1 + shift + test_expect_$result "rebase $* without --onto --root with disjoint history drops patch in onto" " + reset_rebase && + git rebase $* m bp && + test_cmp_rev m HEAD~2 && + test_linear_range 'x y' m.. + " +} +test_run_rebase success '' +test_run_rebase failure -m +test_run_rebase success -i +test_run_rebase failure -p + +test_run_rebase () { + result=$1 + shift + test_expect_$result "rebase $* --root on linear history is a no-op" " + reset_rebase && + git rebase $* --root c && + test_cmp_rev c HEAD + " +} +test_run_rebase failure '' +test_run_rebase failure -m +test_run_rebase failure -i +test_run_rebase failure -p + +test_run_rebase () { + result=$1 + shift + test_expect_$result "rebase $* -f --root on linear history causes re-write" " + reset_rebase && + git rebase $* -f --root c && + ! test_cmp_rev a HEAD~2 && + test_linear_range 'a b c' HEAD + " +} +test_run_rebase success '' +test_run_rebase success -m +test_run_rebase success -i +test_run_rebase success -p + +test_done diff --git a/t/t3425-rebase-topology-merges.sh b/t/t3425-rebase-topology-merges.sh new file mode 100755 index 0000000000..1d195fbd64 --- /dev/null +++ b/t/t3425-rebase-topology-merges.sh @@ -0,0 +1,258 @@ +#!/bin/sh + +test_description='rebase topology tests with merges' +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-rebase.sh + +test_revision_subjects () { + expected="$1" + shift + set -- $(git log --format=%s --no-walk=unsorted "$@") + test "$expected" = "$*" +} + +# a---b-----------c +# \ \ +# d-------e \ +# \ \ \ +# n---o---w---v +# \ +# z +test_expect_success 'setup of non-linear-history' ' + test_commit a && + test_commit b && + test_commit c && + git checkout b && + test_commit d && + test_commit e + + git checkout c && + test_commit g && + revert h g && + git checkout d && + cherry_pick gp g && + test_commit i && + git checkout b && + test_commit f + + git checkout d && + test_commit n && + test_commit o && + test_merge w e && + test_merge v c && + git checkout o && + test_commit z +' + +test_run_rebase () { + result=$1 + shift + test_expect_$result "rebase $* after merge from upstream" " + reset_rebase && + git rebase $* e w && + test_cmp_rev e HEAD~2 && + test_linear_range 'n o' e.. + " +} +test_run_rebase success '' +test_run_rebase success -m +test_run_rebase success -i + +test_run_rebase () { + result=$1 + shift + expected=$1 + shift + test_expect_$result "rebase $* of non-linear history is linearized in place" " + reset_rebase && + git rebase $* d w && + test_cmp_rev d HEAD~3 && + test_linear_range "\'"$expected"\'" d.. + " +} +#TODO: make order consistent across all flavors of rebase +test_run_rebase success 'e n o' '' +test_run_rebase success 'e n o' -m +test_run_rebase success 'n o e' -i + +test_run_rebase () { + result=$1 + shift + expected=$1 + shift + test_expect_$result "rebase $* of non-linear history is linearized upstream" " + reset_rebase && + git rebase $* c w && + test_cmp_rev c HEAD~4 && + test_linear_range "\'"$expected"\'" c.. + " +} +#TODO: make order consistent across all flavors of rebase +test_run_rebase success 'd e n o' '' +test_run_rebase success 'd e n o' -m +test_run_rebase success 'd n o e' -i + +test_run_rebase () { + result=$1 + shift + expected=$1 + shift + test_expect_$result "rebase $* of non-linear history with merges after upstream merge is linearized" " + reset_rebase && + git rebase $* c v && + test_cmp_rev c HEAD~4 && + test_linear_range "\'"$expected"\'" c.. + " +} +#TODO: make order consistent across all flavors of rebase +test_run_rebase success 'd e n o' '' +test_run_rebase success 'd e n o' -m +test_run_rebase success 'd n o e' -i + +test_expect_success "rebase -p is no-op in non-linear history" " + reset_rebase && + git rebase -p d w && + test_cmp_rev w HEAD +" + +test_expect_success "rebase -p is no-op when base inside second parent" " + reset_rebase && + git rebase -p e w && + test_cmp_rev w HEAD +" + +test_expect_failure "rebase -p --root on non-linear history is a no-op" " + reset_rebase && + git rebase -p --root w && + test_cmp_rev w HEAD +" + +test_expect_success "rebase -p re-creates merge from side branch" " + reset_rebase && + git rebase -p z w && + test_cmp_rev z HEAD^ && + test_cmp_rev w^2 HEAD^2 +" + +test_expect_success "rebase -p re-creates internal merge" " + reset_rebase && + git rebase -p c w && + test_cmp_rev c HEAD~4 && + test_cmp_rev HEAD^2^ HEAD~3 && + test_revision_subjects 'd n e o w' HEAD~3 HEAD~2 HEAD^2 HEAD^ HEAD +" + +test_expect_success "rebase -p can re-create two branches on onto" " + reset_rebase && + git rebase -p --onto c d w && + test_cmp_rev c HEAD~3 && + test_cmp_rev c HEAD^2^ && + test_revision_subjects 'n e o w' HEAD~2 HEAD^2 HEAD^ HEAD +" + +# f +# / +# a---b---c---g---h +# \ +# d---gp--i +# \ \ +# e-------u +# +# gp = cherry-picked g +# h = reverted g +test_expect_success 'setup of non-linear-history for patch-equivalence tests' ' + git checkout e && + test_merge u i +' + +test_expect_success "rebase -p re-creates history around dropped commit matching upstream" " + reset_rebase && + git rebase -p h u && + test_cmp_rev h HEAD~3 && + test_cmp_rev HEAD^2^ HEAD~2 && + test_revision_subjects 'd i e u' HEAD~2 HEAD^2 HEAD^ HEAD +" + +test_expect_success "rebase -p --onto in merged history drops patches in upstream" " + reset_rebase && + git rebase -p --onto f h u && + test_cmp_rev f HEAD~3 && + test_cmp_rev HEAD^2^ HEAD~2 && + test_revision_subjects 'd i e u' HEAD~2 HEAD^2 HEAD^ HEAD +" + +test_expect_success "rebase -p --onto in merged history does not drop patches in onto" " + reset_rebase && + git rebase -p --onto h f u && + test_cmp_rev h HEAD~3 && + test_cmp_rev HEAD^2~2 HEAD~2 && + test_revision_subjects 'd gp i e u' HEAD~2 HEAD^2^ HEAD^2 HEAD^ HEAD +" + +# a---b---c---g---h +# \ +# d---gp--s +# \ \ / +# \ X +# \ / \ +# e---t +# +# gp = cherry-picked g +# h = reverted g +test_expect_success 'setup of non-linear-history for dropping whole side' ' + git checkout gp && + test_merge s e && + git checkout e && + test_merge t gp +' + +test_expect_failure "rebase -p drops merge commit when entire first-parent side is dropped" " + reset_rebase && + git rebase -p h s && + test_cmp_rev h HEAD~2 && + test_linear_range 'd e' h.. +" + +test_expect_success "rebase -p drops merge commit when entire second-parent side is dropped" " + reset_rebase && + git rebase -p h t && + test_cmp_rev h HEAD~2 && + test_linear_range 'd e' h.. +" + +# a---b---c +# \ +# d---e +# \ \ +# n---r +# \ +# o +# +# r = tree-same with n +test_expect_success 'setup of non-linear-history for empty commits' ' + git checkout n && + git merge --no-commit e && + git reset n . && + git commit -m r && + git reset --hard && + git clean -f && + git tag r +' + +test_expect_success "rebase -p re-creates empty internal merge commit" " + reset_rebase && + git rebase -p c r && + test_cmp_rev c HEAD~3 && + test_cmp_rev HEAD^2^ HEAD~2 && + test_revision_subjects 'd e n r' HEAD~2 HEAD^2 HEAD^ HEAD +" + +test_expect_success "rebase -p re-creates empty merge commit" " + reset_rebase && + git rebase -p o r && + test_cmp_rev e HEAD^2 && + test_cmp_rev o HEAD^ && + test_revision_subjects 'r' HEAD +" + +test_done diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh index 34c86e5de6..6f489e20ee 100755 --- a/t/t3501-revert-cherry-pick.sh +++ b/t/t3501-revert-cherry-pick.sh @@ -100,4 +100,13 @@ test_expect_success 'revert forbidden on dirty working tree' ' ' +test_expect_success 'chery-pick on unborn branch' ' + git checkout --orphan unborn && + git rm --cached -r . && + rm -rf * && + git cherry-pick initial && + git diff --quiet initial && + ! test_cmp_rev initial HEAD +' + test_done diff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh index a0c6e30d80..fbdc47cfbd 100755 --- a/t/t3505-cherry-pick-empty.sh +++ b/t/t3505-cherry-pick-empty.sh @@ -28,29 +28,21 @@ test_expect_success setup ' ' test_expect_success 'cherry-pick an empty commit' ' - git checkout master && { - git cherry-pick empty-branch^ - test "$?" = 1 - } + git checkout master && + test_expect_code 1 git cherry-pick empty-branch^ ' test_expect_success 'index lockfile was removed' ' - test ! -f .git/index.lock - ' test_expect_success 'cherry-pick a commit with an empty message' ' - git checkout master && { - git cherry-pick empty-branch - test "$?" = 1 - } + git checkout master && + test_expect_code 1 git cherry-pick empty-branch ' test_expect_success 'index lockfile was removed' ' - test ! -f .git/index.lock - ' test_expect_success 'cherry-pick a commit with an empty message with --allow-empty-message' ' @@ -101,7 +93,7 @@ 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 && + git show -s --format=%s >actual && echo "add file2 on master" >expect && test_cmp expect actual ' diff --git a/t/t3506-cherry-pick-ff.sh b/t/t3506-cherry-pick-ff.sh index 51ca391e47..373aad623c 100755 --- a/t/t3506-cherry-pick-ff.sh +++ b/t/t3506-cherry-pick-ff.sh @@ -105,4 +105,12 @@ test_expect_success 'cherry pick a root commit with --ff' ' test "$(git rev-parse --verify HEAD)" = "1df192cd8bc58a2b275d842cede4d221ad9000d1" ' +test_expect_success 'chery-pick --ff on unborn branch' ' + git checkout --orphan unborn && + git rm --cached -r . && + rm -rf * && + git cherry-pick --ff first && + test_cmp_rev first HEAD +' + test_done diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh index c82f7210c4..223b98433c 100755 --- a/t/t3507-cherry-pick-conflict.sh +++ b/t/t3507-cherry-pick-conflict.sh @@ -11,12 +11,6 @@ test_description='test cherry-pick and revert with conflicts . ./test-lib.sh -test_cmp_rev () { - git rev-parse --verify "$1" >expect.rev && - git rev-parse --verify "$2" >actual.rev && - test_cmp expect.rev actual.rev -} - pristine_detach () { git checkout -f "$1^0" && git read-tree -u --reset HEAD && diff --git a/t/t3508-cherry-pick-many-commits.sh b/t/t3508-cherry-pick-many-commits.sh index 340afc760d..19c99d7ef1 100755 --- a/t/t3508-cherry-pick-many-commits.sh +++ b/t/t3508-cherry-pick-many-commits.sh @@ -5,15 +5,11 @@ test_description='test cherry-picking many commits' . ./test-lib.sh check_head_differs_from() { - head=$(git rev-parse --verify HEAD) && - arg=$(git rev-parse --verify "$1") && - test "$head" != "$arg" + ! test_cmp_rev HEAD "$1" } check_head_equals() { - head=$(git rev-parse --verify HEAD) && - arg=$(git rev-parse --verify "$1") && - test "$head" = "$arg" + test_cmp_rev HEAD "$1" } test_expect_success setup ' @@ -59,6 +55,12 @@ one two" ' +test_expect_success 'cherry-pick three one two: fails' ' + git checkout -f master && + git reset --hard first && + test_must_fail git cherry-pick three one two: +' + test_expect_success 'output to keep user entertained during multi-pick' ' cat <<-\EOF >expected && [master OBJID] second diff --git a/t/t3509-cherry-pick-merge-df.sh b/t/t3509-cherry-pick-merge-df.sh index df921d1f33..a5b6a5f331 100755 --- a/t/t3509-cherry-pick-merge-df.sh +++ b/t/t3509-cherry-pick-merge-df.sh @@ -10,17 +10,15 @@ test_expect_success 'Initialize repository' ' git commit -m a ' -test_expect_success SYMLINKS 'Setup rename across paths each below D/F conflicts' ' +test_expect_success 'Setup rename across paths each below D/F conflicts' ' mkdir b && - ln -s ../a b/a && - git add b && + test_ln_s_add ../a b/a && git commit -m b && git checkout -b branch && rm b/a && - mv a b/a && - ln -s b/a a && - git add . && + git mv a b/a && + test_ln_s_add b/a a && git commit -m swap && >f1 && @@ -28,7 +26,7 @@ test_expect_success SYMLINKS 'Setup rename across paths each below D/F conflicts git commit -m f1 ' -test_expect_success SYMLINKS 'Cherry-pick succeeds with rename across D/F conflicts' ' +test_expect_success 'Cherry-pick succeeds with rename across D/F conflicts' ' git reset --hard && git checkout master^0 && git cherry-pick branch diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh index b5fb527b2e..7b7a89dbd5 100755 --- a/t/t3510-cherry-pick-sequence.sh +++ b/t/t3510-cherry-pick-sequence.sh @@ -24,12 +24,6 @@ pristine_detach () { git clean -d -f -f -q -x } -test_cmp_rev () { - git rev-parse --verify "$1" >expect.rev && - git rev-parse --verify "$2" >actual.rev && - test_cmp expect.rev actual.rev -} - test_expect_success setup ' git config advice.detachedhead false && echo unrelated >unrelated && diff --git a/t/t3511-cherry-pick-x.sh b/t/t3511-cherry-pick-x.sh new file mode 100755 index 0000000000..f97727975b --- /dev/null +++ b/t/t3511-cherry-pick-x.sh @@ -0,0 +1,219 @@ +#!/bin/sh + +test_description='Test cherry-pick -x and -s' + +. ./test-lib.sh + +pristine_detach () { + git cherry-pick --quit && + git checkout -f "$1^0" && + git read-tree -u --reset HEAD && + git clean -d -f -f -q -x +} + +mesg_one_line='base: commit message' + +mesg_no_footer="$mesg_one_line + +OneWordBodyThatsNotA-S-o-B" + +mesg_with_footer="$mesg_no_footer + +Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> +Signed-off-by: A.U. Thor <author@example.com> +Signed-off-by: B.U. Thor <buthor@example.com>" + +mesg_broken_footer="$mesg_no_footer + +The signed-off-by string should begin with the words Signed-off-by followed +by a colon and space, and then the signers name and email address. e.g. +Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" + +mesg_with_footer_sob="$mesg_with_footer +Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" + +mesg_with_cherry_footer="$mesg_with_footer_sob +(cherry picked from commit da39a3ee5e6b4b0d3255bfef95601890afd80709) +Tested-by: C.U. Thor <cuthor@example.com>" + + +test_expect_success setup ' + git config advice.detachedhead false && + echo unrelated >unrelated && + git add unrelated && + test_commit initial foo a && + test_commit "$mesg_one_line" foo b mesg-one-line && + git reset --hard initial && + test_commit "$mesg_no_footer" foo b mesg-no-footer && + git reset --hard initial && + test_commit "$mesg_broken_footer" foo b mesg-broken-footer && + git reset --hard initial && + test_commit "$mesg_with_footer" foo b mesg-with-footer && + git reset --hard initial && + test_commit "$mesg_with_footer_sob" foo b mesg-with-footer-sob && + git reset --hard initial && + test_commit "$mesg_with_cherry_footer" foo b mesg-with-cherry-footer && + pristine_detach initial && + test_commit conflicting unrelated +' + +test_expect_success 'cherry-pick -x inserts blank line after one line subject' ' + pristine_detach initial && + sha1=`git rev-parse mesg-one-line^0` && + git cherry-pick -x mesg-one-line && + cat <<-EOF >expect && + $mesg_one_line + + (cherry picked from commit $sha1) + EOF + git log -1 --pretty=format:%B >actual && + test_cmp expect actual +' + +test_expect_success 'cherry-pick -s inserts blank line after one line subject' ' + pristine_detach initial && + git cherry-pick -s mesg-one-line && + cat <<-EOF >expect && + $mesg_one_line + + Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> + EOF + git log -1 --pretty=format:%B >actual && + test_cmp expect actual +' + +test_expect_success 'cherry-pick -s inserts blank line after non-conforming footer' ' + pristine_detach initial && + git cherry-pick -s mesg-broken-footer && + cat <<-EOF >expect && + $mesg_broken_footer + + Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> + EOF + git log -1 --pretty=format:%B >actual && + test_cmp expect actual +' + +test_expect_success 'cherry-pick -x inserts blank line when conforming footer not found' ' + pristine_detach initial && + sha1=`git rev-parse mesg-no-footer^0` && + git cherry-pick -x mesg-no-footer && + cat <<-EOF >expect && + $mesg_no_footer + + (cherry picked from commit $sha1) + EOF + git log -1 --pretty=format:%B >actual && + test_cmp expect actual +' + +test_expect_success 'cherry-pick -s inserts blank line when conforming footer not found' ' + pristine_detach initial && + git cherry-pick -s mesg-no-footer && + cat <<-EOF >expect && + $mesg_no_footer + + Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> + EOF + git log -1 --pretty=format:%B >actual && + test_cmp expect actual +' + +test_expect_success 'cherry-pick -x -s inserts blank line when conforming footer not found' ' + pristine_detach initial && + sha1=`git rev-parse mesg-no-footer^0` && + git cherry-pick -x -s mesg-no-footer && + cat <<-EOF >expect && + $mesg_no_footer + + (cherry picked from commit $sha1) + Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> + EOF + git log -1 --pretty=format:%B >actual && + test_cmp expect actual +' + +test_expect_success 'cherry-pick -s adds sob when last sob doesnt match committer' ' + pristine_detach initial && + git cherry-pick -s mesg-with-footer && + cat <<-EOF >expect && + $mesg_with_footer + Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> + EOF + git log -1 --pretty=format:%B >actual && + test_cmp expect actual +' + +test_expect_success 'cherry-pick -x -s adds sob when last sob doesnt match committer' ' + pristine_detach initial && + sha1=`git rev-parse mesg-with-footer^0` && + git cherry-pick -x -s mesg-with-footer && + cat <<-EOF >expect && + $mesg_with_footer + (cherry picked from commit $sha1) + Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> + EOF + git log -1 --pretty=format:%B >actual && + test_cmp expect actual +' + +test_expect_success 'cherry-pick -s refrains from adding duplicate trailing sob' ' + pristine_detach initial && + git cherry-pick -s mesg-with-footer-sob && + cat <<-EOF >expect && + $mesg_with_footer_sob + EOF + git log -1 --pretty=format:%B >actual && + test_cmp expect actual +' + +test_expect_success 'cherry-pick -x -s adds sob even when trailing sob exists for committer' ' + pristine_detach initial && + sha1=`git rev-parse mesg-with-footer-sob^0` && + git cherry-pick -x -s mesg-with-footer-sob && + cat <<-EOF >expect && + $mesg_with_footer_sob + (cherry picked from commit $sha1) + Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> + EOF + git log -1 --pretty=format:%B >actual && + test_cmp expect actual +' + +test_expect_success 'cherry-pick -x treats "(cherry picked from..." line as part of footer' ' + pristine_detach initial && + sha1=`git rev-parse mesg-with-cherry-footer^0` && + git cherry-pick -x mesg-with-cherry-footer && + cat <<-EOF >expect && + $mesg_with_cherry_footer + (cherry picked from commit $sha1) + EOF + git log -1 --pretty=format:%B >actual && + test_cmp expect actual +' + +test_expect_success 'cherry-pick -s treats "(cherry picked from..." line as part of footer' ' + pristine_detach initial && + git cherry-pick -s mesg-with-cherry-footer && + cat <<-EOF >expect && + $mesg_with_cherry_footer + Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> + EOF + git log -1 --pretty=format:%B >actual && + test_cmp expect actual +' + +test_expect_success 'cherry-pick -x -s treats "(cherry picked from..." line as part of footer' ' + pristine_detach initial && + sha1=`git rev-parse mesg-with-cherry-footer^0` && + git cherry-pick -x -s mesg-with-cherry-footer && + cat <<-EOF >expect && + $mesg_with_cherry_footer + (cherry picked from commit $sha1) + Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> + EOF + git log -1 --pretty=format:%B >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index 9fd28bcf34..5c87b55645 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -262,4 +262,525 @@ test_expect_success 'rm removes subdirectories recursively' ' ! test -d dir ' +cat >expect <<EOF +D submod +EOF + +cat >expect.modified <<EOF + M submod +EOF + +test_expect_success 'rm removes empty submodules from work tree' ' + mkdir submod && + git update-index --add --cacheinfo 160000 $(git rev-parse HEAD) submod && + git config -f .gitmodules submodule.sub.url ./. && + git config -f .gitmodules submodule.sub.path submod && + git submodule init && + git add .gitmodules && + git commit -m "add submodule" && + git rm submod && + test ! -e submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm removes removed submodule from index' ' + git reset --hard && + git submodule update && + rm -rf submod && + git rm submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm removes work tree of unmodified submodules' ' + git reset --hard && + git submodule update && + git rm submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm removes a submodule with a trailing /' ' + git reset --hard && + git submodule update && + git rm submod/ && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm fails when given a file with a trailing /' ' + test_must_fail git rm empty/ +' + +test_expect_success 'rm succeeds when given a directory with a trailing /' ' + git rm -r frotz/ +' + +test_expect_success 'rm of a populated submodule with different HEAD fails unless forced' ' + git reset --hard && + git submodule update && + (cd submod && + git checkout HEAD^ + ) && + test_must_fail git rm submod && + test -d submod && + test -f submod/.git && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect.modified actual && + git rm -f submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm of a populated submodule with modifications fails unless forced' ' + git reset --hard && + git submodule update && + (cd submod && + echo X >empty + ) && + test_must_fail git rm submod && + test -d submod && + test -f submod/.git && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect.modified actual && + git rm -f submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm of a populated submodule with untracked files fails unless forced' ' + git reset --hard && + git submodule update && + (cd submod && + echo X >untracked + ) && + test_must_fail git rm submod && + test -d submod && + test -f submod/.git && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect.modified actual && + git rm -f submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'setup submodule conflict' ' + git reset --hard && + git submodule update && + git checkout -b branch1 && + echo 1 >nitfol && + git add nitfol && + git commit -m "added nitfol 1" && + git checkout -b branch2 master && + echo 2 >nitfol && + git add nitfol && + git commit -m "added nitfol 2" && + git checkout -b conflict1 master && + (cd submod && + git fetch && + git checkout branch1 + ) && + git add submod && + git commit -m "submod 1" && + git checkout -b conflict2 master && + (cd submod && + git checkout branch2 + ) && + git add submod && + git commit -m "submod 2" +' + +cat >expect.conflict <<EOF +UU submod +EOF + +test_expect_success 'rm removes work tree of unmodified conflicted submodule' ' + git checkout conflict1 && + git reset --hard && + git submodule update && + test_must_fail git merge conflict2 && + git rm submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm of a conflicted populated submodule with different HEAD fails unless forced' ' + git checkout conflict1 && + git reset --hard && + git submodule update && + (cd submod && + git checkout HEAD^ + ) && + test_must_fail git merge conflict2 && + test_must_fail git rm submod && + test -d submod && + test -f submod/.git && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect.conflict actual && + git rm -f submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm of a conflicted populated submodule with modifications fails unless forced' ' + git checkout conflict1 && + git reset --hard && + git submodule update && + (cd submod && + echo X >empty + ) && + test_must_fail git merge conflict2 && + test_must_fail git rm submod && + test -d submod && + test -f submod/.git && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect.conflict actual && + git rm -f submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm of a conflicted populated submodule with untracked files fails unless forced' ' + git checkout conflict1 && + git reset --hard && + git submodule update && + (cd submod && + echo X >untracked + ) && + test_must_fail git merge conflict2 && + test_must_fail git rm submod && + test -d submod && + test -f submod/.git && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect.conflict actual && + git rm -f submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm of a conflicted populated submodule with a .git directory fails even when forced' ' + git checkout conflict1 && + git reset --hard && + git submodule update && + (cd submod && + rm .git && + cp -R ../.git/modules/sub .git && + GIT_WORK_TREE=. git config --unset core.worktree + ) && + test_must_fail git merge conflict2 && + test_must_fail git rm submod && + test -d submod && + test -d submod/.git && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect.conflict actual && + test_must_fail git rm -f submod && + test -d submod && + test -d submod/.git && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect.conflict actual && + git merge --abort && + rm -rf submod +' + +test_expect_success 'rm of a conflicted unpopulated submodule succeeds' ' + git checkout conflict1 && + git reset --hard && + test_must_fail git merge conflict2 && + git rm submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm of a populated submodule with a .git directory fails even when forced' ' + git checkout -f master && + git reset --hard && + git submodule update && + (cd submod && + rm .git && + cp -R ../.git/modules/sub .git && + GIT_WORK_TREE=. git config --unset core.worktree + ) && + test_must_fail git rm submod && + test -d submod && + test -d submod/.git && + git status -s -uno --ignore-submodules=none > actual && + ! test -s actual && + test_must_fail git rm -f submod && + test -d submod && + test -d submod/.git && + git status -s -uno --ignore-submodules=none > actual && + ! test -s actual && + rm -rf submod +' + +cat >expect.deepmodified <<EOF + M submod/subsubmod +EOF + +test_expect_success 'setup subsubmodule' ' + git reset --hard && + git submodule update && + (cd submod && + git update-index --add --cacheinfo 160000 $(git rev-parse HEAD) subsubmod && + git config -f .gitmodules submodule.sub.url ../. && + git config -f .gitmodules submodule.sub.path subsubmod && + git submodule init && + git add .gitmodules && + git commit -m "add subsubmodule" && + git submodule update subsubmod + ) && + git commit -a -m "added deep submodule" +' + +test_expect_success 'rm recursively removes work tree of unmodified submodules' ' + git rm submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm of a populated nested submodule with different nested HEAD fails unless forced' ' + git reset --hard && + git submodule update --recursive && + (cd submod/subsubmod && + git checkout HEAD^ + ) && + test_must_fail git rm submod && + test -d submod && + test -f submod/.git && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect.modified actual && + git rm -f submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm of a populated nested submodule with nested modifications fails unless forced' ' + git reset --hard && + git submodule update --recursive && + (cd submod/subsubmod && + echo X >empty + ) && + test_must_fail git rm submod && + test -d submod && + test -f submod/.git && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect.modified actual && + git rm -f submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm of a populated nested submodule with nested untracked files fails unless forced' ' + git reset --hard && + git submodule update --recursive && + (cd submod/subsubmod && + echo X >untracked + ) && + test_must_fail git rm submod && + test -d submod && + test -f submod/.git && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect.modified actual && + git rm -f submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm of a populated nested submodule with a nested .git directory fails even when forced' ' + git reset --hard && + git submodule update --recursive && + (cd submod/subsubmod && + rm .git && + cp -R ../../.git/modules/sub/modules/sub .git && + GIT_WORK_TREE=. git config --unset core.worktree + ) && + test_must_fail git rm submod && + test -d submod && + test -d submod/subsubmod/.git && + git status -s -uno --ignore-submodules=none > actual && + ! test -s actual && + test_must_fail git rm -f submod && + test -d submod && + test -d submod/subsubmod/.git && + git status -s -uno --ignore-submodules=none > actual && + ! test -s actual && + rm -rf submod +' + +test_expect_success 'rm of d/f when d has become a non-directory' ' + rm -rf d && + mkdir d && + >d/f && + git add d && + rm -rf d && + >d && + git rm d/f && + test_must_fail git rev-parse --verify :d/f && + test_path_is_file d +' + +test_expect_success SYMLINKS 'rm of d/f when d has become a dangling symlink' ' + rm -rf d && + mkdir d && + >d/f && + git add d && + rm -rf d && + ln -s nonexistent d && + git rm d/f && + test_must_fail git rev-parse --verify :d/f && + test -h d && + test_path_is_missing d +' + +test_expect_success 'rm of file when it has become a directory' ' + rm -rf d && + >d && + git add d && + rm -f d && + mkdir d && + >d/f && + test_must_fail git rm d && + git rev-parse --verify :d && + test_path_is_file d/f +' + +test_expect_success SYMLINKS 'rm across a symlinked leading path (no index)' ' + rm -rf d e && + mkdir e && + echo content >e/f && + ln -s e d && + git add -A e d && + git commit -m "symlink d to e, e/f exists" && + test_must_fail git rm d/f && + git rev-parse --verify :d && + git rev-parse --verify :e/f && + test -h d && + test_path_is_file e/f +' + +test_expect_failure SYMLINKS 'rm across a symlinked leading path (w/ index)' ' + rm -rf d e && + mkdir d && + echo content >d/f && + git add -A e d && + git commit -m "d/f exists" && + mv d e && + ln -s e d && + test_must_fail git rm d/f && + git rev-parse --verify :d/f && + test -h d && + test_path_is_file e/f +' + +test_expect_success 'setup for testing rm messages' ' + >bar.txt && + >foo.txt && + git add bar.txt foo.txt +' + +test_expect_success 'rm files with different staged content' ' + cat >expect <<-\EOF && + error: the following files have staged content different from both the + file and the HEAD: + bar.txt + foo.txt + (use -f to force removal) + EOF + echo content1 >foo.txt && + echo content1 >bar.txt && + test_must_fail git rm foo.txt bar.txt 2>actual && + test_i18ncmp expect actual +' + +test_expect_success 'rm files with different staged content without hints' ' + cat >expect <<-\EOF && + error: the following files have staged content different from both the + file and the HEAD: + bar.txt + foo.txt + EOF + echo content2 >foo.txt && + echo content2 >bar.txt && + test_must_fail git -c advice.rmhints=false rm foo.txt bar.txt 2>actual && + test_i18ncmp expect actual +' + +test_expect_success 'rm file with local modification' ' + cat >expect <<-\EOF && + error: the following file has local modifications: + foo.txt + (use --cached to keep the file, or -f to force removal) + EOF + git commit -m "testing rm 3" && + echo content3 >foo.txt && + test_must_fail git rm foo.txt 2>actual && + test_i18ncmp expect actual +' + +test_expect_success 'rm file with local modification without hints' ' + cat >expect <<-\EOF && + error: the following file has local modifications: + bar.txt + EOF + echo content4 >bar.txt && + test_must_fail git -c advice.rmhints=false rm bar.txt 2>actual && + test_i18ncmp expect actual +' + +test_expect_success 'rm file with changes in the index' ' + cat >expect <<-\EOF && + error: the following file has changes staged in the index: + foo.txt + (use --cached to keep the file, or -f to force removal) + EOF + git reset --hard && + echo content5 >foo.txt && + git add foo.txt && + test_must_fail git rm foo.txt 2>actual && + test_i18ncmp expect actual +' + +test_expect_success 'rm file with changes in the index without hints' ' + cat >expect <<-\EOF && + error: the following file has changes staged in the index: + foo.txt + EOF + test_must_fail git -c advice.rmhints=false rm foo.txt 2>actual && + test_i18ncmp expect actual +' + +test_expect_success 'rm files with two different errors' ' + cat >expect <<-\EOF && + error: the following file has staged content different from both the + file and the HEAD: + foo1.txt + (use -f to force removal) + error: the following file has changes staged in the index: + bar1.txt + (use --cached to keep the file, or -f to force removal) + EOF + echo content >foo1.txt && + git add foo1.txt && + echo content6 >foo1.txt && + echo content6 >bar1.txt && + git add bar1.txt && + test_must_fail git rm bar1.txt foo1.txt 2>actual && + test_i18ncmp expect actual +' + test_done diff --git a/t/t3700-add.sh b/t/t3700-add.sh index 874b3a6444..aab86e838b 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -30,10 +30,9 @@ test_expect_success \ *) echo fail; git ls-files --stage xfoo1; (exit 1);; esac' -test_expect_success SYMLINKS 'git add: filemode=0 should not get confused by symlink' ' +test_expect_success 'git add: filemode=0 should not get confused by symlink' ' rm -f xfoo1 && - ln -s foo xfoo1 && - git add xfoo1 && + test_ln_s_add foo xfoo1 && case "`git ls-files --stage xfoo1`" in 120000" "*xfoo1) echo pass;; *) echo fail; git ls-files --stage xfoo1; (exit 1);; @@ -51,21 +50,19 @@ test_expect_success \ *) echo fail; git ls-files --stage xfoo2; (exit 1);; esac' -test_expect_success SYMLINKS 'git add: filemode=0 should not get confused by symlink' ' +test_expect_success 'git add: filemode=0 should not get confused by symlink' ' rm -f xfoo2 && - ln -s foo xfoo2 && - git update-index --add xfoo2 && + test_ln_s_add foo xfoo2 && case "`git ls-files --stage xfoo2`" in 120000" "*xfoo2) echo pass;; *) echo fail; git ls-files --stage xfoo2; (exit 1);; esac ' -test_expect_success SYMLINKS \ +test_expect_success \ 'git update-index --add: Test that executable bit is not used...' \ 'git config core.filemode 0 && - ln -s xfoo2 xfoo3 && - git update-index --add xfoo3 && + test_ln_s_add xfoo2 xfoo3 && # runs git update-index --add case "`git ls-files --stage xfoo3`" in 120000" "*xfoo3) echo pass;; *) echo fail; git ls-files --stage xfoo3; (exit 1);; diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh index 098a6ae4a0..9fab25cc96 100755 --- a/t/t3701-add-interactive.sh +++ b/t/t3701-add-interactive.sh @@ -319,7 +319,7 @@ test_expect_success PERL 'split hunk "add -p (edit)"' ' # times to get out. # # 2. Correct version applies the (not)edited version, and asks - # about the next hunk, against wich we say q and program + # about the next hunk, against which we say q and program # exits. for a in s e q n q q do diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh index 37ddabba2d..38b00c37b0 100755 --- a/t/t3900-i18n-commit.sh +++ b/t/t3900-i18n-commit.sh @@ -39,6 +39,42 @@ test_expect_failure 'UTF-16 refused because of NULs' ' git commit -a -F "$TEST_DIRECTORY"/t3900/UTF-16.txt ' +test_expect_success 'UTF-8 invalid characters refused' ' + test_when_finished "rm -f $HOME/stderr $HOME/invalid" && + echo "UTF-8 characters" >F && + printf "Commit message\n\nInvalid surrogate:\355\240\200\n" \ + >"$HOME/invalid" && + git commit -a -F "$HOME/invalid" 2>"$HOME"/stderr && + grep "did not conform" "$HOME"/stderr +' + +test_expect_success 'UTF-8 overlong sequences rejected' ' + test_when_finished "rm -f $HOME/stderr $HOME/invalid" && + rm -f "$HOME/stderr" "$HOME/invalid" && + echo "UTF-8 overlong" >F && + printf "\340\202\251ommit message\n\nThis is not a space:\300\240\n" \ + >"$HOME/invalid" && + git commit -a -F "$HOME/invalid" 2>"$HOME"/stderr && + grep "did not conform" "$HOME"/stderr +' + +test_expect_success 'UTF-8 non-characters refused' ' + test_when_finished "rm -f $HOME/stderr $HOME/invalid" && + echo "UTF-8 non-character 1" >F && + printf "Commit message\n\nNon-character:\364\217\277\276\n" \ + >"$HOME/invalid" && + git commit -a -F "$HOME/invalid" 2>"$HOME"/stderr && + grep "did not conform" "$HOME"/stderr +' + +test_expect_success 'UTF-8 non-characters refused' ' + test_when_finished "rm -f $HOME/stderr $HOME/invalid" && + echo "UTF-8 non-character 2." >F && + printf "Commit message\n\nNon-character:\357\267\220\n" \ + >"$HOME/invalid" && + git commit -a -F "$HOME/invalid" 2>"$HOME"/stderr && + grep "did not conform" "$HOME"/stderr +' for H in ISO8859-1 eucJP ISO-2022-JP do diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index 5dfbda7491..5d22f17ca2 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -200,17 +200,17 @@ test_expect_success 'apply -q is quiet' ' echo foo > file && git stash && git stash apply -q > output.out 2>&1 && - test ! -s output.out + test_must_be_empty output.out ' test_expect_success 'save -q is quiet' ' git stash save --quiet > output.out 2>&1 && - test ! -s output.out + test_must_be_empty output.out ' test_expect_success 'pop -q is quiet' ' git stash pop -q > output.out 2>&1 && - test ! -s output.out + test_must_be_empty output.out ' test_expect_success 'pop -q --index works and is quiet' ' @@ -219,13 +219,13 @@ test_expect_success 'pop -q --index works and is quiet' ' git stash save --quiet && git stash pop -q --index > output.out 2>&1 && test foo = "$(git show :file)" && - test ! -s output.out + test_must_be_empty output.out ' test_expect_success 'drop -q is quiet' ' git stash && git stash drop -q > output.out 2>&1 && - test ! -s output.out + test_must_be_empty output.out ' test_expect_success 'stash -k' ' @@ -336,41 +336,58 @@ test_expect_success SYMLINKS 'stash file to symlink (full stage)' ' # This test creates a commit with a symlink used for the following tests -test_expect_success SYMLINKS 'stash symlink to file' ' +test_expect_success 'stash symlink to file' ' git reset --hard && - ln -s file filelink && - git add filelink && + test_ln_s_add file filelink && git commit -m "Add symlink" && rm filelink && cp file filelink && - git stash save "symlink to file" && + git stash save "symlink to file" +' + +test_expect_success SYMLINKS 'this must have re-created the symlink' ' test -h filelink && - case "$(ls -l filelink)" in *" filelink -> file") :;; *) false;; esac && + case "$(ls -l filelink)" in *" filelink -> file") :;; *) false;; esac +' + +test_expect_success 'unstash must re-create the file' ' git stash apply && ! test -h filelink && test bar = "$(cat file)" ' -test_expect_success SYMLINKS 'stash symlink to file (stage rm)' ' +test_expect_success 'stash symlink to file (stage rm)' ' git reset --hard && git rm filelink && cp file filelink && - git stash save "symlink to file (stage rm)" && + git stash save "symlink to file (stage rm)" +' + +test_expect_success SYMLINKS 'this must have re-created the symlink' ' test -h filelink && - case "$(ls -l filelink)" in *" filelink -> file") :;; *) false;; esac && + case "$(ls -l filelink)" in *" filelink -> file") :;; *) false;; esac +' + +test_expect_success 'unstash must re-create the file' ' git stash apply && ! test -h filelink && test bar = "$(cat file)" ' -test_expect_success SYMLINKS 'stash symlink to file (full stage)' ' +test_expect_success 'stash symlink to file (full stage)' ' git reset --hard && rm filelink && cp file filelink && git add filelink && - git stash save "symlink to file (full stage)" && + git stash save "symlink to file (full stage)" +' + +test_expect_success SYMLINKS 'this must have re-created the symlink' ' test -h filelink && - case "$(ls -l filelink)" in *" filelink -> file") :;; *) false;; esac && + case "$(ls -l filelink)" in *" filelink -> file") :;; *) false;; esac +' + +test_expect_success 'unstash must re-create the file' ' git stash apply && ! test -h filelink && test bar = "$(cat file)" @@ -637,4 +654,41 @@ test_expect_success 'stash where working directory contains "HEAD" file' ' test_cmp output expect ' +test_expect_success 'store called with invalid commit' ' + test_must_fail git stash store foo +' + +test_expect_success 'store updates stash ref and reflog' ' + git stash clear && + git reset --hard && + echo quux >bazzy && + git add bazzy && + STASH_ID=$(git stash create) && + git reset --hard && + ! grep quux bazzy && + git stash store -m quuxery $STASH_ID && + test $(cat .git/refs/stash) = $STASH_ID && + grep $STASH_ID .git/logs/refs/stash && + git stash pop && + grep quux bazzy +' + +test_expect_success 'stash a change to turn a non-directory to a directory' ' + git reset --hard && + >testfile && + git add testfile && + git commit -m "add testfile as a regular file" && + rm testfile && + mkdir testfile && + >testfile/file && + test_must_fail git stash save "recover regular file" && + test -f testfile/file +' + +test_expect_success 'stash a change to turn a non-directory to a directory (forced)' ' + git stash save --force "recover regular file (forced)" && + ! test -f testfile/file && + test -f testfile +' + test_done diff --git a/t/t4000-diff-format.sh b/t/t4000-diff-format.sh index 6ddd46915d..8de36b7d12 100755 --- a/t/t4000-diff-format.sh +++ b/t/t4000-diff-format.sh @@ -15,17 +15,17 @@ line 3' cat path0 >path1 chmod +x path1 -test_expect_success \ - 'update-index --add two files with and without +x.' \ - 'git update-index --add path0 path1' +test_expect_success 'update-index --add two files with and without +x.' ' + git update-index --add path0 path1 +' mv path0 path0- sed -e 's/line/Line/' <path0- >path0 chmod +x path0 rm -f path1 -test_expect_success \ - 'git diff-files -p after editing work tree.' \ - 'git diff-files -p >current' +test_expect_success 'git diff-files -p after editing work tree.' ' + git diff-files -p >actual +' # that's as far as it comes if [ "$(git config --get core.filemode)" = false ] @@ -55,8 +55,38 @@ deleted file mode 100755 -line 3 EOF -test_expect_success \ - 'validate git diff-files -p output.' \ - 'compare_diff_patch current expected' +test_expect_success 'validate git diff-files -p output.' ' + compare_diff_patch expected actual +' + +test_expect_success 'git diff-files -s after editing work tree' ' + git diff-files -s >actual 2>err && + test_must_be_empty actual && + test_must_be_empty err +' + +test_expect_success 'git diff-files --no-patch as synonym for -s' ' + git diff-files --no-patch >actual 2>err && + test_must_be_empty actual && + test_must_be_empty err +' + +test_expect_success 'git diff-files --no-patch --patch shows the patch' ' + git diff-files --no-patch --patch >actual && + compare_diff_patch expected actual +' + +test_expect_success 'git diff-files --no-patch --patch-with-raw shows the patch and raw data' ' + git diff-files --no-patch --patch-with-raw >actual && + grep -q "^:100644 100755 .* 0000000000000000000000000000000000000000 M path0\$" actual && + tail -n +4 actual >actual-patch && + compare_diff_patch expected actual-patch +' + +test_expect_success 'git diff-files --patch --no-patch does not show the patch' ' + git diff-files --patch --no-patch >actual 2>err && + test_must_be_empty actual && + test_must_be_empty err +' test_done diff --git a/t/t4001-diff-rename.sh b/t/t4001-diff-rename.sh index 844277cfa6..2f327b7495 100755 --- a/t/t4001-diff-rename.sh +++ b/t/t4001-diff-rename.sh @@ -102,4 +102,58 @@ test_expect_success 'setup for many rename source candidates' ' grep warning actual.err ' +test_expect_success 'rename pretty print with nothing in common' ' + mkdir -p a/b/ && + : >a/b/c && + git add a/b/c && + git commit -m "create a/b/c" && + mkdir -p c/b/ && + git mv a/b/c c/b/a && + git commit -m "a/b/c -> c/b/a" && + git diff -M --summary HEAD^ HEAD >output && + test_i18ngrep " a/b/c => c/b/a " output && + git diff -M --stat HEAD^ HEAD >output && + test_i18ngrep " a/b/c => c/b/a " output +' + +test_expect_success 'rename pretty print with common prefix' ' + mkdir -p c/d && + git mv c/b/a c/d/e && + git commit -m "c/b/a -> c/d/e" && + git diff -M --summary HEAD^ HEAD >output && + test_i18ngrep " c/{b/a => d/e} " output && + git diff -M --stat HEAD^ HEAD >output && + test_i18ngrep " c/{b/a => d/e} " output +' + +test_expect_success 'rename pretty print with common suffix' ' + mkdir d && + git mv c/d/e d/e && + git commit -m "c/d/e -> d/e" && + git diff -M --summary HEAD^ HEAD >output && + test_i18ngrep " {c/d => d}/e " output && + git diff -M --stat HEAD^ HEAD >output && + test_i18ngrep " {c/d => d}/e " output +' + +test_expect_success 'rename pretty print with common prefix and suffix' ' + mkdir d/f && + git mv d/e d/f/e && + git commit -m "d/e -> d/f/e" && + git diff -M --summary HEAD^ HEAD >output && + test_i18ngrep " d/{ => f}/e " output && + git diff -M --stat HEAD^ HEAD >output && + test_i18ngrep " d/{ => f}/e " output +' + +test_expect_success 'rename pretty print common prefix and suffix overlap' ' + mkdir d/f/f && + git mv d/f/e d/f/f/e && + git commit -m "d/f/e d/f/f/e" && + git diff -M --summary HEAD^ HEAD >output && + test_i18ngrep " d/f/{ => f}/e " output && + git diff -M --stat HEAD^ HEAD >output && + test_i18ngrep " d/f/{ => f}/e " output +' + test_done diff --git a/t/t4008-diff-break-rewrite.sh b/t/t4008-diff-break-rewrite.sh index 73b4a24f5e..27e98a8f9d 100755 --- a/t/t4008-diff-break-rewrite.sh +++ b/t/t4008-diff-break-rewrite.sh @@ -99,11 +99,11 @@ test_expect_success \ 'validate result of -B -M (#4)' \ 'compare_diff_raw expected current' -test_expect_success SYMLINKS \ +test_expect_success \ 'make file0 into something completely different' \ 'rm -f file0 && - ln -s frotz file0 && - git update-index file0 file1' + test_ln_s_add frotz file0 && + git update-index file1' test_expect_success \ 'run diff with -B' \ @@ -114,7 +114,7 @@ cat >expected <<\EOF :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 M100 file1 EOF -test_expect_success SYMLINKS \ +test_expect_success \ 'validate result of -B (#5)' \ 'compare_diff_raw expected current' @@ -129,7 +129,7 @@ cat >expected <<\EOF :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 R file0 file1 EOF -test_expect_success SYMLINKS \ +test_expect_success \ 'validate result of -B -M (#6)' \ 'compare_diff_raw expected current' @@ -144,7 +144,7 @@ cat >expected <<\EOF :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 M file1 EOF -test_expect_success SYMLINKS \ +test_expect_success \ 'validate result of -M (#7)' \ 'compare_diff_raw expected current' diff --git a/t/t4011-diff-symlink.sh b/t/t4011-diff-symlink.sh index f0d5041c11..13e7f621ab 100755 --- a/t/t4011-diff-symlink.sh +++ b/t/t4011-diff-symlink.sh @@ -9,7 +9,7 @@ test_description='Test diff of symlinks. . ./test-lib.sh . "$TEST_DIRECTORY"/diff-lib.sh -test_expect_success SYMLINKS 'diff new symlink and file' ' +test_expect_success 'diff new symlink and file' ' cat >expected <<-\EOF && diff --git a/frotz b/frotz new file mode 120000 @@ -27,22 +27,25 @@ test_expect_success SYMLINKS 'diff new symlink and file' ' @@ -0,0 +1 @@ +xyzzy EOF - ln -s xyzzy frotz && - echo xyzzy >nitfol && + + # the empty tree git update-index && tree=$(git write-tree) && - git update-index --add frotz nitfol && + + test_ln_s_add xyzzy frotz && + echo xyzzy >nitfol && + git update-index --add nitfol && GIT_DIFF_OPTS=--unified=0 git diff-index -M -p $tree >current && compare_diff_patch expected current ' -test_expect_success SYMLINKS 'diff unchanged symlink and file' ' +test_expect_success 'diff unchanged symlink and file' ' tree=$(git write-tree) && git update-index frotz nitfol && test -z "$(git diff-index --name-only $tree)" ' -test_expect_success SYMLINKS 'diff removed symlink and file' ' +test_expect_success 'diff removed symlink and file' ' cat >expected <<-\EOF && diff --git a/frotz b/frotz deleted file mode 120000 @@ -66,12 +69,18 @@ test_expect_success SYMLINKS 'diff removed symlink and file' ' compare_diff_patch expected current ' -test_expect_success SYMLINKS 'diff identical, but newly created symlink and file' ' +test_expect_success 'diff identical, but newly created symlink and file' ' >expected && rm -f frotz nitfol && echo xyzzy >nitfol && test-chmtime +10 nitfol && - ln -s xyzzy frotz && + if test_have_prereq SYMLINKS + then + ln -s xyzzy frotz + else + printf xyzzy >frotz + # the symlink property propagates from the index + fi && git diff-index -M -p $tree >current && compare_diff_patch expected current && @@ -80,7 +89,7 @@ test_expect_success SYMLINKS 'diff identical, but newly created symlink and file compare_diff_patch expected current ' -test_expect_success SYMLINKS 'diff different symlink and file' ' +test_expect_success 'diff different symlink and file' ' cat >expected <<-\EOF && diff --git a/frotz b/frotz index 7c465af..df1db54 120000 @@ -100,7 +109,13 @@ test_expect_success SYMLINKS 'diff different symlink and file' ' +yxyyz EOF rm -f frotz && - ln -s yxyyz frotz && + if test_have_prereq SYMLINKS + then + ln -s yxyyz frotz + else + printf yxyyz >frotz + # the symlink property propagates from the index + fi && echo yxyyz >nitfol && git diff-index -M -p $tree >current && compare_diff_patch expected current diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index ad9f69e607..668933bfb2 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -155,7 +155,7 @@ test_expect_failure 'additional command line cc (rfc822)' ' git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" && git format-patch --cc="S. E. Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch5 && grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch5 && - grep "^ *"S. E. Cipient" <scipient@example.com>\$" patch5 + grep "^ *\"S. E. Cipient\" <scipient@example.com>\$" patch5 ' test_expect_success 'command line headers' ' @@ -183,7 +183,7 @@ test_expect_success 'command line To: header (ascii)' ' test_expect_failure 'command line To: header (rfc822)' ' git format-patch --to="R. E. Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 && - grep "^To: "R. E. Cipient" <rcipient@example.com>\$" patch8 + grep "^To: \"R. E. Cipient\" <rcipient@example.com>\$" patch8 ' test_expect_failure 'command line To: header (rfc2047)' ' @@ -203,7 +203,7 @@ test_expect_failure 'configuration To: header (rfc822)' ' git config format.to "R. E. Cipient <rcipient@example.com>" && git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 && - grep "^To: "R. E. Cipient" <rcipient@example.com>\$" patch9 + grep "^To: \"R. E. Cipient\" <rcipient@example.com>\$" patch9 ' test_expect_failure 'configuration To: header (rfc2047)' ' @@ -271,6 +271,22 @@ test_expect_success 'multiple files' ' ls patches/0001-Side-changes-1.patch patches/0002-Side-changes-2.patch patches/0003-Side-changes-3-with-n-backslash-n-in-it.patch ' +test_expect_success 'reroll count' ' + rm -fr patches && + git format-patch -o patches --cover-letter --reroll-count 4 master..side >list && + ! grep -v "^patches/v4-000[0-3]-" list && + sed -n -e "/^Subject: /p" $(cat list) >subjects && + ! grep -v "^Subject: \[PATCH v4 [0-3]/3\] " subjects +' + +test_expect_success 'reroll count (-v)' ' + rm -fr patches && + git format-patch -o patches --cover-letter -v4 master..side >list && + ! grep -v "^patches/v4-000[0-3]-" list && + sed -n -e "/^Subject: /p" $(cat list) >subjects && + ! grep -v "^Subject: \[PATCH v4 [0-3]/3\] " subjects +' + check_threading () { expect="$1" && shift && @@ -650,8 +666,19 @@ test_expect_success 'format-patch --in-reply-to' ' ' test_expect_success 'format-patch --signoff' ' - git format-patch -1 --signoff --stdout | - grep "^Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" + git format-patch -1 --signoff --stdout >out && + grep "^Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" out +' + +test_expect_success 'format-patch --notes --signoff' ' + git notes --ref test add -m "test message" HEAD && + git format-patch -1 --signoff --stdout --notes=test >out && + # Three dashes must come after S-o-b + ! sed "/^Signed-off-by: /q" out | grep "test message" && + sed "1,/^Signed-off-by: /d" out | grep "test message" && + # Notes message must come after three dashes + ! sed "/^---$/q" out | grep "test message" && + sed "1,/^---$/d" out | grep "test message" ' echo "fatal: --name-only does not make sense" > expect.name-only @@ -715,21 +742,21 @@ test_expect_success 'format-patch --signature --cover-letter' ' test 2 = $(grep "my sig" output | wc -l) ' -test_expect_success 'format.signature="" supresses signatures' ' +test_expect_success 'format.signature="" suppresses signatures' ' git config format.signature "" && git format-patch --stdout -1 >output && check_patch output && ! grep "^-- \$" output ' -test_expect_success 'format-patch --no-signature supresses signatures' ' +test_expect_success 'format-patch --no-signature suppresses signatures' ' git config --unset-all format.signature && git format-patch --stdout --no-signature -1 >output && check_patch output && ! grep "^-- \$" output ' -test_expect_success 'format-patch --signature="" supresses signatures' ' +test_expect_success 'format-patch --signature="" suppresses signatures' ' git format-patch --stdout --signature="" -1 >output && check_patch output && ! grep "^-- \$" output @@ -810,25 +837,26 @@ Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?= =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?= =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?= =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?= - =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3?= - =?UTF-8?q?=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3?= - =?UTF-8?q?=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?= + =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?= + =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?= + =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?= + =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?= + =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?= =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?= =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?= =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?= - =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3?= - =?UTF-8?q?=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3?= - =?UTF-8?q?=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?= + =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?= =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?= =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?= =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?= - =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3?= - =?UTF-8?q?=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3?= - =?UTF-8?q?=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?= - =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?= + =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?= + =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?= + =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?= + =?UTF-8?q?bar?= EOF test_expect_success 'format-patch wraps extremely long subject (rfc2047)' ' rm -rf patches/ && @@ -944,6 +972,311 @@ test_expect_success 'empty subject prefix does not have extra space' ' test_cmp expect actual ' +test_expect_success '--from=ident notices bogus ident' ' + test_must_fail git format-patch -1 --stdout --from=foo >patch +' + +test_expect_success '--from=ident replaces author' ' + git format-patch -1 --stdout --from="Me <me@example.com>" >patch && + cat >expect <<-\EOF && + From: Me <me@example.com> + + From: A U Thor <author@example.com> + + EOF + sed -ne "/^From:/p; /^$/p; /^---$/q" <patch >patch.head && + test_cmp expect patch.head +' + +test_expect_success '--from uses committer ident' ' + git format-patch -1 --stdout --from >patch && + cat >expect <<-\EOF && + From: C O Mitter <committer@example.com> + + From: A U Thor <author@example.com> + + EOF + sed -ne "/^From:/p; /^$/p; /^---$/q" <patch >patch.head && + test_cmp expect patch.head +' + +test_expect_success 'in-body headers trigger content encoding' ' + GIT_AUTHOR_NAME="éxötìc" test_commit exotic && + test_when_finished "git reset --hard HEAD^" && + git format-patch -1 --stdout --from >patch && + cat >expect <<-\EOF && + From: C O Mitter <committer@example.com> + Content-Type: text/plain; charset=UTF-8 + + From: éxötìc <author@example.com> + + EOF + sed -ne "/^From:/p; /^$/p; /^Content-Type/p; /^---$/q" <patch >patch.head && + test_cmp expect patch.head +' + +append_signoff() +{ + C=$(git commit-tree HEAD^^{tree} -p HEAD) && + git format-patch --stdout --signoff $C^..$C >append_signoff.patch && + sed -n -e "1,/^---$/p" append_signoff.patch | + egrep -n "^Subject|Sign|^$" +} + +test_expect_success 'signoff: commit with no body' ' + append_signoff </dev/null >actual && + cat <<\EOF | sed "s/EOL$//" >expected && +4:Subject: [PATCH] EOL +8: +9:Signed-off-by: C O Mitter <committer@example.com> +EOF + test_cmp expected actual +' + +test_expect_success 'signoff: commit with only subject' ' + echo subject | append_signoff >actual && + cat >expected <<\EOF && +4:Subject: [PATCH] subject +8: +9:Signed-off-by: C O Mitter <committer@example.com> +EOF + test_cmp expected actual +' + +test_expect_success 'signoff: commit with only subject that does not end with NL' ' + printf subject | append_signoff >actual && + cat >expected <<\EOF && +4:Subject: [PATCH] subject +8: +9:Signed-off-by: C O Mitter <committer@example.com> +EOF + test_cmp expected actual +' + +test_expect_success 'signoff: no existing signoffs' ' + append_signoff <<\EOF >actual && +subject + +body +EOF + cat >expected <<\EOF && +4:Subject: [PATCH] subject +8: +10: +11:Signed-off-by: C O Mitter <committer@example.com> +EOF + test_cmp expected actual +' + +test_expect_success 'signoff: no existing signoffs and no trailing NL' ' + printf "subject\n\nbody" | append_signoff >actual && + cat >expected <<\EOF && +4:Subject: [PATCH] subject +8: +10: +11:Signed-off-by: C O Mitter <committer@example.com> +EOF + test_cmp expected actual +' + +test_expect_success 'signoff: some random signoff' ' + append_signoff <<\EOF >actual && +subject + +body + +Signed-off-by: my@house +EOF + cat >expected <<\EOF && +4:Subject: [PATCH] subject +8: +10: +11:Signed-off-by: my@house +12:Signed-off-by: C O Mitter <committer@example.com> +EOF + test_cmp expected actual +' + +test_expect_success 'signoff: misc conforming footer elements' ' + append_signoff <<\EOF >actual && +subject + +body + +Signed-off-by: my@house +(cherry picked from commit da39a3ee5e6b4b0d3255bfef95601890afd80709) +Tested-by: Some One <someone@example.com> +Bug: 1234 +EOF + cat >expected <<\EOF && +4:Subject: [PATCH] subject +8: +10: +11:Signed-off-by: my@house +15:Signed-off-by: C O Mitter <committer@example.com> +EOF + test_cmp expected actual +' + +test_expect_success 'signoff: some random signoff-alike' ' + append_signoff <<\EOF >actual && +subject + +body +Fooled-by-me: my@house +EOF + cat >expected <<\EOF && +4:Subject: [PATCH] subject +8: +11: +12:Signed-off-by: C O Mitter <committer@example.com> +EOF + test_cmp expected actual +' + +test_expect_success 'signoff: not really a signoff' ' + append_signoff <<\EOF >actual && +subject + +I want to mention about Signed-off-by: here. +EOF + cat >expected <<\EOF && +4:Subject: [PATCH] subject +8: +9:I want to mention about Signed-off-by: here. +10: +11:Signed-off-by: C O Mitter <committer@example.com> +EOF + test_cmp expected actual +' + +test_expect_success 'signoff: not really a signoff (2)' ' + append_signoff <<\EOF >actual && +subject + +My unfortunate +Signed-off-by: example happens to be wrapped here. +EOF + cat >expected <<\EOF && +4:Subject: [PATCH] subject +8: +10:Signed-off-by: example happens to be wrapped here. +11: +12:Signed-off-by: C O Mitter <committer@example.com> +EOF + test_cmp expected actual +' + +test_expect_success 'signoff: valid S-o-b paragraph in the middle' ' + append_signoff <<\EOF >actual && +subject + +Signed-off-by: my@house +Signed-off-by: your@house + +A lot of houses. +EOF + cat >expected <<\EOF && +4:Subject: [PATCH] subject +8: +9:Signed-off-by: my@house +10:Signed-off-by: your@house +11: +13: +14:Signed-off-by: C O Mitter <committer@example.com> +EOF + test_cmp expected actual +' + +test_expect_success 'signoff: the same signoff at the end' ' + append_signoff <<\EOF >actual && +subject + +body + +Signed-off-by: C O Mitter <committer@example.com> +EOF + cat >expected <<\EOF && +4:Subject: [PATCH] subject +8: +10: +11:Signed-off-by: C O Mitter <committer@example.com> +EOF + test_cmp expected actual +' + +test_expect_success 'signoff: the same signoff at the end, no trailing NL' ' + printf "subject\n\nSigned-off-by: C O Mitter <committer@example.com>" | + append_signoff >actual && + cat >expected <<\EOF && +4:Subject: [PATCH] subject +8: +9:Signed-off-by: C O Mitter <committer@example.com> +EOF + test_cmp expected actual +' + +test_expect_success 'signoff: the same signoff NOT at the end' ' + append_signoff <<\EOF >actual && +subject + +body + +Signed-off-by: C O Mitter <committer@example.com> +Signed-off-by: my@house +EOF + cat >expected <<\EOF && +4:Subject: [PATCH] subject +8: +10: +11:Signed-off-by: C O Mitter <committer@example.com> +12:Signed-off-by: my@house +EOF + test_cmp expected actual +' + +test_expect_success 'signoff: detect garbage in non-conforming footer' ' + append_signoff <<\EOF >actual && +subject + +body + +Tested-by: my@house +Some Trash +Signed-off-by: C O Mitter <committer@example.com> +EOF + cat >expected <<\EOF && +4:Subject: [PATCH] subject +8: +10: +13:Signed-off-by: C O Mitter <committer@example.com> +14: +15:Signed-off-by: C O Mitter <committer@example.com> +EOF + test_cmp expected actual +' + +test_expect_success 'signoff: footer begins with non-signoff without @ sign' ' + append_signoff <<\EOF >actual && +subject + +body + +Reviewed-id: Noone +Tested-by: my@house +Change-id: Ideadbeef +Signed-off-by: C O Mitter <committer@example.com> +Bug: 1234 +EOF + cat >expected <<\EOF && +4:Subject: [PATCH] subject +8: +10: +14:Signed-off-by: C O Mitter <committer@example.com> +EOF + test_cmp expected actual +' + test_expect_success 'format patch ignores color.ui' ' test_unconfig color.ui && git format-patch --stdout -1 >expect && @@ -952,4 +1285,79 @@ test_expect_success 'format patch ignores color.ui' ' test_cmp expect actual ' +test_expect_success 'cover letter using branch description (1)' ' + git checkout rebuild-1 && + test_config branch.rebuild-1.description hello && + git format-patch --stdout --cover-letter master >actual && + grep hello actual >/dev/null +' + +test_expect_success 'cover letter using branch description (2)' ' + git checkout rebuild-1 && + test_config branch.rebuild-1.description hello && + git format-patch --stdout --cover-letter rebuild-1~2..rebuild-1 >actual && + grep hello actual >/dev/null +' + +test_expect_success 'cover letter using branch description (3)' ' + git checkout rebuild-1 && + test_config branch.rebuild-1.description hello && + git format-patch --stdout --cover-letter ^master rebuild-1 >actual && + grep hello actual >/dev/null +' + +test_expect_success 'cover letter using branch description (4)' ' + git checkout rebuild-1 && + test_config branch.rebuild-1.description hello && + git format-patch --stdout --cover-letter master.. >actual && + grep hello actual >/dev/null +' + +test_expect_success 'cover letter using branch description (5)' ' + git checkout rebuild-1 && + test_config branch.rebuild-1.description hello && + git format-patch --stdout --cover-letter -2 HEAD >actual && + grep hello actual >/dev/null +' + +test_expect_success 'cover letter using branch description (6)' ' + git checkout rebuild-1 && + test_config branch.rebuild-1.description hello && + git format-patch --stdout --cover-letter -2 >actual && + grep hello actual >/dev/null +' + +test_expect_success 'cover letter with nothing' ' + git format-patch --stdout --cover-letter >actual && + test_line_count = 0 actual +' + +test_expect_success 'cover letter auto' ' + mkdir -p tmp && + test_when_finished "rm -rf tmp; + git config --unset format.coverletter" && + + git config format.coverletter auto && + git format-patch -o tmp -1 >list && + test_line_count = 1 list && + git format-patch -o tmp -2 >list && + test_line_count = 3 list +' + +test_expect_success 'cover letter auto user override' ' + mkdir -p tmp && + test_when_finished "rm -rf tmp; + git config --unset format.coverletter" && + + git config format.coverletter auto && + git format-patch -o tmp --cover-letter -1 >list && + test_line_count = 2 list && + git format-patch -o tmp --cover-letter -2 >list && + test_line_count = 3 list && + git format-patch -o tmp --no-cover-letter -1 >list && + test_line_count = 1 list && + git format-patch -o tmp --no-cover-letter -2 >list && + test_line_count = 2 list +' + test_done diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index cc3db1304e..3fb4b976a2 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -142,6 +142,351 @@ EOF git diff --ignore-space-at-eol > out test_expect_success 'another test, with --ignore-space-at-eol' 'test_cmp expect out' +test_expect_success 'ignore-blank-lines: only new lines' ' + test_seq 5 >x && + git update-index x && + test_seq 5 | sed "/3/i \\ +" >x && + git diff --ignore-blank-lines >out && + >expect && + test_cmp out expect +' + +test_expect_success 'ignore-blank-lines: only new lines with space' ' + test_seq 5 >x && + git update-index x && + test_seq 5 | sed "/3/i \ " >x && + git diff -w --ignore-blank-lines >out && + >expect && + test_cmp out expect +' + +test_expect_success 'ignore-blank-lines: after change' ' + cat <<-\EOF >x && + 1 + 2 + + 3 + 4 + 5 + + 6 + 7 + EOF + git update-index x && + cat <<-\EOF >x && + change + + 1 + 2 + 3 + 4 + 5 + 6 + + 7 + EOF + git diff --inter-hunk-context=100 --ignore-blank-lines >out.tmp && + cat <<-\EOF >expected && + diff --git a/x b/x + --- a/x + +++ b/x + @@ -1,6 +1,7 @@ + +change + + + 1 + 2 + - + 3 + 4 + 5 + EOF + compare_diff_patch expected out.tmp +' + +test_expect_success 'ignore-blank-lines: before change' ' + cat <<-\EOF >x && + 1 + 2 + + 3 + 4 + 5 + 6 + 7 + EOF + git update-index x && + cat <<-\EOF >x && + + 1 + 2 + 3 + 4 + 5 + + 6 + 7 + change + EOF + git diff --inter-hunk-context=100 --ignore-blank-lines >out.tmp && + cat <<-\EOF >expected && + diff --git a/x b/x + --- a/x + +++ b/x + @@ -4,5 +4,7 @@ + 3 + 4 + 5 + + + 6 + 7 + +change + EOF + compare_diff_patch expected out.tmp +' + +test_expect_success 'ignore-blank-lines: between changes' ' + cat <<-\EOF >x && + 1 + 2 + 3 + 4 + 5 + + + 6 + 7 + 8 + 9 + 10 + EOF + git update-index x && + cat <<-\EOF >x && + change + 1 + 2 + + 3 + 4 + 5 + 6 + 7 + 8 + + 9 + 10 + change + EOF + git diff --ignore-blank-lines >out.tmp && + cat <<-\EOF >expected && + diff --git a/x b/x + --- a/x + +++ b/x + @@ -1,5 +1,7 @@ + +change + 1 + 2 + + + 3 + 4 + 5 + @@ -8,5 +8,7 @@ + 6 + 7 + 8 + + + 9 + 10 + +change + EOF + compare_diff_patch expected out.tmp +' + +test_expect_success 'ignore-blank-lines: between changes (with interhunkctx)' ' + test_seq 10 >x && + git update-index x && + cat <<-\EOF >x && + change + 1 + 2 + + 3 + 4 + 5 + + 6 + 7 + 8 + 9 + + 10 + change + EOF + git diff --inter-hunk-context=2 --ignore-blank-lines >out.tmp && + cat <<-\EOF >expected && + diff --git a/x b/x + --- a/x + +++ b/x + @@ -1,10 +1,15 @@ + +change + 1 + 2 + + + 3 + 4 + 5 + + + 6 + 7 + 8 + 9 + + + 10 + +change + EOF + compare_diff_patch expected out.tmp +' + +test_expect_success 'ignore-blank-lines: scattered spaces' ' + test_seq 10 >x && + git update-index x && + cat <<-\EOF >x && + change + 1 + 2 + 3 + + 4 + + 5 + + 6 + + + 7 + + 8 + 9 + 10 + change + EOF + git diff --inter-hunk-context=4 --ignore-blank-lines >out.tmp && + cat <<-\EOF >expected && + diff --git a/x b/x + --- a/x + +++ b/x + @@ -1,3 +1,4 @@ + +change + 1 + 2 + 3 + @@ -8,3 +15,4 @@ + 8 + 9 + 10 + +change + EOF + compare_diff_patch expected out.tmp +' + +test_expect_success 'ignore-blank-lines: spaces coalesce' ' + test_seq 6 >x && + git update-index x && + cat <<-\EOF >x && + change + 1 + 2 + 3 + + 4 + + 5 + + 6 + change + EOF + git diff --inter-hunk-context=4 --ignore-blank-lines >out.tmp && + cat <<-\EOF >expected && + diff --git a/x b/x + --- a/x + +++ b/x + @@ -1,6 +1,11 @@ + +change + 1 + 2 + 3 + + + 4 + + + 5 + + + 6 + +change + EOF + compare_diff_patch expected out.tmp +' + +test_expect_success 'ignore-blank-lines: mix changes and blank lines' ' + test_seq 16 >x && + git update-index x && + cat <<-\EOF >x && + change + 1 + 2 + + 3 + 4 + 5 + change + 6 + 7 + 8 + + 9 + 10 + 11 + change + 12 + 13 + 14 + + 15 + 16 + change + EOF + git diff --ignore-blank-lines >out.tmp && + cat <<-\EOF >expected && + diff --git a/x b/x + --- a/x + +++ b/x + @@ -1,8 +1,11 @@ + +change + 1 + 2 + + + 3 + 4 + 5 + +change + 6 + 7 + 8 + @@ -9,8 +13,11 @@ + 9 + 10 + 11 + +change + 12 + 13 + 14 + + + 15 + 16 + +change + EOF + compare_diff_patch expected out.tmp +' + test_expect_success 'check mixed spaces and tabs in indent' ' # This is indented with SP HT SP. diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh index 082d3e83bd..38a092a0da 100755 --- a/t/t4018-diff-funcname.sh +++ b/t/t4018-diff-funcname.sh @@ -93,11 +93,6 @@ sed -e ' s/song;/song();/ ' <Beer.perl >Beer-correct.perl -test_config () { - git config "$1" "$2" && - test_when_finished "git config --unset $1" -} - test_expect_funcname () { lang=${2-java} test_expect_code 1 git diff --no-index -U1 \ diff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh index 5d20acf436..55d549fcf4 100755 --- a/t/t4023-diff-rename-typechange.sh +++ b/t/t4023-diff-rename-typechange.sh @@ -4,44 +4,44 @@ test_description='typechange rename detection' . ./test-lib.sh -test_expect_success SYMLINKS setup ' +test_expect_success setup ' rm -f foo bar && cat "$TEST_DIRECTORY"/../COPYING >foo && - ln -s linklink bar && - git add foo bar && + test_ln_s_add linklink bar && + git add foo && git commit -a -m Initial && git tag one && - rm -f foo bar && + git rm -f foo bar && cat "$TEST_DIRECTORY"/../COPYING >bar && - ln -s linklink foo && - git add foo bar && + test_ln_s_add linklink foo && + git add bar && git commit -a -m Second && git tag two && - rm -f foo bar && + git rm -f foo bar && cat "$TEST_DIRECTORY"/../COPYING >foo && git add foo && git commit -a -m Third && git tag three && mv foo bar && - ln -s linklink foo && - git add foo bar && + test_ln_s_add linklink foo && + git add bar && git commit -a -m Fourth && git tag four && # This is purely for sanity check - rm -f foo bar && + git rm -f foo bar && cat "$TEST_DIRECTORY"/../COPYING >foo && cat "$TEST_DIRECTORY"/../Makefile >bar && git add foo bar && git commit -a -m Fifth && git tag five && - rm -f foo bar && + git rm -f foo bar && cat "$TEST_DIRECTORY"/../Makefile >foo && cat "$TEST_DIRECTORY"/../COPYING >bar && git add foo bar && @@ -50,7 +50,7 @@ test_expect_success SYMLINKS setup ' ' -test_expect_success SYMLINKS 'cross renames to be detected for regular files' ' +test_expect_success 'cross renames to be detected for regular files' ' git diff-tree five six -r --name-status -B -M | sort >actual && { @@ -61,7 +61,7 @@ test_expect_success SYMLINKS 'cross renames to be detected for regular files' ' ' -test_expect_success SYMLINKS 'cross renames to be detected for typechange' ' +test_expect_success 'cross renames to be detected for typechange' ' git diff-tree one two -r --name-status -B -M | sort >actual && { @@ -72,7 +72,7 @@ test_expect_success SYMLINKS 'cross renames to be detected for typechange' ' ' -test_expect_success SYMLINKS 'moves and renames' ' +test_expect_success 'moves and renames' ' git diff-tree three four -r --name-status -B -M | sort >actual && { diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh index 53ec330ce8..f75f46f92d 100755 --- a/t/t4030-diff-textconv.sh +++ b/t/t4030-diff-textconv.sh @@ -139,12 +139,10 @@ index 0000000..67be421 +frotz \ No newline at end of file EOF -# make a symlink the hard way that works on symlink-challenged file systems + test_expect_success 'textconv does not act on symlinks' ' - printf frotz > file && - git add file && - git ls-files -s | sed -e s/100644/120000/ | - git update-index --index-info && + rm -f file && + test_ln_s_add frotz file && git commit -m typechange && git show >diff && find_diff <diff >actual && diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh index 40ab333a8a..f2f55fc51c 100755 --- a/t/t4034-diff-words.sh +++ b/t/t4034-diff-words.sh @@ -230,7 +230,7 @@ test_expect_success '.gitattributes override config' ' ' test_expect_success 'setup: remove diff driver regex' ' - test_might_fail git config --unset diff.testdriver.wordRegex + test_unconfig diff.testdriver.wordRegex ' test_expect_success 'use configured regex' ' @@ -335,8 +335,7 @@ test_expect_success 'word-diff with diff.sbe' ' c EOF - test_when_finished "git config --unset diff.suppress-blank-empty" && - git config diff.suppress-blank-empty true && + test_config diff.suppress-blank-empty true && word_diff --word-diff=plain ' @@ -368,7 +367,7 @@ test_expect_success 'setup history with two files' ' 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]+|." && + test_config diff.tex.wordRegex "[a-z]+|." && cat >expect <<-\EOF && diff --git a/a.tex b/a.tex --- a/a.tex diff --git a/t/t4038-diff-combined.sh b/t/t4038-diff-combined.sh index 40277c77aa..1019d7b35f 100755 --- a/t/t4038-diff-combined.sh +++ b/t/t4038-diff-combined.sh @@ -3,6 +3,7 @@ test_description='combined diff' . ./test-lib.sh +. "$TEST_DIRECTORY"/diff-lib.sh setup_helper () { one=$1 branch=$2 side=$3 && @@ -89,4 +90,315 @@ test_expect_success 'diagnose truncated file' ' grep "diff --cc file" out ' +test_expect_success 'setup for --cc --raw' ' + blob=$(echo file | git hash-object --stdin -w) && + base_tree=$(echo "100644 blob $blob file" | git mktree) && + trees= && + for i in `test_seq 1 40` + do + blob=$(echo file$i | git hash-object --stdin -w) && + trees="$trees$(echo "100644 blob $blob file" | git mktree)$LF" + done +' + +test_expect_success 'check --cc --raw with four trees' ' + four_trees=$(echo "$trees" | sed -e 4q) && + git diff --cc --raw $four_trees $base_tree >out && + # Check for four leading colons in the output: + grep "^::::[^:]" out +' + +test_expect_success 'check --cc --raw with forty trees' ' + git diff --cc --raw $trees $base_tree >out && + # Check for forty leading colons in the output: + grep "^::::::::::::::::::::::::::::::::::::::::[^:]" out +' + +test_expect_success 'setup combined ignore spaces' ' + git checkout master && + >test && + git add test && + git commit -m initial && + + tr -d Q <<-\EOF >test && + always coalesce + eol space coalesce Q + space change coalesce + all spa ces coalesce + eol spaces Q + space change + all spa ces + EOF + git commit -m "test space change" -a && + + git checkout -b side HEAD^ && + tr -d Q <<-\EOF >test && + always coalesce + eol space coalesce + space change coalesce + all spaces coalesce + eol spaces + space change + all spaces + EOF + git commit -m "test other space changes" -a && + + test_must_fail git merge master && + tr -d Q <<-\EOF >test && + eol spaces Q + space change + all spa ces + EOF + git commit -m merged -a +' + +test_expect_success 'check combined output (no ignore space)' ' + git show >actual.tmp && + sed -e "1,/^@@@/d" < actual.tmp >actual && + tr -d Q <<-\EOF >expected && + --always coalesce + - eol space coalesce + - space change coalesce + - all spaces coalesce + - eol spaces + - space change + - all spaces + -eol space coalesce Q + -space change coalesce + -all spa ces coalesce + + eol spaces Q + + space change + + all spa ces + EOF + compare_diff_patch expected actual +' + +test_expect_success 'check combined output (ignore space at eol)' ' + git show --ignore-space-at-eol >actual.tmp && + sed -e "1,/^@@@/d" < actual.tmp >actual && + tr -d Q <<-\EOF >expected && + --always coalesce + --eol space coalesce + - space change coalesce + - all spaces coalesce + -space change coalesce + -all spa ces coalesce + eol spaces Q + - space change + - all spaces + + space change + + all spa ces + EOF + compare_diff_patch expected actual +' + +test_expect_success 'check combined output (ignore space change)' ' + git show -b >actual.tmp && + sed -e "1,/^@@@/d" < actual.tmp >actual && + tr -d Q <<-\EOF >expected && + --always coalesce + --eol space coalesce + --space change coalesce + - all spaces coalesce + -all spa ces coalesce + eol spaces Q + space change + - all spaces + + all spa ces + EOF + compare_diff_patch expected actual +' + +test_expect_success 'check combined output (ignore all spaces)' ' + git show -w >actual.tmp && + sed -e "1,/^@@@/d" < actual.tmp >actual && + tr -d Q <<-\EOF >expected && + --always coalesce + --eol space coalesce + --space change coalesce + --all spaces coalesce + eol spaces Q + space change + all spa ces + EOF + compare_diff_patch expected actual +' + +test_expect_success 'combine diff coalesce simple' ' + >test && + git add test && + git commit -m initial && + test_seq 4 >test && + git commit -a -m empty1 && + git branch side1 && + git checkout HEAD^ && + test_seq 5 >test && + git commit -a -m empty2 && + test_must_fail git merge side1 && + >test && + git commit -a -m merge && + git show >actual.tmp && + sed -e "1,/^@@@/d" < actual.tmp >actual && + tr -d Q <<-\EOF >expected && + --1 + --2 + --3 + --4 + - 5 + EOF + compare_diff_patch expected actual +' + +test_expect_success 'combine diff coalesce tricky' ' + >test && + git add test && + git commit -m initial --allow-empty && + cat <<-\EOF >test && + 3 + 1 + 2 + 3 + 4 + EOF + git commit -a -m empty1 && + git branch -f side1 && + git checkout HEAD^ && + cat <<-\EOF >test && + 1 + 3 + 5 + 4 + EOF + git commit -a -m empty2 && + git branch -f side2 && + test_must_fail git merge side1 && + >test && + git commit -a -m merge && + git show >actual.tmp && + sed -e "1,/^@@@/d" < actual.tmp >actual && + tr -d Q <<-\EOF >expected && + -3 + --1 + -2 + --3 + - 5 + --4 + EOF + compare_diff_patch expected actual && + git checkout -f side1 && + test_must_fail git merge side2 && + >test && + git commit -a -m merge && + git show >actual.tmp && + sed -e "1,/^@@@/d" < actual.tmp >actual && + tr -d Q <<-\EOF >expected && + - 3 + --1 + - 2 + --3 + -5 + --4 + EOF + compare_diff_patch expected actual +' + +test_expect_failure 'combine diff coalesce three parents' ' + >test && + git add test && + git commit -m initial --allow-empty && + cat <<-\EOF >test && + 3 + 1 + 2 + 3 + 4 + EOF + git commit -a -m empty1 && + git checkout -B side1 && + git checkout HEAD^ && + cat <<-\EOF >test && + 1 + 3 + 7 + 5 + 4 + EOF + git commit -a -m empty2 && + git branch -f side2 && + git checkout HEAD^ && + cat <<-\EOF >test && + 3 + 1 + 6 + 5 + 4 + EOF + git commit -a -m empty3 && + >test && + git add test && + TREE=$(git write-tree) && + COMMIT=$(git commit-tree -p HEAD -p side1 -p side2 -m merge $TREE) && + git show $COMMIT >actual.tmp && + sed -e "1,/^@@@/d" < actual.tmp >actual && + tr -d Q <<-\EOF >expected && + -- 3 + ---1 + - 6 + - 2 + --3 + -7 + - -5 + ---4 + EOF + compare_diff_patch expected actual +' + +# Test for a bug reported at +# http://thread.gmane.org/gmane.comp.version-control.git/224410 +# where a delete lines were missing from combined diff output when they +# occurred exactly before the context lines of a later change. +test_expect_success 'combine diff missing delete bug' ' + git commit -m initial --allow-empty && + cat <<-\EOF >test && + 1 + 2 + 3 + 4 + EOF + git add test && + git commit -a -m side1 && + git checkout -B side1 && + git checkout HEAD^ && + cat <<-\EOF >test && + 0 + 1 + 2 + 3 + 4modified + EOF + git add test && + git commit -m side2 && + git branch -f side2 && + test_must_fail git merge --no-commit side1 && + cat <<-\EOF >test && + 1 + 2 + 3 + 4modified + EOF + git add test && + git commit -a -m merge && + git diff-tree -c -p HEAD >actual.tmp && + sed -e "1,/^@@@/d" < actual.tmp >actual && + tr -d Q <<-\EOF >expected && + - 0 + 1 + 2 + 3 + -4 + +4modified + EOF + compare_diff_patch expected actual +' + test_done diff --git a/t/t4041-diff-submodule-option.sh b/t/t4041-diff-submodule-option.sh index 6c01d0c056..1751c83307 100755 --- a/t/t4041-diff-submodule-option.sh +++ b/t/t4041-diff-submodule-option.sh @@ -1,6 +1,7 @@ #!/bin/sh # # Copyright (c) 2009 Jens Lehmann, based on t7401 by Ping Yin +# Copyright (c) 2011 Alexey Shumkin (+ non-UTF-8 commit encoding tests) # test_description='Support for verbose submodule differences in git diff @@ -10,19 +11,23 @@ This test tries to verify the sanity of the --submodule option of git diff. . ./test-lib.sh +# String "added" in German (translated with Google Translate), encoded in UTF-8, +# used in sample commit log messages in add_file() function below. +added=$(printf "hinzugef\303\274gt") add_file () { - sm=$1 - shift - owd=$(pwd) - cd "$sm" - for name; do - echo "$name" > "$name" && - git add "$name" && - test_tick && - git commit -m "Add $name" - done >/dev/null - git rev-parse --verify HEAD | cut -c1-7 - cd "$owd" + ( + cd "$1" && + shift && + for name + do + echo "$name" >"$name" && + git add "$name" && + test_tick && + msg_added_iso88591=$(echo "Add $name ($added $name)" | iconv -f utf-8 -t iso8859-1) && + git -c 'i18n.commitEncoding=iso8859-1' commit -m "$msg_added_iso88591" + done >/dev/null && + git rev-parse --short --verify HEAD + ) } commit_file () { test_tick && @@ -33,92 +38,133 @@ test_create_repo sm1 && add_file . foo >/dev/null head1=$(add_file sm1 foo1 foo2) +fullhead1=$(cd sm1; git rev-parse --verify HEAD) -test_expect_success 'added submodule' " +test_expect_success 'added submodule' ' git add sm1 && git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 0000000...$head1 (new submodule) -EOF + Submodule sm1 0000000...$head1 (new submodule) + EOF + test_cmp expected actual +' + +test_expect_success 'added submodule, set diff.submodule' ' + git config diff.submodule log && + git add sm1 && + git diff --cached >actual && + cat >expected <<-EOF && + Submodule sm1 0000000...$head1 (new submodule) + EOF + git config --unset diff.submodule && + test_cmp expected actual +' + +test_expect_success '--submodule=short overrides diff.submodule' ' + test_config diff.submodule log && + git add sm1 && + git diff --submodule=short --cached >actual && + cat >expected <<-EOF && + diff --git a/sm1 b/sm1 + new file mode 160000 + index 0000000..$head1 + --- /dev/null + +++ b/sm1 + @@ -0,0 +1 @@ + +Subproject commit $fullhead1 + EOF test_cmp expected actual -" +' + +test_expect_success 'diff.submodule does not affect plumbing' ' + test_config diff.submodule log && + git diff-index -p HEAD >actual && + cat >expected <<-EOF && + diff --git a/sm1 b/sm1 + new file mode 160000 + index 0000000..$head1 + --- /dev/null + +++ b/sm1 + @@ -0,0 +1 @@ + +Subproject commit $fullhead1 + EOF + test_cmp expected actual +' commit_file sm1 && head2=$(add_file sm1 foo3) -test_expect_success 'modified submodule(forward)' " +test_expect_success 'modified submodule(forward)' ' git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 $head1..$head2: - > Add foo3 -EOF + Submodule sm1 $head1..$head2: + > Add foo3 ($added foo3) + EOF test_cmp expected actual -" +' -test_expect_success 'modified submodule(forward)' " +test_expect_success 'modified submodule(forward)' ' git diff --submodule=log >actual && cat >expected <<-EOF && -Submodule sm1 $head1..$head2: - > Add foo3 -EOF + Submodule sm1 $head1..$head2: + > Add foo3 ($added foo3) + EOF test_cmp expected actual -" +' -test_expect_success 'modified submodule(forward) --submodule' " +test_expect_success 'modified submodule(forward) --submodule' ' git diff --submodule >actual && cat >expected <<-EOF && -Submodule sm1 $head1..$head2: - > Add foo3 -EOF + Submodule sm1 $head1..$head2: + > Add foo3 ($added foo3) + EOF test_cmp expected actual -" +' -fullhead1=$(cd sm1; git rev-list --max-count=1 $head1) -fullhead2=$(cd sm1; git rev-list --max-count=1 $head2) -test_expect_success 'modified submodule(forward) --submodule=short' " +fullhead2=$(cd sm1; git rev-parse --verify HEAD) +test_expect_success 'modified submodule(forward) --submodule=short' ' git diff --submodule=short >actual && cat >expected <<-EOF && -diff --git a/sm1 b/sm1 -index $head1..$head2 160000 ---- a/sm1 -+++ b/sm1 -@@ -1 +1 @@ --Subproject commit $fullhead1 -+Subproject commit $fullhead2 -EOF + diff --git a/sm1 b/sm1 + index $head1..$head2 160000 + --- a/sm1 + +++ b/sm1 + @@ -1 +1 @@ + -Subproject commit $fullhead1 + +Subproject commit $fullhead2 + EOF test_cmp expected actual -" +' commit_file sm1 && head3=$( cd sm1 && git reset --hard HEAD~2 >/dev/null && - git rev-parse --verify HEAD | cut -c1-7 + git rev-parse --short --verify HEAD ) -test_expect_success 'modified submodule(backward)' " +test_expect_success 'modified submodule(backward)' ' git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 $head2..$head3 (rewind): - < Add foo3 - < Add foo2 -EOF + Submodule sm1 $head2..$head3 (rewind): + < Add foo3 ($added foo3) + < Add foo2 ($added foo2) + EOF test_cmp expected actual -" +' -head4=$(add_file sm1 foo4 foo5) && -head4_full=$(GIT_DIR=sm1/.git git rev-parse --verify HEAD) -test_expect_success 'modified submodule(backward and forward)' " +head4=$(add_file sm1 foo4 foo5) +test_expect_success 'modified submodule(backward and forward)' ' git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 $head2...$head4: - > Add foo5 - > Add foo4 - < Add foo3 - < Add foo2 -EOF + Submodule sm1 $head2...$head4: + > Add foo5 ($added foo5) + > Add foo4 ($added foo4) + < Add foo3 ($added foo3) + < Add foo2 ($added foo2) + EOF test_cmp expected actual -" +' commit_file sm1 && mv sm1 sm1-bak && @@ -128,319 +174,319 @@ git add sm1 && rm -f sm1 && mv sm1-bak sm1 -test_expect_success 'typechanged submodule(submodule->blob), --cached' " +test_expect_success 'typechanged submodule(submodule->blob), --cached' ' git diff --submodule=log --cached >actual && cat >expected <<-EOF && -Submodule sm1 41fbea9...0000000 (submodule deleted) -diff --git a/sm1 b/sm1 -new file mode 100644 -index 0000000..9da5fb8 ---- /dev/null -+++ b/sm1 -@@ -0,0 +1 @@ -+sm1 -EOF + Submodule sm1 $head4...0000000 (submodule deleted) + diff --git a/sm1 b/sm1 + new file mode 100644 + index 0000000..$head5 + --- /dev/null + +++ b/sm1 + @@ -0,0 +1 @@ + +sm1 + EOF test_cmp expected actual -" +' -test_expect_success 'typechanged submodule(submodule->blob)' " +test_expect_success 'typechanged submodule(submodule->blob)' ' git diff --submodule=log >actual && cat >expected <<-EOF && -diff --git a/sm1 b/sm1 -deleted file mode 100644 -index 9da5fb8..0000000 ---- a/sm1 -+++ /dev/null -@@ -1 +0,0 @@ --sm1 -Submodule sm1 0000000...$head4 (new submodule) -EOF + diff --git a/sm1 b/sm1 + deleted file mode 100644 + index $head5..0000000 + --- a/sm1 + +++ /dev/null + @@ -1 +0,0 @@ + -sm1 + Submodule sm1 0000000...$head4 (new submodule) + EOF test_cmp expected actual -" +' rm -rf sm1 && git checkout-index sm1 -test_expect_success 'typechanged submodule(submodule->blob)' " +test_expect_success 'typechanged submodule(submodule->blob)' ' git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 $head4...0000000 (submodule deleted) -diff --git a/sm1 b/sm1 -new file mode 100644 -index 0000000..$head5 ---- /dev/null -+++ b/sm1 -@@ -0,0 +1 @@ -+sm1 -EOF + Submodule sm1 $head4...0000000 (submodule deleted) + diff --git a/sm1 b/sm1 + new file mode 100644 + index 0000000..$head5 + --- /dev/null + +++ b/sm1 + @@ -0,0 +1 @@ + +sm1 + EOF test_cmp expected actual -" +' rm -f sm1 && test_create_repo sm1 && head6=$(add_file sm1 foo6 foo7) -fullhead6=$(cd sm1; git rev-list --max-count=1 $head6) -test_expect_success 'nonexistent commit' " +fullhead6=$(cd sm1; git rev-parse --verify HEAD) +test_expect_success 'nonexistent commit' ' git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 $head4...$head6 (commits not present) -EOF + Submodule sm1 $head4...$head6 (commits not present) + EOF test_cmp expected actual -" +' commit_file -test_expect_success 'typechanged submodule(blob->submodule)' " +test_expect_success 'typechanged submodule(blob->submodule)' ' git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -diff --git a/sm1 b/sm1 -deleted file mode 100644 -index $head5..0000000 ---- a/sm1 -+++ /dev/null -@@ -1 +0,0 @@ --sm1 -Submodule sm1 0000000...$head6 (new submodule) -EOF + diff --git a/sm1 b/sm1 + deleted file mode 100644 + index $head5..0000000 + --- a/sm1 + +++ /dev/null + @@ -1 +0,0 @@ + -sm1 + Submodule sm1 0000000...$head6 (new submodule) + EOF test_cmp expected actual -" +' commit_file sm1 && -test_expect_success 'submodule is up to date' " +test_expect_success 'submodule is up to date' ' git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -EOF + EOF test_cmp expected actual -" +' -test_expect_success 'submodule contains untracked content' " +test_expect_success 'submodule contains untracked content' ' echo new > sm1/new-file && git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 contains untracked content -EOF + Submodule sm1 contains untracked content + EOF test_cmp expected actual -" +' -test_expect_success 'submodule contains untracked content (untracked ignored)' " +test_expect_success 'submodule contains untracked content (untracked ignored)' ' git diff-index -p --ignore-submodules=untracked --submodule=log HEAD >actual && ! test -s actual -" +' -test_expect_success 'submodule contains untracked content (dirty ignored)' " +test_expect_success 'submodule contains untracked content (dirty ignored)' ' git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual && ! test -s actual -" +' -test_expect_success 'submodule contains untracked content (all ignored)' " +test_expect_success 'submodule contains untracked content (all ignored)' ' git diff-index -p --ignore-submodules=all --submodule=log HEAD >actual && ! test -s actual -" +' -test_expect_success 'submodule contains untracked and modifed content' " +test_expect_success 'submodule contains untracked and modifed content' ' echo new > sm1/foo6 && git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 contains untracked content -Submodule sm1 contains modified content -EOF + Submodule sm1 contains untracked content + Submodule sm1 contains modified content + EOF test_cmp expected actual -" +' -test_expect_success 'submodule contains untracked and modifed content (untracked ignored)' " +test_expect_success 'submodule contains untracked and modifed content (untracked ignored)' ' echo new > sm1/foo6 && git diff-index -p --ignore-submodules=untracked --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 contains modified content -EOF + Submodule sm1 contains modified content + EOF test_cmp expected actual -" +' -test_expect_success 'submodule contains untracked and modifed content (dirty ignored)' " +test_expect_success 'submodule contains untracked and modifed content (dirty ignored)' ' echo new > sm1/foo6 && git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual && ! test -s actual -" +' -test_expect_success 'submodule contains untracked and modifed content (all ignored)' " +test_expect_success 'submodule contains untracked and modifed content (all ignored)' ' echo new > sm1/foo6 && git diff-index -p --ignore-submodules --submodule=log HEAD >actual && ! test -s actual -" +' -test_expect_success 'submodule contains modifed content' " +test_expect_success 'submodule contains modifed content' ' rm -f sm1/new-file && git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 contains modified content -EOF + Submodule sm1 contains modified content + EOF test_cmp expected actual -" +' (cd sm1; git commit -mchange foo6 >/dev/null) && -head8=$(cd sm1; git rev-parse --verify HEAD | cut -c1-7) && -test_expect_success 'submodule is modified' " +head8=$(cd sm1; git rev-parse --short --verify HEAD) && +test_expect_success 'submodule is modified' ' git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 $head6..$head8: - > change -EOF + Submodule sm1 $head6..$head8: + > change + EOF test_cmp expected actual -" +' -test_expect_success 'modified submodule contains untracked content' " +test_expect_success 'modified submodule contains untracked content' ' echo new > sm1/new-file && git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 contains untracked content -Submodule sm1 $head6..$head8: - > change -EOF + Submodule sm1 contains untracked content + Submodule sm1 $head6..$head8: + > change + EOF test_cmp expected actual -" +' -test_expect_success 'modified submodule contains untracked content (untracked ignored)' " +test_expect_success 'modified submodule contains untracked content (untracked ignored)' ' git diff-index -p --ignore-submodules=untracked --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 $head6..$head8: - > change -EOF + Submodule sm1 $head6..$head8: + > change + EOF test_cmp expected actual -" +' -test_expect_success 'modified submodule contains untracked content (dirty ignored)' " +test_expect_success 'modified submodule contains untracked content (dirty ignored)' ' git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 $head6..$head8: - > change -EOF + Submodule sm1 $head6..$head8: + > change + EOF test_cmp expected actual -" +' -test_expect_success 'modified submodule contains untracked content (all ignored)' " +test_expect_success 'modified submodule contains untracked content (all ignored)' ' git diff-index -p --ignore-submodules=all --submodule=log HEAD >actual && ! test -s actual -" +' -test_expect_success 'modified submodule contains untracked and modifed content' " +test_expect_success 'modified submodule contains untracked and modifed content' ' echo modification >> sm1/foo6 && git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 contains untracked content -Submodule sm1 contains modified content -Submodule sm1 $head6..$head8: - > change -EOF + Submodule sm1 contains untracked content + Submodule sm1 contains modified content + Submodule sm1 $head6..$head8: + > change + EOF test_cmp expected actual -" +' -test_expect_success 'modified submodule contains untracked and modifed content (untracked ignored)' " +test_expect_success 'modified submodule contains untracked and modifed content (untracked ignored)' ' echo modification >> sm1/foo6 && git diff-index -p --ignore-submodules=untracked --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 contains modified content -Submodule sm1 $head6..$head8: - > change -EOF + Submodule sm1 contains modified content + Submodule sm1 $head6..$head8: + > change + EOF test_cmp expected actual -" +' -test_expect_success 'modified submodule contains untracked and modifed content (dirty ignored)' " +test_expect_success 'modified submodule contains untracked and modifed content (dirty ignored)' ' echo modification >> sm1/foo6 && git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 $head6..$head8: - > change -EOF + Submodule sm1 $head6..$head8: + > change + EOF test_cmp expected actual -" +' -test_expect_success 'modified submodule contains untracked and modifed content (all ignored)' " +test_expect_success 'modified submodule contains untracked and modifed content (all ignored)' ' echo modification >> sm1/foo6 && git diff-index -p --ignore-submodules --submodule=log HEAD >actual && ! test -s actual -" +' -test_expect_success 'modified submodule contains modifed content' " +test_expect_success 'modified submodule contains modifed content' ' rm -f sm1/new-file && git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 contains modified content -Submodule sm1 $head6..$head8: - > change -EOF + Submodule sm1 contains modified content + Submodule sm1 $head6..$head8: + > change + EOF test_cmp expected actual -" +' rm -rf sm1 -test_expect_success 'deleted submodule' " +test_expect_success 'deleted submodule' ' git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 $head6...0000000 (submodule deleted) -EOF + Submodule sm1 $head6...0000000 (submodule deleted) + EOF test_cmp expected actual -" +' test_create_repo sm2 && head7=$(add_file sm2 foo8 foo9) && git add sm2 -test_expect_success 'multiple submodules' " +test_expect_success 'multiple submodules' ' git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 $head6...0000000 (submodule deleted) -Submodule sm2 0000000...$head7 (new submodule) -EOF + Submodule sm1 $head6...0000000 (submodule deleted) + Submodule sm2 0000000...$head7 (new submodule) + EOF test_cmp expected actual -" +' -test_expect_success 'path filter' " +test_expect_success 'path filter' ' git diff-index -p --submodule=log HEAD sm2 >actual && cat >expected <<-EOF && -Submodule sm2 0000000...$head7 (new submodule) -EOF + Submodule sm2 0000000...$head7 (new submodule) + EOF test_cmp expected actual -" +' commit_file sm2 -test_expect_success 'given commit' " +test_expect_success 'given commit' ' git diff-index -p --submodule=log HEAD^ >actual && cat >expected <<-EOF && -Submodule sm1 $head6...0000000 (submodule deleted) -Submodule sm2 0000000...$head7 (new submodule) -EOF + Submodule sm1 $head6...0000000 (submodule deleted) + Submodule sm2 0000000...$head7 (new submodule) + EOF test_cmp expected actual -" +' -test_expect_success 'given commit --submodule' " +test_expect_success 'given commit --submodule' ' git diff-index -p --submodule HEAD^ >actual && cat >expected <<-EOF && -Submodule sm1 $head6...0000000 (submodule deleted) -Submodule sm2 0000000...$head7 (new submodule) -EOF + Submodule sm1 $head6...0000000 (submodule deleted) + Submodule sm2 0000000...$head7 (new submodule) + EOF test_cmp expected actual -" +' -fullhead7=$(cd sm2; git rev-list --max-count=1 $head7) +fullhead7=$(cd sm2; git rev-parse --verify HEAD) -test_expect_success 'given commit --submodule=short' " +test_expect_success 'given commit --submodule=short' ' git diff-index -p --submodule=short HEAD^ >actual && cat >expected <<-EOF && -diff --git a/sm1 b/sm1 -deleted file mode 160000 -index $head6..0000000 ---- a/sm1 -+++ /dev/null -@@ -1 +0,0 @@ --Subproject commit $fullhead6 -diff --git a/sm2 b/sm2 -new file mode 160000 -index 0000000..$head7 ---- /dev/null -+++ b/sm2 -@@ -0,0 +1 @@ -+Subproject commit $fullhead7 -EOF - test_cmp expected actual -" + diff --git a/sm1 b/sm1 + deleted file mode 160000 + index $head6..0000000 + --- a/sm1 + +++ /dev/null + @@ -1 +0,0 @@ + -Subproject commit $fullhead6 + diff --git a/sm2 b/sm2 + new file mode 160000 + index 0000000..$head7 + --- /dev/null + +++ b/sm2 + @@ -0,0 +1 @@ + +Subproject commit $fullhead7 + EOF + test_cmp expected actual +' test_expect_success 'setup .git file for sm2' ' (cd sm2 && @@ -452,9 +498,9 @@ test_expect_success 'setup .git file for sm2' ' test_expect_success 'diff --submodule with .git file' ' git diff --submodule HEAD^ >actual && cat >expected <<-EOF && -Submodule sm1 $head6...0000000 (submodule deleted) -Submodule sm2 0000000...$head7 (new submodule) -EOF + Submodule sm1 $head6...0000000 (submodule deleted) + Submodule sm2 0000000...$head7 (new submodule) + EOF test_cmp expected actual ' diff --git a/t/t4042-diff-textconv-caching.sh b/t/t4042-diff-textconv-caching.sh index 91f8198f05..04a44d5c61 100755 --- a/t/t4042-diff-textconv-caching.sh +++ b/t/t4042-diff-textconv-caching.sh @@ -106,4 +106,12 @@ test_expect_success 'switching diff driver produces correct results' ' test_cmp expect actual ' +# The point here is to test that we can log the notes cache and still use it to +# produce a diff later (older versions of git would segfault on this). It's +# much more likely to come up in the real world with "log --all -p", but using +# --no-walk lets us reliably reproduce the order of traversal. +test_expect_success 'log notes cache and still use cache for -p' ' + git log --no-walk -p refs/notes/textconv/magic HEAD +' + test_done diff --git a/t/t4055-diff-context.sh b/t/t4055-diff-context.sh new file mode 100755 index 0000000000..97172b46b2 --- /dev/null +++ b/t/t4055-diff-context.sh @@ -0,0 +1,92 @@ +#!/bin/sh +# +# Copyright (c) 2012 Mozilla Foundation +# + +test_description='diff.context configuration' + +. ./test-lib.sh + +test_expect_success 'setup' ' + cat >template <<-\EOF && + firstline + b + c + d + e + f + preline + TARGET + postline + i + j + k + l + m + n + EOF + sed "/TARGET/d" >x <template && + git update-index --add x && + git commit -m initial && + + sed "s/TARGET/ADDED/" >x <template && + git update-index --add x && + git commit -m next && + + sed "s/TARGET/MODIFIED/" >x <template +' + +test_expect_success 'the default number of context lines is 3' ' + git diff >output && + ! grep "^ d" output && + grep "^ e" output && + grep "^ j" output && + ! grep "^ k" output +' + +test_expect_success 'diff.context honored by "log"' ' + git log -1 -p >output && + ! grep firstline output && + git config diff.context 8 && + git log -1 -p >output && + grep "^ firstline" output +' + +test_expect_success 'The -U option overrides diff.context' ' + git config diff.context 8 && + git log -U4 -1 >output && + ! grep "^ firstline" output +' + +test_expect_success 'diff.context honored by "diff"' ' + git config diff.context 8 && + git diff >output && + grep "^ firstline" output +' + +test_expect_success 'plumbing not affected' ' + git config diff.context 8 && + git diff-files -p >output && + ! grep "^ firstline" output +' + +test_expect_success 'non-integer config parsing' ' + git config diff.context no && + test_must_fail git diff 2>output && + test_i18ngrep "bad config value" output +' + +test_expect_success 'negative integer config parsing' ' + git config diff.context -1 && + test_must_fail git diff 2>output && + test_i18ngrep "bad config file" output +' + +test_expect_success '-U0 is valid, so is diff.context=0' ' + git config diff.context 0 && + git diff >output && + grep "^-ADDED" output && + grep "^+MODIFIED" output +' + +test_done diff --git a/t/t4111-apply-subdir.sh b/t/t4111-apply-subdir.sh index 7c398432ba..1618a6dbc7 100755 --- a/t/t4111-apply-subdir.sh +++ b/t/t4111-apply-subdir.sh @@ -86,6 +86,20 @@ test_expect_success 'apply --index from subdir of toplevel' ' test_cmp expected sub/dir/file ' +test_expect_success 'apply half-broken patch from subdir of toplevel' ' + ( + cd sub/dir && + test_must_fail git apply <<-EOF + --- sub/dir/file + +++ sub/dir/file + @@ -1,0 +1,0 @@ + --- file_in_root + +++ file_in_root + @@ -1,0 +1,0 @@ + EOF + ) +' + test_expect_success 'apply from .git dir' ' cp postimage expected && cp preimage .git/file && diff --git a/t/t4114-apply-typechange.sh b/t/t4114-apply-typechange.sh index f12826fb09..ebadbc347f 100755 --- a/t/t4114-apply-typechange.sh +++ b/t/t4114-apply-typechange.sh @@ -9,20 +9,19 @@ test_description='git apply should not get confused with type changes. . ./test-lib.sh -test_expect_success SYMLINKS 'setup repository and commits' ' +test_expect_success 'setup repository and commits' ' echo "hello world" > foo && echo "hi planet" > bar && git update-index --add foo bar && git commit -m initial && git branch initial && rm -f foo && - ln -s bar foo && - git update-index foo && + test_ln_s_add bar foo && git commit -m "foo symlinked to bar" && git branch foo-symlinked-to-bar && - rm -f foo && + git rm -f foo && echo "how far is the sun?" > foo && - git update-index foo && + git update-index --add foo && git commit -m "foo back to file" && git branch foo-back-to-file && printf "\0" > foo && @@ -42,7 +41,7 @@ test_expect_success SYMLINKS 'setup repository and commits' ' git branch foo-baz-renamed-from-foo ' -test_expect_success SYMLINKS 'file renamed from foo to foo/baz' ' +test_expect_success 'file renamed from foo to foo/baz' ' git checkout -f initial && git diff-tree -M -p HEAD foo-baz-renamed-from-foo > patch && git apply --index < patch @@ -50,7 +49,7 @@ test_expect_success SYMLINKS 'file renamed from foo to foo/baz' ' test_debug 'cat patch' -test_expect_success SYMLINKS 'file renamed from foo/baz to foo' ' +test_expect_success 'file renamed from foo/baz to foo' ' git checkout -f foo-baz-renamed-from-foo && git diff-tree -M -p HEAD initial > patch && git apply --index < patch @@ -58,7 +57,7 @@ test_expect_success SYMLINKS 'file renamed from foo/baz to foo' ' test_debug 'cat patch' -test_expect_success SYMLINKS 'directory becomes file' ' +test_expect_success 'directory becomes file' ' git checkout -f foo-becomes-a-directory && git diff-tree -p HEAD initial > patch && git apply --index < patch @@ -66,7 +65,7 @@ test_expect_success SYMLINKS 'directory becomes file' ' test_debug 'cat patch' -test_expect_success SYMLINKS 'file becomes directory' ' +test_expect_success 'file becomes directory' ' git checkout -f initial && git diff-tree -p HEAD foo-becomes-a-directory > patch && git apply --index < patch @@ -74,7 +73,7 @@ test_expect_success SYMLINKS 'file becomes directory' ' test_debug 'cat patch' -test_expect_success SYMLINKS 'file becomes symlink' ' +test_expect_success 'file becomes symlink' ' git checkout -f initial && git diff-tree -p HEAD foo-symlinked-to-bar > patch && git apply --index < patch @@ -82,21 +81,21 @@ test_expect_success SYMLINKS 'file becomes symlink' ' test_debug 'cat patch' -test_expect_success SYMLINKS 'symlink becomes file' ' +test_expect_success 'symlink becomes file' ' git checkout -f foo-symlinked-to-bar && git diff-tree -p HEAD foo-back-to-file > patch && git apply --index < patch ' test_debug 'cat patch' -test_expect_success SYMLINKS 'binary file becomes symlink' ' +test_expect_success 'binary file becomes symlink' ' git checkout -f foo-becomes-binary && git diff-tree -p --binary HEAD foo-symlinked-to-bar > patch && git apply --index < patch ' test_debug 'cat patch' -test_expect_success SYMLINKS 'symlink becomes binary file' ' +test_expect_success 'symlink becomes binary file' ' git checkout -f foo-symlinked-to-bar && git diff-tree -p --binary HEAD foo-becomes-binary > patch && git apply --index < patch @@ -104,7 +103,7 @@ test_expect_success SYMLINKS 'symlink becomes binary file' ' test_debug 'cat patch' -test_expect_success SYMLINKS 'symlink becomes directory' ' +test_expect_success 'symlink becomes directory' ' git checkout -f foo-symlinked-to-bar && git diff-tree -p HEAD foo-becomes-a-directory > patch && git apply --index < patch @@ -112,7 +111,7 @@ test_expect_success SYMLINKS 'symlink becomes directory' ' test_debug 'cat patch' -test_expect_success SYMLINKS 'directory becomes symlink' ' +test_expect_success 'directory becomes symlink' ' git checkout -f foo-becomes-a-directory && git diff-tree -p HEAD foo-symlinked-to-bar > patch && git apply --index < patch diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh index 7674dd2ec9..872fcda6cb 100755 --- a/t/t4115-apply-symlink.sh +++ b/t/t4115-apply-symlink.sh @@ -9,18 +9,16 @@ test_description='git apply symlinks and partial files . ./test-lib.sh -test_expect_success SYMLINKS setup ' +test_expect_success setup ' - ln -s path1/path2/path3/path4/path5 link1 && - git add link? && + test_ln_s_add path1/path2/path3/path4/path5 link1 && git commit -m initial && git branch side && rm -f link? && - ln -s htap6 link1 && - git update-index link? && + test_ln_s_add htap6 link1 && git commit -m second && git diff-tree -p HEAD^ HEAD >patch && @@ -37,7 +35,7 @@ test_expect_success SYMLINKS 'apply symlink patch' ' ' -test_expect_success SYMLINKS 'apply --index symlink patch' ' +test_expect_success 'apply --index symlink patch' ' git checkout -f side && git apply --index patch && diff --git a/t/t4122-apply-symlink-inside.sh b/t/t4122-apply-symlink-inside.sh index 39407376ba..70b3a06e1d 100755 --- a/t/t4122-apply-symlink-inside.sh +++ b/t/t4122-apply-symlink-inside.sh @@ -10,11 +10,11 @@ lecho () { done } -test_expect_success SYMLINKS setup ' +test_expect_success setup ' mkdir -p arch/i386/boot arch/x86_64 && lecho 1 2 3 4 5 >arch/i386/boot/Makefile && - ln -s ../i386/boot arch/x86_64/boot && + test_ln_s_add ../i386/boot arch/x86_64/boot && git add . && test_tick && git commit -m initial && @@ -31,7 +31,7 @@ test_expect_success SYMLINKS setup ' ' -test_expect_success SYMLINKS apply ' +test_expect_success apply ' git checkout test && git diff --exit-code test && @@ -40,7 +40,7 @@ test_expect_success SYMLINKS apply ' ' -test_expect_success SYMLINKS 'check result' ' +test_expect_success 'check result' ' git diff --exit-code master && git diff --exit-code --cached master && diff --git a/t/t4124-apply-ws-rule.sh b/t/t4124-apply-ws-rule.sh index 6f6ee88b28..5d0c598338 100755 --- a/t/t4124-apply-ws-rule.sh +++ b/t/t4124-apply-ws-rule.sh @@ -47,7 +47,7 @@ test_fix () { # find touched lines $DIFF file target | sed -n -e "s/^> //p" >fixed - # the changed lines are all expeced to change + # the changed lines are all expected to change fixed_cnt=$(wc -l <fixed) case "$1" in '') expect_cnt=$fixed_cnt ;; @@ -486,4 +486,30 @@ test_expect_success 'same, but with CR-LF line endings && cr-at-eol unset' ' test_cmp one expect ' +test_expect_success 'whitespace=fix to expand' ' + qz_to_tab_space >preimage <<-\EOF && + QQa + QQb + QQc + ZZZZZZZZZZZZZZZZd + QQe + QQf + QQg + EOF + qz_to_tab_space >patch <<-\EOF && + diff --git a/preimage b/preimage + --- a/preimage + +++ b/preimage + @@ -1,7 +1,6 @@ + QQa + QQb + QQc + -QQd + QQe + QQf + QQg + EOF + git -c core.whitespace=tab-in-indent apply --whitespace=fix patch +' + test_done diff --git a/t/t4150-am.sh b/t/t4150-am.sh index cdafd7e7c1..5edb79a058 100755 --- a/t/t4150-am.sh +++ b/t/t4150-am.sh @@ -17,7 +17,7 @@ test_expect_success 'setup: messages' ' vero eos et accusam et justo duo dolores et ea rebum. EOF - q_to_tab <<-\EOF >>msg && + qz_to_tab_space <<-\EOF >>msg && QDuis autem vel eum iriure dolor in hendrerit in vulputate velit Qesse molestie consequat, vel illum dolore eu feugiat nulla facilisis Qat vero eros et accumsan et iusto odio dignissim qui blandit @@ -147,7 +147,7 @@ test_expect_success 'am applies patch correctly' ' git checkout first && test_tick && git am <patch1 && - ! test -d .git/rebase-apply && + test_path_is_missing .git/rebase-apply && git diff --exit-code second && test "$(git rev-parse second)" = "$(git rev-parse HEAD)" && test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)" @@ -158,7 +158,7 @@ test_expect_success 'am applies patch e-mail not in a mbox' ' git reset --hard && git checkout first && git am patch1.eml && - ! test -d .git/rebase-apply && + test_path_is_missing .git/rebase-apply && git diff --exit-code second && test "$(git rev-parse second)" = "$(git rev-parse HEAD)" && test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)" @@ -169,7 +169,7 @@ test_expect_success 'am applies patch e-mail not in a mbox with CRLF' ' git reset --hard && git checkout first && git am patch1-crlf.eml && - ! test -d .git/rebase-apply && + test_path_is_missing .git/rebase-apply && git diff --exit-code second && test "$(git rev-parse second)" = "$(git rev-parse HEAD)" && test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)" @@ -180,7 +180,7 @@ test_expect_success 'am applies patch e-mail with preceding whitespace' ' git reset --hard && git checkout first && git am patch1-ws.eml && - ! test -d .git/rebase-apply && + test_path_is_missing .git/rebase-apply && git diff --exit-code second && test "$(git rev-parse second)" = "$(git rev-parse HEAD)" && test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)" @@ -206,7 +206,7 @@ test_expect_success 'am changes committer and keeps author' ' git reset --hard && git checkout first && git am patch2 && - ! test -d .git/rebase-apply && + test_path_is_missing .git/rebase-apply && test "$(git rev-parse master^^)" = "$(git rev-parse HEAD^^)" && git diff --exit-code master..HEAD && git diff --exit-code master^..HEAD^ && @@ -258,7 +258,7 @@ test_expect_success 'am --keep really keeps the subject' ' git reset --hard && git checkout HEAD^ && git am --keep patch4 && - ! test -d .git/rebase-apply && + test_path_is_missing .git/rebase-apply && git cat-file commit HEAD >actual && grep "Re: Re: Re: \[PATCH 1/5 v2\] \[foo\] third" actual ' @@ -268,7 +268,7 @@ test_expect_success 'am --keep-non-patch really keeps the non-patch part' ' git reset --hard && git checkout HEAD^ && git am --keep-non-patch patch4 && - ! test -d .git/rebase-apply && + test_path_is_missing .git/rebase-apply && git cat-file commit HEAD >actual && grep "^\[foo\] third" actual ' @@ -283,7 +283,7 @@ test_expect_success 'am -3 falls back to 3-way merge' ' test_tick && git commit -m "copied stuff" && git am -3 lorem-move.patch && - ! test -d .git/rebase-apply && + test_path_is_missing .git/rebase-apply && git diff --exit-code lorem ' @@ -297,7 +297,7 @@ test_expect_success 'am -3 -p0 can read --no-prefix patch' ' test_tick && git commit -m "copied stuff" && git am -3 -p0 lorem-zero.patch && - ! test -d .git/rebase-apply && + test_path_is_missing .git/rebase-apply && git diff --exit-code lorem ' @@ -307,7 +307,7 @@ test_expect_success 'am can rename a file' ' git reset --hard && git checkout lorem^0 && git am rename.patch && - ! test -d .git/rebase-apply && + test_path_is_missing .git/rebase-apply && git update-index --refresh && git diff --exit-code rename ' @@ -318,7 +318,7 @@ test_expect_success 'am -3 can rename a file' ' git reset --hard && git checkout lorem^0 && git am -3 rename.patch && - ! test -d .git/rebase-apply && + test_path_is_missing .git/rebase-apply && git update-index --refresh && git diff --exit-code rename ' @@ -329,7 +329,7 @@ test_expect_success 'am -3 can rename a file after falling back to 3-way merge' git reset --hard && git checkout lorem^0 && git am -3 rename-add.patch && - ! test -d .git/rebase-apply && + test_path_is_missing .git/rebase-apply && git update-index --refresh && git diff --exit-code rename ' @@ -358,11 +358,17 @@ test_expect_success 'am pauses on conflict' ' test_expect_success 'am --skip works' ' echo goodbye >expected && git am --skip && - ! test -d .git/rebase-apply && + test_path_is_missing .git/rebase-apply && git diff --exit-code lorem2^^ -- file && test_cmp expected another ' +test_expect_success 'am --abort removes a stray directory' ' + mkdir .git/rebase-apply && + git am --abort && + test_path_is_missing .git/rebase-apply +' + test_expect_success 'am --resolved works' ' echo goodbye >expected && rm -fr .git/rebase-apply && @@ -373,7 +379,7 @@ test_expect_success 'am --resolved works' ' echo resolved >>file && git add file && git am --resolved && - ! test -d .git/rebase-apply && + test_path_is_missing .git/rebase-apply && test_cmp expected another ' @@ -382,7 +388,7 @@ test_expect_success 'am takes patches from a Pine mailbox' ' git reset --hard && git checkout first && cat pine patch1 | git am && - ! test -d .git/rebase-apply && + test_path_is_missing .git/rebase-apply && git diff --exit-code master^..HEAD ' @@ -391,7 +397,7 @@ test_expect_success 'am fails on mail without patch' ' git reset --hard && test_must_fail git am <failmail && git am --abort && - ! test -d .git/rebase-apply + test_path_is_missing .git/rebase-apply ' test_expect_success 'am fails on empty patch' ' @@ -400,7 +406,7 @@ test_expect_success 'am fails on empty patch' ' echo "---" >>failmail && test_must_fail git am <failmail && git am --skip && - ! test -d .git/rebase-apply + test_path_is_missing .git/rebase-apply ' test_expect_success 'am works from stdin in subdirectory' ' diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh index 6872ba1a42..5493500ef1 100755 --- a/t/t4201-shortlog.sh +++ b/t/t4201-shortlog.sh @@ -120,6 +120,30 @@ test_expect_success 'shortlog from non-git directory' ' test_cmp expect out ' +test_expect_success 'shortlog should add newline when input line matches wraplen' ' + cat >expect <<\EOF && +A U Thor (2): + bbbbbbbbbbbbbbbbbb: bbbbbbbb bbb bbbb bbbbbbb bb bbbb bbb bbbbb bbbbbb + aaaaaaaaaaaaaaaaaaaaaa: aaaaaa aaaaaaaaaa aaaa aaaaaaaa aa aaaa aa aaa + +EOF + git shortlog -w >out <<\EOF && +commit 0000000000000000000000000000000000000001 +Author: A U Thor <author@example.com> +Date: Thu Apr 7 15:14:13 2005 -0700 + + aaaaaaaaaaaaaaaaaaaaaa: aaaaaa aaaaaaaaaa aaaa aaaaaaaa aa aaaa aa aaa + +commit 0000000000000000000000000000000000000002 +Author: A U Thor <author@example.com> +Date: Thu Apr 7 15:14:13 2005 -0700 + + bbbbbbbbbbbbbbbbbb: bbbbbbbb bbb bbbb bbbbbbb bb bbbb bbb bbbbb bbbbbb + +EOF + test_cmp expect out +' + iconvfromutf8toiso88591() { printf "%s" "$*" | iconv -f UTF-8 -t ISO8859-1 } diff --git a/t/t4202-log.sh b/t/t4202-log.sh index a343bf6c62..cb03d28769 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -280,6 +280,16 @@ test_expect_success 'log --graph with merge' ' test_cmp expect actual ' +test_expect_success 'log --raw --graph -m with merge' ' + git log --raw --graph --oneline -m master | head -n 500 >actual && + grep "initial" actual +' + +test_expect_success 'diff-tree --graph' ' + git diff-tree --graph master^ | head -n 500 >actual && + grep "one" actual +' + cat > expect <<\EOF * commit master |\ Merge: A B @@ -409,8 +419,6 @@ test_expect_success 'log --graph with merge' ' ' test_expect_success 'log.decorate configuration' ' - test_might_fail git config --unset-all log.decorate && - git log --oneline >expect.none && git log --oneline --decorate >expect.short && git log --oneline --decorate=full >expect.full && @@ -419,8 +427,7 @@ test_expect_success 'log.decorate configuration' ' git log --oneline >actual && test_cmp expect.short actual && - git config --unset-all log.decorate && - git config log.decorate true && + test_config log.decorate true && git log --oneline >actual && test_cmp expect.short actual && git log --oneline --decorate=full >actual && @@ -428,8 +435,7 @@ test_expect_success 'log.decorate configuration' ' git log --oneline --decorate=no >actual && test_cmp expect.none actual && - git config --unset-all log.decorate && - git config log.decorate no && + test_config log.decorate no && git log --oneline >actual && test_cmp expect.none actual && git log --oneline --decorate >actual && @@ -437,8 +443,7 @@ test_expect_success 'log.decorate configuration' ' git log --oneline --decorate=full >actual && test_cmp expect.full actual && - git config --unset-all log.decorate && - git config log.decorate 1 && + test_config log.decorate 1 && git log --oneline >actual && test_cmp expect.short actual && git log --oneline --decorate=full >actual && @@ -446,8 +451,7 @@ test_expect_success 'log.decorate configuration' ' git log --oneline --decorate=no >actual && test_cmp expect.none actual && - git config --unset-all log.decorate && - git config log.decorate short && + test_config log.decorate short && git log --oneline >actual && test_cmp expect.short actual && git log --oneline --no-decorate >actual && @@ -455,8 +459,7 @@ test_expect_success 'log.decorate configuration' ' git log --oneline --decorate=full >actual && test_cmp expect.full actual && - git config --unset-all log.decorate && - git config log.decorate full && + test_config log.decorate full && git log --oneline >actual && test_cmp expect.full actual && git log --oneline --no-decorate >actual && @@ -464,16 +467,15 @@ test_expect_success 'log.decorate configuration' ' git log --oneline --decorate >actual && test_cmp expect.short actual - git config --unset-all log.decorate && + test_unconfig log.decorate && git log --pretty=raw >expect.raw && - git config log.decorate full && + test_config log.decorate full && git log --pretty=raw >actual && test_cmp expect.raw actual ' test_expect_success 'reflog is expected format' ' - test_might_fail git config --remove-section log && git log -g --abbrev-commit --pretty=oneline >expect && git reflog >actual && test_cmp expect actual @@ -486,10 +488,6 @@ test_expect_success 'whatchanged is expected format' ' ' test_expect_success 'log.abbrevCommit configuration' ' - test_when_finished "git config --unset log.abbrevCommit" && - - test_might_fail git config --unset log.abbrevCommit && - git log --abbrev-commit >expect.log.abbrev && git log --no-abbrev-commit >expect.log.full && git log --pretty=raw >expect.log.raw && @@ -498,7 +496,7 @@ test_expect_success 'log.abbrevCommit configuration' ' git whatchanged --abbrev-commit >expect.whatchanged.abbrev && git whatchanged --no-abbrev-commit >expect.whatchanged.full && - git config log.abbrevCommit true && + test_config log.abbrevCommit true && git log >actual && test_cmp expect.log.abbrev actual && @@ -532,6 +530,20 @@ test_expect_success 'show added path under "--follow -M"' ' ) ' +test_expect_success 'git log -c --follow' ' + test_create_repo follow-c && + ( + cd follow-c && + test_commit initial file original && + git rm file && + test_commit rename file2 original && + git reset --hard initial && + test_commit modify file foo && + git merge -m merge rename && + git log -c --follow file2 + ) +' + cat >expect <<\EOF * commit COMMIT_OBJECT_NAME |\ Merge: MERGE_PARENTS diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh index 1f182f612c..baa4685dcc 100755 --- a/t/t4203-mailmap.sh +++ b/t/t4203-mailmap.sh @@ -13,6 +13,11 @@ fuzz_blame () { } test_expect_success setup ' + cat >contacts <<-\EOF && + A U Thor <author@example.com> + nick1 <bugs@company.xx> + EOF + echo one >one && git add one && test_tick && @@ -23,6 +28,44 @@ test_expect_success setup ' git commit --author "nick1 <bugs@company.xx>" -m second ' +test_expect_success 'check-mailmap no arguments' ' + test_must_fail git check-mailmap +' + +test_expect_success 'check-mailmap arguments' ' + cat >expect <<-\EOF && + A U Thor <author@example.com> + nick1 <bugs@company.xx> + EOF + git check-mailmap \ + "A U Thor <author@example.com>" \ + "nick1 <bugs@company.xx>" >actual && + test_cmp expect actual +' + +test_expect_success 'check-mailmap --stdin' ' + cat >expect <<-\EOF && + A U Thor <author@example.com> + nick1 <bugs@company.xx> + EOF + git check-mailmap --stdin <contacts >actual && + test_cmp expect actual +' + +test_expect_success 'check-mailmap --stdin arguments' ' + cat >expect <<-\EOF && + Internal Guy <bugs@company.xy> + EOF + cat <contacts >>expect && + git check-mailmap --stdin "Internal Guy <bugs@company.xy>" \ + <contacts >actual && + test_cmp expect actual +' + +test_expect_success 'check-mailmap bogus contact' ' + test_must_fail git check-mailmap bogus +' + cat >expect <<\EOF A U Thor (1): initial @@ -149,6 +192,122 @@ test_expect_success 'No mailmap files, but configured' ' test_cmp expect actual ' +test_expect_success 'setup mailmap blob tests' ' + git checkout -b map && + test_when_finished "git checkout master" && + cat >just-bugs <<-\EOF && + Blob Guy <bugs@company.xx> + EOF + cat >both <<-\EOF && + Blob Guy <author@example.com> + Blob Guy <bugs@company.xx> + EOF + git add just-bugs both && + git commit -m "my mailmaps" && + echo "Repo Guy <author@example.com>" >.mailmap && + echo "Internal Guy <author@example.com>" >internal.map +' + +test_expect_success 'mailmap.blob set' ' + cat >expect <<-\EOF && + Blob Guy (1): + second + + Repo Guy (1): + initial + + EOF + git -c mailmap.blob=map:just-bugs shortlog HEAD >actual && + test_cmp expect actual +' + +test_expect_success 'mailmap.blob overrides .mailmap' ' + cat >expect <<-\EOF && + Blob Guy (2): + initial + second + + EOF + git -c mailmap.blob=map:both shortlog HEAD >actual && + test_cmp expect actual +' + +test_expect_success 'mailmap.file overrides mailmap.blob' ' + cat >expect <<-\EOF && + Blob Guy (1): + second + + Internal Guy (1): + initial + + EOF + git \ + -c mailmap.blob=map:both \ + -c mailmap.file=internal.map \ + shortlog HEAD >actual && + test_cmp expect actual +' + +test_expect_success 'mailmap.blob can be missing' ' + cat >expect <<-\EOF && + Repo Guy (1): + initial + + nick1 (1): + second + + EOF + git -c mailmap.blob=map:nonexistent shortlog HEAD >actual && + test_cmp expect actual +' + +test_expect_success 'mailmap.blob defaults to off in non-bare repo' ' + git init non-bare && + ( + cd non-bare && + test_commit one .mailmap "Fake Name <author@example.com>" && + echo " 1 Fake Name" >expect && + git shortlog -ns HEAD >actual && + test_cmp expect actual && + rm .mailmap && + echo " 1 A U Thor" >expect && + git shortlog -ns HEAD >actual && + test_cmp expect actual + ) +' + +test_expect_success 'mailmap.blob defaults to HEAD:.mailmap in bare repo' ' + git clone --bare non-bare bare && + ( + cd bare && + echo " 1 Fake Name" >expect && + git shortlog -ns HEAD >actual && + test_cmp expect actual + ) +' + +test_expect_success 'cleanup after mailmap.blob tests' ' + rm -f .mailmap +' + +test_expect_success 'single-character name' ' + echo " 1 A <author@example.com>" >expect && + echo " 1 nick1 <bugs@company.xx>" >>expect && + echo "A <author@example.com>" >.mailmap && + test_when_finished "rm .mailmap" && + git shortlog -es HEAD >actual && + test_cmp expect actual +' + +test_expect_success 'preserve canonical email case' ' + echo " 1 A U Thor <AUTHOR@example.com>" >expect && + echo " 1 nick1 <bugs@company.xx>" >>expect && + echo "<AUTHOR@example.com> <author@example.com>" >.mailmap && + test_when_finished "rm .mailmap" && + git shortlog -es HEAD >actual && + test_cmp expect actual +' + # Extended mailmap configurations should give us the following output for shortlog cat >expect <<\EOF A U Thor <author@example.com> (1): @@ -239,6 +398,62 @@ test_expect_success 'Log output (complex mapping)' ' test_cmp expect actual ' +cat >expect <<\EOF +Author: CTO <cto@company.xx> +Author: Santa Claus <santa.claus@northpole.xx> +Author: Santa Claus <santa.claus@northpole.xx> +Author: Other Author <other@author.xx> +Author: Other Author <other@author.xx> +Author: Some Dude <some@dude.xx> +Author: A U Thor <author@example.com> +EOF + +test_expect_success 'Log output with --use-mailmap' ' + git log --use-mailmap | grep Author >actual && + test_cmp expect actual +' + +cat >expect <<\EOF +Author: CTO <cto@company.xx> +Author: Santa Claus <santa.claus@northpole.xx> +Author: Santa Claus <santa.claus@northpole.xx> +Author: Other Author <other@author.xx> +Author: Other Author <other@author.xx> +Author: Some Dude <some@dude.xx> +Author: A U Thor <author@example.com> +EOF + +test_expect_success 'Log output with log.mailmap' ' + git -c log.mailmap=True log | grep Author >actual && + test_cmp expect actual +' + +cat >expect <<\EOF +Author: Santa Claus <santa.claus@northpole.xx> +Author: Santa Claus <santa.claus@northpole.xx> +EOF + +test_expect_success 'Grep author with --use-mailmap' ' + git log --use-mailmap --author Santa | grep Author >actual && + test_cmp expect actual +' +cat >expect <<\EOF +Author: Santa Claus <santa.claus@northpole.xx> +Author: Santa Claus <santa.claus@northpole.xx> +EOF + +test_expect_success 'Grep author with log.mailmap' ' + git -c log.mailmap=True log --author Santa | grep Author >actual && + test_cmp expect actual +' + +>expect + +test_expect_success 'Only grep replaced author with --use-mailmap' ' + git log --use-mailmap --author "<cto@coompany.xx>" >actual && + test_cmp expect actual +' + # git blame cat >expect <<\EOF ^OBJI (A U Thor DATE 1) one diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh index 98a43d457a..fb00041139 100755 --- a/t/t4205-log-pretty-formats.sh +++ b/t/t4205-log-pretty-formats.sh @@ -1,20 +1,38 @@ #!/bin/sh # # Copyright (c) 2010, Will Palmer +# Copyright (c) 2011, Alexey Shumkin (+ non-UTF-8 commit encoding tests) # test_description='Test pretty formats' . ./test-lib.sh +sample_utf8_part=$(printf "f\303\244ng") + +commit_msg () { + # String "initial. initial" partly in German + # (translated with Google Translate), + # encoded in UTF-8, used as a commit log message below. + msg="initial. an${sample_utf8_part}lich\n" + if test -n "$1" + then + printf "$msg" | iconv -f utf-8 -t "$1" + else + printf "$msg" + fi +} + test_expect_success 'set up basic repos' ' >foo && >bar && git add foo && test_tick && - git commit -m initial && + git config i18n.commitEncoding iso8859-1 && + git commit -m "$(commit_msg iso8859-1)" && git add bar && test_tick && - git commit -m "add bar" + git commit -m "add bar" && + git config --unset i18n.commitEncoding ' test_expect_success 'alias builtin format' ' @@ -38,6 +56,20 @@ test_expect_success 'alias user-defined format' ' test_cmp expected actual ' +test_expect_success 'alias user-defined tformat with %s (iso8859-1 encoding)' ' + git config i18n.logOutputEncoding iso8859-1 && + git log --oneline >expected-s && + git log --pretty="tformat:%h %s" >actual-s && + git config --unset i18n.logOutputEncoding && + test_cmp expected-s actual-s +' + +test_expect_success 'alias user-defined tformat with %s (utf-8 encoding)' ' + git log --oneline >expected-s && + git log --pretty="tformat:%h %s" >actual-s && + test_cmp expected-s actual-s +' + test_expect_success 'alias user-defined tformat' ' git log --pretty="tformat:%h" >expected && git config pretty.test-alias "tformat:%h" && @@ -72,13 +104,13 @@ test_expect_success 'alias loop' ' ' test_expect_success 'NUL separation' ' - printf "add bar\0initial" >expected && + printf "add bar\0$(commit_msg)" >expected && git log -z --pretty="format:%s" >actual && test_cmp expected actual ' test_expect_success 'NUL termination' ' - printf "add bar\0initial\0" >expected && + printf "add bar\0$(commit_msg)\0" >expected && git log -z --pretty="tformat:%s" >actual && test_cmp expected actual ' @@ -86,7 +118,7 @@ test_expect_success 'NUL termination' ' test_expect_success 'NUL separation with --stat' ' stat0_part=$(git diff --stat HEAD^ HEAD) && stat1_part=$(git diff-tree --no-commit-id --stat --root HEAD^) && - printf "add bar\n$stat0_part\n\0initial\n$stat1_part\n" >expected && + printf "add bar\n$stat0_part\n\0$(commit_msg)\n$stat1_part\n" >expected && git log -z --stat --pretty="format:%s" >actual && test_i18ncmp expected actual ' @@ -94,9 +126,188 @@ test_expect_success 'NUL separation with --stat' ' test_expect_failure 'NUL termination with --stat' ' stat0_part=$(git diff --stat HEAD^ HEAD) && stat1_part=$(git diff-tree --no-commit-id --stat --root HEAD^) && - printf "add bar\n$stat0_part\n\0initial\n$stat1_part\n\0" >expected && + printf "add bar\n$stat0_part\n\0$(commit_msg)\n$stat1_part\n0" >expected && git log -z --stat --pretty="tformat:%s" >actual && test_i18ncmp expected actual ' +test_expect_success 'setup more commits' ' + test_commit "message one" one one message-one && + test_commit "message two" two two message-two && + head1=$(git rev-parse --verify --short HEAD~0) && + head2=$(git rev-parse --verify --short HEAD~1) && + head3=$(git rev-parse --verify --short HEAD~2) && + head4=$(git rev-parse --verify --short HEAD~3) +' + +test_expect_success 'left alignment formatting' ' + git log --pretty="format:%<(40)%s" >actual && + # complete the incomplete line at the end + echo >>actual && + qz_to_tab_space <<EOF >expected && +message two Z +message one Z +add bar Z +$(commit_msg) Z +EOF + test_cmp expected actual +' + +test_expect_success 'left alignment formatting at the nth column' ' + git log --pretty="format:%h %<|(40)%s" >actual && + # complete the incomplete line at the end + echo >>actual && + qz_to_tab_space <<EOF >expected && +$head1 message two Z +$head2 message one Z +$head3 add bar Z +$head4 $(commit_msg) Z +EOF + test_cmp expected actual +' + +test_expect_success 'left alignment formatting with no padding' ' + git log --pretty="format:%<(1)%s" >actual && + # complete the incomplete line at the end + echo >>actual && + cat <<EOF >expected && +message two +message one +add bar +$(commit_msg) +EOF + test_cmp expected actual +' + +test_expect_success 'left alignment formatting with trunc' ' + git log --pretty="format:%<(10,trunc)%s" >actual && + # complete the incomplete line at the end + echo >>actual && + qz_to_tab_space <<EOF >expected && +message .. +message .. +add bar Z +initial... +EOF + test_cmp expected actual +' + +test_expect_success 'left alignment formatting with ltrunc' ' + git log --pretty="format:%<(10,ltrunc)%s" >actual && + # complete the incomplete line at the end + echo >>actual && + qz_to_tab_space <<EOF >expected && +..sage two +..sage one +add bar Z +..${sample_utf8_part}lich +EOF + test_cmp expected actual +' + +test_expect_success 'left alignment formatting with mtrunc' ' + git log --pretty="format:%<(10,mtrunc)%s" >actual && + # complete the incomplete line at the end + echo >>actual && + qz_to_tab_space <<EOF >expected && +mess.. two +mess.. one +add bar Z +init..lich +EOF + test_cmp expected actual +' + +test_expect_success 'right alignment formatting' ' + git log --pretty="format:%>(40)%s" >actual && + # complete the incomplete line at the end + echo >>actual && + qz_to_tab_space <<EOF >expected && +Z message two +Z message one +Z add bar +Z $(commit_msg) +EOF + test_cmp expected actual +' + +test_expect_success 'right alignment formatting at the nth column' ' + git log --pretty="format:%h %>|(40)%s" >actual && + # complete the incomplete line at the end + echo >>actual && + qz_to_tab_space <<EOF >expected && +$head1 message two +$head2 message one +$head3 add bar +$head4 $(commit_msg) +EOF + test_cmp expected actual +' + +test_expect_success 'right alignment formatting with no padding' ' + git log --pretty="format:%>(1)%s" >actual && + # complete the incomplete line at the end + echo >>actual && + cat <<EOF >expected && +message two +message one +add bar +$(commit_msg) +EOF + test_cmp expected actual +' + +test_expect_success 'center alignment formatting' ' + git log --pretty="format:%><(40)%s" >actual && + # complete the incomplete line at the end + echo >>actual && + qz_to_tab_space <<EOF >expected && +Z message two Z +Z message one Z +Z add bar Z +Z $(commit_msg) Z +EOF + test_cmp expected actual +' + +test_expect_success 'center alignment formatting at the nth column' ' + git log --pretty="format:%h %><|(40)%s" >actual && + # complete the incomplete line at the end + echo >>actual && + qz_to_tab_space <<EOF >expected && +$head1 message two Z +$head2 message one Z +$head3 add bar Z +$head4 $(commit_msg) Z +EOF + test_cmp expected actual +' + +test_expect_success 'center alignment formatting with no padding' ' + git log --pretty="format:%><(1)%s" >actual && + # complete the incomplete line at the end + echo >>actual && + cat <<EOF >expected && +message two +message one +add bar +$(commit_msg) +EOF + test_cmp expected actual +' + +test_expect_success 'left/right alignment formatting with stealing' ' + git commit --amend -m short --author "long long long <long@me.com>" && + git log --pretty="format:%<(10,trunc)%s%>>(10,ltrunc)% an" >actual && + # complete the incomplete line at the end + echo >>actual && + cat <<EOF >expected && +short long long long +message .. A U Thor +add bar A U Thor +initial... A U Thor +EOF + test_cmp expected actual +' + test_done diff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh index bbde31b019..925f577a3c 100755 --- a/t/t4207-log-decoration-colors.sh +++ b/t/t4207-log-decoration-colors.sh @@ -44,15 +44,15 @@ test_expect_success setup ' ' cat >expected <<EOF -${c_commit}COMMIT_ID (${c_HEAD}HEAD${c_reset}${c_commit},\ +${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_HEAD}HEAD${c_reset}${c_commit},\ ${c_tag}tag: v1.0${c_reset}${c_commit},\ ${c_tag}tag: B${c_reset}${c_commit},\ ${c_branch}master${c_reset}${c_commit})${c_reset} B -${c_commit}COMMIT_ID (${c_tag}tag: A1${c_reset}${c_commit},\ +${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_tag}tag: A1${c_reset}${c_commit},\ ${c_remoteBranch}other/master${c_reset}${c_commit})${c_reset} A1 -${c_commit}COMMIT_ID (${c_stash}refs/stash${c_reset}${c_commit})${c_reset}\ +${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_stash}refs/stash${c_reset}${c_commit})${c_reset}\ On master: Changes to A.t -${c_commit}COMMIT_ID (${c_tag}tag: A${c_reset}${c_commit})${c_reset} A +${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_tag}tag: A${c_reset}${c_commit})${c_reset} A EOF # We want log to show all, but the second parent to refs/stash is irrelevant diff --git a/t/t4208-log-magic-pathspec.sh b/t/t4208-log-magic-pathspec.sh index 2c482b622b..72300b5f24 100755 --- a/t/t4208-log-magic-pathspec.sh +++ b/t/t4208-log-magic-pathspec.sh @@ -11,11 +11,24 @@ test_expect_success 'setup' ' mkdir sub ' -test_expect_success '"git log :/" should be ambiguous' ' - test_must_fail git log :/ 2>error && +test_expect_success '"git log :/" should not be ambiguous' ' + git log :/ +' + +test_expect_success '"git log :/a" should be ambiguous (applied both rev and worktree)' ' + : >a && + test_must_fail git log :/a 2>error && grep ambiguous error ' +test_expect_success '"git log :/a -- " should not be ambiguous' ' + git log :/a -- +' + +test_expect_success '"git log -- :/a" should not be ambiguous' ' + git log -- :/a +' + test_expect_success '"git log :" should be ambiguous' ' test_must_fail git log : 2>error && grep ambiguous error diff --git a/t/t4209-log-pickaxe.sh b/t/t4209-log-pickaxe.sh index eed727341d..38fb80f643 100755 --- a/t/t4209-log-pickaxe.sh +++ b/t/t4209-log-pickaxe.sh @@ -80,6 +80,20 @@ test_expect_success 'log -G -i (match)' ' test_cmp expect actual ' +test_expect_success 'log -G --textconv (missing textconv tool)' ' + echo "* diff=test" >.gitattributes && + test_must_fail git -c diff.test.textconv=missing log -Gfoo && + rm .gitattributes +' + +test_expect_success 'log -G --no-textconv (missing textconv tool)' ' + echo "* diff=test" >.gitattributes && + git -c diff.test.textconv=missing log -Gfoo --no-textconv >actual && + >expect && + test_cmp expect actual && + rm .gitattributes +' + test_expect_success 'log -S (nomatch)' ' git log -Spicked --format=%H >actual && >expect && @@ -116,4 +130,18 @@ test_expect_success 'log -S -i (nomatch)' ' test_cmp expect actual ' +test_expect_success 'log -S --textconv (missing textconv tool)' ' + echo "* diff=test" >.gitattributes && + test_must_fail git -c diff.test.textconv=missing log -Sfoo && + rm .gitattributes +' + +test_expect_success 'log -S --no-textconv (missing textconv tool)' ' + echo "* diff=test" >.gitattributes && + git -c diff.test.textconv=missing log -Sfoo --no-textconv >actual && + >expect && + test_cmp expect actual && + rm .gitattributes +' + test_done diff --git a/t/t4210-log-i18n.sh b/t/t4210-log-i18n.sh new file mode 100755 index 0000000000..52a74729ba --- /dev/null +++ b/t/t4210-log-i18n.sh @@ -0,0 +1,58 @@ +#!/bin/sh + +test_description='test log with i18n features' +. ./test-lib.sh + +# two forms of é +utf8_e=$(printf '\303\251') +latin1_e=$(printf '\351') + +test_expect_success 'create commits in different encodings' ' + test_tick && + cat >msg <<-EOF && + utf8 + + t${utf8_e}st + EOF + git add msg && + git -c i18n.commitencoding=utf8 commit -F msg && + cat >msg <<-EOF && + latin1 + + t${latin1_e}st + EOF + git add msg && + git -c i18n.commitencoding=ISO-8859-1 commit -F msg +' + +test_expect_success 'log --grep searches in log output encoding (utf8)' ' + cat >expect <<-\EOF && + latin1 + utf8 + EOF + git log --encoding=utf8 --format=%s --grep=$utf8_e >actual && + test_cmp expect actual +' + +test_expect_success 'log --grep searches in log output encoding (latin1)' ' + cat >expect <<-\EOF && + latin1 + utf8 + EOF + git log --encoding=ISO-8859-1 --format=%s --grep=$latin1_e >actual && + test_cmp expect actual +' + +test_expect_success 'log --grep does not find non-reencoded values (utf8)' ' + >expect && + git log --encoding=utf8 --format=%s --grep=$latin1_e >actual && + test_cmp expect actual +' + +test_expect_success 'log --grep does not find non-reencoded values (latin1)' ' + >expect && + git log --encoding=ISO-8859-1 --format=%s --grep=$utf8_e >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh new file mode 100755 index 0000000000..7665d6785c --- /dev/null +++ b/t/t4211-line-log.sh @@ -0,0 +1,80 @@ +#!/bin/sh + +test_description='test log -L' +. ./test-lib.sh + +test_expect_success 'setup (import history)' ' + git fast-import < "$TEST_DIRECTORY"/t4211/history.export && + git reset --hard +' + +canned_test_1 () { + test_expect_$1 "$2" " + git log $2 >actual && + test_cmp \"\$TEST_DIRECTORY\"/t4211/expect.$3 actual + " +} + +canned_test () { + canned_test_1 success "$@" +} +canned_test_failure () { + canned_test_1 failure "$@" +} + +test_bad_opts () { + test_expect_success "invalid args: $1" " + test_must_fail git log $1 2>errors && + grep '$2' errors + " +} + +canned_test "-L 4,12:a.c simple" simple-f +canned_test "-L 4,+9:a.c simple" simple-f +canned_test "-L '/long f/,/^}/:a.c' simple" simple-f +canned_test "-L :f:a.c simple" simple-f-to-main + +canned_test "-L '/main/,/^}/:a.c' simple" simple-main +canned_test "-L :main:a.c simple" simple-main-to-end + +canned_test "-L 1,+4:a.c simple" beginning-of-file + +canned_test "-L 20:a.c simple" end-of-file + +canned_test "-L '/long f/',/^}/:a.c -L /main/,/^}/:a.c simple" two-ranges +canned_test "-L 24,+1:a.c simple" vanishes-early + +canned_test "-M -L '/long f/,/^}/:b.c' move-support" move-support-f +canned_test "-M -L ':f:b.c' parallel-change" parallel-change-f-to-main + +canned_test "-L 4,12:a.c -L :main:a.c simple" multiple +canned_test "-L 4,18:a.c -L :main:a.c simple" multiple-overlapping +canned_test "-L :main:a.c -L 4,18:a.c simple" multiple-overlapping +canned_test "-L 4:a.c -L 8,12:a.c simple" multiple-superset +canned_test "-L 8,12:a.c -L 4:a.c simple" multiple-superset + +test_bad_opts "-L" "switch.*requires a value" +test_bad_opts "-L b.c" "argument.*not of the form" +test_bad_opts "-L 1:" "argument.*not of the form" +test_bad_opts "-L 1:nonexistent" "There is no path" +test_bad_opts "-L 1:simple" "There is no path" +test_bad_opts "-L '/foo:b.c'" "argument.*not of the form" +test_bad_opts "-L 1000:b.c" "has only.*lines" +test_bad_opts "-L 1,1000:b.c" "has only.*lines" +test_bad_opts "-L :b.c" "argument.*not of the form" +test_bad_opts "-L :foo:b.c" "no match" + +# There is a separate bug when an empty -L range is the first -L encountered, +# thus to demonstrate this particular bug, the empty -L range must follow a +# non-empty -L range. +test_expect_success '-L {empty-range} (any -L)' ' + n=$(expr $(wc -l <b.c) + 1) && + git log -L1,1:b.c -L$n:b.c +' + +test_expect_success '-L {empty-range} (first -L)' ' + n=$(expr $(wc -l <b.c) + 1) && + git log -L$n:b.c +' + +test_done diff --git a/t/t4211/expect.beginning-of-file b/t/t4211/expect.beginning-of-file new file mode 100644 index 0000000000..91b4054898 --- /dev/null +++ b/t/t4211/expect.beginning-of-file @@ -0,0 +1,43 @@ +commit 4a23ae5c98d59a58c6da036156959f2dc9f472ad +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:47:40 2013 +0100 + + change at very beginning + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -1,3 +1,4 @@ ++#include <unistd.h> + #include <stdio.h> + + long f(long x) + +commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:45:16 2013 +0100 + + touch both functions + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -1,3 +1,3 @@ + #include <stdio.h> + +-int f(int x) ++long f(long x) + +commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:44:48 2013 +0100 + + initial + +diff --git a/a.c b/a.c +--- /dev/null ++++ b/a.c +@@ -0,0 +1,3 @@ ++#include <stdio.h> ++ ++int f(int x) diff --git a/t/t4211/expect.end-of-file b/t/t4211/expect.end-of-file new file mode 100644 index 0000000000..bd25bb2f59 --- /dev/null +++ b/t/t4211/expect.end-of-file @@ -0,0 +1,62 @@ +commit 4659538844daa2849b1a9e7d6fadb96fcd26fc83 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:48:43 2013 +0100 + + change back to complete line + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -20,3 +20,5 @@ + printf("%ld\n", f(15)); + return 0; +-} +\ No newline at end of file ++} ++ ++/* incomplete lines are bad! */ + +commit 100b61a6f2f720f812620a9d10afb3a960ccb73c +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:48:10 2013 +0100 + + change to an incomplete line at end + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -20,3 +20,3 @@ + printf("%ld\n", f(15)); + return 0; +-} ++} +\ No newline at end of file + +commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:45:16 2013 +0100 + + touch both functions + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -19,3 +19,3 @@ +- printf("%d\n", f(15)); ++ printf("%ld\n", f(15)); + return 0; + } + +commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:44:48 2013 +0100 + + initial + +diff --git a/a.c b/a.c +--- /dev/null ++++ b/a.c +@@ -0,0 +18,3 @@ ++ printf("%d\n", f(15)); ++ return 0; ++} diff --git a/t/t4211/expect.move-support-f b/t/t4211/expect.move-support-f new file mode 100644 index 0000000000..c905e01bc2 --- /dev/null +++ b/t/t4211/expect.move-support-f @@ -0,0 +1,80 @@ +commit 6ce3c4ff690136099bb17e1a8766b75764726ea7 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:49:50 2013 +0100 + + another simple change + +diff --git a/b.c b/b.c +--- a/b.c ++++ b/b.c +@@ -4,9 +4,9 @@ + long f(long x) + { + int s = 0; + while (x) { +- x >>= 1; ++ x /= 2; + s++; + } + return s; + } + +commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:45:16 2013 +0100 + + touch both functions + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -3,9 +3,9 @@ +-int f(int x) ++long f(long x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; + } + +commit f04fb20f2c77850996cba739709acc6faecc58f7 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:44:55 2013 +0100 + + change f() + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -3,8 +3,9 @@ + int f(int x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } ++ return s; + } + +commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:44:48 2013 +0100 + + initial + +diff --git a/a.c b/a.c +--- /dev/null ++++ b/a.c +@@ -0,0 +3,8 @@ ++int f(int x) ++{ ++ int s = 0; ++ while (x) { ++ x >>= 1; ++ s++; ++ } ++} diff --git a/t/t4211/expect.multiple b/t/t4211/expect.multiple new file mode 100644 index 0000000000..76ad5b598c --- /dev/null +++ b/t/t4211/expect.multiple @@ -0,0 +1,104 @@ +commit 4659538844daa2849b1a9e7d6fadb96fcd26fc83 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:48:43 2013 +0100 + + change back to complete line + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -18,5 +18,7 @@ + int main () + { + printf("%ld\n", f(15)); + return 0; +-} +\ No newline at end of file ++} ++ ++/* incomplete lines are bad! */ + +commit 100b61a6f2f720f812620a9d10afb3a960ccb73c +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:48:10 2013 +0100 + + change to an incomplete line at end + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -18,5 +18,5 @@ + int main () + { + printf("%ld\n", f(15)); + return 0; +-} ++} +\ No newline at end of file + +commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:45:16 2013 +0100 + + touch both functions + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -3,9 +3,9 @@ +-int f(int x) ++long f(long x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; + } +@@ -17,5 +17,5 @@ + int main () + { +- printf("%d\n", f(15)); ++ printf("%ld\n", f(15)); + return 0; + } + +commit f04fb20f2c77850996cba739709acc6faecc58f7 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:44:55 2013 +0100 + + change f() + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -3,8 +3,9 @@ + int f(int x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } ++ return s; + } + +commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:44:48 2013 +0100 + + initial + +diff --git a/a.c b/a.c +--- /dev/null ++++ b/a.c +@@ -0,0 +3,8 @@ ++int f(int x) ++{ ++ int s = 0; ++ while (x) { ++ x >>= 1; ++ s++; ++ } ++} diff --git a/t/t4211/expect.multiple-overlapping b/t/t4211/expect.multiple-overlapping new file mode 100644 index 0000000000..d930b6eec4 --- /dev/null +++ b/t/t4211/expect.multiple-overlapping @@ -0,0 +1,187 @@ +commit 4659538844daa2849b1a9e7d6fadb96fcd26fc83 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:48:43 2013 +0100 + + change back to complete line + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -4,19 +4,21 @@ + long f(long x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; + } + + /* + * This is only an example! + */ + + int main () + { + printf("%ld\n", f(15)); + return 0; +-} +\ No newline at end of file ++} ++ ++/* incomplete lines are bad! */ + +commit 100b61a6f2f720f812620a9d10afb3a960ccb73c +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:48:10 2013 +0100 + + change to an incomplete line at end + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -4,19 +4,19 @@ + long f(long x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; + } + + /* + * This is only an example! + */ + + int main () + { + printf("%ld\n", f(15)); + return 0; +-} ++} +\ No newline at end of file + +commit 39b6eb2d5b706d3322184a169f666f25ed3fbd00 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:45:41 2013 +0100 + + touch comment + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -3,19 +3,19 @@ + long f(long x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; + } + + /* +- * A comment. ++ * This is only an example! + */ + + int main () + { + printf("%ld\n", f(15)); + return 0; + } + +commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:45:16 2013 +0100 + + touch both functions + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -3,19 +3,19 @@ +-int f(int x) ++long f(long x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; + } + + /* + * A comment. + */ + + int main () + { +- printf("%d\n", f(15)); ++ printf("%ld\n", f(15)); + return 0; + } + +commit f04fb20f2c77850996cba739709acc6faecc58f7 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:44:55 2013 +0100 + + change f() + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -3,18 +3,19 @@ + int f(int x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } ++ return s; + } + + /* + * A comment. + */ + + int main () + { + printf("%d\n", f(15)); + return 0; + } + +commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:44:48 2013 +0100 + + initial + +diff --git a/a.c b/a.c +--- /dev/null ++++ b/a.c +@@ -0,0 +3,18 @@ ++int f(int x) ++{ ++ int s = 0; ++ while (x) { ++ x >>= 1; ++ s++; ++ } ++} ++ ++/* ++ * A comment. ++ */ ++ ++int main () ++{ ++ printf("%d\n", f(15)); ++ return 0; ++} diff --git a/t/t4211/expect.multiple-superset b/t/t4211/expect.multiple-superset new file mode 100644 index 0000000000..d930b6eec4 --- /dev/null +++ b/t/t4211/expect.multiple-superset @@ -0,0 +1,187 @@ +commit 4659538844daa2849b1a9e7d6fadb96fcd26fc83 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:48:43 2013 +0100 + + change back to complete line + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -4,19 +4,21 @@ + long f(long x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; + } + + /* + * This is only an example! + */ + + int main () + { + printf("%ld\n", f(15)); + return 0; +-} +\ No newline at end of file ++} ++ ++/* incomplete lines are bad! */ + +commit 100b61a6f2f720f812620a9d10afb3a960ccb73c +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:48:10 2013 +0100 + + change to an incomplete line at end + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -4,19 +4,19 @@ + long f(long x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; + } + + /* + * This is only an example! + */ + + int main () + { + printf("%ld\n", f(15)); + return 0; +-} ++} +\ No newline at end of file + +commit 39b6eb2d5b706d3322184a169f666f25ed3fbd00 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:45:41 2013 +0100 + + touch comment + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -3,19 +3,19 @@ + long f(long x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; + } + + /* +- * A comment. ++ * This is only an example! + */ + + int main () + { + printf("%ld\n", f(15)); + return 0; + } + +commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:45:16 2013 +0100 + + touch both functions + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -3,19 +3,19 @@ +-int f(int x) ++long f(long x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; + } + + /* + * A comment. + */ + + int main () + { +- printf("%d\n", f(15)); ++ printf("%ld\n", f(15)); + return 0; + } + +commit f04fb20f2c77850996cba739709acc6faecc58f7 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:44:55 2013 +0100 + + change f() + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -3,18 +3,19 @@ + int f(int x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } ++ return s; + } + + /* + * A comment. + */ + + int main () + { + printf("%d\n", f(15)); + return 0; + } + +commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:44:48 2013 +0100 + + initial + +diff --git a/a.c b/a.c +--- /dev/null ++++ b/a.c +@@ -0,0 +3,18 @@ ++int f(int x) ++{ ++ int s = 0; ++ while (x) { ++ x >>= 1; ++ s++; ++ } ++} ++ ++/* ++ * A comment. ++ */ ++ ++int main () ++{ ++ printf("%d\n", f(15)); ++ return 0; ++} diff --git a/t/t4211/expect.parallel-change-f-to-main b/t/t4211/expect.parallel-change-f-to-main new file mode 100644 index 0000000000..052def8074 --- /dev/null +++ b/t/t4211/expect.parallel-change-f-to-main @@ -0,0 +1,160 @@ +commit 0469c60bc4837d52d97b1f081dec5f98dea20fed +Merge: ba227c6 6ce3c4f +Author: Thomas Rast <trast@inf.ethz.ch> +Date: Fri Apr 12 16:16:24 2013 +0200 + + Merge across the rename + + +commit 6ce3c4ff690136099bb17e1a8766b75764726ea7 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:49:50 2013 +0100 + + another simple change + +diff --git a/b.c b/b.c +--- a/b.c ++++ b/b.c +@@ -4,14 +4,14 @@ + long f(long x) + { + int s = 0; + while (x) { +- x >>= 1; ++ x /= 2; + s++; + } + return s; + } + + /* + * This is only an example! + */ + + +commit ba227c6632349700fbb957dec2b50f5e2358be3f +Author: Thomas Rast <trast@inf.ethz.ch> +Date: Fri Apr 12 16:15:57 2013 +0200 + + change on another line of history while rename happens + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -4,14 +4,14 @@ + long f(long x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; + } + + /* +- * This is only an example! ++ * This is only a short example! + */ + + +commit 39b6eb2d5b706d3322184a169f666f25ed3fbd00 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:45:41 2013 +0100 + + touch comment + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -3,14 +3,14 @@ + long f(long x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; + } + + /* +- * A comment. ++ * This is only an example! + */ + + +commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:45:16 2013 +0100 + + touch both functions + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -3,14 +3,14 @@ +-int f(int x) ++long f(long x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; + } + + /* + * A comment. + */ + + +commit f04fb20f2c77850996cba739709acc6faecc58f7 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:44:55 2013 +0100 + + change f() + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -3,13 +3,14 @@ + int f(int x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } ++ return s; + } + + /* + * A comment. + */ + + +commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:44:48 2013 +0100 + + initial + +diff --git a/a.c b/a.c +--- /dev/null ++++ b/a.c +@@ -0,0 +3,13 @@ ++int f(int x) ++{ ++ int s = 0; ++ while (x) { ++ x >>= 1; ++ s++; ++ } ++} ++ ++/* ++ * A comment. ++ */ ++ diff --git a/t/t4211/expect.simple-f b/t/t4211/expect.simple-f new file mode 100644 index 0000000000..a1f5bc49c8 --- /dev/null +++ b/t/t4211/expect.simple-f @@ -0,0 +1,59 @@ +commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:45:16 2013 +0100 + + touch both functions + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -3,9 +3,9 @@ +-int f(int x) ++long f(long x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; + } + +commit f04fb20f2c77850996cba739709acc6faecc58f7 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:44:55 2013 +0100 + + change f() + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -3,8 +3,9 @@ + int f(int x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } ++ return s; + } + +commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:44:48 2013 +0100 + + initial + +diff --git a/a.c b/a.c +--- /dev/null ++++ b/a.c +@@ -0,0 +3,8 @@ ++int f(int x) ++{ ++ int s = 0; ++ while (x) { ++ x >>= 1; ++ s++; ++ } ++} diff --git a/t/t4211/expect.simple-f-to-main b/t/t4211/expect.simple-f-to-main new file mode 100644 index 0000000000..a475768710 --- /dev/null +++ b/t/t4211/expect.simple-f-to-main @@ -0,0 +1,100 @@ +commit 39b6eb2d5b706d3322184a169f666f25ed3fbd00 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:45:41 2013 +0100 + + touch comment + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -3,14 +3,14 @@ + long f(long x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; + } + + /* +- * A comment. ++ * This is only an example! + */ + + +commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:45:16 2013 +0100 + + touch both functions + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -3,14 +3,14 @@ +-int f(int x) ++long f(long x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; + } + + /* + * A comment. + */ + + +commit f04fb20f2c77850996cba739709acc6faecc58f7 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:44:55 2013 +0100 + + change f() + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -3,13 +3,14 @@ + int f(int x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } ++ return s; + } + + /* + * A comment. + */ + + +commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:44:48 2013 +0100 + + initial + +diff --git a/a.c b/a.c +--- /dev/null ++++ b/a.c +@@ -0,0 +3,13 @@ ++int f(int x) ++{ ++ int s = 0; ++ while (x) { ++ x >>= 1; ++ s++; ++ } ++} ++ ++/* ++ * A comment. ++ */ ++ diff --git a/t/t4211/expect.simple-main b/t/t4211/expect.simple-main new file mode 100644 index 0000000000..39ce39bebe --- /dev/null +++ b/t/t4211/expect.simple-main @@ -0,0 +1,68 @@ +commit 4659538844daa2849b1a9e7d6fadb96fcd26fc83 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:48:43 2013 +0100 + + change back to complete line + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -18,5 +18,5 @@ + int main () + { + printf("%ld\n", f(15)); + return 0; +-} +\ No newline at end of file ++} + +commit 100b61a6f2f720f812620a9d10afb3a960ccb73c +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:48:10 2013 +0100 + + change to an incomplete line at end + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -18,5 +18,5 @@ + int main () + { + printf("%ld\n", f(15)); + return 0; +-} ++} +\ No newline at end of file + +commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:45:16 2013 +0100 + + touch both functions + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -17,5 +17,5 @@ + int main () + { +- printf("%d\n", f(15)); ++ printf("%ld\n", f(15)); + return 0; + } + +commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:44:48 2013 +0100 + + initial + +diff --git a/a.c b/a.c +--- /dev/null ++++ b/a.c +@@ -0,0 +16,5 @@ ++int main () ++{ ++ printf("%d\n", f(15)); ++ return 0; ++} diff --git a/t/t4211/expect.simple-main-to-end b/t/t4211/expect.simple-main-to-end new file mode 100644 index 0000000000..8480bd9cc4 --- /dev/null +++ b/t/t4211/expect.simple-main-to-end @@ -0,0 +1,70 @@ +commit 4659538844daa2849b1a9e7d6fadb96fcd26fc83 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:48:43 2013 +0100 + + change back to complete line + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -18,5 +18,7 @@ + int main () + { + printf("%ld\n", f(15)); + return 0; +-} +\ No newline at end of file ++} ++ ++/* incomplete lines are bad! */ + +commit 100b61a6f2f720f812620a9d10afb3a960ccb73c +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:48:10 2013 +0100 + + change to an incomplete line at end + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -18,5 +18,5 @@ + int main () + { + printf("%ld\n", f(15)); + return 0; +-} ++} +\ No newline at end of file + +commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:45:16 2013 +0100 + + touch both functions + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -17,5 +17,5 @@ + int main () + { +- printf("%d\n", f(15)); ++ printf("%ld\n", f(15)); + return 0; + } + +commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:44:48 2013 +0100 + + initial + +diff --git a/a.c b/a.c +--- /dev/null ++++ b/a.c +@@ -0,0 +16,5 @@ ++int main () ++{ ++ printf("%d\n", f(15)); ++ return 0; ++} diff --git a/t/t4211/expect.two-ranges b/t/t4211/expect.two-ranges new file mode 100644 index 0000000000..6109aa0dce --- /dev/null +++ b/t/t4211/expect.two-ranges @@ -0,0 +1,102 @@ +commit 4659538844daa2849b1a9e7d6fadb96fcd26fc83 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:48:43 2013 +0100 + + change back to complete line + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -18,5 +18,5 @@ + int main () + { + printf("%ld\n", f(15)); + return 0; +-} +\ No newline at end of file ++} + +commit 100b61a6f2f720f812620a9d10afb3a960ccb73c +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:48:10 2013 +0100 + + change to an incomplete line at end + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -18,5 +18,5 @@ + int main () + { + printf("%ld\n", f(15)); + return 0; +-} ++} +\ No newline at end of file + +commit a6eb82647d5d67f893da442f8f9375fd89a3b1e2 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:45:16 2013 +0100 + + touch both functions + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -3,9 +3,9 @@ +-int f(int x) ++long f(long x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; + } +@@ -17,5 +17,5 @@ + int main () + { +- printf("%d\n", f(15)); ++ printf("%ld\n", f(15)); + return 0; + } + +commit f04fb20f2c77850996cba739709acc6faecc58f7 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:44:55 2013 +0100 + + change f() + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -3,8 +3,9 @@ + int f(int x) + { + int s = 0; + while (x) { + x >>= 1; + s++; + } ++ return s; + } + +commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:44:48 2013 +0100 + + initial + +diff --git a/a.c b/a.c +--- /dev/null ++++ b/a.c +@@ -0,0 +3,8 @@ ++int f(int x) ++{ ++ int s = 0; ++ while (x) { ++ x >>= 1; ++ s++; ++ } ++} diff --git a/t/t4211/expect.vanishes-early b/t/t4211/expect.vanishes-early new file mode 100644 index 0000000000..1f7cd06941 --- /dev/null +++ b/t/t4211/expect.vanishes-early @@ -0,0 +1,39 @@ +commit 4659538844daa2849b1a9e7d6fadb96fcd26fc83 +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:48:43 2013 +0100 + + change back to complete line + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -22,1 +24,1 @@ +-} +\ No newline at end of file ++/* incomplete lines are bad! */ + +commit 100b61a6f2f720f812620a9d10afb3a960ccb73c +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:48:10 2013 +0100 + + change to an incomplete line at end + +diff --git a/a.c b/a.c +--- a/a.c ++++ b/a.c +@@ -22,1 +22,1 @@ +-} ++} +\ No newline at end of file + +commit de4c48ae814792c02a49c4c3c0c757ae69c55f6a +Author: Thomas Rast <trast@student.ethz.ch> +Date: Thu Feb 28 10:44:48 2013 +0100 + + initial + +diff --git a/a.c b/a.c +--- /dev/null ++++ b/a.c +@@ -0,0 +20,1 @@ ++} diff --git a/t/t4211/history.export b/t/t4211/history.export new file mode 100644 index 0000000000..f9f41e211e --- /dev/null +++ b/t/t4211/history.export @@ -0,0 +1,406 @@ +blob +mark :1 +data 157 +#include <stdio.h> + +int f(int x) +{ + int s = 0; + while (x) { + x >>= 1; + s++; + } +} + +/* + * A comment. + */ + +int main () +{ + printf("%d\n", f(15)); + return 0; +} + +reset refs/tags/simple +commit refs/tags/simple +mark :2 +author Thomas Rast <trast@student.ethz.ch> 1362044688 +0100 +committer Thomas Rast <trast@student.ethz.ch> 1362044688 +0100 +data 8 +initial +M 100644 :1 a.c + +blob +mark :3 +data 168 +#include <stdio.h> + +int f(int x) +{ + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; +} + +/* + * A comment. + */ + +int main () +{ + printf("%d\n", f(15)); + return 0; +} + +commit refs/tags/simple +mark :4 +author Thomas Rast <trast@student.ethz.ch> 1362044695 +0100 +committer Thomas Rast <trast@student.ethz.ch> 1362044695 +0100 +data 11 +change f() +from :2 +M 100644 :3 a.c + +blob +mark :5 +data 171 +#include <stdio.h> + +long f(long x) +{ + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; +} + +/* + * A comment. + */ + +int main () +{ + printf("%ld\n", f(15)); + return 0; +} + +commit refs/tags/simple +mark :6 +author Thomas Rast <trast@student.ethz.ch> 1362044716 +0100 +committer Thomas Rast <trast@student.ethz.ch> 1362044716 +0100 +data 21 +touch both functions +from :4 +M 100644 :5 a.c + +blob +mark :7 +data 185 +#include <stdio.h> + +long f(long x) +{ + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; +} + +/* + * This is only an example! + */ + +int main () +{ + printf("%ld\n", f(15)); + return 0; +} + +commit refs/tags/simple +mark :8 +author Thomas Rast <trast@student.ethz.ch> 1362044741 +0100 +committer Thomas Rast <trast@student.ethz.ch> 1362044741 +0100 +data 14 +touch comment +from :6 +M 100644 :7 a.c + +blob +mark :9 +data 205 +#include <unistd.h> +#include <stdio.h> + +long f(long x) +{ + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; +} + +/* + * This is only an example! + */ + +int main () +{ + printf("%ld\n", f(15)); + return 0; +} + +commit refs/tags/simple +mark :10 +author Thomas Rast <trast@student.ethz.ch> 1362044860 +0100 +committer Thomas Rast <trast@student.ethz.ch> 1362044860 +0100 +data 25 +change at very beginning +from :8 +M 100644 :9 a.c + +blob +mark :11 +data 204 +#include <unistd.h> +#include <stdio.h> + +long f(long x) +{ + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; +} + +/* + * This is only an example! + */ + +int main () +{ + printf("%ld\n", f(15)); + return 0; +} +commit refs/tags/simple +mark :12 +author Thomas Rast <trast@student.ethz.ch> 1362044890 +0100 +committer Thomas Rast <trast@student.ethz.ch> 1362044890 +0100 +data 36 +change to an incomplete line at end +from :10 +M 100644 :11 a.c + +blob +mark :13 +data 238 +#include <unistd.h> +#include <stdio.h> + +long f(long x) +{ + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; +} + +/* + * This is only an example! + */ + +int main () +{ + printf("%ld\n", f(15)); + return 0; +} + +/* incomplete lines are bad! */ + +commit refs/tags/simple +mark :14 +author Thomas Rast <trast@student.ethz.ch> 1362044923 +0100 +committer Thomas Rast <trast@student.ethz.ch> 1362044923 +0100 +data 29 +change back to complete line +from :12 +M 100644 :13 a.c + +commit refs/tags/move-support +mark :15 +author Thomas Rast <trast@student.ethz.ch> 1362044968 +0100 +committer Thomas Rast <trast@student.ethz.ch> 1362044968 +0100 +data 10 +move file +from :14 +D a.c +M 100644 :13 b.c + +blob +mark :16 +data 237 +#include <unistd.h> +#include <stdio.h> + +long f(long x) +{ + int s = 0; + while (x) { + x /= 2; + s++; + } + return s; +} + +/* + * This is only an example! + */ + +int main () +{ + printf("%ld\n", f(15)); + return 0; +} + +/* incomplete lines are bad! */ + +commit refs/tags/move-support +mark :17 +author Thomas Rast <trast@student.ethz.ch> 1362044990 +0100 +committer Thomas Rast <trast@student.ethz.ch> 1362044990 +0100 +data 22 +another simple change +from :15 +M 100644 :16 b.c + +blob +mark :18 +data 254 +#include <unistd.h> +#include <stdio.h> + +long f(long x); + +/* + * This is only an example! + */ + +int main () +{ + printf("%ld\n", f(15)); + return 0; +} + +/* incomplete lines are bad! */ + +long f(long x) +{ + int s = 0; + while (x) { + x /= 2; + s++; + } + return s; +} + +commit refs/heads/master +mark :19 +author Thomas Rast <trast@student.ethz.ch> 1362045024 +0100 +committer Thomas Rast <trast@student.ethz.ch> 1362045024 +0100 +data 21 +move within the file +from :17 +M 100644 :18 b.c + +blob +mark :20 +data 243 +#include <unistd.h> +#include <stdio.h> + +long f(long x) +{ + int s = 0; + while (x) { + x >>= 1; + s++; + } + return s; +} + +/* + * This is only a short example! + */ + +int main () +{ + printf("%ld\n", f(15)); + return 0; +} + +/* incomplete lines are bad! */ + +commit refs/heads/parallel-change +mark :21 +author Thomas Rast <trast@inf.ethz.ch> 1365776157 +0200 +committer Thomas Rast <trast@inf.ethz.ch> 1365776157 +0200 +data 55 +change on another line of history while rename happens +from :14 +M 100644 :20 a.c + +blob +mark :22 +data 242 +#include <unistd.h> +#include <stdio.h> + +long f(long x) +{ + int s = 0; + while (x) { + x /= 2; + s++; + } + return s; +} + +/* + * This is only a short example! + */ + +int main () +{ + printf("%ld\n", f(15)); + return 0; +} + +/* incomplete lines are bad! */ + +commit refs/heads/parallel-change +mark :23 +author Thomas Rast <trast@inf.ethz.ch> 1365776184 +0200 +committer Thomas Rast <trast@inf.ethz.ch> 1365776191 +0200 +data 24 +Merge across the rename +from :21 +merge :17 +D a.c +M 100644 :22 b.c + +reset refs/heads/parallel-change +from :23 + diff --git a/t/t4212-log-corrupt.sh b/t/t4212-log-corrupt.sh new file mode 100755 index 0000000000..ec5099b83d --- /dev/null +++ b/t/t4212-log-corrupt.sh @@ -0,0 +1,42 @@ +#!/bin/sh + +test_description='git log with invalid commit headers' + +. ./test-lib.sh + +test_expect_success 'setup' ' + test_commit foo && + + git cat-file commit HEAD | + sed "/^author /s/>/>-<>/" >broken_email.commit && + git hash-object -w -t commit broken_email.commit >broken_email.hash && + git update-ref refs/heads/broken_email $(cat broken_email.hash) +' + +test_expect_success 'git log with broken author email' ' + { + echo commit $(cat broken_email.hash) + echo "Author: A U Thor <author@example.com>" + echo "Date: Thu Jan 1 00:00:00 1970 +0000" + echo + echo " foo" + } >expect.out && + : >expect.err && + + git log broken_email >actual.out 2>actual.err && + + test_cmp expect.out actual.out && + test_cmp expect.err actual.err +' + +test_expect_success 'git log --format with broken author email' ' + echo "A U Thor+author@example.com+" >expect.out && + : >expect.err && + + git log --format="%an+%ae+%ad" broken_email >actual.out 2>actual.err && + + test_cmp expect.out actual.out && + test_cmp expect.err actual.err +' + +test_done diff --git a/t/t4300-merge-tree.sh b/t/t4300-merge-tree.sh index 46c3fe76d3..9015e47654 100755 --- a/t/t4300-merge-tree.sh +++ b/t/t4300-merge-tree.sh @@ -26,8 +26,6 @@ EXPECTED test_expect_success 'file add !A, B' ' cat >expected <<\EXPECTED && -added in local - our 100644 43d5a8ed6ef6c00ff775008633f95787d088285d ONE EXPECTED git reset --hard initial && @@ -38,9 +36,6 @@ EXPECTED test_expect_success 'file add A, B (same)' ' cat >expected <<\EXPECTED && -added in both - our 100644 43d5a8ed6ef6c00ff775008633f95787d088285d ONE - their 100644 43d5a8ed6ef6c00ff775008633f95787d088285d ONE EXPECTED git reset --hard initial && @@ -181,9 +176,6 @@ AAA" && test_expect_success 'file remove A, !B' ' cat >expected <<\EXPECTED && -removed in local - base 100644 43d5a8ed6ef6c00ff775008633f95787d088285d ONE - their 100644 43d5a8ed6ef6c00ff775008633f95787d088285d ONE EXPECTED git reset --hard initial && @@ -213,6 +205,19 @@ EXPECTED test_cmp expected actual ' +test_expect_success 'file remove A, B (same)' ' + cat >expected <<\EXPECTED && +EXPECTED + + git reset --hard initial && + test_commit "rm-a-b-base" "ONE" "AAA" && + git rm ONE && + git commit -m "rm-a-b" && + git tag "rm-a-b" && + git merge-tree rm-a-b-base rm-a-b rm-a-b >actual && + test_cmp expected actual +' + test_expect_success 'file change A, remove B' ' cat >expected <<\EXPECTED && removed in remote @@ -254,4 +259,97 @@ EXPECTED test_cmp expected actual ' +test_expect_success 'tree add A, B (same)' ' + cat >expect <<-\EOF && + EOF + git reset --hard initial && + mkdir sub && + test_commit "add sub/file" "sub/file" "file" add-tree-A && + git merge-tree initial add-tree-A add-tree-A >actual && + test_cmp expect actual +' + +test_expect_success 'tree add A, B (different)' ' + cat >expect <<-\EOF && + added in both + our 100644 43d5a8ed6ef6c00ff775008633f95787d088285d sub/file + their 100644 ba629238ca89489f2b350e196ca445e09d8bb834 sub/file + @@ -1 +1,5 @@ + +<<<<<<< .our + AAA + +======= + +BBB + +>>>>>>> .their + EOF + git reset --hard initial && + mkdir sub && + test_commit "add sub/file" "sub/file" "AAA" add-tree-a-b-A && + git reset --hard initial && + mkdir sub && + test_commit "add sub/file" "sub/file" "BBB" add-tree-a-b-B && + git merge-tree initial add-tree-a-b-A add-tree-a-b-B >actual && + test_cmp expect actual +' + +test_expect_success 'tree unchanged A, removed B' ' + cat >expect <<-\EOF && + removed in remote + base 100644 43d5a8ed6ef6c00ff775008633f95787d088285d sub/file + our 100644 43d5a8ed6ef6c00ff775008633f95787d088285d sub/file + @@ -1 +0,0 @@ + -AAA + EOF + git reset --hard initial && + mkdir sub && + test_commit "add sub/file" "sub/file" "AAA" tree-remove-b-initial && + git rm sub/file && + test_tick && + git commit -m "remove sub/file" && + git tag tree-remove-b-B && + git merge-tree tree-remove-b-initial tree-remove-b-initial tree-remove-b-B >actual && + test_cmp expect actual +' + +test_expect_success 'turn file to tree' ' + git reset --hard initial && + rm initial-file && + mkdir initial-file && + test_commit "turn-file-to-tree" "initial-file/ONE" "CCC" && + git merge-tree initial initial turn-file-to-tree >actual && + cat >expect <<-\EOF && + added in remote + their 100644 43aa4fdec31eb92e1fdc2f0ce6ea9ddb7c32bcf7 initial-file/ONE + @@ -0,0 +1 @@ + +CCC + removed in remote + base 100644 e79c5e8f964493290a409888d5413a737e8e5dd5 initial-file + our 100644 e79c5e8f964493290a409888d5413a737e8e5dd5 initial-file + @@ -1 +0,0 @@ + -initial + EOF + test_cmp expect actual +' + +test_expect_success 'turn tree to file' ' + git reset --hard initial && + mkdir dir && + test_commit "add-tree" "dir/path" "AAA" && + test_commit "add-another-tree" "dir/another" "BBB" && + rm -fr dir && + test_commit "make-file" "dir" "CCC" && + git merge-tree add-tree add-another-tree make-file >actual && + cat >expect <<-\EOF && + removed in remote + base 100644 43d5a8ed6ef6c00ff775008633f95787d088285d dir/path + our 100644 43d5a8ed6ef6c00ff775008633f95787d088285d dir/path + @@ -1 +0,0 @@ + -AAA + added in remote + their 100644 43aa4fdec31eb92e1fdc2f0ce6ea9ddb7c32bcf7 dir + @@ -0,0 +1 @@ + +CCC + EOF + test_cmp expect actual +' + test_done diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index ecf00edab2..c2023b1a3d 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -25,36 +25,81 @@ commit id embedding: ' . ./test-lib.sh -UNZIP=${UNZIP:-unzip} GZIP=${GZIP:-gzip} GUNZIP=${GUNZIP:-gzip -d} SUBSTFORMAT=%H%n -check_zip() { - zipfile=$1.zip +test_lazy_prereq TAR_NEEDS_PAX_FALLBACK ' + ( + mkdir pax && + cd pax && + "$TAR" xf "$TEST_DIRECTORY"/t5000/pax.tar && + test -f PaxHeaders.1791/file + ) +' + +get_pax_header() { + file=$1 + header=$2= + + while read len rest + do + if test "$len" = $(echo "$len $rest" | wc -c) + then + case "$rest" in + $header*) + echo "${rest#$header}" + ;; + esac + fi + done <"$file" +} + +check_tar() { + tarfile=$1.tar 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" " + test_expect_success ' extract tar archive' ' + (mkdir $dir && cd $dir && "$TAR" xf -) <$tarfile + ' + + test_expect_success TAR_NEEDS_PAX_FALLBACK ' interpret pax headers' ' + ( + cd $dir && + for header in *.paxheader + do + data=${header%.paxheader}.data && + if test -h $data -o -e $data + then + path=$(get_pax_header $header path) && + if test -n "$path" + then + mv "$data" "$path" + fi + fi + done + ) + ' + + test_expect_success ' validate filenames' ' (cd ${dir_with_prefix}a && find .) | sort >$listfile && test_cmp a.lst $listfile - " + ' - test_expect_success UNZIP " validate file contents" " + test_expect_success ' validate file contents' ' diff -r a ${dir_with_prefix}a - " + ' } test_expect_success \ 'populate workdir' \ - 'mkdir a b c && + 'mkdir a && echo simple textfile >a/a && + ten=0123456789 && hundred=$ten$ten$ten$ten$ten$ten$ten$ten$ten$ten && + echo long filename >a/four$hundred && mkdir a/bin && cp /bin/sh a/bin && printf "A\$Format:%s\$O" "$SUBSTFORMAT" >a/substfile1 && @@ -83,6 +128,12 @@ test_expect_success \ git update-ref HEAD $(TZ=GMT GIT_COMMITTER_DATE="2005-05-27 22:00:00" \ git commit-tree $treeid </dev/null)' +test_expect_success 'setup export-subst' ' + echo "substfile?" export-subst >>.git/info/attributes && + git log --max-count=1 "--pretty=format:A${SUBSTFORMAT}O" HEAD \ + >a/substfile1 +' + test_expect_success \ 'create bare clone' \ 'git clone --bare . bare.git && @@ -96,13 +147,19 @@ test_expect_success \ 'git archive' \ 'git archive HEAD >b.tar' -test_expect_success \ - 'git tar-tree' \ - 'git tar-tree HEAD >b2.tar' +check_tar b -test_expect_success \ - 'git archive vs. git tar-tree' \ - 'test_cmp b.tar b2.tar' +test_expect_success 'git archive --prefix=prefix/' ' + git archive --prefix=prefix/ HEAD >with_prefix.tar +' + +check_tar with_prefix prefix/ + +test_expect_success 'git-archive --prefix=olde-' ' + git archive --prefix=olde- HEAD >with_olde-prefix.tar +' + +check_tar with_olde-prefix olde- test_expect_success 'git archive on large files' ' test_config core.bigfilethreshold 1 && @@ -139,96 +196,14 @@ test_expect_success \ 'git get-tar-commit-id <b.tar >b.commitid && test_cmp .git/$(git symbolic-ref HEAD) b.commitid' -test_expect_success \ - 'extract tar archive' \ - '(cd b && "$TAR" xf -) <b.tar' - -test_expect_success \ - 'validate filenames' \ - '(cd b/a && find .) | sort >b.lst && - test_cmp a.lst b.lst' - -test_expect_success \ - 'validate file contents' \ - 'diff -r a b/a' - -test_expect_success \ - 'git tar-tree with prefix' \ - 'git tar-tree HEAD prefix >c.tar' - -test_expect_success \ - 'extract tar archive with prefix' \ - '(cd c && "$TAR" xf -) <c.tar' - -test_expect_success \ - 'validate filenames with prefix' \ - '(cd c/prefix/a && find .) | sort >c.lst && - test_cmp a.lst c.lst' - -test_expect_success \ - 'validate file contents with prefix' \ - 'diff -r a c/prefix/a' - -test_expect_success \ - 'create archives with substfiles' \ - 'cp .git/info/attributes .git/info/attributes.before && - echo "substfile?" export-subst >>.git/info/attributes && - git archive HEAD >f.tar && - git archive --prefix=prefix/ HEAD >g.tar && - mv .git/info/attributes.before .git/info/attributes' - -test_expect_success \ - 'extract substfiles' \ - '(mkdir f && cd f && "$TAR" xf -) <f.tar' - -test_expect_success \ - 'validate substfile contents' \ - 'git log --max-count=1 "--pretty=format:A${SUBSTFORMAT}O" HEAD \ - >f/a/substfile1.expected && - test_cmp f/a/substfile1.expected f/a/substfile1 && - test_cmp a/substfile2 f/a/substfile2 -' - -test_expect_success \ - 'extract substfiles from archive with prefix' \ - '(mkdir g && cd g && "$TAR" xf -) <g.tar' - -test_expect_success \ - 'validate substfile contents from archive with prefix' \ - 'git log --max-count=1 "--pretty=format:A${SUBSTFORMAT}O" HEAD \ - >g/prefix/a/substfile1.expected && - test_cmp g/prefix/a/substfile1.expected g/prefix/a/substfile1 && - test_cmp a/substfile2 g/prefix/a/substfile2 +test_expect_success 'git tar-tree' ' + git tar-tree HEAD >tar-tree.tar && + test_cmp b.tar tar-tree.tar ' -$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' - -test_expect_success \ - 'git archive --format=zip vs. the same in a bare repo' \ - 'test_cmp d.zip d1.zip' - -test_expect_success 'git archive --format=zip with --output' \ - 'git archive --format=zip --output=d2.zip HEAD && - test_cmp d.zip d2.zip' - -test_expect_success 'git archive with --output, inferring format' ' - git archive --output=d3.zip HEAD && - test_cmp d.zip d3.zip +test_expect_success 'git tar-tree with prefix' ' + git tar-tree HEAD prefix >tar-tree_with_prefix.tar && + test_cmp with_prefix.tar tar-tree_with_prefix.tar ' test_expect_success 'git archive with --output, override inferred format' ' @@ -237,26 +212,6 @@ test_expect_success 'git archive with --output, override inferred format' ' ' test_expect_success \ - 'git archive --format=zip with prefix' \ - 'git archive --format=zip --prefix=prefix/ HEAD >e.zip' - -check_zip e prefix/ - -test_expect_success 'git archive -0 --format=zip on large files' ' - test_config core.bigfilethreshold 1 && - git archive -0 --format=zip HEAD >large.zip -' - -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' \ 'GIT_DIR=some/non-existing/directory git archive --list' @@ -268,22 +223,11 @@ test_expect_success 'clients cannot access unreachable commits' ' test_must_fail git archive --remote=. $sha1 >remote.tar ' -test_expect_success 'git-archive --prefix=olde-' ' - git archive --prefix=olde- >h.tar HEAD && - ( - mkdir h && - cd h && - "$TAR" xf - <../h.tar - ) && - test -d h/olde-a && - test -d h/olde-a/bin && - test -f h/olde-a/bin/sh -' - test_expect_success 'setup tar filters' ' git config tar.tar.foo.command "tr ab ba" && git config tar.bar.command "tr ab ba" && - git config tar.bar.remote true + git config tar.bar.remote true && + git config tar.invalid baz ' test_expect_success 'archive --list mentions user filter' ' diff --git a/t/t5000/pax.tar b/t/t5000/pax.tar Binary files differnew file mode 100644 index 0000000000..d911737149 --- /dev/null +++ b/t/t5000/pax.tar diff --git a/t/t5002-archive-attr-pattern.sh b/t/t5002-archive-attr-pattern.sh new file mode 100755 index 0000000000..6667d159ab --- /dev/null +++ b/t/t5002-archive-attr-pattern.sh @@ -0,0 +1,84 @@ +#!/bin/sh + +test_description='git archive attribute pattern tests' + +. ./test-lib.sh + +test_expect_exists() { + test_expect_success " $1 exists" "test -e $1" +} + +test_expect_missing() { + test_expect_success " $1 does not exist" "test ! -e $1" +} + +test_expect_success 'setup' ' + echo ignored >ignored && + echo ignored export-ignore >>.git/info/attributes && + git add ignored && + + mkdir not-ignored-dir && + echo ignored-in-tree >not-ignored-dir/ignored && + echo not-ignored-in-tree >not-ignored-dir/ignored-only-if-dir && + git add not-ignored-dir && + + mkdir ignored-only-if-dir && + echo ignored by ignored dir >ignored-only-if-dir/ignored-by-ignored-dir && + echo ignored-only-if-dir/ export-ignore >>.git/info/attributes && + git add ignored-only-if-dir && + + mkdir -p ignored-without-slash && + echo "ignored without slash" >ignored-without-slash/foo && + git add ignored-without-slash/foo && + echo "ignored-without-slash export-ignore" >>.git/info/attributes && + + mkdir -p wildcard-without-slash && + echo "ignored without slash" >wildcard-without-slash/foo && + git add wildcard-without-slash/foo && + echo "wild*-without-slash export-ignore" >>.git/info/attributes && + + mkdir -p deep/and/slashless && + echo "ignored without slash" >deep/and/slashless/foo && + git add deep/and/slashless/foo && + echo "deep/and/slashless export-ignore" >>.git/info/attributes && + + mkdir -p deep/with/wildcard && + echo "ignored without slash" >deep/with/wildcard/foo && + git add deep/with/wildcard/foo && + echo "deep/*t*/wildcard export-ignore" >>.git/info/attributes && + + mkdir -p one-level-lower/two-levels-lower/ignored-only-if-dir && + echo ignored by ignored dir >one-level-lower/two-levels-lower/ignored-only-if-dir/ignored-by-ignored-dir && + git add one-level-lower && + + git commit -m. && + + git clone --bare . bare && + cp .git/info/attributes bare/info/attributes +' + +test_expect_success 'git archive' ' + git archive HEAD >archive.tar && + (mkdir archive && cd archive && "$TAR" xf -) <archive.tar +' + +test_expect_missing archive/ignored +test_expect_missing archive/not-ignored-dir/ignored +test_expect_exists archive/not-ignored-dir/ignored-only-if-dir +test_expect_exists archive/not-ignored-dir/ +test_expect_missing archive/ignored-only-if-dir/ +test_expect_missing archive/ignored-ony-if-dir/ignored-by-ignored-dir +test_expect_missing archive/ignored-without-slash/ && +test_expect_missing archive/ignored-without-slash/foo && +test_expect_missing archive/wildcard-without-slash/ +test_expect_missing archive/wildcard-without-slash/foo && +test_expect_missing archive/deep/and/slashless/ && +test_expect_missing archive/deep/and/slashless/foo && +test_expect_missing archive/deep/with/wildcard/ && +test_expect_missing archive/deep/with/wildcard/foo && +test_expect_exists archive/one-level-lower/ +test_expect_missing archive/one-level-lower/two-levels-lower/ignored-only-if-dir/ +test_expect_missing archive/one-level-lower/two-levels-lower/ignored-ony-if-dir/ignored-by-ignored-dir + + +test_done diff --git a/t/t5003-archive-zip.sh b/t/t5003-archive-zip.sh new file mode 100755 index 0000000000..c72f71eb18 --- /dev/null +++ b/t/t5003-archive-zip.sh @@ -0,0 +1,131 @@ +#!/bin/sh + +test_description='git archive --format=zip test' + +. ./test-lib.sh + +SUBSTFORMAT=%H%n + +test_lazy_prereq UNZIP_SYMLINKS ' + ( + mkdir unzip-symlinks && + cd unzip-symlinks && + "$GIT_UNZIP" "$TEST_DIRECTORY"/t5003/infozip-symlinks.zip && + test -h symlink + ) +' + +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 && "$GIT_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 && + echo simple textfile >a/a && + mkdir a/bin && + cp /bin/sh a/bin && + printf "A\$Format:%s\$O" "$SUBSTFORMAT" >a/substfile1 && + printf "A not substituted O" >a/substfile2 && + (p=long_path_to_a_file && cd a && + for depth in 1 2 3 4 5; do mkdir $p && cd $p; done && + echo text >file_with_long_path) +' + +test_expect_success SYMLINKS,UNZIP_SYMLINKS 'add symlink' ' + ln -s a a/symlink_to_a +' + +test_expect_success 'prepare file list' ' + (cd a && find .) | sort >a.lst +' + +test_expect_success \ + 'add ignored file' \ + 'echo ignore me >a/ignored && + echo ignored export-ignore >.git/info/attributes' + +test_expect_success \ + 'add files to repository' \ + 'find a -type f | xargs git update-index --add && + find a -type l | xargs git update-index --add && + treeid=`git write-tree` && + echo $treeid >treeid && + git update-ref HEAD $(TZ=GMT GIT_COMMITTER_DATE="2005-05-27 22:00:00" \ + git commit-tree $treeid </dev/null)' + +test_expect_success 'setup export-subst' ' + echo "substfile?" export-subst >>.git/info/attributes && + git log --max-count=1 "--pretty=format:A${SUBSTFORMAT}O" HEAD \ + >a/substfile1 +' + +test_expect_success \ + 'create bare clone' \ + 'git clone --bare . bare.git && + cp .git/info/attributes bare.git/info/attributes' + +test_expect_success \ + 'remove ignored file' \ + 'rm a/ignored' + +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' + +test_expect_success \ + 'git archive --format=zip vs. the same in a bare repo' \ + 'test_cmp d.zip d1.zip' + +test_expect_success 'git archive --format=zip with --output' \ + 'git archive --format=zip --output=d2.zip HEAD && + test_cmp d.zip d2.zip' + +test_expect_success 'git archive with --output, inferring format' ' + git archive --output=d3.zip HEAD && + test_cmp d.zip d3.zip +' + +test_expect_success \ + 'git archive --format=zip with prefix' \ + 'git archive --format=zip --prefix=prefix/ HEAD >e.zip' + +check_zip e prefix/ + +test_expect_success 'git archive -0 --format=zip on large files' ' + test_config core.bigfilethreshold 1 && + git archive -0 --format=zip HEAD >large.zip +' + +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_done diff --git a/t/t5003/infozip-symlinks.zip b/t/t5003/infozip-symlinks.zip Binary files differnew file mode 100644 index 0000000000..065728c631 --- /dev/null +++ b/t/t5003/infozip-symlinks.zip diff --git a/t/t5004-archive-corner-cases.sh b/t/t5004-archive-corner-cases.sh new file mode 100755 index 0000000000..67f3b54bed --- /dev/null +++ b/t/t5004-archive-corner-cases.sh @@ -0,0 +1,116 @@ +#!/bin/sh + +test_description='test corner cases of git-archive' +. ./test-lib.sh + +test_expect_success 'create commit with empty tree' ' + git commit --allow-empty -m foo +' + +# Make a dir and clean it up afterwards +make_dir() { + mkdir "$1" && + test_when_finished "rm -rf '$1'" +} + +# Check that the dir given in "$1" contains exactly the +# set of paths given as arguments. +check_dir() { + dir=$1; shift + { + echo "$dir" && + for i in "$@"; do + echo "$dir/$i" + done + } | sort >expect && + find "$dir" ! -name pax_global_header -print | sort >actual && + test_cmp expect actual +} + + +# bsdtar/libarchive versions before 3.1.3 consider a tar file with a +# global pax header that is not followed by a file record as corrupt. +if "$TAR" tf "$TEST_DIRECTORY"/t5004/empty-with-pax-header.tar >/dev/null 2>&1 +then + test_set_prereq HEADER_ONLY_TAR_OK +fi + +test_expect_success HEADER_ONLY_TAR_OK 'tar archive of commit with empty tree' ' + git archive --format=tar HEAD >empty-with-pax-header.tar && + make_dir extract && + "$TAR" xf empty-with-pax-header.tar -C extract && + check_dir extract +' + +test_expect_success 'tar archive of empty tree is empty' ' + git archive --format=tar HEAD: >empty.tar && + perl -e "print \"\\0\" x 10240" >10knuls.tar && + test_cmp 10knuls.tar empty.tar +' + +test_expect_success 'tar archive of empty tree with prefix' ' + git archive --format=tar --prefix=foo/ HEAD >prefix.tar && + make_dir extract && + "$TAR" xf prefix.tar -C extract && + check_dir extract foo +' + +test_expect_success UNZIP 'zip archive of empty tree is empty' ' + # Detect the exit code produced when our particular flavor of unzip + # sees an empty archive. Infozip will generate a warning and exit with + # code 1. But in the name of sanity, we do not expect other unzip + # implementations to do the same thing (it would be perfectly + # reasonable to exit 0, for example). + # + # This makes our test less rigorous on some platforms (unzip may not + # handle the empty repo at all, making our later check of its exit code + # a no-op). But we cannot do anything reasonable except skip the test + # on such platforms anyway, and this is the moral equivalent. + "$GIT_UNZIP" "$TEST_DIRECTORY"/t5004/empty.zip + expect_code=$? + + git archive --format=zip HEAD >empty.zip && + make_dir extract && + ( + cd extract && + test_expect_code $expect_code "$GIT_UNZIP" ../empty.zip + ) && + check_dir extract +' + +test_expect_success UNZIP 'zip archive of empty tree with prefix' ' + # We do not have to play exit-code tricks here, because our + # result should not be empty; it has a directory in it. + git archive --format=zip --prefix=foo/ HEAD >prefix.zip && + make_dir extract && + ( + cd extract && + "$GIT_UNZIP" ../prefix.zip + ) && + check_dir extract foo +' + +test_expect_success 'archive complains about pathspec on empty tree' ' + test_must_fail git archive --format=tar HEAD -- foo >/dev/null +' + +test_expect_success 'create a commit with an empty subtree' ' + empty_tree=$(git hash-object -t tree /dev/null) && + root_tree=$(printf "040000 tree $empty_tree\tsub\n" | git mktree) +' + +test_expect_success 'archive empty subtree with no pathspec' ' + git archive --format=tar $root_tree >subtree-all.tar && + make_dir extract && + "$TAR" xf subtree-all.tar -C extract && + check_dir extract sub +' + +test_expect_success 'archive empty subtree by direct pathspec' ' + git archive --format=tar $root_tree -- sub >subtree-path.tar && + make_dir extract && + "$TAR" xf subtree-path.tar -C extract && + check_dir extract sub +' + +test_done diff --git a/t/t5004/empty-with-pax-header.tar b/t/t5004/empty-with-pax-header.tar Binary files differnew file mode 100644 index 0000000000..da9e39e6cf --- /dev/null +++ b/t/t5004/empty-with-pax-header.tar diff --git a/t/t5004/empty.zip b/t/t5004/empty.zip Binary files differnew file mode 100644 index 0000000000..1a76bb6005 --- /dev/null +++ b/t/t5004/empty.zip diff --git a/t/t5150-request-pull.sh b/t/t5150-request-pull.sh index 432f98c357..1afa0d5c44 100755 --- a/t/t5150-request-pull.sh +++ b/t/t5150-request-pull.sh @@ -80,12 +80,12 @@ test_expect_success 'setup: two scripts for reading pull requests' ' cat <<-EOT >fuzz.sed #!/bin/sed -nf + s/$downstream_url_for_sed/URL/g s/$_x40/OBJECT_NAME/g s/A U Thor/AUTHOR/g s/[-0-9]\{10\} [:0-9]\{8\} [-+][0-9]\{4\}/DATE/g s/ [^ ].*/ SUBJECT/g s/ [^ ].* (DATE)/ SUBJECT (DATE)/g - s/$downstream_url_for_sed/URL/g s/for-upstream/BRANCH/g s/mnemonic.txt/FILENAME/g s/^version [0-9]/VERSION/ diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh index 5b1250f0d2..35926debe3 100755 --- a/t/t5303-pack-corruption-resilience.sh +++ b/t/t5303-pack-corruption-resilience.sh @@ -51,7 +51,7 @@ do_corrupt_object() { ofs=`git show-index < ${pack}.idx | grep $1 | cut -f1 -d" "` && ofs=$(($ofs + $2)) && chmod +w ${pack}.pack && - dd of=${pack}.pack count=1 bs=1 conv=notrunc seek=$ofs && + dd of=${pack}.pack bs=1 conv=notrunc seek=$ofs && test_must_fail git verify-pack ${pack}.pack } @@ -276,6 +276,33 @@ test_expect_success \ git cat-file blob $blob_3 > /dev/null' test_expect_success \ + 'corruption of delta base reference pointing to wrong object' \ + 'create_new_pack --delta-base-offset && + git prune-packed && + printf "\220\033" | do_corrupt_object $blob_3 2 && + git cat-file blob $blob_1 >/dev/null && + git cat-file blob $blob_2 >/dev/null && + test_must_fail git cat-file blob $blob_3 >/dev/null' + +test_expect_success \ + '... but having a loose copy allows for full recovery' \ + 'mv ${pack}.idx tmp && + git hash-object -t blob -w file_3 && + mv tmp ${pack}.idx && + git cat-file blob $blob_1 > /dev/null && + git cat-file blob $blob_2 > /dev/null && + git cat-file blob $blob_3 > /dev/null' + +test_expect_success \ + '... and then a repack "clears" the corruption' \ + 'do_repack --delta-base-offset --no-reuse-delta && + git prune-packed && + git verify-pack ${pack}.pack && + git cat-file blob $blob_1 > /dev/null && + git cat-file blob $blob_2 > /dev/null && + git cat-file blob $blob_3 > /dev/null' + +test_expect_success \ 'corrupting header to have too small output buffer fails unpack' \ 'create_new_pack && git prune-packed && diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh index d645328609..e4bb3a1457 100755 --- a/t/t5304-prune.sh +++ b/t/t5304-prune.sh @@ -195,4 +195,30 @@ test_expect_success 'gc: prune old objects after local clone' ' ) ' +test_expect_success 'garbage report in count-objects -v' ' + : >.git/objects/pack/foo && + : >.git/objects/pack/foo.bar && + : >.git/objects/pack/foo.keep && + : >.git/objects/pack/foo.pack && + : >.git/objects/pack/fake.bar && + : >.git/objects/pack/fake.keep && + : >.git/objects/pack/fake.pack && + : >.git/objects/pack/fake.idx && + : >.git/objects/pack/fake2.keep && + : >.git/objects/pack/fake3.idx && + git count-objects -v 2>stderr && + grep "index file .git/objects/pack/fake.idx is too small" stderr && + grep "^warning:" stderr | sort >actual && + cat >expected <<\EOF && +warning: garbage found: .git/objects/pack/fake.bar +warning: garbage found: .git/objects/pack/foo +warning: garbage found: .git/objects/pack/foo.bar +warning: no corresponding .idx nor .pack: .git/objects/pack/fake2.keep +warning: no corresponding .idx: .git/objects/pack/foo.keep +warning: no corresponding .idx: .git/objects/pack/foo.pack +warning: no corresponding .pack: .git/objects/pack/fake3.idx +EOF + test_cmp expected actual +' + test_done diff --git a/t/t5404-tracking-branches.sh b/t/t5404-tracking-branches.sh index c24003565d..2b8c0bac7d 100755 --- a/t/t5404-tracking-branches.sh +++ b/t/t5404-tracking-branches.sh @@ -36,7 +36,7 @@ test_expect_success 'prepare pushable branches' ' ' test_expect_success 'mixed-success push returns error' ' - test_must_fail git push + test_must_fail git push origin : ' test_expect_success 'check tracking branches updated correctly after push' ' diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh index baa670cea5..ea2e0d4b48 100755 --- a/t/t5407-post-rewrite-hook.sh +++ b/t/t5407-post-rewrite-hook.sh @@ -31,8 +31,8 @@ clear_hook_input () { } verify_hook_input () { - test_cmp "$TRASH_DIRECTORY"/post-rewrite.args expected.args && - test_cmp "$TRASH_DIRECTORY"/post-rewrite.data expected.data + test_cmp expected.args "$TRASH_DIRECTORY"/post-rewrite.args && + test_cmp expected.data "$TRASH_DIRECTORY"/post-rewrite.data } test_expect_success 'git commit --amend' ' diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh index 6322e8ade8..fd2598e601 100755 --- a/t/t5500-fetch-pack.sh +++ b/t/t5500-fetch-pack.sh @@ -130,16 +130,32 @@ test_expect_success 'single given branch clone' ' test_must_fail git --git-dir=branch-a/.git rev-parse origin/B ' +test_expect_success 'clone shallow depth 1' ' + git clone --no-single-branch --depth 1 "file://$(pwd)/." shallow0 && + test "`git --git-dir=shallow0/.git rev-list --count HEAD`" = 1 +' + +test_expect_success 'clone shallow depth 1 with fsck' ' + git config --global fetch.fsckobjects true && + git clone --no-single-branch --depth 1 "file://$(pwd)/." shallow0fsck && + test "`git --git-dir=shallow0fsck/.git rev-list --count HEAD`" = 1 && + git config --global --unset fetch.fsckobjects +' + test_expect_success 'clone shallow' ' git clone --no-single-branch --depth 2 "file://$(pwd)/." shallow ' +test_expect_success 'clone shallow depth count' ' + test "`git --git-dir=shallow/.git rev-list --count HEAD`" = 2 +' + test_expect_success 'clone shallow object count' ' ( cd shallow && git count-objects -v ) > count.shallow && - grep "^in-pack: 18" count.shallow + grep "^in-pack: 12" count.shallow ' test_expect_success 'clone shallow object count (part 2)' ' @@ -256,12 +272,36 @@ test_expect_success 'additional simple shallow deepenings' ' ) ' +test_expect_success 'clone shallow depth count' ' + test "`git --git-dir=shallow/.git rev-list --count HEAD`" = 11 +' + test_expect_success 'clone shallow object count' ' ( cd shallow && git count-objects -v ) > count.shallow && - grep "^count: 52" count.shallow + grep "^count: 55" count.shallow +' + +test_expect_success 'fetch --no-shallow on full repo' ' + test_must_fail git fetch --noshallow +' + +test_expect_success 'fetch --depth --no-shallow' ' + ( + cd shallow && + test_must_fail git fetch --depth=1 --noshallow + ) +' + +test_expect_success 'turn shallow to complete repository' ' + ( + cd shallow && + git fetch --unshallow && + ! test -f .git/shallow && + git fsck --full + ) ' test_expect_success 'clone shallow without --no-single-branch' ' @@ -273,7 +313,7 @@ test_expect_success 'clone shallow object count' ' cd shallow2 && git count-objects -v ) > count.shallow2 && - grep "^in-pack: 6" count.shallow2 + grep "^in-pack: 3" count.shallow2 ' test_expect_success 'clone shallow with --branch' ' @@ -281,7 +321,7 @@ test_expect_success 'clone shallow with --branch' ' ' test_expect_success 'clone shallow object count' ' - echo "in-pack: 6" > count3.expected && + echo "in-pack: 3" > count3.expected && GIT_DIR=shallow3/.git git count-objects -v | grep "^in-pack" > count3.actual && test_cmp count3.expected count3.actual @@ -310,7 +350,7 @@ EOF GIT_DIR=shallow6/.git git tag -l >taglist.actual && test_cmp taglist.expected taglist.actual && - echo "in-pack: 7" > count6.expected && + echo "in-pack: 4" > count6.expected && GIT_DIR=shallow6/.git git count-objects -v | grep "^in-pack" > count6.actual && test_cmp count6.expected count6.actual @@ -325,12 +365,35 @@ EOF GIT_DIR=shallow7/.git git tag -l >taglist.actual && test_cmp taglist.expected taglist.actual && - echo "in-pack: 7" > count7.expected && + echo "in-pack: 4" > count7.expected && GIT_DIR=shallow7/.git git count-objects -v | grep "^in-pack" > count7.actual && test_cmp count7.expected count7.actual ' +test_expect_success 'clone shallow with packed refs' ' + git pack-refs --all && + git clone --depth 1 --branch A "file://$(pwd)/." shallow8 && + echo "in-pack: 4" > count8.expected && + GIT_DIR=shallow8/.git git count-objects -v | + grep "^in-pack" > count8.actual && + test_cmp count8.expected count8.actual +' + +test_expect_success 'fetch in shallow repo unreachable shallow objects' ' + ( + git clone --bare --branch B --single-branch "file://$(pwd)/." no-reflog && + git clone --depth 1 "file://$(pwd)/no-reflog" shallow9 && + cd no-reflog && + git tag -d TAGB1 TAGB2 && + git update-ref refs/heads/B B~~ && + git gc --prune=now && + cd ../shallow9 && + git fetch origin && + git fsck --no-dangling + ) +' + test_expect_success 'setup tests for the --stdin parameter' ' for head in C D E F do diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh index 60de2d6ede..f30c03885c 100755 --- a/t/t5503-tagfollow.sh +++ b/t/t5503-tagfollow.sh @@ -4,10 +4,6 @@ test_description='test automatic tag following' . ./test-lib.sh -if ! test_have_prereq NOT_MINGW; then - say "GIT_DEBUG_SEND_PACK not supported - skipping tests" -fi - # End state of the repository: # # T - tag1 S - tag2 @@ -17,7 +13,7 @@ fi # \ C - origin/cat \ # origin/master master -test_expect_success NOT_MINGW setup ' +test_expect_success setup ' test_tick && echo ichi >file && git add file && @@ -39,28 +35,35 @@ test_expect_success NOT_MINGW setup ' ' U=UPLOAD_LOG +UPATH="$(pwd)/$U" -test_expect_success NOT_MINGW 'setup expect' ' +test_expect_success 'setup expect' ' cat - <<EOF >expect -#S want $A -#E EOF ' -test_expect_success NOT_MINGW 'fetch A (new commit : 1 connection)' ' +get_needs () { + test -s "$1" && + perl -alne ' + next unless $F[1] eq "upload-pack<"; + last if $F[2] eq "0000"; + print $F[2], " ", $F[3]; + ' "$1" +} + +test_expect_success 'fetch A (new commit : 1 connection)' ' rm -f $U && ( cd cloned && - GIT_DEBUG_SEND_PACK=3 git fetch 3>../$U && + GIT_TRACE_PACKET=$UPATH git fetch && test $A = $(git rev-parse --verify origin/master) ) && - test -s $U && - cut -d" " -f1,2 $U >actual && + get_needs $U >actual && test_cmp expect actual ' -test_expect_success NOT_MINGW "create tag T on A, create C on branch cat" ' +test_expect_success "create tag T on A, create C on branch cat" ' git tag -a -m tag1 tag1 $A && T=$(git rev-parse --verify tag1) && @@ -72,30 +75,27 @@ test_expect_success NOT_MINGW "create tag T on A, create C on branch cat" ' git checkout master ' -test_expect_success NOT_MINGW 'setup expect' ' +test_expect_success 'setup expect' ' cat - <<EOF >expect -#S want $C want $T -#E EOF ' -test_expect_success NOT_MINGW 'fetch C, T (new branch, tag : 1 connection)' ' +test_expect_success 'fetch C, T (new branch, tag : 1 connection)' ' rm -f $U && ( cd cloned && - GIT_DEBUG_SEND_PACK=3 git fetch 3>../$U && + GIT_TRACE_PACKET=$UPATH git fetch && test $C = $(git rev-parse --verify origin/cat) && test $T = $(git rev-parse --verify tag1) && test $A = $(git rev-parse --verify tag1^0) ) && - test -s $U && - cut -d" " -f1,2 $U >actual && + get_needs $U >actual && test_cmp expect actual ' -test_expect_success NOT_MINGW "create commits O, B, tag S on B" ' +test_expect_success "create commits O, B, tag S on B" ' test_tick && echo O >file && git add file && @@ -111,39 +111,34 @@ test_expect_success NOT_MINGW "create commits O, B, tag S on B" ' S=$(git rev-parse --verify tag2) ' -test_expect_success NOT_MINGW 'setup expect' ' +test_expect_success 'setup expect' ' cat - <<EOF >expect -#S want $B want $S -#E EOF ' -test_expect_success NOT_MINGW 'fetch B, S (commit and tag : 1 connection)' ' +test_expect_success 'fetch B, S (commit and tag : 1 connection)' ' rm -f $U && ( cd cloned && - GIT_DEBUG_SEND_PACK=3 git fetch 3>../$U && + GIT_TRACE_PACKET=$UPATH git fetch && test $B = $(git rev-parse --verify origin/master) && test $B = $(git rev-parse --verify tag2^0) && test $S = $(git rev-parse --verify tag2) ) && - test -s $U && - cut -d" " -f1,2 $U >actual && + get_needs $U >actual && test_cmp expect actual ' -test_expect_success NOT_MINGW 'setup expect' ' +test_expect_success 'setup expect' ' cat - <<EOF >expect -#S want $B want $S -#E EOF ' -test_expect_success NOT_MINGW 'new clone fetch master and tags' ' +test_expect_success 'new clone fetch master and tags' ' git branch -D cat rm -f $U ( @@ -151,15 +146,14 @@ test_expect_success NOT_MINGW 'new clone fetch master and tags' ' cd clone2 && git init && git remote add origin .. && - GIT_DEBUG_SEND_PACK=3 git fetch 3>../$U && + GIT_TRACE_PACKET=$UPATH git fetch && test $B = $(git rev-parse --verify origin/master) && test $S = $(git rev-parse --verify tag2) && test $B = $(git rev-parse --verify tag2^0) && test $T = $(git rev-parse --verify tag1) && test $A = $(git rev-parse --verify tag1^0) ) && - test -s $U && - cut -d" " -f1,2 $U >actual && + get_needs $U >actual && test_cmp expect actual ' diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index ccc55ebf4b..8f6e3922dc 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -42,107 +42,104 @@ check_tracking_branch () { } test_expect_success setup ' - setup_repository one && setup_repository two && ( - cd two && git branch another + cd two && + git branch another ) && git clone one test - ' test_expect_success C_LOCALE_OUTPUT 'remote information for the origin' ' -( - cd test && - tokens_match origin "$(git remote)" && - check_remote_track origin master side && - check_tracking_branch origin HEAD master side -) + ( + cd test && + tokens_match origin "$(git remote)" && + check_remote_track origin master side && + check_tracking_branch origin HEAD master side + ) ' test_expect_success 'add another remote' ' -( - cd test && - git remote add -f second ../two && - tokens_match "origin second" "$(git remote)" && - check_tracking_branch second master side another && - git for-each-ref "--format=%(refname)" refs/remotes | - sed -e "/^refs\/remotes\/origin\//d" \ - -e "/^refs\/remotes\/second\//d" >actual && - >expect && - test_cmp expect actual -) + ( + cd test && + git remote add -f second ../two && + tokens_match "origin second" "$(git remote)" && + check_tracking_branch second master side another && + git for-each-ref "--format=%(refname)" refs/remotes | + sed -e "/^refs\/remotes\/origin\//d" \ + -e "/^refs\/remotes\/second\//d" >actual && + >expect && + test_cmp expect actual + ) ' -test_expect_success C_LOCALE_OUTPUT 'check remote tracking' ' -( - cd test && - check_remote_track origin master side && - check_remote_track second master side another -) +test_expect_success C_LOCALE_OUTPUT 'check remote-tracking' ' + ( + cd test && + check_remote_track origin master side && + check_remote_track second master side another + ) ' test_expect_success 'remote forces tracking branches' ' -( - cd test && - case `git config remote.second.fetch` in - +*) true ;; - *) false ;; - esac -) + ( + cd test && + case `git config remote.second.fetch` in + +*) true ;; + *) false ;; + esac + ) ' test_expect_success 'remove remote' ' -( - cd test && - git symbolic-ref refs/remotes/second/HEAD refs/remotes/second/master && - git remote rm second -) + ( + cd test && + git symbolic-ref refs/remotes/second/HEAD refs/remotes/second/master && + git remote rm second + ) ' test_expect_success C_LOCALE_OUTPUT 'remove remote' ' -( - cd test && - tokens_match origin "$(git remote)" && - check_remote_track origin master side && - git for-each-ref "--format=%(refname)" refs/remotes | - sed -e "/^refs\/remotes\/origin\//d" >actual && - >expect && - test_cmp expect actual -) + ( + cd test && + tokens_match origin "$(git remote)" && + check_remote_track origin master side && + git for-each-ref "--format=%(refname)" refs/remotes | + sed -e "/^refs\/remotes\/origin\//d" >actual && + >expect && + test_cmp expect actual + ) ' test_expect_success 'remove remote protects local branches' ' -( - cd test && - { cat >expect1 <<EOF -Note: A branch outside the refs/remotes/ hierarchy was not removed; -to delete it, use: - git branch -d master -EOF - } && - { cat >expect2 <<EOF -Note: Some branches outside the refs/remotes/ hierarchy were not removed; -to delete them, use: - git branch -d foobranch - git branch -d master -EOF - } && - git tag footag && - git config --add remote.oops.fetch "+refs/*:refs/*" && - git remote remove oops 2>actual1 && - git branch foobranch && - git config --add remote.oops.fetch "+refs/*:refs/*" && - git remote rm oops 2>actual2 && - git branch -d foobranch && - git tag -d footag && - test_i18ncmp expect1 actual1 && - test_i18ncmp expect2 actual2 -) -' - -cat > test/expect << EOF + ( + cd test && + cat >expect1 <<-\EOF && + Note: A branch outside the refs/remotes/ hierarchy was not removed; + to delete it, use: + git branch -d master + EOF + cat >expect2 <<-\EOF && + Note: Some branches outside the refs/remotes/ hierarchy were not removed; + to delete them, use: + git branch -d foobranch + git branch -d master + EOF + git tag footag && + git config --add remote.oops.fetch "+refs/*:refs/*" && + git remote remove oops 2>actual1 && + git branch foobranch && + git config --add remote.oops.fetch "+refs/*:refs/*" && + git remote rm oops 2>actual2 && + git branch -d foobranch && + git tag -d footag && + test_i18ncmp expect1 actual1 && + test_i18ncmp expect2 actual2 + ) +' + +cat >test/expect <<EOF * remote origin Fetch URL: $(pwd)/one Push URL: $(pwd)/one @@ -172,36 +169,40 @@ cat > test/expect << EOF EOF test_expect_success 'show' ' - (cd test && - git config --add remote.origin.fetch refs/heads/master:refs/heads/upstream && - git fetch && - git checkout -b ahead origin/master && - echo 1 >> file && - test_tick && - git commit -m update file && - git checkout master && - git branch --track octopus origin/master && - git branch --track rebase origin/master && - git branch -d -r origin/master && - git config --add remote.two.url ../two && - git config --add remote.two.pushurl ../three && - git config branch.rebase.rebase true && - git config branch.octopus.merge "topic-a topic-b topic-c" && - (cd ../one && - echo 1 > file && - test_tick && - git commit -m update file) && - git config --add remote.origin.push : && - git config --add remote.origin.push refs/heads/master:refs/heads/upstream && - git config --add remote.origin.push +refs/tags/lastbackup && - git config --add remote.two.push +refs/heads/ahead:refs/heads/master && - git config --add remote.two.push refs/heads/master:refs/heads/another && - git remote show origin two > output && - git branch -d rebase octopus && - test_i18ncmp expect output) -' - -cat > test/expect << EOF + ( + cd test && + git config --add remote.origin.fetch refs/heads/master:refs/heads/upstream && + git fetch && + git checkout -b ahead origin/master && + echo 1 >>file && + test_tick && + git commit -m update file && + git checkout master && + git branch --track octopus origin/master && + git branch --track rebase origin/master && + git branch -d -r origin/master && + git config --add remote.two.url ../two && + git config --add remote.two.pushurl ../three && + git config branch.rebase.rebase true && + git config branch.octopus.merge "topic-a topic-b topic-c" && + ( + cd ../one && + echo 1 >file && + test_tick && + git commit -m update file + ) && + git config --add remote.origin.push : && + git config --add remote.origin.push refs/heads/master:refs/heads/upstream && + git config --add remote.origin.push +refs/tags/lastbackup && + git config --add remote.two.push +refs/heads/ahead:refs/heads/master && + git config --add remote.two.push refs/heads/master:refs/heads/another && + git remote show origin two >output && + git branch -d rebase octopus && + test_i18ncmp expect output + ) +' + +cat >test/expect <<EOF * remote origin Fetch URL: $(pwd)/one Push URL: $(pwd)/one @@ -219,152 +220,187 @@ cat > test/expect << EOF EOF test_expect_success 'show -n' ' - (mv one one.unreachable && - cd test && - git remote show -n origin > output && - mv ../one.unreachable ../one && - test_i18ncmp expect output) + mv one one.unreachable && + ( + cd test && + git remote show -n origin >output && + mv ../one.unreachable ../one && + test_i18ncmp expect output + ) ' test_expect_success 'prune' ' - (cd one && - git branch -m side side2) && - (cd test && - git fetch origin && - git remote prune origin && - git rev-parse refs/remotes/origin/side2 && - test_must_fail git rev-parse refs/remotes/origin/side) + ( + cd one && + git branch -m side side2 + ) && + ( + cd test && + git fetch origin && + git remote prune origin && + git rev-parse refs/remotes/origin/side2 && + test_must_fail git rev-parse refs/remotes/origin/side + ) ' test_expect_success 'set-head --delete' ' - (cd test && - git symbolic-ref refs/remotes/origin/HEAD && - git remote set-head --delete origin && - test_must_fail git symbolic-ref refs/remotes/origin/HEAD) + ( + cd test && + git symbolic-ref refs/remotes/origin/HEAD && + git remote set-head --delete origin && + test_must_fail git symbolic-ref refs/remotes/origin/HEAD + ) ' test_expect_success 'set-head --auto' ' - (cd test && - git remote set-head --auto origin && - echo refs/remotes/origin/master >expect && - git symbolic-ref refs/remotes/origin/HEAD >output && - test_cmp expect output + ( + cd test && + git remote set-head --auto origin && + echo refs/remotes/origin/master >expect && + git symbolic-ref refs/remotes/origin/HEAD >output && + test_cmp expect output ) ' -cat >test/expect <<EOF +cat >test/expect <<\EOF error: Multiple remote HEAD branches. Please choose one explicitly with: git remote set-head two another git remote set-head two master EOF test_expect_success 'set-head --auto fails w/multiple HEADs' ' - (cd test && - test_must_fail git remote set-head --auto two >output 2>&1 && - test_i18ncmp expect output) + ( + cd test && + test_must_fail git remote set-head --auto two >output 2>&1 && + test_i18ncmp expect output + ) ' -cat >test/expect <<EOF +cat >test/expect <<\EOF refs/remotes/origin/side2 EOF test_expect_success 'set-head explicit' ' - (cd test && - git remote set-head origin side2 && - git symbolic-ref refs/remotes/origin/HEAD >output && - git remote set-head origin master && - test_cmp expect output) + ( + cd test && + git remote set-head origin side2 && + git symbolic-ref refs/remotes/origin/HEAD >output && + git remote set-head origin master && + test_cmp expect output + ) ' -cat > test/expect << EOF +cat >test/expect <<EOF Pruning origin URL: $(pwd)/one * [would prune] origin/side2 EOF test_expect_success 'prune --dry-run' ' - (cd one && - git branch -m side2 side) && - (cd test && - git remote prune --dry-run origin > output && - git rev-parse refs/remotes/origin/side2 && - test_must_fail git rev-parse refs/remotes/origin/side && - (cd ../one && - git branch -m side side2) && - test_i18ncmp expect output) + ( + cd one && + git branch -m side2 side) && + ( + cd test && + git remote prune --dry-run origin >output && + git rev-parse refs/remotes/origin/side2 && + test_must_fail git rev-parse refs/remotes/origin/side && + ( + cd ../one && + git branch -m side side2) && + test_i18ncmp expect output + ) ' test_expect_success 'add --mirror && prune' ' - (mkdir mirror && - cd mirror && - git init --bare && - git remote add --mirror -f origin ../one) && - (cd one && - git branch -m side2 side) && - (cd mirror && - git rev-parse --verify refs/heads/side2 && - test_must_fail git rev-parse --verify refs/heads/side && - git fetch origin && - git remote prune origin && - test_must_fail git rev-parse --verify refs/heads/side2 && - git rev-parse --verify refs/heads/side) + mkdir mirror && + ( + cd mirror && + git init --bare && + git remote add --mirror -f origin ../one + ) && + ( + cd one && + git branch -m side2 side + ) && + ( + cd mirror && + git rev-parse --verify refs/heads/side2 && + test_must_fail git rev-parse --verify refs/heads/side && + git fetch origin && + git remote prune origin && + test_must_fail git rev-parse --verify refs/heads/side2 && + git rev-parse --verify refs/heads/side + ) ' test_expect_success 'add --mirror=fetch' ' mkdir mirror-fetch && git init mirror-fetch/parent && - (cd mirror-fetch/parent && - test_commit one) && + ( + cd mirror-fetch/parent && + test_commit one + ) && git init --bare mirror-fetch/child && - (cd mirror-fetch/child && - git remote add --mirror=fetch -f parent ../parent) + ( + cd mirror-fetch/child && + git remote add --mirror=fetch -f parent ../parent + ) ' test_expect_success 'fetch mirrors act as mirrors during fetch' ' - (cd mirror-fetch/parent && - git branch new && - git branch -m master renamed + ( + cd mirror-fetch/parent && + git branch new && + git branch -m master renamed ) && - (cd mirror-fetch/child && - git fetch parent && - git rev-parse --verify refs/heads/new && - git rev-parse --verify refs/heads/renamed + ( + cd mirror-fetch/child && + git fetch parent && + git rev-parse --verify refs/heads/new && + git rev-parse --verify refs/heads/renamed ) ' test_expect_success 'fetch mirrors can prune' ' - (cd mirror-fetch/child && - git remote prune parent && - test_must_fail git rev-parse --verify refs/heads/master + ( + cd mirror-fetch/child && + git remote prune parent && + test_must_fail git rev-parse --verify refs/heads/master ) ' test_expect_success 'fetch mirrors do not act as mirrors during push' ' - (cd mirror-fetch/parent && - git checkout HEAD^0 + ( + cd mirror-fetch/parent && + git checkout HEAD^0 ) && - (cd mirror-fetch/child && - git branch -m renamed renamed2 && - git push parent + ( + cd mirror-fetch/child && + git branch -m renamed renamed2 && + git push parent : ) && - (cd mirror-fetch/parent && - git rev-parse --verify renamed && - test_must_fail git rev-parse --verify refs/heads/renamed2 + ( + cd mirror-fetch/parent && + git rev-parse --verify renamed && + test_must_fail git rev-parse --verify refs/heads/renamed2 ) ' test_expect_success 'add fetch mirror with specific branches' ' git init --bare mirror-fetch/track && - (cd mirror-fetch/track && - git remote add --mirror=fetch -t heads/new parent ../parent + ( + cd mirror-fetch/track && + git remote add --mirror=fetch -t heads/new parent ../parent ) ' test_expect_success 'fetch mirror respects specific branches' ' - (cd mirror-fetch/track && - git fetch parent && - git rev-parse --verify refs/heads/new && - test_must_fail git rev-parse --verify refs/heads/renamed + ( + cd mirror-fetch/track && + git fetch parent && + git rev-parse --verify refs/heads/new && + test_must_fail git rev-parse --verify refs/heads/renamed ) ' @@ -372,60 +408,72 @@ test_expect_success 'add --mirror=push' ' mkdir mirror-push && git init --bare mirror-push/public && git init mirror-push/private && - (cd mirror-push/private && - test_commit one && - git remote add --mirror=push public ../public + ( + cd mirror-push/private && + test_commit one && + git remote add --mirror=push public ../public ) ' test_expect_success 'push mirrors act as mirrors during push' ' - (cd mirror-push/private && - git branch new && - git branch -m master renamed && - git push public + ( + cd mirror-push/private && + git branch new && + git branch -m master renamed && + git push public ) && - (cd mirror-push/private && - git rev-parse --verify refs/heads/new && - git rev-parse --verify refs/heads/renamed && - test_must_fail git rev-parse --verify refs/heads/master + ( + cd mirror-push/private && + git rev-parse --verify refs/heads/new && + git rev-parse --verify refs/heads/renamed && + test_must_fail git rev-parse --verify refs/heads/master ) ' test_expect_success 'push mirrors do not act as mirrors during fetch' ' - (cd mirror-push/public && - git branch -m renamed renamed2 && - git symbolic-ref HEAD refs/heads/renamed2 + ( + cd mirror-push/public && + git branch -m renamed renamed2 && + git symbolic-ref HEAD refs/heads/renamed2 ) && - (cd mirror-push/private && - git fetch public && - git rev-parse --verify refs/heads/renamed && - test_must_fail git rev-parse --verify refs/heads/renamed2 + ( + cd mirror-push/private && + git fetch public && + git rev-parse --verify refs/heads/renamed && + test_must_fail git rev-parse --verify refs/heads/renamed2 ) ' test_expect_success 'push mirrors do not allow you to specify refs' ' git init mirror-push/track && - (cd mirror-push/track && - test_must_fail git remote add --mirror=push -t new public ../public + ( + cd mirror-push/track && + test_must_fail git remote add --mirror=push -t new public ../public ) ' test_expect_success 'add alt && prune' ' - (mkdir alttst && - cd alttst && - git init && - git remote add -f origin ../one && - git config remote.alt.url ../one && - git config remote.alt.fetch "+refs/heads/*:refs/remotes/origin/*") && - (cd one && - git branch -m side side2) && - (cd alttst && - git rev-parse --verify refs/remotes/origin/side && - test_must_fail git rev-parse --verify refs/remotes/origin/side2 && - git fetch alt && - git remote prune alt && - test_must_fail git rev-parse --verify refs/remotes/origin/side && - git rev-parse --verify refs/remotes/origin/side2) + mkdir alttst && + ( + cd alttst && + git init && + git remote add -f origin ../one && + git config remote.alt.url ../one && + git config remote.alt.fetch "+refs/heads/*:refs/remotes/origin/*" + ) && + ( + cd one && + git branch -m side side2 + ) && + ( + cd alttst && + git rev-parse --verify refs/remotes/origin/side && + test_must_fail git rev-parse --verify refs/remotes/origin/side2 && + git fetch alt && + git remote prune alt && + test_must_fail git rev-parse --verify refs/remotes/origin/side && + git rev-parse --verify refs/remotes/origin/side2 + ) ' cat >test/expect <<\EOF @@ -433,20 +481,24 @@ some-tag EOF test_expect_success 'add with reachable tags (default)' ' - (cd one && - >foobar && - git add foobar && - git commit -m "Foobar" && - git tag -a -m "Foobar tag" foobar-tag && - git reset --hard HEAD~1 && - git tag -a -m "Some tag" some-tag) && - (mkdir add-tags && - cd add-tags && - git init && - git remote add -f origin ../one && - git tag -l some-tag >../test/output && - git tag -l foobar-tag >>../test/output && - test_must_fail git config remote.origin.tagopt) && + ( + cd one && + >foobar && + git add foobar && + git commit -m "Foobar" && + git tag -a -m "Foobar tag" foobar-tag && + git reset --hard HEAD~1 && + git tag -a -m "Some tag" some-tag + ) && + mkdir add-tags && + ( + cd add-tags && + git init && + git remote add -f origin ../one && + git tag -l some-tag >../test/output && + git tag -l foobar-tag >>../test/output && + test_must_fail git config remote.origin.tagopt + ) && test_cmp test/expect test/output ' @@ -457,14 +509,16 @@ foobar-tag EOF test_expect_success 'add --tags' ' - (rm -rf add-tags && - mkdir add-tags && - cd add-tags && - git init && - git remote add -f --tags origin ../one && - git tag -l some-tag >../test/output && - git tag -l foobar-tag >>../test/output && - git config remote.origin.tagopt >>../test/output) && + rm -rf add-tags && + ( + mkdir add-tags && + cd add-tags && + git init && + git remote add -f --tags origin ../one && + git tag -l some-tag >../test/output && + git tag -l foobar-tag >>../test/output && + git config remote.origin.tagopt >>../test/output + ) && test_cmp test/expect test/output ' @@ -473,25 +527,31 @@ cat >test/expect <<\EOF EOF test_expect_success 'add --no-tags' ' - (rm -rf add-tags && - mkdir add-no-tags && - cd add-no-tags && - git init && - git remote add -f --no-tags origin ../one && - git tag -l some-tag >../test/output && - git tag -l foobar-tag >../test/output && - git config remote.origin.tagopt >>../test/output) && - (cd one && - git tag -d some-tag foobar-tag) && + rm -rf add-tags && + ( + mkdir add-no-tags && + cd add-no-tags && + git init && + git remote add -f --no-tags origin ../one && + git tag -l some-tag >../test/output && + git tag -l foobar-tag >../test/output && + git config remote.origin.tagopt >>../test/output + ) && + ( + cd one && + git tag -d some-tag foobar-tag + ) && test_cmp test/expect test/output ' test_expect_success 'reject --no-no-tags' ' - (cd add-no-tags && - test_must_fail git remote add -f --no-no-tags neworigin ../one) + ( + cd add-no-tags && + test_must_fail git remote add -f --no-no-tags neworigin ../one + ) ' -cat > one/expect << EOF +cat >one/expect <<\EOF apis/master apis/side drosophila/another @@ -500,17 +560,17 @@ cat > one/expect << EOF EOF test_expect_success 'update' ' - - (cd one && - git remote add drosophila ../two && - git remote add apis ../mirror && - git remote update && - git branch -r > output && - test_cmp expect output) - + ( + cd one && + git remote add drosophila ../two && + git remote add apis ../mirror && + git remote update && + git branch -r >output && + test_cmp expect output + ) ' -cat > one/expect << EOF +cat >one/expect <<\EOF drosophila/another drosophila/master drosophila/side @@ -521,34 +581,40 @@ cat > one/expect << EOF EOF test_expect_success 'update with arguments' ' - - (cd one && - for b in $(git branch -r) - do + ( + cd one && + for b in $(git branch -r) + do git branch -r -d $b || break - done && - git remote add manduca ../mirror && - git remote add megaloprepus ../mirror && - git config remotes.phobaeticus "drosophila megaloprepus" && - git config remotes.titanus manduca && - git remote update phobaeticus titanus && - git branch -r > output && - test_cmp expect output) - + done && + git remote add manduca ../mirror && + git remote add megaloprepus ../mirror && + git config remotes.phobaeticus "drosophila megaloprepus" && + git config remotes.titanus manduca && + git remote update phobaeticus titanus && + git branch -r >output && + test_cmp expect output + ) ' test_expect_success 'update --prune' ' - - (cd one && - git branch -m side2 side3) && - (cd test && - git remote update --prune && - (cd ../one && git branch -m side3 side2) && - git rev-parse refs/remotes/origin/side3 && - test_must_fail git rev-parse refs/remotes/origin/side2) + ( + cd one && + git branch -m side2 side3 + ) && + ( + cd test && + git remote update --prune && + ( + cd ../one && + git branch -m side3 side2 + ) && + git rev-parse refs/remotes/origin/side3 && + test_must_fail git rev-parse refs/remotes/origin/side2 + ) ' -cat > one/expect << EOF +cat >one/expect <<-\EOF apis/master apis/side manduca/master @@ -558,176 +624,204 @@ cat > one/expect << EOF EOF test_expect_success 'update default' ' - - (cd one && - for b in $(git branch -r) - do + ( + cd one && + for b in $(git branch -r) + do git branch -r -d $b || break - done && - git config remote.drosophila.skipDefaultUpdate true && - git remote update default && - git branch -r > output && - test_cmp expect output) - + done && + git config remote.drosophila.skipDefaultUpdate true && + git remote update default && + git branch -r >output && + test_cmp expect output + ) ' -cat > one/expect << EOF +cat >one/expect <<\EOF drosophila/another drosophila/master drosophila/side EOF test_expect_success 'update default (overridden, with funny whitespace)' ' - - (cd one && - for b in $(git branch -r) - do + ( + cd one && + for b in $(git branch -r) + do git branch -r -d $b || break - done && - git config remotes.default "$(printf "\t drosophila \n")" && - git remote update default && - git branch -r > output && - test_cmp expect output) - + done && + git config remotes.default "$(printf "\t drosophila \n")" && + git remote update default && + git branch -r >output && + test_cmp expect output + ) ' test_expect_success 'update (with remotes.default defined)' ' - - (cd one && - for b in $(git branch -r) - do + ( + cd one && + for b in $(git branch -r) + do git branch -r -d $b || break - done && - git config remotes.default "drosophila" && - git remote update && - git branch -r > output && - test_cmp expect output) - + done && + git config remotes.default "drosophila" && + git remote update && + git branch -r >output && + test_cmp expect output + ) ' test_expect_success '"remote show" does not show symbolic refs' ' - git clone one three && - (cd three && - git remote show origin > output && - ! grep "^ *HEAD$" < output && - ! grep -i stale < output) - + ( + cd three && + git remote show origin >output && + ! grep "^ *HEAD$" < output && + ! grep -i stale < output + ) ' test_expect_success 'reject adding remote with an invalid name' ' - test_must_fail git remote add some:url desired-name - ' # The first three test if the tracking branches are properly renamed, # the last two ones check if the config is updated. test_expect_success 'rename a remote' ' - git clone one four && - (cd four && - git remote rename origin upstream && - rmdir .git/refs/remotes/origin && - test "$(git symbolic-ref refs/remotes/upstream/HEAD)" = "refs/remotes/upstream/master" && - test "$(git rev-parse upstream/master)" = "$(git rev-parse master)" && - test "$(git config remote.upstream.fetch)" = "+refs/heads/*:refs/remotes/upstream/*" && - test "$(git config branch.master.remote)" = "upstream") - + ( + cd four && + git remote rename origin upstream && + rmdir .git/refs/remotes/origin && + test "$(git symbolic-ref refs/remotes/upstream/HEAD)" = "refs/remotes/upstream/master" && + test "$(git rev-parse upstream/master)" = "$(git rev-parse master)" && + test "$(git config remote.upstream.fetch)" = "+refs/heads/*:refs/remotes/upstream/*" && + test "$(git config branch.master.remote)" = "upstream" + ) ' test_expect_success 'rename does not update a non-default fetch refspec' ' - git clone one four.one && - (cd four.one && - git config remote.origin.fetch +refs/heads/*:refs/heads/origin/* && - git remote rename origin upstream && - test "$(git config remote.upstream.fetch)" = "+refs/heads/*:refs/heads/origin/*" && - git rev-parse -q origin/master) - + ( + cd four.one && + git config remote.origin.fetch +refs/heads/*:refs/heads/origin/* && + git remote rename origin upstream && + test "$(git config remote.upstream.fetch)" = "+refs/heads/*:refs/heads/origin/*" && + git rev-parse -q origin/master + ) ' test_expect_success 'rename a remote with name part of fetch spec' ' - git clone one four.two && - (cd four.two && - git remote rename origin remote && - git remote rename remote upstream && - test "$(git config remote.upstream.fetch)" = "+refs/heads/*:refs/remotes/upstream/*") - + ( + cd four.two && + git remote rename origin remote && + git remote rename remote upstream && + test "$(git config remote.upstream.fetch)" = "+refs/heads/*:refs/remotes/upstream/*" + ) ' test_expect_success 'rename a remote with name prefix of other remote' ' - git clone one four.three && - (cd four.three && - git remote add o git://example.com/repo.git && - git remote rename o upstream && - test "$(git rev-parse origin/master)" = "$(git rev-parse master)") - + ( + cd four.three && + git remote add o git://example.com/repo.git && + git remote rename o upstream && + test "$(git rev-parse origin/master)" = "$(git rev-parse master)" + ) ' -cat > remotes_origin << EOF +cat >remotes_origin <<EOF URL: $(pwd)/one Push: refs/heads/master:refs/heads/upstream +Push: refs/heads/next:refs/heads/upstream2 Pull: refs/heads/master:refs/heads/origin +Pull: refs/heads/next:refs/heads/origin2 EOF test_expect_success 'migrate a remote from named file in $GIT_DIR/remotes' ' git clone one five && origin_url=$(pwd)/one && - (cd five && - git remote remove origin && - mkdir -p .git/remotes && - cat ../remotes_origin > .git/remotes/origin && - git remote rename origin origin && - ! test -f .git/remotes/origin && - test "$(git config remote.origin.url)" = "$origin_url" && - test "$(git config remote.origin.push)" = "refs/heads/master:refs/heads/upstream" && - test "$(git config remote.origin.fetch)" = "refs/heads/master:refs/heads/origin") + ( + cd five && + git remote remove origin && + mkdir -p .git/remotes && + cat ../remotes_origin >.git/remotes/origin && + git remote rename origin origin && + test_path_is_missing .git/remotes/origin && + test "$(git config remote.origin.url)" = "$origin_url" && + cat >push_expected <<-\EOF && + refs/heads/master:refs/heads/upstream + refs/heads/next:refs/heads/upstream2 + EOF + cat >fetch_expected <<-\EOF && + refs/heads/master:refs/heads/origin + refs/heads/next:refs/heads/origin2 + EOF + git config --get-all remote.origin.push >push_actual && + git config --get-all remote.origin.fetch >fetch_actual && + test_cmp push_expected push_actual && + test_cmp fetch_expected fetch_actual + ) ' test_expect_success 'migrate a remote from named file in $GIT_DIR/branches' ' git clone one six && origin_url=$(pwd)/one && - (cd six && - git remote rm origin && - echo "$origin_url" > .git/branches/origin && - git remote rename origin origin && - ! test -f .git/branches/origin && - test "$(git config remote.origin.url)" = "$origin_url" && - test "$(git config remote.origin.fetch)" = "refs/heads/master:refs/heads/origin") + ( + cd six && + git remote rm origin && + echo "$origin_url" >.git/branches/origin && + git remote rename origin origin && + test_path_is_missing .git/branches/origin && + test "$(git config remote.origin.url)" = "$origin_url" && + test "$(git config remote.origin.fetch)" = "refs/heads/master:refs/heads/origin" && + test "$(git config remote.origin.push)" = "HEAD:refs/heads/master" + ) ' -test_expect_success 'remote prune to cause a dangling symref' ' +test_expect_success 'migrate a remote from named file in $GIT_DIR/branches (2)' ' git clone one seven && ( + cd seven && + git remote rm origin && + echo "quux#foom" > .git/branches/origin && + git remote rename origin origin && + test_path_is_missing .git/branches/origin && + test "$(git config remote.origin.url)" = "quux" && + test "$(git config remote.origin.fetch)" = "refs/heads/foom:refs/heads/origin" + test "$(git config remote.origin.push)" = "HEAD:refs/heads/foom" + ) +' + +test_expect_success 'remote prune to cause a dangling symref' ' + git clone one eight && + ( cd one && git checkout side2 && git branch -D master ) && ( - cd seven && + cd eight && git remote prune origin ) >err 2>&1 && test_i18ngrep "has become dangling" err && : And the dangling symref will not cause other annoying errors && ( - cd seven && + cd eight && git branch -a ) 2>err && ! grep "points nowhere" err && ( - cd seven && + cd eight && test_must_fail git branch nomore origin ) 2>err && grep "dangling symref" err ' test_expect_success 'show empty remote' ' - test_create_repo empty && git clone empty empty-clone && ( @@ -1003,4 +1097,26 @@ test_expect_success 'remote set-url --delete baz' ' cmp expect actual ' +test_expect_success 'extra args: setup' ' + # add a dummy origin so that this does not trigger failure + git remote add origin . +' + +test_extra_arg () { + test_expect_success "extra args: $*" " + test_must_fail git remote $* bogus_extra_arg 2>actual && + grep '^usage:' actual + " +} + +test_extra_arg add nick url +test_extra_arg rename origin newname +test_extra_arg remove origin +test_extra_arg set-head origin master +# set-branches takes any number of args +test_extra_arg set-url origin newurl oldurl +# show takes any number of args +# prune takes any number of args +# update takes any number of args + test_done diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index d7a19a1829..fde689166a 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -370,30 +370,39 @@ test_expect_success 'bundle should record HEAD correctly' ' ' -test_expect_success 'explicit fetch should not update tracking' ' +test_expect_success 'mark initial state of origin/master' ' + ( + cd three && + git tag base-origin-master refs/remotes/origin/master + ) +' + +test_expect_success 'explicit fetch should update tracking' ' cd "$D" && git branch -f side && ( cd three && + git update-ref refs/remotes/origin/master base-origin-master && o=$(git rev-parse --verify refs/remotes/origin/master) && git fetch origin master && n=$(git rev-parse --verify refs/remotes/origin/master) && - test "$o" = "$n" && + test "$o" != "$n" && test_must_fail git rev-parse --verify refs/remotes/origin/side ) ' -test_expect_success 'explicit pull should not update tracking' ' +test_expect_success 'explicit pull should update tracking' ' cd "$D" && git branch -f side && ( cd three && + git update-ref refs/remotes/origin/master base-origin-master && o=$(git rev-parse --verify refs/remotes/origin/master) && git pull origin master && n=$(git rev-parse --verify refs/remotes/origin/master) && - test "$o" = "$n" && + test "$o" != "$n" && test_must_fail git rev-parse --verify refs/remotes/origin/side ) ' @@ -404,6 +413,7 @@ test_expect_success 'configured fetch updates tracking' ' git branch -f side && ( cd three && + git update-ref refs/remotes/origin/master base-origin-master && o=$(git rev-parse --verify refs/remotes/origin/master) && git fetch origin && n=$(git rev-parse --verify refs/remotes/origin/master) && @@ -412,6 +422,22 @@ test_expect_success 'configured fetch updates tracking' ' ) ' +test_expect_success 'non-matching refspecs do not confuse tracking update' ' + cd "$D" && + git update-ref refs/odd/location HEAD && + ( + cd three && + git update-ref refs/remotes/origin/master base-origin-master && + git config --add remote.origin.fetch \ + refs/odd/location:refs/remotes/origin/odd && + o=$(git rev-parse --verify refs/remotes/origin/master) && + git fetch origin master && + n=$(git rev-parse --verify refs/remotes/origin/master) && + test "$o" != "$n" && + test_must_fail git rev-parse --verify refs/remotes/origin/odd + ) +' + test_expect_success 'pushing nonexistent branch by mistake should not segv' ' cd "$D" && diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh index d16e5d384a..321c3e5234 100755 --- a/t/t5512-ls-remote.sh +++ b/t/t5512-ls-remote.sh @@ -126,4 +126,16 @@ test_expect_success 'Report match with --exit-code' ' test_cmp expect actual ' +for configsection in transfer uploadpack +do + test_expect_success "Hide some refs with $configsection.hiderefs" ' + test_config $configsection.hiderefs refs/tags && + git ls-remote . >actual && + test_unconfig $configsection.hiderefs && + git ls-remote . | + sed -e "/ refs\/tags\//d" >expect && + test_cmp expect actual + ' +done + test_done diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index b5417cc951..4691d51b8c 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -1,16 +1,28 @@ #!/bin/sh -test_description='fetching and pushing, with or without wildcard' +test_description='Basic fetch/push functionality. + +This test checks the following functionality: + +* command-line syntax +* refspecs +* fast-forward detection, and overriding it +* configuration +* hooks +* --porcelain output format +* hiderefs +' . ./test-lib.sh D=`pwd` mk_empty () { - rm -fr testrepo && - mkdir testrepo && + repo_name="$1" + rm -fr "$repo_name" && + mkdir "$repo_name" && ( - cd testrepo && + cd "$repo_name" && git init && git config receive.denyCurrentBranch warn && mv .git/hooks .git/hooks-disabled @@ -18,32 +30,33 @@ mk_empty () { } mk_test () { - mk_empty && + repo_name="$1" + shift + + mk_empty "$repo_name" && ( for ref in "$@" do - git push testrepo $the_first_commit:refs/$ref || { - echo "Oops, push refs/$ref failure" - exit 1 - } + git push "$repo_name" $the_first_commit:refs/$ref || + exit done && - cd testrepo && + cd "$repo_name" && for ref in "$@" do - r=$(git show-ref -s --verify refs/$ref) && - test "z$r" = "z$the_first_commit" || { - echo "Oops, refs/$ref is wrong" - exit 1 - } + echo "$the_first_commit" >expect && + git show-ref -s --verify refs/$ref >actual && + test_cmp expect actual || + exit done && git fsck --full ) } mk_test_with_hooks() { + repo_name=$1 mk_test "$@" && ( - cd testrepo && + cd "$repo_name" && mkdir .git/hooks && cd .git/hooks && @@ -75,22 +88,23 @@ mk_test_with_hooks() { } mk_child() { - rm -rf "$1" && - git clone testrepo "$1" + rm -rf "$2" && + git clone "$1" "$2" } check_push_result () { + repo_name="$1" + shift + ( - cd testrepo && - it="$1" && - shift + cd "$repo_name" && + echo "$1" >expect && + shift && for ref in "$@" do - r=$(git show-ref -s --verify refs/$ref) && - test "z$r" = "z$it" || { - echo "Oops, refs/$ref is wrong" - exit 1 - } + git show-ref -s --verify refs/$ref >actual && + test_cmp expect actual || + exit done && git fsck --full ) @@ -113,35 +127,33 @@ test_expect_success setup ' ' test_expect_success 'fetch without wildcard' ' - mk_empty && + mk_empty testrepo && ( cd testrepo && git fetch .. refs/heads/master:refs/remotes/origin/master && - r=$(git show-ref -s --verify refs/remotes/origin/master) && - test "z$r" = "z$the_commit" && - - test 1 = $(git for-each-ref refs/remotes/origin | wc -l) + echo "$the_commit commit refs/remotes/origin/master" >expect && + git for-each-ref refs/remotes/origin >actual && + test_cmp expect actual ) ' test_expect_success 'fetch with wildcard' ' - mk_empty && + mk_empty testrepo && ( cd testrepo && git config remote.up.url .. && git config remote.up.fetch "refs/heads/*:refs/remotes/origin/*" && git fetch up && - r=$(git show-ref -s --verify refs/remotes/origin/master) && - test "z$r" = "z$the_commit" && - - test 1 = $(git for-each-ref refs/remotes/origin | wc -l) + echo "$the_commit commit refs/remotes/origin/master" >expect && + git for-each-ref refs/remotes/origin >actual && + test_cmp expect actual ) ' test_expect_success 'fetch with insteadOf' ' - mk_empty && + mk_empty testrepo && ( TRASH=$(pwd)/ && cd testrepo && @@ -150,15 +162,14 @@ test_expect_success 'fetch with insteadOf' ' git config remote.up.fetch "refs/heads/*:refs/remotes/origin/*" && git fetch up && - r=$(git show-ref -s --verify refs/remotes/origin/master) && - test "z$r" = "z$the_commit" && - - test 1 = $(git for-each-ref refs/remotes/origin | wc -l) + echo "$the_commit commit refs/remotes/origin/master" >expect && + git for-each-ref refs/remotes/origin >actual && + test_cmp expect actual ) ' test_expect_success 'fetch with pushInsteadOf (should not rewrite)' ' - mk_empty && + mk_empty testrepo && ( TRASH=$(pwd)/ && cd testrepo && @@ -167,321 +178,310 @@ test_expect_success 'fetch with pushInsteadOf (should not rewrite)' ' git config remote.up.fetch "refs/heads/*:refs/remotes/origin/*" && git fetch up && - r=$(git show-ref -s --verify refs/remotes/origin/master) && - test "z$r" = "z$the_commit" && - - test 1 = $(git for-each-ref refs/remotes/origin | wc -l) + echo "$the_commit commit refs/remotes/origin/master" >expect && + git for-each-ref refs/remotes/origin >actual && + test_cmp expect actual ) ' test_expect_success 'push without wildcard' ' - mk_empty && + mk_empty testrepo && git push testrepo refs/heads/master:refs/remotes/origin/master && ( cd testrepo && - r=$(git show-ref -s --verify refs/remotes/origin/master) && - test "z$r" = "z$the_commit" && - - test 1 = $(git for-each-ref refs/remotes/origin | wc -l) + echo "$the_commit commit refs/remotes/origin/master" >expect && + git for-each-ref refs/remotes/origin >actual && + test_cmp expect actual ) ' test_expect_success 'push with wildcard' ' - mk_empty && + mk_empty testrepo && git push testrepo "refs/heads/*:refs/remotes/origin/*" && ( cd testrepo && - r=$(git show-ref -s --verify refs/remotes/origin/master) && - test "z$r" = "z$the_commit" && - - test 1 = $(git for-each-ref refs/remotes/origin | wc -l) + echo "$the_commit commit refs/remotes/origin/master" >expect && + git for-each-ref refs/remotes/origin >actual && + test_cmp expect actual ) ' test_expect_success 'push with insteadOf' ' - mk_empty && + mk_empty testrepo && TRASH="$(pwd)/" && - git config "url.$TRASH.insteadOf" trash/ && + test_config "url.$TRASH.insteadOf" trash/ && git push trash/testrepo refs/heads/master:refs/remotes/origin/master && ( cd testrepo && - r=$(git show-ref -s --verify refs/remotes/origin/master) && - test "z$r" = "z$the_commit" && - - test 1 = $(git for-each-ref refs/remotes/origin | wc -l) + echo "$the_commit commit refs/remotes/origin/master" >expect && + git for-each-ref refs/remotes/origin >actual && + test_cmp expect actual ) ' test_expect_success 'push with pushInsteadOf' ' - mk_empty && + mk_empty testrepo && TRASH="$(pwd)/" && - git config "url.$TRASH.pushInsteadOf" trash/ && + test_config "url.$TRASH.pushInsteadOf" trash/ && git push trash/testrepo refs/heads/master:refs/remotes/origin/master && ( cd testrepo && - r=$(git show-ref -s --verify refs/remotes/origin/master) && - test "z$r" = "z$the_commit" && - - test 1 = $(git for-each-ref refs/remotes/origin | wc -l) + echo "$the_commit commit refs/remotes/origin/master" >expect && + git for-each-ref refs/remotes/origin >actual && + test_cmp expect actual ) ' test_expect_success 'push with pushInsteadOf and explicit pushurl (pushInsteadOf should not rewrite)' ' - mk_empty && - TRASH="$(pwd)/" && - git config "url.trash2/.pushInsteadOf" trash/ && - git config remote.r.url trash/wrong && - git config remote.r.pushurl "$TRASH/testrepo" && + mk_empty testrepo && + test_config "url.trash2/.pushInsteadOf" testrepo/ && + test_config "url.trash3/.pusnInsteadOf" trash/wrong && + test_config remote.r.url trash/wrong && + test_config remote.r.pushurl "testrepo/" && git push r refs/heads/master:refs/remotes/origin/master && ( cd testrepo && - r=$(git show-ref -s --verify refs/remotes/origin/master) && - test "z$r" = "z$the_commit" && - - test 1 = $(git for-each-ref refs/remotes/origin | wc -l) + echo "$the_commit commit refs/remotes/origin/master" >expect && + git for-each-ref refs/remotes/origin >actual && + test_cmp expect actual ) ' test_expect_success 'push with matching heads' ' - mk_test heads/master && - git push testrepo && - check_push_result $the_commit heads/master + mk_test testrepo heads/master && + git push testrepo : && + check_push_result testrepo $the_commit heads/master ' test_expect_success 'push with matching heads on the command line' ' - mk_test heads/master && + mk_test testrepo heads/master && git push testrepo : && - check_push_result $the_commit heads/master + check_push_result testrepo $the_commit heads/master ' test_expect_success 'failed (non-fast-forward) push with matching heads' ' - mk_test heads/master && + mk_test testrepo heads/master && git push testrepo : && git commit --amend -massaged && test_must_fail git push testrepo && - check_push_result $the_commit heads/master && + check_push_result testrepo $the_commit heads/master && git reset --hard $the_commit ' test_expect_success 'push --force with matching heads' ' - mk_test heads/master && + mk_test testrepo heads/master && git push testrepo : && git commit --amend -massaged && - git push --force testrepo && - ! check_push_result $the_commit heads/master && + git push --force testrepo : && + ! check_push_result testrepo $the_commit heads/master && git reset --hard $the_commit ' test_expect_success 'push with matching heads and forced update' ' - mk_test heads/master && + mk_test testrepo heads/master && git push testrepo : && git commit --amend -massaged && git push testrepo +: && - ! check_push_result $the_commit heads/master && + ! check_push_result testrepo $the_commit heads/master && git reset --hard $the_commit ' test_expect_success 'push with no ambiguity (1)' ' - mk_test heads/master && + mk_test testrepo heads/master && git push testrepo master:master && - check_push_result $the_commit heads/master + check_push_result testrepo $the_commit heads/master ' test_expect_success 'push with no ambiguity (2)' ' - mk_test remotes/origin/master && + mk_test testrepo remotes/origin/master && git push testrepo master:origin/master && - check_push_result $the_commit remotes/origin/master + check_push_result testrepo $the_commit remotes/origin/master ' test_expect_success 'push with colon-less refspec, no ambiguity' ' - mk_test heads/master heads/t/master && + mk_test testrepo heads/master heads/t/master && git branch -f t/master master && git push testrepo master && - check_push_result $the_commit heads/master && - check_push_result $the_first_commit heads/t/master + check_push_result testrepo $the_commit heads/master && + check_push_result testrepo $the_first_commit heads/t/master ' test_expect_success 'push with weak ambiguity (1)' ' - mk_test heads/master remotes/origin/master && + mk_test testrepo heads/master remotes/origin/master && git push testrepo master:master && - check_push_result $the_commit heads/master && - check_push_result $the_first_commit remotes/origin/master + check_push_result testrepo $the_commit heads/master && + check_push_result testrepo $the_first_commit remotes/origin/master ' test_expect_success 'push with weak ambiguity (2)' ' - mk_test heads/master remotes/origin/master remotes/another/master && + mk_test testrepo heads/master remotes/origin/master remotes/another/master && git push testrepo master:master && - check_push_result $the_commit heads/master && - check_push_result $the_first_commit remotes/origin/master remotes/another/master + check_push_result testrepo $the_commit heads/master && + check_push_result testrepo $the_first_commit remotes/origin/master remotes/another/master ' test_expect_success 'push with ambiguity' ' - mk_test heads/frotz tags/frotz && - if git push testrepo master:frotz - then - echo "Oops, should have failed" - false - else - check_push_result $the_first_commit heads/frotz tags/frotz - fi + mk_test testrepo heads/frotz tags/frotz && + test_must_fail git push testrepo master:frotz && + check_push_result testrepo $the_first_commit heads/frotz tags/frotz ' test_expect_success 'push with colon-less refspec (1)' ' - mk_test heads/frotz tags/frotz && + mk_test testrepo heads/frotz tags/frotz && git branch -f frotz master && git push testrepo frotz && - check_push_result $the_commit heads/frotz && - check_push_result $the_first_commit tags/frotz + check_push_result testrepo $the_commit heads/frotz && + check_push_result testrepo $the_first_commit tags/frotz ' test_expect_success 'push with colon-less refspec (2)' ' - mk_test heads/frotz tags/frotz && + mk_test testrepo heads/frotz tags/frotz && if git show-ref --verify -q refs/heads/frotz then git branch -D frotz fi && git tag -f frotz && - git push testrepo frotz && - check_push_result $the_commit tags/frotz && - check_push_result $the_first_commit heads/frotz + git push -f testrepo frotz && + check_push_result testrepo $the_commit tags/frotz && + check_push_result testrepo $the_first_commit heads/frotz ' test_expect_success 'push with colon-less refspec (3)' ' - mk_test && + mk_test testrepo && if git show-ref --verify -q refs/tags/frotz then git tag -d frotz fi && git branch -f frotz master && git push testrepo frotz && - check_push_result $the_commit heads/frotz && + check_push_result testrepo $the_commit heads/frotz && test 1 = $( cd testrepo && git show-ref | wc -l ) ' test_expect_success 'push with colon-less refspec (4)' ' - mk_test && + mk_test testrepo && if git show-ref --verify -q refs/heads/frotz then git branch -D frotz fi && git tag -f frotz && git push testrepo frotz && - check_push_result $the_commit tags/frotz && + check_push_result testrepo $the_commit tags/frotz && test 1 = $( cd testrepo && git show-ref | wc -l ) ' test_expect_success 'push head with non-existent, incomplete dest' ' - mk_test && + mk_test testrepo && git push testrepo master:branch && - check_push_result $the_commit heads/branch + check_push_result testrepo $the_commit heads/branch ' test_expect_success 'push tag with non-existent, incomplete dest' ' - mk_test && + mk_test testrepo && git tag -f v1.0 && git push testrepo v1.0:tag && - check_push_result $the_commit tags/tag + check_push_result testrepo $the_commit tags/tag ' test_expect_success 'push sha1 with non-existent, incomplete dest' ' - mk_test && + mk_test testrepo && test_must_fail git push testrepo `git rev-parse master`:foo ' test_expect_success 'push ref expression with non-existent, incomplete dest' ' - mk_test && + mk_test testrepo && test_must_fail git push testrepo master^:branch ' test_expect_success 'push with HEAD' ' - mk_test heads/master && + mk_test testrepo heads/master && git checkout master && git push testrepo HEAD && - check_push_result $the_commit heads/master + check_push_result testrepo $the_commit heads/master ' test_expect_success 'push with HEAD nonexisting at remote' ' - mk_test heads/master && + mk_test testrepo heads/master && git checkout -b local master && git push testrepo HEAD && - check_push_result $the_commit heads/local + check_push_result testrepo $the_commit heads/local ' test_expect_success 'push with +HEAD' ' - mk_test heads/master && + mk_test testrepo heads/master && git checkout master && git branch -D local && git checkout -b local && git push testrepo master local && - check_push_result $the_commit heads/master && - check_push_result $the_commit heads/local && + check_push_result testrepo $the_commit heads/master && + check_push_result testrepo $the_commit heads/local && # Without force rewinding should fail git reset --hard HEAD^ && test_must_fail git push testrepo HEAD && - check_push_result $the_commit heads/local && + check_push_result testrepo $the_commit heads/local && # With force rewinding should succeed git push testrepo +HEAD && - check_push_result $the_first_commit heads/local + check_push_result testrepo $the_first_commit heads/local ' test_expect_success 'push HEAD with non-existent, incomplete dest' ' - mk_test && + mk_test testrepo && git checkout master && git push testrepo HEAD:branch && - check_push_result $the_commit heads/branch + check_push_result testrepo $the_commit heads/branch ' test_expect_success 'push with config remote.*.push = HEAD' ' - mk_test heads/local && + mk_test testrepo heads/local && git checkout master && git branch -f local $the_commit && ( @@ -489,46 +489,68 @@ test_expect_success 'push with config remote.*.push = HEAD' ' git checkout local && git reset --hard $the_first_commit ) && - git config remote.there.url testrepo && - git config remote.there.push HEAD && - git config branch.master.remote there && + test_config remote.there.url testrepo && + test_config remote.there.push HEAD && + test_config branch.master.remote there && git push && - check_push_result $the_commit heads/master && - check_push_result $the_first_commit heads/local + check_push_result testrepo $the_commit heads/master && + check_push_result testrepo $the_first_commit heads/local +' + +test_expect_success 'push with remote.pushdefault' ' + mk_test up_repo heads/master && + mk_test down_repo heads/master && + test_config remote.up.url up_repo && + test_config remote.down.url down_repo && + test_config branch.master.remote up && + test_config remote.pushdefault down && + test_config push.default matching && + git push && + check_push_result up_repo $the_first_commit heads/master && + check_push_result down_repo $the_commit heads/master ' -# clean up the cruft left with the previous one -git config --remove-section remote.there -git config --remove-section branch.master - test_expect_success 'push with config remote.*.pushurl' ' - mk_test heads/master && + mk_test testrepo heads/master && git checkout master && - git config remote.there.url test2repo && - git config remote.there.pushurl testrepo && - git push there && - check_push_result $the_commit heads/master + test_config remote.there.url test2repo && + test_config remote.there.pushurl testrepo && + git push there : && + check_push_result testrepo $the_commit heads/master +' + +test_expect_success 'push with config branch.*.pushremote' ' + mk_test up_repo heads/master && + mk_test side_repo heads/master && + mk_test down_repo heads/master && + test_config remote.up.url up_repo && + test_config remote.pushdefault side_repo && + test_config remote.down.url down_repo && + test_config branch.master.remote up && + test_config branch.master.pushremote down && + test_config push.default matching && + git push && + check_push_result up_repo $the_first_commit heads/master && + check_push_result side_repo $the_first_commit heads/master && + check_push_result down_repo $the_commit heads/master ' -# clean up the cruft left with the previous one -git config --remove-section remote.there - test_expect_success 'push with dry-run' ' - mk_test heads/master && + mk_test testrepo heads/master && ( cd testrepo && old_commit=$(git show-ref -s --verify refs/heads/master) ) && - git push --dry-run testrepo && - check_push_result $old_commit heads/master + git push --dry-run testrepo : && + check_push_result testrepo $old_commit heads/master ' test_expect_success 'push updates local refs' ' - mk_test heads/master && - mk_child child && + mk_test testrepo heads/master && + mk_child testrepo child && ( cd child && git pull .. master && @@ -541,9 +563,9 @@ test_expect_success 'push updates local refs' ' test_expect_success 'push updates up-to-date local refs' ' - mk_test heads/master && - mk_child child1 && - mk_child child2 && + mk_test testrepo heads/master && + mk_child testrepo child1 && + mk_child testrepo child2 && (cd child1 && git pull .. master && git push) && ( cd child2 && @@ -557,8 +579,8 @@ test_expect_success 'push updates up-to-date local refs' ' test_expect_success 'push preserves up-to-date packed refs' ' - mk_test heads/master && - mk_child child && + mk_test testrepo heads/master && + mk_child testrepo child && ( cd child && git push && @@ -569,8 +591,8 @@ test_expect_success 'push preserves up-to-date packed refs' ' test_expect_success 'push does not update local refs on failure' ' - mk_test heads/master && - mk_child child && + mk_test testrepo heads/master && + mk_child testrepo child && mkdir testrepo/.git/hooks && echo "#!/no/frobnication/today" >testrepo/.git/hooks/pre-receive && chmod +x testrepo/.git/hooks/pre-receive && @@ -586,7 +608,7 @@ test_expect_success 'push does not update local refs on failure' ' test_expect_success 'allow deleting an invalid remote ref' ' - mk_test heads/master && + mk_test testrepo heads/master && rm -f testrepo/.git/objects/??/* && git push testrepo :refs/heads/master && (cd testrepo && test_must_fail git rev-parse --verify refs/heads/master) @@ -594,7 +616,7 @@ test_expect_success 'allow deleting an invalid remote ref' ' ' test_expect_success 'pushing valid refs triggers post-receive and post-update hooks' ' - mk_test_with_hooks heads/master heads/next && + mk_test_with_hooks testrepo heads/master heads/next && orgmaster=$(cd testrepo && git show-ref -s --verify refs/heads/master) && newmaster=$(git show-ref -s --verify refs/heads/master) && orgnext=$(cd testrepo && git show-ref -s --verify refs/heads/next) && @@ -630,7 +652,7 @@ test_expect_success 'pushing valid refs triggers post-receive and post-update ho ' test_expect_success 'deleting dangling ref triggers hooks with correct args' ' - mk_test_with_hooks heads/master && + mk_test_with_hooks testrepo heads/master && rm -f testrepo/.git/objects/??/* && git push testrepo :refs/heads/master && ( @@ -659,7 +681,7 @@ test_expect_success 'deleting dangling ref triggers hooks with correct args' ' ' test_expect_success 'deletion of a non-existent ref is not fed to post-receive and post-update hooks' ' - mk_test_with_hooks heads/master && + mk_test_with_hooks testrepo heads/master && orgmaster=$(cd testrepo && git show-ref -s --verify refs/heads/master) && newmaster=$(git show-ref -s --verify refs/heads/master) && git push testrepo master :refs/heads/nonexistent && @@ -691,7 +713,7 @@ test_expect_success 'deletion of a non-existent ref is not fed to post-receive a ' test_expect_success 'deletion of a non-existent ref alone does trigger post-receive and post-update hooks' ' - mk_test_with_hooks heads/master && + mk_test_with_hooks testrepo heads/master && git push testrepo :refs/heads/nonexistent && ( cd testrepo/.git && @@ -711,7 +733,7 @@ test_expect_success 'deletion of a non-existent ref alone does trigger post-rece ' test_expect_success 'mixed ref updates, deletes, invalid deletes trigger hooks with correct input' ' - mk_test_with_hooks heads/master heads/next heads/pu && + mk_test_with_hooks testrepo heads/master heads/next heads/pu && orgmaster=$(cd testrepo && git show-ref -s --verify refs/heads/master) && newmaster=$(git show-ref -s --verify refs/heads/master) && orgnext=$(cd testrepo && git show-ref -s --verify refs/heads/next) && @@ -757,14 +779,14 @@ test_expect_success 'mixed ref updates, deletes, invalid deletes trigger hooks w ' test_expect_success 'allow deleting a ref using --delete' ' - mk_test heads/master && + mk_test testrepo heads/master && (cd testrepo && git config receive.denyDeleteCurrent warn) && git push testrepo --delete master && (cd testrepo && test_must_fail git rev-parse --verify refs/heads/master) ' test_expect_success 'allow deleting a tag using --delete' ' - mk_test heads/master && + mk_test testrepo heads/master && git tag -a -m dummy_message deltag heads/master && git push testrepo --tags && (cd testrepo && git rev-parse --verify -q refs/tags/deltag) && @@ -773,17 +795,17 @@ test_expect_success 'allow deleting a tag using --delete' ' ' test_expect_success 'push --delete without args aborts' ' - mk_test heads/master && + mk_test testrepo heads/master && test_must_fail git push testrepo --delete ' test_expect_success 'push --delete refuses src:dest refspecs' ' - mk_test heads/master && + mk_test testrepo heads/master && test_must_fail git push testrepo --delete master:foo ' test_expect_success 'warn on push to HEAD of non-bare repository' ' - mk_test heads/master && + mk_test testrepo heads/master && ( cd testrepo && git checkout master && @@ -794,7 +816,7 @@ test_expect_success 'warn on push to HEAD of non-bare repository' ' ' test_expect_success 'deny push to HEAD of non-bare repository' ' - mk_test heads/master && + mk_test testrepo heads/master && ( cd testrepo && git checkout master && @@ -804,7 +826,7 @@ test_expect_success 'deny push to HEAD of non-bare repository' ' ' test_expect_success 'allow push to HEAD of bare repository (bare)' ' - mk_test heads/master && + mk_test testrepo heads/master && ( cd testrepo && git checkout master && @@ -816,7 +838,7 @@ test_expect_success 'allow push to HEAD of bare repository (bare)' ' ' test_expect_success 'allow push to HEAD of non-bare repository (config)' ' - mk_test heads/master && + mk_test testrepo heads/master && ( cd testrepo && git checkout master && @@ -827,63 +849,63 @@ test_expect_success 'allow push to HEAD of non-bare repository (config)' ' ' test_expect_success 'fetch with branches' ' - mk_empty && + mk_empty testrepo && git branch second $the_first_commit && git checkout second && echo ".." > testrepo/.git/branches/branch1 && ( cd testrepo && git fetch branch1 && - r=$(git show-ref -s --verify refs/heads/branch1) && - test "z$r" = "z$the_commit" && - test 1 = $(git for-each-ref refs/heads | wc -l) + echo "$the_commit commit refs/heads/branch1" >expect && + git for-each-ref refs/heads >actual && + test_cmp expect actual ) && git checkout master ' test_expect_success 'fetch with branches containing #' ' - mk_empty && + mk_empty testrepo && echo "..#second" > testrepo/.git/branches/branch2 && ( cd testrepo && git fetch branch2 && - r=$(git show-ref -s --verify refs/heads/branch2) && - test "z$r" = "z$the_first_commit" && - test 1 = $(git for-each-ref refs/heads | wc -l) + echo "$the_first_commit commit refs/heads/branch2" >expect && + git for-each-ref refs/heads >actual && + test_cmp expect actual ) && git checkout master ' test_expect_success 'push with branches' ' - mk_empty && + mk_empty testrepo && git checkout second && echo "testrepo" > .git/branches/branch1 && git push branch1 && ( cd testrepo && - r=$(git show-ref -s --verify refs/heads/master) && - test "z$r" = "z$the_first_commit" && - test 1 = $(git for-each-ref refs/heads | wc -l) + echo "$the_first_commit commit refs/heads/master" >expect && + git for-each-ref refs/heads >actual && + test_cmp expect actual ) ' test_expect_success 'push with branches containing #' ' - mk_empty && + mk_empty testrepo && echo "testrepo#branch3" > .git/branches/branch2 && git push branch2 && ( cd testrepo && - r=$(git show-ref -s --verify refs/heads/branch3) && - test "z$r" = "z$the_first_commit" && - test 1 = $(git for-each-ref refs/heads | wc -l) + echo "$the_first_commit commit refs/heads/branch3" >expect && + git for-each-ref refs/heads >actual && + test_cmp expect actual ) && git checkout master ' test_expect_success 'push into aliased refs (consistent)' ' - mk_test heads/master && - mk_child child1 && - mk_child child2 && + mk_test testrepo heads/master && + mk_child testrepo child1 && + mk_child testrepo child2 && ( cd child1 && git branch foo && @@ -903,9 +925,9 @@ test_expect_success 'push into aliased refs (consistent)' ' ' test_expect_success 'push into aliased refs (inconsistent)' ' - mk_test heads/master && - mk_child child1 && - mk_child child2 && + mk_test testrepo heads/master && + mk_child testrepo child1 && + mk_child testrepo child2 && ( cd child1 && git branch foo && @@ -929,29 +951,50 @@ test_expect_success 'push into aliased refs (inconsistent)' ' ) ' +test_expect_success 'push requires --force to update lightweight tag' ' + mk_test testrepo heads/master && + mk_child testrepo child1 && + mk_child testrepo child2 && + ( + cd child1 && + git tag Tag && + git push ../child2 Tag && + git push ../child2 Tag && + >file1 && + git add file1 && + git commit -m "file1" && + git tag -f Tag && + test_must_fail git push ../child2 Tag && + git push --force ../child2 Tag && + git tag -f Tag && + test_must_fail git push ../child2 Tag HEAD~ && + git push --force ../child2 Tag + ) +' + test_expect_success 'push --porcelain' ' - mk_empty && + mk_empty testrepo && echo >.git/foo "To testrepo" && echo >>.git/foo "* refs/heads/master:refs/remotes/origin/master [new branch]" && echo >>.git/foo "Done" && git push >.git/bar --porcelain testrepo refs/heads/master:refs/remotes/origin/master && ( cd testrepo && - r=$(git show-ref -s --verify refs/remotes/origin/master) && - test "z$r" = "z$the_commit" && - test 1 = $(git for-each-ref refs/remotes/origin | wc -l) + echo "$the_commit commit refs/remotes/origin/master" >expect && + git for-each-ref refs/remotes/origin >actual && + test_cmp expect actual ) && test_cmp .git/foo .git/bar ' test_expect_success 'push --porcelain bad url' ' - mk_empty && + mk_empty testrepo && test_must_fail git push >.git/bar --porcelain asdfasdfasd refs/heads/master:refs/remotes/origin/master && test_must_fail grep -q Done .git/bar ' test_expect_success 'push --porcelain rejected' ' - mk_empty && + mk_empty testrepo && git push testrepo refs/heads/master:refs/remotes/origin/master && (cd testrepo && git reset --hard origin/master^ @@ -965,7 +1008,7 @@ test_expect_success 'push --porcelain rejected' ' ' test_expect_success 'push --porcelain --dry-run rejected' ' - mk_empty && + mk_empty testrepo && git push testrepo refs/heads/master:refs/remotes/origin/master && (cd testrepo && git reset --hard origin/master @@ -980,19 +1023,153 @@ test_expect_success 'push --porcelain --dry-run rejected' ' ' 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 + mk_test testrepo heads/master heads/second heads/foo heads/bar && + git push --prune testrepo : && + check_push_result testrepo $the_commit heads/master && + check_push_result testrepo $the_first_commit heads/second && + ! check_push_result testrepo $the_first_commit heads/foo heads/bar ' test_expect_success 'push --prune refspec' ' - mk_test tmp/master tmp/second tmp/foo tmp/bar && + mk_test testrepo 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 + check_push_result testrepo $the_commit tmp/master && + check_push_result testrepo $the_first_commit tmp/second && + ! check_push_result testrepo $the_first_commit tmp/foo tmp/bar +' + +for configsection in transfer receive +do + test_expect_success "push to update a ref hidden by $configsection.hiderefs" ' + mk_test testrepo heads/master hidden/one hidden/two hidden/three && + ( + cd testrepo && + git config $configsection.hiderefs refs/hidden + ) && + + # push to unhidden ref succeeds normally + git push testrepo master:refs/heads/master && + check_push_result testrepo $the_commit heads/master && + + # push to update a hidden ref should fail + test_must_fail git push testrepo master:refs/hidden/one && + check_push_result testrepo $the_first_commit hidden/one && + + # push to delete a hidden ref should fail + test_must_fail git push testrepo :refs/hidden/two && + check_push_result testrepo $the_first_commit hidden/two && + + # idempotent push to update a hidden ref should fail + test_must_fail git push testrepo $the_first_commit:refs/hidden/three && + check_push_result testrepo $the_first_commit hidden/three + ' +done + +test_expect_success 'fetch exact SHA1' ' + mk_test testrepo heads/master hidden/one && + git push testrepo master:refs/hidden/one && + ( + cd testrepo && + git config transfer.hiderefs refs/hidden + ) && + check_push_result testrepo $the_commit hidden/one && + + mk_child testrepo child && + ( + cd child && + + # make sure $the_commit does not exist here + git repack -a -d && + git prune && + test_must_fail git cat-file -t $the_commit && + + # fetching the hidden object should fail by default + test_must_fail git fetch -v ../testrepo $the_commit:refs/heads/copy && + test_must_fail git rev-parse --verify refs/heads/copy && + + # the server side can allow it to succeed + ( + cd ../testrepo && + git config uploadpack.allowtipsha1inwant true + ) && + + git fetch -v ../testrepo $the_commit:refs/heads/copy && + result=$(git rev-parse --verify refs/heads/copy) && + test "$the_commit" = "$result" + ) +' + +test_expect_success 'fetch follows tags by default' ' + mk_test testrepo heads/master && + rm -fr src dst && + git init src && + ( + cd src && + git pull ../testrepo master && + git tag -m "annotated" tag && + git for-each-ref >tmp1 && + ( + cat tmp1 + sed -n "s|refs/heads/master$|refs/remotes/origin/master|p" tmp1 + ) | + sort -k 3 >../expect + ) && + git init dst && + ( + cd dst && + git remote add origin ../src && + git config branch.master.remote origin && + git config branch.master.merge refs/heads/master && + git pull && + git for-each-ref >../actual + ) && + test_cmp expect actual +' + +test_expect_success 'push does not follow tags by default' ' + mk_test testrepo heads/master && + rm -fr src dst && + git init src && + git init --bare dst && + ( + cd src && + git pull ../testrepo master && + git tag -m "annotated" tag && + git checkout -b another && + git commit --allow-empty -m "future commit" && + git tag -m "future" future && + git checkout master && + git for-each-ref refs/heads/master >../expect && + git push ../dst master + ) && + ( + cd dst && + git for-each-ref >../actual + ) && + test_cmp expect actual +' + +test_expect_success 'push --follow-tag only pushes relevant tags' ' + mk_test testrepo heads/master && + rm -fr src dst && + git init src && + git init --bare dst && + ( + cd src && + git pull ../testrepo master && + git tag -m "annotated" tag && + git checkout -b another && + git commit --allow-empty -m "future commit" && + git tag -m "future" future && + git checkout master && + git for-each-ref refs/heads/master refs/tags/tag >../expect + git push --follow-tag ../dst master + ) && + ( + cd dst && + git for-each-ref >../actual + ) && + test_cmp expect actual ' test_done diff --git a/t/t5517-push-mirror.sh b/t/t5517-push-mirror.sh index e2ad260508..12a5dfb17e 100755 --- a/t/t5517-push-mirror.sh +++ b/t/t5517-push-mirror.sh @@ -256,7 +256,7 @@ test_expect_success 'remote.foo.mirror=no has no effect' ' git branch keep master && git push --mirror up && git branch -D keep && - git push up + git push up : ) && ( cd mirror && diff --git a/t/t5519-push-alternates.sh b/t/t5519-push-alternates.sh index c00c9b071d..11fcd37700 100755 --- a/t/t5519-push-alternates.sh +++ b/t/t5519-push-alternates.sh @@ -40,7 +40,7 @@ test_expect_success 'alice works and pushes' ' cd alice-work && echo more >file && git commit -a -m second && - git push ../alice-pub + git push ../alice-pub : ) ' @@ -57,7 +57,7 @@ test_expect_success 'bob fetches from alice, works and pushes' ' git pull ../alice-pub master && echo more bob >file && git commit -a -m third && - git push ../bob-pub + git push ../bob-pub : ) && # Check that the second commit by Alice is not sent @@ -86,7 +86,7 @@ test_expect_success 'alice works and pushes again' ' cd alice-work && echo more alice >file && git commit -a -m fourth && - git push ../alice-pub + git push ../alice-pub : ) ' @@ -99,7 +99,7 @@ test_expect_success 'bob works and pushes' ' cd bob-work && echo yet more bob >file && git commit -a -m fifth && - git push ../bob-pub + git push ../bob-pub : ) ' @@ -115,7 +115,7 @@ test_expect_success 'alice works and pushes yet again' ' git commit -a -m sixth.2 && echo more and more alice >>file && git commit -a -m sixth.3 && - git push ../alice-pub + git push ../alice-pub : ) ' @@ -136,7 +136,7 @@ test_expect_success 'bob works and pushes again' ' git hash-object -t commit -w commit && echo even more bob >file && git commit -a -m seventh && - git push ../bob-pub + git push ../bob-pub : ) ' diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh index 35304b41e9..ed4d9c8318 100755 --- a/t/t5520-pull.sh +++ b/t/t5520-pull.sh @@ -57,6 +57,35 @@ test_expect_success 'pulling into void does not overwrite untracked files' ' ) ' +test_expect_success 'pulling into void does not overwrite staged files' ' + git init cloned-staged-colliding && + ( + cd cloned-staged-colliding && + echo "alternate content" >file && + git add file && + test_must_fail git pull .. master && + echo "alternate content" >expect && + test_cmp expect file && + git cat-file blob :file >file.index && + test_cmp expect file.index + ) +' + + +test_expect_success 'pulling into void does not remove new staged files' ' + git init cloned-staged-new && + ( + cd cloned-staged-new && + echo "new tracked file" >newfile && + git add newfile && + git pull .. master && + echo "new tracked file" >expect && + test_cmp expect newfile && + git cat-file blob :newfile >newfile.index && + test_cmp expect newfile.index + ) +' + test_expect_success 'test . as a remote' ' git branch copy master && @@ -96,8 +125,7 @@ test_expect_success '--rebase' ' ' test_expect_success 'pull.rebase' ' git reset --hard before-rebase && - git config --bool pull.rebase true && - test_when_finished "git config --unset pull.rebase" && + test_config pull.rebase true && git pull . copy && test $(git rev-parse HEAD^) = $(git rev-parse copy) && test new = $(git show HEAD:file2) @@ -105,8 +133,7 @@ test_expect_success 'pull.rebase' ' test_expect_success 'branch.to-rebase.rebase' ' git reset --hard before-rebase && - git config --bool branch.to-rebase.rebase true && - test_when_finished "git config --unset branch.to-rebase.rebase" && + test_config branch.to-rebase.rebase true && git pull . copy && test $(git rev-parse HEAD^) = $(git rev-parse copy) && test new = $(git show HEAD:file2) @@ -114,10 +141,8 @@ test_expect_success 'branch.to-rebase.rebase' ' test_expect_success 'branch.to-rebase.rebase should override pull.rebase' ' git reset --hard before-rebase && - git config --bool pull.rebase true && - test_when_finished "git config --unset pull.rebase" && - git config --bool branch.to-rebase.rebase false && - test_when_finished "git config --unset branch.to-rebase.rebase" && + test_config pull.rebase true && + test_config branch.to-rebase.rebase false && git pull . copy && test $(git rev-parse HEAD^) != $(git rev-parse copy) && test new = $(git show HEAD:file2) @@ -171,9 +196,9 @@ test_expect_success 'pull --rebase dies early with dirty working directory' ' git update-ref refs/remotes/me/copy copy^ && COPY=$(git rev-parse --verify me/copy) && git rebase --onto $COPY copy && - git config branch.to-rebase.remote me && - git config branch.to-rebase.merge refs/heads/copy && - git config branch.to-rebase.rebase true && + test_config branch.to-rebase.remote me && + test_config branch.to-rebase.merge refs/heads/copy && + test_config branch.to-rebase.rebase true && echo dirty >> file && git add file && test_must_fail git pull && diff --git a/t/t5521-pull-options.sh b/t/t5521-pull-options.sh index 1b06691bb4..453aba53f4 100755 --- a/t/t5521-pull-options.sh +++ b/t/t5521-pull-options.sh @@ -15,8 +15,19 @@ test_expect_success 'git pull -q' ' mkdir clonedq && (cd clonedq && git init && git pull -q "../parent" >out 2>err && - test ! -s err && - test ! -s out) + test_must_be_empty err && + test_must_be_empty out) +' + +test_expect_success 'git pull -q --rebase' ' + mkdir clonedqrb && + (cd clonedqrb && git init && + git pull -q --rebase "../parent" >out 2>err && + test_must_be_empty err && + test_must_be_empty out && + git pull -q --rebase "../parent" >out 2>err && + test_must_be_empty err && + test_must_be_empty out) ' test_expect_success 'git pull' ' @@ -24,7 +35,15 @@ test_expect_success 'git pull' ' (cd cloned && git init && git pull "../parent" >out 2>err && test -s err && - test ! -s out) + test_must_be_empty out) +' + +test_expect_success 'git pull --rebase' ' + mkdir clonedrb && + (cd clonedrb && git init && + git pull --rebase "../parent" >out 2>err && + test -s err && + test_must_be_empty out) ' test_expect_success 'git pull -v' ' @@ -32,22 +51,30 @@ test_expect_success 'git pull -v' ' (cd clonedv && git init && git pull -v "../parent" >out 2>err && test -s err && - test ! -s out) + test_must_be_empty out) +' + +test_expect_success 'git pull -v --rebase' ' + mkdir clonedvrb && + (cd clonedvrb && git init && + git pull -v --rebase "../parent" >out 2>err && + test -s err && + test_must_be_empty out) ' test_expect_success 'git pull -v -q' ' mkdir clonedvq && (cd clonedvq && git init && git pull -v -q "../parent" >out 2>err && - test ! -s out && - test ! -s err) + test_must_be_empty out && + test_must_be_empty err) ' test_expect_success 'git pull -q -v' ' mkdir clonedqv && (cd clonedqv && git init && git pull -q -v "../parent" >out 2>err && - test ! -s out && + test_must_be_empty out && test -s err) ' diff --git a/t/t5528-push-default.sh b/t/t5528-push-default.sh index 4736da8f36..6a5ac3add4 100755 --- a/t/t5528-push-default.sh +++ b/t/t5528-push-default.sh @@ -15,17 +15,19 @@ test_expect_success 'setup bare remotes' ' # $1 = local revision # $2 = remote revision (tested to be equal to the local one) +# $3 = [optional] repo to check for actual output (repo1 by default) check_pushed_commit () { git log -1 --format='%h %s' "$1" >expect && - git --git-dir=repo1 log -1 --format='%h %s' "$2" >actual && + git --git-dir="${3:-repo1}" log -1 --format='%h %s' "$2" >actual && test_cmp expect actual } # $1 = push.default value # $2 = expected target branch for the push +# $3 = [optional] repo to check for actual output (repo1 by default) test_push_success () { git -c push.default="$1" push && - check_pushed_commit HEAD "$2" + check_pushed_commit HEAD "$2" "$3" } # $1 = push.default value @@ -37,6 +39,26 @@ test_push_failure () { test_cmp expect actual } +# $1 = success or failure +# $2 = push.default value +# $3 = branch to check for actual output (master or foo) +# $4 = [optional] switch to triangular workflow +test_pushdefault_workflow () { + workflow=central + pushdefault=parent1 + if test -n "${4-}"; then + workflow=triangular + pushdefault=parent2 + fi + test_expect_success "push.default = $2 $1 in $workflow workflows" " + test_config branch.master.remote parent1 && + test_config branch.master.merge refs/heads/foo && + test_config remote.pushdefault $pushdefault && + test_commit commit-for-$2${4+-triangular} && + test_push_$1 $2 $3 ${4+repo2} + " +} + test_expect_success '"upstream" pushes to configured upstream' ' git checkout master && test_config branch.master.remote parent1 && @@ -48,7 +70,6 @@ test_expect_success '"upstream" pushes to configured upstream' ' 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 ' @@ -57,7 +78,6 @@ 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 ' @@ -115,4 +135,41 @@ test_expect_success 'push to existing branch, upstream configured with different test_cmp expect-other-name actual-other-name ' +# We are on 'master', which integrates with 'foo' from parent1 +# remote (set in test_pushdefault_workflow helper). Push to +# parent1 in centralized, and push to parent2 in triangular workflow. +# The parent1 repository has 'master' and 'foo' branches, while +# the parent2 repository has only 'master' branch. +# +# test_pushdefault_workflow() arguments: +# $1 = success or failure +# $2 = push.default value +# $3 = branch to check for actual output (master or foo) +# $4 = [optional] switch to triangular workflow + +# update parent1's master (which is not our upstream) +test_pushdefault_workflow success current master + +# update parent1's foo (which is our upstream) +test_pushdefault_workflow success upstream foo + +# upsream is foo which is not the name of the current branch +test_pushdefault_workflow failure simple master + +# master and foo are updated +test_pushdefault_workflow success matching master + +# master is updated +test_pushdefault_workflow success current master triangular + +# upstream mode cannot be used in triangular +test_pushdefault_workflow failure upstream foo triangular + +# in triangular, 'simple' works as 'current' and update the branch +# with the same name. +test_pushdefault_workflow success simple master triangular + +# master is updated (parent2 does not have foo) +test_pushdefault_workflow success matching master triangular + test_done diff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh index 1947c28c64..8c16e045a0 100755 --- a/t/t5531-deep-submodule-push.sh +++ b/t/t5531-deep-submodule-push.sh @@ -16,6 +16,7 @@ test_expect_success setup ' ( cd gar/bage && git init && + git config push.default matching && >junk && git add junk && git commit -m "Initial junk" diff --git a/t/t5535-fetch-push-symref.sh b/t/t5535-fetch-push-symref.sh new file mode 100755 index 0000000000..8ed58d27f2 --- /dev/null +++ b/t/t5535-fetch-push-symref.sh @@ -0,0 +1,42 @@ +#!/bin/sh + +test_description='avoiding conflicting update thru symref aliasing' + +. ./test-lib.sh + +test_expect_success 'setup' ' + test_commit one && + git clone . src && + git clone src dst1 && + git clone src dst2 && + test_commit two && + ( cd src && git pull ) +' + +test_expect_success 'push' ' + ( + cd src && + git push ../dst1 "refs/remotes/*:refs/remotes/*" + ) && + git ls-remote src "refs/remotes/*" >expect && + git ls-remote dst1 "refs/remotes/*" >actual && + test_cmp expect actual && + ( cd src && git symbolic-ref refs/remotes/origin/HEAD ) >expect && + ( cd dst1 && git symbolic-ref refs/remotes/origin/HEAD ) >actual && + test_cmp expect actual +' + +test_expect_success 'fetch' ' + ( + cd dst2 && + git fetch ../src "refs/remotes/*:refs/remotes/*" + ) && + git ls-remote src "refs/remotes/*" >expect && + git ls-remote dst2 "refs/remotes/*" >actual && + test_cmp expect actual && + ( cd src && git symbolic-ref refs/remotes/origin/HEAD ) >expect && + ( cd dst2 && git symbolic-ref refs/remotes/origin/HEAD ) >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t5541-http-push.sh b/t/t5541-http-push.sh index 4b4b4a604f..beb00be4b1 100755 --- a/t/t5541-http-push.sh +++ b/t/t5541-http-push.sh @@ -181,8 +181,7 @@ test_expect_success 'push (chunked)' ' git checkout master && test_commit commit path3 && HEAD=$(git rev-parse --verify HEAD) && - git config http.postbuffer 4 && - test_when_finished "git config --unset http.postbuffer" && + test_config http.postbuffer 4 && git push -v -v origin $BRANCH 2>err && grep "POST git-receive-pack (chunked)" err && (cd "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git && @@ -295,5 +294,35 @@ test_expect_success 'push to auth-only-for-push repo' ' test_cmp expect actual ' +test_expect_success 'create repo without http.receivepack set' ' + cd "$ROOT_PATH" && + git init half-auth && + ( + cd half-auth && + test_commit one + ) && + git clone --bare half-auth "$HTTPD_DOCUMENT_ROOT_PATH/half-auth.git" +' + +test_expect_success 'clone via half-auth-complete does not need password' ' + cd "$ROOT_PATH" && + set_askpass wrong && + git clone "$HTTPD_URL"/half-auth-complete/smart/half-auth.git \ + half-auth-clone && + expect_askpass none +' + +test_expect_success 'push into half-auth-complete requires password' ' + cd "$ROOT_PATH/half-auth-clone" && + echo two >expect && + test_commit two && + set_askpass user@host && + git push "$HTTPD_URL/half-auth-complete/smart/half-auth.git" && + git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/half-auth.git" \ + log -1 --format=%s >actual && + expect_askpass both user@host && + test_cmp expect actual +' + stop_httpd test_done diff --git a/t/t5550-http-fetch.sh b/t/t5550-http-fetch.sh index 80d20c876b..f7d0f146f0 100755 --- a/t/t5550-http-fetch.sh +++ b/t/t5550-http-fetch.sh @@ -13,6 +13,7 @@ LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5550'} start_httpd test_expect_success 'setup repository' ' + git config push.default matching && echo content1 >file && git add file && git commit -m one diff --git a/t/t5551-http-fetch.sh b/t/t5551-http-fetch.sh index 5060879d6d..55a866af80 100755 --- a/t/t5551-http-fetch.sh +++ b/t/t5551-http-fetch.sh @@ -13,6 +13,7 @@ LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5551'} start_httpd test_expect_success 'setup repository' ' + git config push.default matching && echo content >file && git add file && git commit -m one @@ -130,6 +131,21 @@ test_expect_success 'clone from auth-only-for-push repository' ' test_cmp expect actual ' +test_expect_success 'clone from auth-only-for-objects repository' ' + echo two >expect && + set_askpass user@host && + git clone --bare "$HTTPD_URL/auth-fetch/smart/repo.git" half-auth && + expect_askpass both user@host && + git --git-dir=half-auth log -1 --format=%s >actual && + test_cmp expect actual +' + +test_expect_success 'no-op half-auth fetch does not require a password' ' + set_askpass wrong && + git --git-dir=half-auth fetch && + expect_askpass none +' + test_expect_success 'disable dumb http on server' ' git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \ config http.getanyfile false @@ -142,6 +158,35 @@ test_expect_success 'GIT_SMART_HTTP can disable smart http' ' test_must_fail git fetch) ' +test_expect_success 'invalid Content-Type rejected' ' + test_must_fail git clone $HTTPD_URL/broken_smart/repo.git 2>actual + grep "not valid:" actual +' + +test_expect_success 'create namespaced refs' ' + test_commit namespaced && + git push public HEAD:refs/namespaces/ns/refs/heads/master && + git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \ + symbolic-ref refs/namespaces/ns/HEAD refs/namespaces/ns/refs/heads/master +' + +test_expect_success 'smart clone respects namespace' ' + git clone "$HTTPD_URL/smart_namespace/repo.git" ns-smart && + echo namespaced >expect && + git --git-dir=ns-smart/.git log -1 --format=%s >actual && + test_cmp expect actual +' + +test_expect_success 'dumb clone via http-backend respects namespace' ' + git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \ + config http.getanyfile true && + GIT_SMART_HTTP=0 git clone \ + "$HTTPD_URL/smart_namespace/repo.git" ns-dumb && + echo namespaced >expect && + git --git-dir=ns-dumb/.git log -1 --format=%s >actual && + test_cmp expect actual +' + test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE test_expect_success EXPENSIVE 'create 50,000 tags in the repo' ' @@ -164,13 +209,17 @@ test_expect_success EXPENSIVE 'create 50,000 tags in the repo' ' # 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 + 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 + test_line_count = 0 err && + ( + cd too-many-refs && + test $(git for-each-ref refs/tags | wc -l) = 50000 + ) ' stop_httpd diff --git a/t/t5560-http-backend-noserver.sh b/t/t5560-http-backend-noserver.sh index ef98d95e00..9be9ae3436 100755 --- a/t/t5560-http-backend-noserver.sh +++ b/t/t5560-http-backend-noserver.sh @@ -5,7 +5,7 @@ test_description='test git-http-backend-noserver' HTTPD_DOCUMENT_ROOT_PATH="$TRASH_DIRECTORY" -test_have_prereq MINGW && export GREP_OPTIONS=-U +test_have_prereq GREP_STRIPS_CR && export GREP_OPTIONS=-U run_backend() { echo "$2" | diff --git a/t/t5570-git-daemon.sh b/t/t5570-git-daemon.sh index a3a4e47e1d..f01edffa3c 100755 --- a/t/t5570-git-daemon.sh +++ b/t/t5570-git-daemon.sh @@ -8,6 +8,7 @@ LIB_GIT_DAEMON_PORT=${LIB_GIT_DAEMON_PORT-5570} start_git_daemon test_expect_success 'setup repository' ' + git config push.default matching && echo content >file && git add file && git commit -m one diff --git a/t/t5571-pre-push-hook.sh b/t/t5571-pre-push-hook.sh new file mode 100755 index 0000000000..6f9916a390 --- /dev/null +++ b/t/t5571-pre-push-hook.sh @@ -0,0 +1,131 @@ +#!/bin/sh + +test_description='check pre-push hooks' +. ./test-lib.sh + +# Setup hook that always succeeds +HOOKDIR="$(git rev-parse --git-dir)/hooks" +HOOK="$HOOKDIR/pre-push" +mkdir -p "$HOOKDIR" +write_script "$HOOK" <<EOF +cat >/dev/null +exit 0 +EOF + +test_expect_success 'setup' ' + git config push.default upstream && + git init --bare repo1 && + git remote add parent1 repo1 && + test_commit one && + git push parent1 HEAD:foreign +' +write_script "$HOOK" <<EOF +cat >/dev/null +exit 1 +EOF + +COMMIT1="$(git rev-parse HEAD)" +export COMMIT1 + +test_expect_success 'push with failing hook' ' + test_commit two && + test_must_fail git push parent1 HEAD +' + +test_expect_success '--no-verify bypasses hook' ' + git push --no-verify parent1 HEAD +' + +COMMIT2="$(git rev-parse HEAD)" +export COMMIT2 + +write_script "$HOOK" <<'EOF' +echo "$1" >actual +echo "$2" >>actual +cat >>actual +EOF + +cat >expected <<EOF +parent1 +repo1 +refs/heads/master $COMMIT2 refs/heads/foreign $COMMIT1 +EOF + +test_expect_success 'push with hook' ' + git push parent1 master:foreign && + diff expected actual +' + +test_expect_success 'add a branch' ' + git checkout -b other parent1/foreign && + test_commit three +' + +COMMIT3="$(git rev-parse HEAD)" +export COMMIT3 + +cat >expected <<EOF +parent1 +repo1 +refs/heads/other $COMMIT3 refs/heads/foreign $COMMIT2 +EOF + +test_expect_success 'push to default' ' + git push && + diff expected actual +' + +cat >expected <<EOF +parent1 +repo1 +refs/tags/one $COMMIT1 refs/tags/tag1 $_z40 +HEAD~ $COMMIT2 refs/heads/prev $_z40 +EOF + +test_expect_success 'push non-branches' ' + git push parent1 one:tag1 HEAD~:refs/heads/prev && + diff expected actual +' + +cat >expected <<EOF +parent1 +repo1 +(delete) $_z40 refs/heads/prev $COMMIT2 +EOF + +test_expect_success 'push delete' ' + git push parent1 :prev && + diff expected actual +' + +cat >expected <<EOF +repo1 +repo1 +HEAD $COMMIT3 refs/heads/other $_z40 +EOF + +test_expect_success 'push to URL' ' + git push repo1 HEAD && + diff expected actual +' + +# Test that filling pipe buffers doesn't cause failure +# Too slow to leave enabled for general use +if false +then + printf 'parent1\nrepo1\n' >expected + nr=1000 + while test $nr -lt 2000 + do + nr=$(( $nr + 1 )) + git branch b/$nr $COMMIT3 + echo "refs/heads/b/$nr $COMMIT3 refs/heads/b/$nr $_z40" >>expected + done + + test_expect_success 'push many refs' ' + git push parent1 "refs/heads/b/*:refs/heads/b/*" && + diff expected actual + ' +fi + +test_done diff --git a/t/t5600-clone-fail-cleanup.sh b/t/t5600-clone-fail-cleanup.sh index ee06d28649..4435693bb2 100755 --- a/t/t5600-clone-fail-cleanup.sh +++ b/t/t5600-clone-fail-cleanup.sh @@ -37,6 +37,16 @@ test_expect_success \ test_expect_success \ 'successful clone must leave the directory' \ - 'cd bar' + 'test -d bar' + +test_expect_success 'failed clone --separate-git-dir should not leave any directories' ' + mkdir foo/.git/objects.bak/ && + mv foo/.git/objects/* foo/.git/objects.bak/ && + test_must_fail git clone --separate-git-dir gitdir foo worktree && + test_must_fail test -e gitdir && + test_must_fail test -e worktree && + mv foo/.git/objects.bak/* foo/.git/objects/ && + rmdir foo/.git/objects.bak +' test_done diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index 67869b4813..0629149edd 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -280,4 +280,9 @@ test_expect_success 'clone checking out a tag' ' test_cmp fetch.expected fetch.actual ' +test_expect_success NOT_MINGW,NOT_CYGWIN 'clone local path foo:bar' ' + cp -R src "foo:bar" && + git clone "./foo:bar" foobar +' + test_done diff --git a/t/t5700-clone-reference.sh b/t/t5700-clone-reference.sh index c47d450cc3..6537911a43 100755 --- a/t/t5700-clone-reference.sh +++ b/t/t5700-clone-reference.sh @@ -54,11 +54,14 @@ cd "$base_dir" 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.D"' +test_expect_success 'cloning with reference (no -l -s)' ' + GIT_TRACE_PACKET=$U.D git clone --reference B "file://$(pwd)/A" D +' -test_expect_success 'fetched no objects' \ -'! grep "^want" "$U.D"' +test_expect_success 'fetched no objects' ' + test -s "$U.D" && + ! grep " want" "$U.D" +' cd "$base_dir" @@ -173,12 +176,26 @@ test_expect_success 'fetch with incomplete alternates' ' ( cd K && git remote add J "file://$base_dir/J" && - GIT_DEBUG_SEND_PACK=3 git fetch J 3>"$U.K" + GIT_TRACE_PACKET=$U.K git fetch J ) && master_object=$(cd A && git for-each-ref --format="%(objectname)" refs/heads/master) && - ! grep "^want $master_object" "$U.K" && + test -s "$U.K" && + ! 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" + ! grep " want $tag_object" "$U.K" +' + +test_expect_success 'clone using repo with gitfile as a reference' ' + git clone --separate-git-dir=L A M && + git clone --reference=M A N && + echo "$base_dir/L/objects" >expected && + test_cmp expected "$base_dir/N/.git/objects/info/alternates" +' + +test_expect_success 'clone using repo pointed at by gitfile as reference' ' + git clone --reference=M/.git A O && + echo "$base_dir/L/objects" >expected && + test_cmp expected "$base_dir/O/.git/objects/info/alternates" ' test_done diff --git a/t/t5702-clone-options.sh b/t/t5702-clone-options.sh index 02cb024723..85cadfad6d 100755 --- a/t/t5702-clone-options.sh +++ b/t/t5702-clone-options.sh @@ -22,7 +22,7 @@ test_expect_success 'clone -o' ' test_expect_success 'redirected clone' ' git clone "file://$(pwd)/parent" clone-redirected >out 2>err && - test ! -s err + test_must_be_empty err ' test_expect_success 'redirected clone -v' ' diff --git a/t/t5704-bundle.sh b/t/t5704-bundle.sh index 9e43731fe5..a45c31692e 100755 --- a/t/t5704-bundle.sh +++ b/t/t5704-bundle.sh @@ -58,4 +58,14 @@ test_expect_success 'ridiculously long subject in boundary' ' grep "^-[0-9a-f]\\{40\\} " boundary ' +test_expect_success 'prerequisites with an empty commit message' ' + : >file1 && + git add file1 && + test_tick && + git commit --allow-empty-message -m "" && + test_commit file2 && + git bundle create bundle HEAD^.. && + git bundle verify bundle +' + test_done diff --git a/t/t5710-info-alternate.sh b/t/t5710-info-alternate.sh index aa045295de..5a6e49d18d 100755 --- a/t/t5710-info-alternate.sh +++ b/t/t5710-info-alternate.sh @@ -58,7 +58,7 @@ test_expect_success 'creating too deep nesting' \ git clone -l -s D E && git clone -l -s E F && git clone -l -s F G && -git clone -l -s G H' +git clone --bare -l -s G H' test_expect_success 'invalidity of deepest repository' \ 'cd H && { diff --git a/t/t5800-remote-helpers.sh b/t/t5800-remote-testpy.sh index e7dc668cef..1e683d4220 100755 --- a/t/t5800-remote-helpers.sh +++ b/t/t5800-remote-testpy.sh @@ -3,12 +3,12 @@ # Copyright (c) 2010 Sverre Rabbelier # -test_description='Test remote-helper import and export commands' +test_description='Test python remote-helper framework' . ./test-lib.sh if ! test_have_prereq PYTHON ; then - skip_all='skipping git-remote-hg tests, python not available' + skip_all='skipping python remote-helper tests, python not available' test_done fi @@ -17,7 +17,7 @@ import sys if sys.hexversion < 0x02040000: sys.exit(1) ' || { - skip_all='skipping git-remote-hg tests, python version < 2.4' + skip_all='skipping python remote-helper tests, python version < 2.4' test_done } @@ -38,12 +38,12 @@ test_expect_success 'setup repository' ' ' test_expect_success 'cloning from local repo' ' - git clone "testgit::${PWD}/server" localclone && + git clone "testpy::${PWD}/server" localclone && test_cmp public/file localclone/file ' test_expect_success 'cloning from remote repo' ' - git clone "testgit::file://${PWD}/server" clone && + git clone "testpy::file://${PWD}/server" clone && test_cmp public/file clone/file ' @@ -73,11 +73,11 @@ test_expect_success 'pushing to local repo' ' ' # Generally, skip this test. It demonstrates a now-fixed race in -# git-remote-testgit, but is too slow to leave in for general use. +# git-remote-testpy, 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 -R server server2 && - git clone "testgit::${PWD}/server2" localclone2 && + git clone "testpy::${PWD}/server2" localclone2 && (cd localclone2 && echo content >>file && git commit -a -m three && @@ -145,4 +145,25 @@ test_expect_failure 'push new branch with old:new refspec' ' compare_refs clone HEAD server refs/heads/new-refspec ' +test_expect_success 'proper failure checks for fetching' ' + (GIT_REMOTE_TESTGIT_FAILURE=1 && + export GIT_REMOTE_TESTGIT_FAILURE && + cd localclone && + test_must_fail git fetch 2>&1 | \ + grep "Error while running fast-import" + ) +' + +# We sleep to give fast-export a chance to catch the SIGPIPE +test_expect_failure 'proper failure checks for pushing' ' + (GIT_REMOTE_TESTGIT_FAILURE=1 && + export GIT_REMOTE_TESTGIT_FAILURE && + GIT_REMOTE_TESTGIT_SLEEPY=1 && + export GIT_REMOTE_TESTGIT_SLEEPY && + cd localclone && + test_must_fail git push --all 2>&1 | \ + grep "Error while running fast-export" + ) +' + test_done diff --git a/t/t5801-remote-helpers.sh b/t/t5801-remote-helpers.sh new file mode 100755 index 0000000000..8c4c5396a8 --- /dev/null +++ b/t/t5801-remote-helpers.sh @@ -0,0 +1,231 @@ +#!/bin/sh +# +# Copyright (c) 2010 Sverre Rabbelier +# + +test_description='Test remote-helper import and export commands' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-gpg.sh + +compare_refs() { + git --git-dir="$1/.git" rev-parse --verify $2 >expect && + git --git-dir="$3/.git" rev-parse --verify $4 >actual && + test_cmp expect actual +} + +test_expect_success 'setup repository' ' + git init server && + (cd server && + echo content >file && + git add file && + git commit -m one) +' + +test_expect_success 'cloning from local repo' ' + git clone "testgit::${PWD}/server" local && + test_cmp server/file local/file +' + +test_expect_success 'create new commit on remote' ' + (cd server && + echo content >>file && + git commit -a -m two) +' + +test_expect_success 'pulling from local repo' ' + (cd local && git pull) && + test_cmp server/file local/file +' + +test_expect_success 'pushing to local repo' ' + (cd local && + echo content >>file && + git commit -a -m three && + git push) && + compare_refs local HEAD server HEAD +' + +test_expect_success 'fetch new branch' ' + (cd server && + git reset --hard && + git checkout -b new && + echo content >>file && + git commit -a -m five + ) && + (cd local && + git fetch origin new + ) && + compare_refs server HEAD local FETCH_HEAD +' + +test_expect_success 'fetch multiple branches' ' + (cd local && + git fetch + ) && + compare_refs server master local refs/remotes/origin/master && + compare_refs server new local refs/remotes/origin/new +' + +test_expect_success 'push when remote has extra refs' ' + (cd local && + git reset --hard origin/master && + echo content >>file && + git commit -a -m six && + git push + ) && + compare_refs local master server master +' + +test_expect_success 'push new branch by name' ' + (cd local && + git checkout -b new-name && + echo content >>file && + git commit -a -m seven && + git push origin new-name + ) && + compare_refs local HEAD server refs/heads/new-name +' + +test_expect_failure 'push new branch with old:new refspec' ' + (cd local && + git push origin new-name:new-refspec + ) && + compare_refs local HEAD server refs/heads/new-refspec +' + +test_expect_success 'cloning without refspec' ' + GIT_REMOTE_TESTGIT_REFSPEC="" \ + git clone "testgit::${PWD}/server" local2 2>error && + grep "This remote helper should implement refspec capability" error && + compare_refs local2 HEAD server HEAD +' + +test_expect_success 'pulling without refspecs' ' + (cd local2 && + git reset --hard && + GIT_REMOTE_TESTGIT_REFSPEC="" git pull 2>../error) && + grep "This remote helper should implement refspec capability" error && + compare_refs local2 HEAD server HEAD +' + +test_expect_success 'pushing without refspecs' ' + test_when_finished "(cd local2 && git reset --hard origin)" && + (cd local2 && + echo content >>file && + git commit -a -m ten && + GIT_REMOTE_TESTGIT_REFSPEC="" && + export GIT_REMOTE_TESTGIT_REFSPEC && + test_must_fail git push 2>../error) && + grep "remote-helper doesn.t support push; refspec needed" error +' + +test_expect_success 'pulling without marks' ' + (cd local2 && + GIT_REMOTE_TESTGIT_NO_MARKS=1 git pull) && + compare_refs local2 HEAD server HEAD +' + +test_expect_failure 'pushing without marks' ' + test_when_finished "(cd local2 && git reset --hard origin)" && + (cd local2 && + echo content >>file && + git commit -a -m twelve && + GIT_REMOTE_TESTGIT_NO_MARKS=1 git push) && + compare_refs local2 HEAD server HEAD +' + +test_expect_success 'push all with existing object' ' + (cd local && + git branch dup2 master && + git push origin --all + ) && + compare_refs local dup2 server dup2 +' + +test_expect_success 'push ref with existing object' ' + (cd local && + git branch dup master && + git push origin dup + ) && + compare_refs local dup server dup +' + +test_expect_success GPG 'push signed tag' ' + (cd local && + git checkout master && + git tag -s -m signed-tag signed-tag && + git push origin signed-tag + ) && + compare_refs local signed-tag^{} server signed-tag^{} && + test_must_fail compare_refs local signed-tag server signed-tag +' + +test_expect_success GPG 'push signed tag with signed-tags capability' ' + (cd local && + git checkout master && + git tag -s -m signed-tag signed-tag-2 && + GIT_REMOTE_TESTGIT_SIGNED_TAGS=1 git push origin signed-tag-2 + ) && + compare_refs local signed-tag-2 server signed-tag-2 +' + +test_expect_success 'push update refs' ' + (cd local && + git checkout -b update master && + echo update >>file && + git commit -a -m update && + git push origin update && + git rev-parse --verify remotes/origin/update >expect && + git rev-parse --verify testgit/origin/heads/update >actual && + test_cmp expect actual + ) +' + +test_expect_success 'push update refs failure' ' + (cd local && + git checkout update && + echo "update fail" >>file && + git commit -a -m "update fail" && + git rev-parse --verify testgit/origin/heads/update >expect && + GIT_REMOTE_TESTGIT_PUSH_ERROR="non-fast forward" && + export GIT_REMOTE_TESTGIT_PUSH_ERROR && + test_expect_code 1 git push origin update && + git rev-parse --verify testgit/origin/heads/update >actual && + test_cmp expect actual + ) +' + +test_expect_success 'proper failure checks for fetching' ' + (GIT_REMOTE_TESTGIT_FAILURE=1 && + export GIT_REMOTE_TESTGIT_FAILURE && + cd local && + test_must_fail git fetch 2> error && + cat error && + grep -q "Error while running fast-import" error + ) +' + +test_expect_success 'proper failure checks for pushing' ' + (GIT_REMOTE_TESTGIT_FAILURE=1 && + export GIT_REMOTE_TESTGIT_FAILURE && + cd local && + test_must_fail git push --all + ) +' + +test_expect_success 'push messages' ' + (cd local && + git checkout -b new_branch master && + echo new >>file && + git commit -a -m new && + git push origin new_branch && + git fetch origin && + echo new >>file && + git commit -a -m new && + git push origin new_branch 2> msg && + ! grep "\[new branch\]" msg + ) +' + +test_done diff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh index fb07536a0f..43ad772484 100755 --- a/t/t6002-rev-list-bisect.sh +++ b/t/t6002-rev-list-bisect.sh @@ -39,25 +39,25 @@ test_bisection_diff() date >path0 git update-index --add path0 save_tag tree git write-tree -on_committer_date "1971-08-16 00:00:00" hide_error save_tag root unique_commit root tree -on_committer_date "1971-08-16 00:00:01" save_tag l0 unique_commit l0 tree -p root -on_committer_date "1971-08-16 00:00:02" save_tag l1 unique_commit l1 tree -p l0 -on_committer_date "1971-08-16 00:00:03" save_tag l2 unique_commit l2 tree -p l1 -on_committer_date "1971-08-16 00:00:04" save_tag a0 unique_commit a0 tree -p l2 -on_committer_date "1971-08-16 00:00:05" save_tag a1 unique_commit a1 tree -p a0 -on_committer_date "1971-08-16 00:00:06" save_tag b1 unique_commit b1 tree -p a0 -on_committer_date "1971-08-16 00:00:07" save_tag c1 unique_commit c1 tree -p b1 -on_committer_date "1971-08-16 00:00:08" save_tag b2 unique_commit b2 tree -p b1 -on_committer_date "1971-08-16 00:00:09" save_tag b3 unique_commit b2 tree -p b2 -on_committer_date "1971-08-16 00:00:10" save_tag c2 unique_commit c2 tree -p c1 -p b2 -on_committer_date "1971-08-16 00:00:11" save_tag c3 unique_commit c3 tree -p c2 -on_committer_date "1971-08-16 00:00:12" save_tag a2 unique_commit a2 tree -p a1 -on_committer_date "1971-08-16 00:00:13" save_tag a3 unique_commit a3 tree -p a2 -on_committer_date "1971-08-16 00:00:14" save_tag b4 unique_commit b4 tree -p b3 -p a3 -on_committer_date "1971-08-16 00:00:15" save_tag a4 unique_commit a4 tree -p a3 -p b4 -p c3 -on_committer_date "1971-08-16 00:00:16" save_tag l3 unique_commit l3 tree -p a4 -on_committer_date "1971-08-16 00:00:17" save_tag l4 unique_commit l4 tree -p l3 -on_committer_date "1971-08-16 00:00:18" save_tag l5 unique_commit l5 tree -p l4 +on_committer_date "00:00" hide_error save_tag root unique_commit root tree +on_committer_date "00:01" save_tag l0 unique_commit l0 tree -p root +on_committer_date "00:02" save_tag l1 unique_commit l1 tree -p l0 +on_committer_date "00:03" save_tag l2 unique_commit l2 tree -p l1 +on_committer_date "00:04" save_tag a0 unique_commit a0 tree -p l2 +on_committer_date "00:05" save_tag a1 unique_commit a1 tree -p a0 +on_committer_date "00:06" save_tag b1 unique_commit b1 tree -p a0 +on_committer_date "00:07" save_tag c1 unique_commit c1 tree -p b1 +on_committer_date "00:08" save_tag b2 unique_commit b2 tree -p b1 +on_committer_date "00:09" save_tag b3 unique_commit b2 tree -p b2 +on_committer_date "00:10" save_tag c2 unique_commit c2 tree -p c1 -p b2 +on_committer_date "00:11" save_tag c3 unique_commit c3 tree -p c2 +on_committer_date "00:12" save_tag a2 unique_commit a2 tree -p a1 +on_committer_date "00:13" save_tag a3 unique_commit a3 tree -p a2 +on_committer_date "00:14" save_tag b4 unique_commit b4 tree -p b3 -p a3 +on_committer_date "00:15" save_tag a4 unique_commit a4 tree -p a3 -p b4 -p c3 +on_committer_date "00:16" save_tag l3 unique_commit l3 tree -p a4 +on_committer_date "00:17" save_tag l4 unique_commit l4 tree -p l3 +on_committer_date "00:18" save_tag l5 unique_commit l5 tree -p l4 git update-ref HEAD $(tag l5) @@ -90,29 +90,29 @@ git update-ref HEAD $(tag l5) # F -on_committer_date "1971-08-16 00:00:00" hide_error save_tag F unique_commit F tree -on_committer_date "1971-08-16 00:00:01" save_tag e8 unique_commit e8 tree -p F -on_committer_date "1971-08-16 00:00:02" save_tag e7 unique_commit e7 tree -p e8 -on_committer_date "1971-08-16 00:00:03" save_tag e6 unique_commit e6 tree -p e7 -on_committer_date "1971-08-16 00:00:04" save_tag e5 unique_commit e5 tree -p e6 -on_committer_date "1971-08-16 00:00:05" save_tag f4 unique_commit f4 tree -p F -on_committer_date "1971-08-16 00:00:06" save_tag f3 unique_commit f3 tree -p f4 -on_committer_date "1971-08-16 00:00:07" save_tag f2 unique_commit f2 tree -p f3 -on_committer_date "1971-08-16 00:00:08" save_tag f1 unique_commit f1 tree -p f2 -on_committer_date "1971-08-16 00:00:09" save_tag e4 unique_commit e4 tree -p e5 -on_committer_date "1971-08-16 00:00:10" save_tag e3 unique_commit e3 tree -p e4 -on_committer_date "1971-08-16 00:00:11" save_tag e2 unique_commit e2 tree -p e3 -on_committer_date "1971-08-16 00:00:12" save_tag e1 unique_commit e1 tree -p e2 -on_committer_date "1971-08-16 00:00:13" save_tag E unique_commit E tree -p e1 -p f1 - -on_committer_date "1971-08-16 00:00:00" hide_error save_tag U unique_commit U tree -on_committer_date "1971-08-16 00:00:01" save_tag u0 unique_commit u0 tree -p U -on_committer_date "1971-08-16 00:00:01" save_tag u1 unique_commit u1 tree -p u0 -on_committer_date "1971-08-16 00:00:02" save_tag u2 unique_commit u2 tree -p u0 -on_committer_date "1971-08-16 00:00:03" save_tag u3 unique_commit u3 tree -p u0 -on_committer_date "1971-08-16 00:00:04" save_tag u4 unique_commit u4 tree -p u0 -on_committer_date "1971-08-16 00:00:05" save_tag u5 unique_commit u5 tree -p u0 -on_committer_date "1971-08-16 00:00:06" save_tag V unique_commit V tree -p u1 -p u2 -p u3 -p u4 -p u5 +on_committer_date "00:00" hide_error save_tag F unique_commit F tree +on_committer_date "00:01" save_tag e8 unique_commit e8 tree -p F +on_committer_date "00:02" save_tag e7 unique_commit e7 tree -p e8 +on_committer_date "00:03" save_tag e6 unique_commit e6 tree -p e7 +on_committer_date "00:04" save_tag e5 unique_commit e5 tree -p e6 +on_committer_date "00:05" save_tag f4 unique_commit f4 tree -p F +on_committer_date "00:06" save_tag f3 unique_commit f3 tree -p f4 +on_committer_date "00:07" save_tag f2 unique_commit f2 tree -p f3 +on_committer_date "00:08" save_tag f1 unique_commit f1 tree -p f2 +on_committer_date "00:09" save_tag e4 unique_commit e4 tree -p e5 +on_committer_date "00:10" save_tag e3 unique_commit e3 tree -p e4 +on_committer_date "00:11" save_tag e2 unique_commit e2 tree -p e3 +on_committer_date "00:12" save_tag e1 unique_commit e1 tree -p e2 +on_committer_date "00:13" save_tag E unique_commit E tree -p e1 -p f1 + +on_committer_date "00:00" hide_error save_tag U unique_commit U tree +on_committer_date "00:01" save_tag u0 unique_commit u0 tree -p U +on_committer_date "00:01" save_tag u1 unique_commit u1 tree -p u0 +on_committer_date "00:02" save_tag u2 unique_commit u2 tree -p u0 +on_committer_date "00:03" save_tag u3 unique_commit u3 tree -p u0 +on_committer_date "00:04" save_tag u4 unique_commit u4 tree -p u0 +on_committer_date "00:05" save_tag u5 unique_commit u5 tree -p u0 +on_committer_date "00:06" save_tag V unique_commit V tree -p u1 -p u2 -p u3 -p u4 -p u5 test_sequence() { diff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh index e4c52b0214..24d1836f41 100755 --- a/t/t6003-rev-list-topo-order.sh +++ b/t/t6003-rev-list-topo-order.sh @@ -16,39 +16,34 @@ list_duplicates() date >path0 git update-index --add path0 save_tag tree git write-tree -on_committer_date "1971-08-16 00:00:00" hide_error save_tag root unique_commit root tree -on_committer_date "1971-08-16 00:00:01" save_tag l0 unique_commit l0 tree -p root -on_committer_date "1971-08-16 00:00:02" save_tag l1 unique_commit l1 tree -p l0 -on_committer_date "1971-08-16 00:00:03" save_tag l2 unique_commit l2 tree -p l1 -on_committer_date "1971-08-16 00:00:04" save_tag a0 unique_commit a0 tree -p l2 -on_committer_date "1971-08-16 00:00:05" save_tag a1 unique_commit a1 tree -p a0 -on_committer_date "1971-08-16 00:00:06" save_tag b1 unique_commit b1 tree -p a0 -on_committer_date "1971-08-16 00:00:07" save_tag c1 unique_commit c1 tree -p b1 -on_committer_date "1971-08-16 00:00:08" as_author foobar@example.com save_tag b2 unique_commit b2 tree -p b1 -on_committer_date "1971-08-16 00:00:09" save_tag b3 unique_commit b3 tree -p b2 -on_committer_date "1971-08-16 00:00:10" save_tag c2 unique_commit c2 tree -p c1 -p b2 -on_committer_date "1971-08-16 00:00:11" save_tag c3 unique_commit c3 tree -p c2 -on_committer_date "1971-08-16 00:00:12" save_tag a2 unique_commit a2 tree -p a1 -on_committer_date "1971-08-16 00:00:13" save_tag a3 unique_commit a3 tree -p a2 -on_committer_date "1971-08-16 00:00:14" save_tag b4 unique_commit b4 tree -p b3 -p a3 -on_committer_date "1971-08-16 00:00:15" save_tag a4 unique_commit a4 tree -p a3 -p b4 -p c3 -on_committer_date "1971-08-16 00:00:16" save_tag l3 unique_commit l3 tree -p a4 -on_committer_date "1971-08-16 00:00:17" save_tag l4 unique_commit l4 tree -p l3 -on_committer_date "1971-08-16 00:00:18" save_tag l5 unique_commit l5 tree -p l4 -on_committer_date "1971-08-16 00:00:19" save_tag m1 unique_commit m1 tree -p a4 -p c3 -on_committer_date "1971-08-16 00:00:20" save_tag m2 unique_commit m2 tree -p c3 -p a4 -on_committer_date "1971-08-16 00:00:21" hide_error save_tag alt_root unique_commit alt_root tree -on_committer_date "1971-08-16 00:00:22" save_tag r0 unique_commit r0 tree -p alt_root -on_committer_date "1971-08-16 00:00:23" save_tag r1 unique_commit r1 tree -p r0 -on_committer_date "1971-08-16 00:00:24" save_tag l5r1 unique_commit l5r1 tree -p l5 -p r1 -on_committer_date "1971-08-16 00:00:25" save_tag r1l5 unique_commit r1l5 tree -p r1 -p l5 +on_dates "00:00" "00:00" hide_error save_tag root unique_commit root tree +on_dates "00:01" "00:01" save_tag l0 unique_commit l0 tree -p root +on_dates "00:02" "00:02" save_tag l1 unique_commit l1 tree -p l0 +on_dates "00:03" "00:03" save_tag l2 unique_commit l2 tree -p l1 +on_dates "00:04" "00:04" save_tag a0 unique_commit a0 tree -p l2 +on_dates "00:05" "00:05" save_tag a1 unique_commit a1 tree -p a0 +on_dates "00:06" "00:06" save_tag b1 unique_commit b1 tree -p a0 +on_dates "00:07" "00:07" save_tag c1 unique_commit c1 tree -p b1 +on_dates "00:08" "00:08" as_author foobar@example.com save_tag b2 unique_commit b2 tree -p b1 +on_dates "00:09" "00:09" save_tag b3 unique_commit b3 tree -p b2 +on_dates "00:10" "00:10" save_tag c2 unique_commit c2 tree -p c1 -p b2 +on_dates "00:11" "00:11" save_tag c3 unique_commit c3 tree -p c2 +on_dates "00:12" "00:00" save_tag a2 unique_commit a2 tree -p a1 +on_dates "00:13" "00:01" save_tag a3 unique_commit a3 tree -p a2 +on_dates "00:14" "00:14" save_tag b4 unique_commit b4 tree -p b3 -p a3 +on_dates "00:15" "00:15" save_tag a4 unique_commit a4 tree -p a3 -p b4 -p c3 +on_dates "00:16" "00:16" save_tag l3 unique_commit l3 tree -p a4 +on_dates "00:17" "00:17" save_tag l4 unique_commit l4 tree -p l3 +on_dates "00:18" "00:18" save_tag l5 unique_commit l5 tree -p l4 +on_dates "00:19" "00:19" save_tag m1 unique_commit m1 tree -p a4 -p c3 +on_dates "00:20" "00:20" save_tag m2 unique_commit m2 tree -p c3 -p a4 +on_dates "00:21" "00:21" hide_error save_tag alt_root unique_commit alt_root tree +on_dates "00:22" "00:22" save_tag r0 unique_commit r0 tree -p alt_root +on_dates "00:23" "00:23" save_tag r1 unique_commit r1 tree -p r0 +on_dates "00:24" "00:24" save_tag l5r1 unique_commit l5r1 tree -p l5 -p r1 +on_dates "00:25" "00:25" save_tag r1l5 unique_commit r1l5 tree -p r1 -p l5 -# -# note: as of 20/6, it isn't possible to create duplicate parents, so this -# can't be tested. -# -#on_committer_date "1971-08-16 00:00:20" save_tag m3 unique_commit m3 tree -p c3 -p a4 -p c3 hide_error save_tag e1 as_author e@example.com unique_commit e1 tree save_tag e2 as_author e@example.com unique_commit e2 tree -p e1 save_tag f1 as_author f@example.com unique_commit f1 tree -p e1 @@ -105,6 +100,50 @@ l0 root EOF +test_output_expect_success 'simple date order' 'git rev-list --date-order HEAD' <<EOF +l5 +l4 +l3 +a4 +b4 +a3 +a2 +c3 +c2 +b3 +b2 +c1 +b1 +a1 +a0 +l2 +l1 +l0 +root +EOF + +test_output_expect_success 'simple author-date order' 'git rev-list --author-date-order HEAD' <<EOF +l5 +l4 +l3 +a4 +b4 +c3 +c2 +b3 +b2 +c1 +b1 +a3 +a2 +a1 +a0 +l2 +l1 +l0 +root +EOF + test_output_expect_success 'two diamonds topo order (g6)' 'git rev-list --topo-order g4' <<EOF g4 h2 diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh index f94f0c48e6..98744038ec 100755 --- a/t/t6006-rev-list-format.sh +++ b/t/t6006-rev-list-format.sh @@ -1,67 +1,105 @@ #!/bin/sh +# Copyright (c) 2009 Jens Lehmann +# Copyright (c) 2011 Alexey Shumkin (+ non-UTF-8 commit encoding tests) + test_description='git rev-list --pretty=format test' . ./test-lib.sh +. "$TEST_DIRECTORY"/lib-terminal.sh test_tick +# String "added" in German +# (translated with Google Translate), +# encoded in UTF-8, used as a commit log message below. +added=$(printf "added (hinzugef\303\274gt) foo") +added_iso88591=$(echo "$added" | iconv -f utf-8 -t iso8859-1) +# same but "changed" +changed=$(printf "changed (ge\303\244ndert) foo") +changed_iso88591=$(echo "$changed" | iconv -f utf-8 -t iso8859-1) + test_expect_success 'setup' ' -touch foo && git add foo && git commit -m "added foo" && - echo changed >foo && git commit -a -m "changed foo" + : >foo && + git add foo && + git config i18n.commitEncoding iso8859-1 && + git commit -m "$added_iso88591" && + head1=$(git rev-parse --verify HEAD) && + head1_short=$(git rev-parse --verify --short $head1) && + tree1=$(git rev-parse --verify HEAD:) && + tree1_short=$(git rev-parse --verify --short $tree1) && + echo "$changed" > foo && + git commit -a -m "$changed_iso88591" && + head2=$(git rev-parse --verify HEAD) && + head2_short=$(git rev-parse --verify --short $head2) && + tree2=$(git rev-parse --verify HEAD:) && + tree2_short=$(git rev-parse --verify --short $tree2) + git config --unset i18n.commitEncoding ' -# usage: test_format name format_string <expected_output -test_format() { +# usage: test_format name format_string [failure] <expected_output +test_format () { cat >expect.$1 - test_expect_success "format $1" " -git rev-list --pretty=format:'$2' master >output.$1 && -test_cmp expect.$1 output.$1 -" + test_expect_${3:-success} "format $1" " + git rev-list --pretty=format:'$2' master >output.$1 && + test_cmp expect.$1 output.$1 + " } -test_format percent %%h <<'EOF' -commit 131a310eb913d107dd3c09a65d1651175898735d +# Feed to --format to provide predictable colored sequences. +AUTO_COLOR='%C(auto,red)foo%C(auto,reset)' +has_color () { + printf '\033[31mfoo\033[m\n' >expect && + test_cmp expect "$1" +} + +has_no_color () { + echo foo >expect && + test_cmp expect "$1" +} + +test_format percent %%h <<EOF +commit $head2 %h -commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873 +commit $head1 %h EOF -test_format hash %H%n%h <<'EOF' -commit 131a310eb913d107dd3c09a65d1651175898735d -131a310eb913d107dd3c09a65d1651175898735d -131a310 -commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873 -86c75cfd708a0e5868dc876ed5b8bb66c80b4873 -86c75cf +test_format hash %H%n%h <<EOF +commit $head2 +$head2 +$head2_short +commit $head1 +$head1 +$head1_short EOF -test_format tree %T%n%t <<'EOF' -commit 131a310eb913d107dd3c09a65d1651175898735d -fe722612f26da5064c32ca3843aa154bdb0b08a0 -fe72261 -commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873 -4d5fcadc293a348e88f777dc0920f11e7d71441c -4d5fcad +test_format tree %T%n%t <<EOF +commit $head2 +$tree2 +$tree2_short +commit $head1 +$tree1 +$tree1_short EOF -test_format parents %P%n%p <<'EOF' -commit 131a310eb913d107dd3c09a65d1651175898735d -86c75cfd708a0e5868dc876ed5b8bb66c80b4873 -86c75cf -commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873 +test_format parents %P%n%p <<EOF +commit $head2 +$head1 +$head1_short +commit $head1 EOF # we don't test relative here -test_format author %an%n%ae%n%ad%n%aD%n%at <<'EOF' -commit 131a310eb913d107dd3c09a65d1651175898735d +test_format author %an%n%ae%n%ad%n%aD%n%at <<EOF +commit $head2 A U Thor author@example.com Thu Apr 7 15:13:13 2005 -0700 Thu, 7 Apr 2005 15:13:13 -0700 1112911993 -commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873 +commit $head1 A U Thor author@example.com Thu Apr 7 15:13:13 2005 -0700 @@ -69,14 +107,14 @@ Thu, 7 Apr 2005 15:13:13 -0700 1112911993 EOF -test_format committer %cn%n%ce%n%cd%n%cD%n%ct <<'EOF' -commit 131a310eb913d107dd3c09a65d1651175898735d +test_format committer %cn%n%ce%n%cd%n%cD%n%ct <<EOF +commit $head2 C O Mitter committer@example.com Thu Apr 7 15:13:13 2005 -0700 Thu, 7 Apr 2005 15:13:13 -0700 1112911993 -commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873 +commit $head1 C O Mitter committer@example.com Thu Apr 7 15:13:13 2005 -0700 @@ -84,86 +122,155 @@ Thu, 7 Apr 2005 15:13:13 -0700 1112911993 EOF -test_format encoding %e <<'EOF' -commit 131a310eb913d107dd3c09a65d1651175898735d -commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873 +test_format encoding %e <<EOF +commit $head2 +iso8859-1 +commit $head1 +iso8859-1 EOF -test_format subject %s <<'EOF' -commit 131a310eb913d107dd3c09a65d1651175898735d -changed foo -commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873 -added foo +test_format subject %s <<EOF +commit $head2 +$changed +commit $head1 +$added EOF -test_format body %b <<'EOF' -commit 131a310eb913d107dd3c09a65d1651175898735d -commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873 +test_format body %b <<EOF +commit $head2 +commit $head1 EOF -test_format raw-body %B <<'EOF' -commit 131a310eb913d107dd3c09a65d1651175898735d -changed foo +test_format raw-body %B <<EOF +commit $head2 +$changed -commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873 -added foo +commit $head1 +$added EOF -test_format colors %Credfoo%Cgreenbar%Cbluebaz%Cresetxyzzy <<'EOF' -commit 131a310eb913d107dd3c09a65d1651175898735d +test_format colors %Credfoo%Cgreenbar%Cbluebaz%Cresetxyzzy <<EOF +commit $head2 [31mfoo[32mbar[34mbaz[mxyzzy -commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873 +commit $head1 [31mfoo[32mbar[34mbaz[mxyzzy EOF -test_format advanced-colors '%C(red yellow bold)foo%C(reset)' <<'EOF' -commit 131a310eb913d107dd3c09a65d1651175898735d +test_format advanced-colors '%C(red yellow bold)foo%C(reset)' <<EOF +commit $head2 [1;31;43mfoo[m -commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873 +commit $head1 [1;31;43mfoo[m EOF -cat >commit-msg <<'EOF' +test_expect_success '%C(auto) does not enable color by default' ' + git log --format=$AUTO_COLOR -1 >actual && + has_no_color actual +' + +test_expect_success '%C(auto) enables colors for color.diff' ' + git -c color.diff=always log --format=$AUTO_COLOR -1 >actual && + has_color actual +' + +test_expect_success '%C(auto) enables colors for color.ui' ' + git -c color.ui=always log --format=$AUTO_COLOR -1 >actual && + has_color actual +' + +test_expect_success '%C(auto) respects --color' ' + git log --format=$AUTO_COLOR -1 --color >actual && + has_color actual +' + +test_expect_success '%C(auto) respects --no-color' ' + git -c color.ui=always log --format=$AUTO_COLOR -1 --no-color >actual && + has_no_color actual +' + +test_expect_success TTY '%C(auto) respects --color=auto (stdout is tty)' ' + ( + TERM=vt100 && export TERM && + test_terminal \ + git log --format=$AUTO_COLOR -1 --color=auto >actual && + has_color actual + ) +' + +test_expect_success '%C(auto) respects --color=auto (stdout not tty)' ' + ( + TERM=vt100 && export TERM && + git log --format=$AUTO_COLOR -1 --color=auto >actual && + has_no_color actual + ) +' + +iconv -f utf-8 -t iso8859-1 > commit-msg <<EOF Test printing of complex bodies This commit message is much longer than the others, and it will be encoded in iso8859-1. We should therefore include an iso8859 character: ¡bueno! EOF + test_expect_success 'setup complex body' ' -git config i18n.commitencoding iso8859-1 && - echo change2 >foo && git commit -a -F commit-msg + git config i18n.commitencoding iso8859-1 && + echo change2 >foo && git commit -a -F commit-msg && + head3=$(git rev-parse --verify HEAD) && + head3_short=$(git rev-parse --short $head3) ' -test_format complex-encoding %e <<'EOF' -commit f58db70b055c5718631e5c61528b28b12090cdea +test_format complex-encoding %e <<EOF +commit $head3 +iso8859-1 +commit $head2 +iso8859-1 +commit $head1 iso8859-1 -commit 131a310eb913d107dd3c09a65d1651175898735d -commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873 EOF -test_format complex-subject %s <<'EOF' -commit f58db70b055c5718631e5c61528b28b12090cdea +test_format complex-subject %s <<EOF +commit $head3 Test printing of complex bodies -commit 131a310eb913d107dd3c09a65d1651175898735d -changed foo -commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873 -added foo +commit $head2 +$changed_iso88591 +commit $head1 +$added_iso88591 EOF -test_format complex-body %b <<'EOF' -commit f58db70b055c5718631e5c61528b28b12090cdea -This commit message is much longer than the others, -and it will be encoded in iso8859-1. We should therefore -include an iso8859 character: ¡bueno! +test_expect_success 'prepare expected messages (for test %b)' ' + cat <<-EOF >expected.utf-8 && + commit $head3 + This commit message is much longer than the others, + and it will be encoded in iso8859-1. We should therefore + include an iso8859 character: ¡bueno! + + commit $head2 + commit $head1 + EOF + iconv -f utf-8 -t iso8859-1 expected.utf-8 >expected.iso8859-1 +' -commit 131a310eb913d107dd3c09a65d1651175898735d -commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873 +test_format complex-body %b <expected.iso8859-1 + +# Git uses i18n.commitEncoding if no i18n.logOutputEncoding set +# so unset i18n.commitEncoding to test encoding conversion +git config --unset i18n.commitEncoding + +test_format complex-subject-commitencoding-unset %s <<EOF +commit $head3 +Test printing of complex bodies +commit $head2 +$changed +commit $head1 +$added EOF +test_format complex-body-commitencoding-unset %b <expected.utf-8 + test_expect_success '%x00 shows NUL' ' - echo >expect commit f58db70b055c5718631e5c61528b28b12090cdea && + echo >expect commit $head3 && echo >>expect fooQbar && git rev-list -1 --format=foo%x00bar HEAD >actual.nul && nul_to_q <actual.nul >actual && @@ -210,12 +317,12 @@ test_expect_success 'add LF before non-empty (2)' ' test_expect_success 'add SP before non-empty (1)' ' git show -s --pretty=format:"%s% bThanks" HEAD^^ >actual && - test $(wc -w <actual) = 2 + test $(wc -w <actual) = 3 ' test_expect_success 'add SP before non-empty (2)' ' git show -s --pretty=format:"%s% sThanks" HEAD^^ >actual && - test $(wc -w <actual) = 4 + test $(wc -w <actual) = 6 ' test_expect_success '--abbrev' ' diff --git a/t/t6009-rev-list-parent.sh b/t/t6009-rev-list-parent.sh index 30507407ff..66cda17ef3 100755 --- a/t/t6009-rev-list-parent.sh +++ b/t/t6009-rev-list-parent.sh @@ -133,4 +133,17 @@ test_expect_success 'dodecapus' ' check_revlist "--min-parents=13" && check_revlist "--min-parents=4 --max-parents=11" tetrapus ' + +test_expect_success 'ancestors with the same commit time' ' + + test_tick_keep=$test_tick && + for i in 1 2 3 4 5 6 7 8; do + test_tick=$test_tick_keep + test_commit t$i + done && + git rev-list t1^! --not t$i >result && + >expect && + test_cmp expect result +' + test_done diff --git a/t/t6012-rev-list-simplify.sh b/t/t6012-rev-list-simplify.sh index 839ad97b79..57ce2395d6 100755 --- a/t/t6012-rev-list-simplify.sh +++ b/t/t6012-rev-list-simplify.sh @@ -14,21 +14,24 @@ unnote () { test_expect_success setup ' echo "Hi there" >file && - git add file && - test_tick && git commit -m "Initial file" && + echo "initial" >lost && + git add file lost && + test_tick && git commit -m "Initial file and lost" && note A && git branch other-branch && echo "Hello" >file && - git add file && - test_tick && git commit -m "Modified file" && + echo "second" >lost && + git add file lost && + test_tick && git commit -m "Modified file and lost" && note B && git checkout other-branch && echo "Hello" >file && - git add file && + >lost && + git add file lost && test_tick && git commit -m "Modified the file identically" && note C && @@ -37,7 +40,9 @@ test_expect_success setup ' test_tick && git commit -m "Add another file" && note D && - test_tick && git merge -m "merge" master && + test_tick && + test_must_fail git merge -m "merge" master && + >lost && git commit -a -m "merge" && note E && echo "Yet another" >elif && @@ -56,19 +61,37 @@ test_expect_success setup ' echo "Final change" >file && test_tick && git commit -a -m "Final change" && - note I + note I && + + git symbolic-ref HEAD refs/heads/unrelated && + git rm -f "*" && + echo "Unrelated branch" >side && + git add side && + test_tick && git commit -m "Side root" && + note J && + + git checkout master && + test_tick && git merge -m "Coolest" unrelated && + note K && + + echo "Immaterial" >elif && + git add elif && + test_tick && git commit -m "Last" && + note L ' FMT='tformat:%P %H | %s' -check_result () { +check_outcome () { + outcome=$1 + shift for c in $1 do echo "$c" done >expect && shift && param="$*" && - test_expect_success "log $param" ' + test_expect_$outcome "log $param" ' git log --pretty="$FMT" --parents $param | unnote >actual && sed -e "s/^.* \([^ ]*\) .*/\1/" >check <actual && @@ -79,13 +102,29 @@ check_result () { ' } -check_result 'I H G F E D C B A' --full-history -check_result 'I H E C B A' --full-history -- file -check_result 'I H E C B A' --full-history --topo-order -- file -check_result 'I H E C B A' --full-history --date-order -- file +check_result () { + check_outcome success "$@" +} + +check_result 'L K J I H G F E D C B A' --full-history +check_result 'K I H E C B A' --full-history -- file +check_result 'K I H E C B A' --full-history --topo-order -- file +check_result 'K I H E C B A' --full-history --date-order -- file check_result 'I E C B A' --simplify-merges -- file check_result 'I B A' -- file check_result 'I B A' --topo-order -- file check_result 'H' --first-parent -- another-file +check_result 'E C B A' --full-history E -- lost +test_expect_success 'full history simplification without parent' ' + printf "%s\n" E C B A >expect && + git log --pretty="$FMT" --full-history E -- lost | + unnote >actual && + sed -e "s/^.* \([^ ]*\) .*/\1/" >check <actual && + test_cmp expect check || { + cat actual + false + } +' + test_done diff --git a/t/t6019-rev-list-ancestry-path.sh b/t/t6019-rev-list-ancestry-path.sh index 39b4cb0ecd..dabebaee0b 100755 --- a/t/t6019-rev-list-ancestry-path.sh +++ b/t/t6019-rev-list-ancestry-path.sh @@ -13,6 +13,13 @@ test_description='--ancestry-path' # # D..M -- M.t == M # --ancestry-path D..M -- M.t == M +# +# F...I == F G H I +# --ancestry-path F...I == F H I +# +# G..M -- G.t == [nothing - was dropped in "-s ours" merge L] +# --ancestry-path G..M -- G.t == L +# --ancestry-path --simplify-merges G^..M -- G.t == G L . ./test-lib.sh @@ -63,13 +70,52 @@ test_expect_success 'rev-list D..M -- M.t' ' test_cmp expect actual ' -test_expect_success 'rev-list --ancestry-patch D..M -- M.t' ' +test_expect_success 'rev-list --ancestry-path D..M -- M.t' ' echo M >expect && git rev-list --ancestry-path --format=%s D..M -- M.t | sed -e "/^commit /d" >actual && test_cmp expect actual ' +test_expect_success 'rev-list F...I' ' + for c in F G H I; do echo $c; done >expect && + git rev-list --format=%s F...I | + sed -e "/^commit /d" | + sort >actual && + test_cmp expect actual +' + +test_expect_success 'rev-list --ancestry-path F...I' ' + for c in F H I; do echo $c; done >expect && + git rev-list --ancestry-path --format=%s F...I | + sed -e "/^commit /d" | + sort >actual && + test_cmp expect actual +' + +# G.t is dropped in an "-s ours" merge +test_expect_success 'rev-list G..M -- G.t' ' + >expect && + git rev-list --format=%s G..M -- G.t | + sed -e "/^commit /d" >actual && + test_cmp expect actual +' + +test_expect_success 'rev-list --ancestry-path G..M -- G.t' ' + echo L >expect && + git rev-list --ancestry-path --format=%s G..M -- G.t | + sed -e "/^commit /d" >actual && + test_cmp expect actual +' + +test_expect_success 'rev-list --ancestry-path --simplify-merges G^..M -- G.t' ' + for c in G L; do echo $c; done >expect && + git rev-list --ancestry-path --simplify-merges --format=%s G^..M -- G.t | + sed -e "/^commit /d" | + sort >actual && + test_cmp expect actual +' + # b---bc # / \ / # a X diff --git a/t/t6021-merge-criss-cross.sh b/t/t6021-merge-criss-cross.sh index 331b9b07d4..d15b313d4b 100755 --- a/t/t6021-merge-criss-cross.sh +++ b/t/t6021-merge-criss-cross.sh @@ -3,7 +3,7 @@ # Copyright (c) 2005 Fredrik Kuivinen # -# See http://marc.theaimsgroup.com/?l=git&m=111463358500362&w=2 for a +# See http://marc.info/?l=git&m=111463358500362&w=2 for a # nice description of what this is about. diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh index 72e28ee535..064f5cefeb 100755 --- a/t/t6030-bisect-porcelain.sh +++ b/t/t6030-bisect-porcelain.sh @@ -164,7 +164,7 @@ test_expect_success 'bisect start: existing ".git/BISECT_START" not modified if cp .git/BISECT_START saved && test_must_fail git bisect start $HASH4 foo -- && git branch > branch.output && - test_i18ngrep "* (no branch)" branch.output > /dev/null && + test_i18ngrep "* (no branch, bisect started on other)" branch.output > /dev/null && test_cmp saved .git/BISECT_START ' test_expect_success 'bisect start: no ".git/BISECT_START" if mistaken rev' ' @@ -190,7 +190,7 @@ test_expect_success 'bisect start: no ".git/BISECT_START" if checkout error' ' # $HASH1 is good, $HASH4 is bad, we skip $HASH3 # but $HASH2 is bad, # so we should find $HASH2 as the first bad commit -test_expect_success 'bisect skip: successfull result' ' +test_expect_success 'bisect skip: successful result' ' git bisect reset && git bisect start $HASH4 $HASH1 && git bisect skip && @@ -676,9 +676,7 @@ test_expect_success 'bisect fails if tree is broken on trial commit' ' check_same() { echo "Checking $1 is the same as $2" && - git rev-parse "$1" > expected.same && - git rev-parse "$2" > expected.actual && - test_cmp expected.same expected.actual + test_cmp_rev "$1" "$2" } test_expect_success 'bisect: --no-checkout - start commit bad' ' @@ -743,4 +741,42 @@ test_expect_success 'bisect: demonstrate identification of damage boundary' " git bisect reset " +cat > expected.bisect-log <<EOF +# bad: [32a594a3fdac2d57cf6d02987e30eec68511498c] Add <4: Ciao for now> into <hello>. +# good: [7b7f204a749c3125d5224ed61ea2ae1187ad046f] Add <2: A new day for git> into <hello>. +git bisect start '32a594a3fdac2d57cf6d02987e30eec68511498c' '7b7f204a749c3125d5224ed61ea2ae1187ad046f' +# good: [3de952f2416b6084f557ec417709eac740c6818c] Add <3: Another new day for git> into <hello>. +git bisect good 3de952f2416b6084f557ec417709eac740c6818c +# first bad commit: [32a594a3fdac2d57cf6d02987e30eec68511498c] Add <4: Ciao for now> into <hello>. +EOF + +test_expect_success 'bisect log: successfull result' ' + git bisect reset && + git bisect start $HASH4 $HASH2 && + git bisect good && + git bisect log >bisect-log.txt && + test_cmp expected.bisect-log bisect-log.txt && + git bisect reset +' + +cat > expected.bisect-skip-log <<EOF +# bad: [32a594a3fdac2d57cf6d02987e30eec68511498c] Add <4: Ciao for now> into <hello>. +# good: [7b7f204a749c3125d5224ed61ea2ae1187ad046f] Add <2: A new day for git> into <hello>. +git bisect start '32a594a3fdac2d57cf6d02987e30eec68511498c' '7b7f204a749c3125d5224ed61ea2ae1187ad046f' +# skip: [3de952f2416b6084f557ec417709eac740c6818c] Add <3: Another new day for git> into <hello>. +git bisect skip 3de952f2416b6084f557ec417709eac740c6818c +# only skipped commits left to test +# possible first bad commit: [32a594a3fdac2d57cf6d02987e30eec68511498c] Add <4: Ciao for now> into <hello>. +# possible first bad commit: [3de952f2416b6084f557ec417709eac740c6818c] Add <3: Another new day for git> into <hello>. +EOF + +test_expect_success 'bisect log: only skip commits left' ' + git bisect reset && + git bisect start $HASH4 $HASH2 && + test_must_fail git bisect skip && + git bisect log >bisect-skip-log.txt && + test_cmp expected.bisect-skip-log bisect-skip-log.txt && + git bisect reset +' + test_done diff --git a/t/t6035-merge-dir-to-symlink.sh b/t/t6035-merge-dir-to-symlink.sh index 2599ae50eb..9324ea4416 100755 --- a/t/t6035-merge-dir-to-symlink.sh +++ b/t/t6035-merge-dir-to-symlink.sh @@ -3,7 +3,7 @@ test_description='merging when a directory was replaced with a symlink' . ./test-lib.sh -test_expect_success SYMLINKS 'create a commit where dir a/b changed to symlink' ' +test_expect_success 'create a commit where dir a/b changed to symlink' ' mkdir -p a/b/c a/b-2/c && > a/b/c/d && > a/b-2/c/d && @@ -12,12 +12,12 @@ test_expect_success SYMLINKS 'create a commit where dir a/b changed to symlink' git commit -m base && git tag start && rm -rf a/b && - ln -s b-2 a/b && git add -A && + test_ln_s_add b-2 a/b && git commit -m "dir to symlink" ' -test_expect_success SYMLINKS 'checkout does not clobber untracked symlink' ' +test_expect_success 'checkout does not clobber untracked symlink' ' git checkout HEAD^0 && git reset --hard master && git rm --cached a/b && @@ -25,7 +25,7 @@ test_expect_success SYMLINKS 'checkout does not clobber untracked symlink' ' test_must_fail git checkout start^0 ' -test_expect_success SYMLINKS 'a/b-2/c/d is kept when clobbering symlink b' ' +test_expect_success 'a/b-2/c/d is kept when clobbering symlink b' ' git checkout HEAD^0 && git reset --hard master && git rm --cached a/b && @@ -34,14 +34,14 @@ test_expect_success SYMLINKS 'a/b-2/c/d is kept when clobbering symlink b' ' test -f a/b-2/c/d ' -test_expect_success SYMLINKS 'checkout should not have deleted a/b-2/c/d' ' +test_expect_success 'checkout should not have deleted a/b-2/c/d' ' git checkout HEAD^0 && git reset --hard master && git checkout start^0 && test -f a/b-2/c/d ' -test_expect_success SYMLINKS 'setup for merge test' ' +test_expect_success 'setup for merge test' ' git reset --hard && test -f a/b-2/c/d && echo x > a/x && @@ -50,39 +50,51 @@ test_expect_success SYMLINKS 'setup for merge test' ' git tag baseline ' -test_expect_success SYMLINKS 'Handle D/F conflict, do not lose a/b-2/c/d in merge (resolve)' ' +test_expect_success 'Handle D/F conflict, do not lose a/b-2/c/d in merge (resolve)' ' git reset --hard && git checkout baseline^0 && git merge -s resolve master && - test -h a/b && test -f a/b-2/c/d ' -test_expect_success SYMLINKS 'Handle D/F conflict, do not lose a/b-2/c/d in merge (recursive)' ' +test_expect_success SYMLINKS 'a/b was resolved as symlink' ' + test -h a/b +' + +test_expect_success 'Handle D/F conflict, do not lose a/b-2/c/d in merge (recursive)' ' git reset --hard && git checkout baseline^0 && git merge -s recursive master && - test -h a/b && test -f a/b-2/c/d ' -test_expect_success SYMLINKS 'Handle F/D conflict, do not lose a/b-2/c/d in merge (resolve)' ' +test_expect_success SYMLINKS 'a/b was resolved as symlink' ' + test -h a/b +' + +test_expect_success 'Handle F/D conflict, do not lose a/b-2/c/d in merge (resolve)' ' git reset --hard && git checkout master^0 && git merge -s resolve baseline^0 && - test -h a/b && test -f a/b-2/c/d ' -test_expect_success SYMLINKS 'Handle F/D conflict, do not lose a/b-2/c/d in merge (recursive)' ' +test_expect_success SYMLINKS 'a/b was resolved as symlink' ' + test -h a/b +' + +test_expect_success 'Handle F/D conflict, do not lose a/b-2/c/d in merge (recursive)' ' git reset --hard && git checkout master^0 && git merge -s recursive baseline^0 && - test -h a/b && test -f a/b-2/c/d ' -test_expect_failure SYMLINKS 'do not lose untracked in merge (resolve)' ' +test_expect_success SYMLINKS 'a/b was resolved as symlink' ' + test -h a/b +' + +test_expect_failure 'do not lose untracked in merge (resolve)' ' git reset --hard && git checkout baseline^0 && >a/b/c/e && @@ -91,7 +103,7 @@ test_expect_failure SYMLINKS 'do not lose untracked in merge (resolve)' ' test -f a/b-2/c/d ' -test_expect_success SYMLINKS 'do not lose untracked in merge (recursive)' ' +test_expect_success 'do not lose untracked in merge (recursive)' ' git reset --hard && git checkout baseline^0 && >a/b/c/e && @@ -100,52 +112,61 @@ test_expect_success SYMLINKS 'do not lose untracked in merge (recursive)' ' test -f a/b-2/c/d ' -test_expect_success SYMLINKS 'do not lose modifications in merge (resolve)' ' +test_expect_success 'do not lose modifications in merge (resolve)' ' git reset --hard && git checkout baseline^0 && echo more content >>a/b/c/d && test_must_fail git merge -s resolve master ' -test_expect_success SYMLINKS 'do not lose modifications in merge (recursive)' ' +test_expect_success 'do not lose modifications in merge (recursive)' ' git reset --hard && git checkout baseline^0 && echo more content >>a/b/c/d && test_must_fail git merge -s recursive master ' -test_expect_success SYMLINKS 'setup a merge where dir a/b-2 changed to symlink' ' +test_expect_success 'setup a merge where dir a/b-2 changed to symlink' ' git reset --hard && git checkout start^0 && rm -rf a/b-2 && - ln -s b a/b-2 && git add -A && + test_ln_s_add b a/b-2 && git commit -m "dir a/b-2 to symlink" && git tag test2 ' -test_expect_success SYMLINKS 'merge should not have D/F conflicts (resolve)' ' +test_expect_success 'merge should not have D/F conflicts (resolve)' ' git reset --hard && git checkout baseline^0 && git merge -s resolve test2 && - test -h a/b-2 && test -f a/b/c/d ' -test_expect_success SYMLINKS 'merge should not have D/F conflicts (recursive)' ' +test_expect_success SYMLINKS 'a/b-2 was resolved as symlink' ' + test -h a/b-2 +' + +test_expect_success 'merge should not have D/F conflicts (recursive)' ' git reset --hard && git checkout baseline^0 && git merge -s recursive test2 && - test -h a/b-2 && test -f a/b/c/d ' -test_expect_success SYMLINKS 'merge should not have F/D conflicts (recursive)' ' +test_expect_success SYMLINKS 'a/b-2 was resolved as symlink' ' + test -h a/b-2 +' + +test_expect_success 'merge should not have F/D conflicts (recursive)' ' git reset --hard && git checkout -b foo test2 && git merge -s recursive baseline^0 && - test -h a/b-2 && test -f a/b/c/d ' +test_expect_success SYMLINKS 'a/b-2 was resolved as symlink' ' + test -h a/b-2 +' + test_done diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh index 5c87f28e4e..decdc33c52 100755 --- a/t/t6050-replace.sh +++ b/t/t6050-replace.sh @@ -140,6 +140,17 @@ test_expect_success '"git replace" replacing' ' test "$HASH2" = "$(git replace)" ' +test_expect_success '"git replace" resolves sha1' ' + SHORTHASH2=$(git rev-parse --short=8 $HASH2) && + git replace -d $SHORTHASH2 && + git replace $SHORTHASH2 $R && + git show $HASH2 | grep "O Thor" && + test_must_fail git replace $HASH2 $R && + git replace -f $HASH2 $R && + test_must_fail git replace -f && + test "$HASH2" = "$(git replace)" +' + # This creates a side branch where the bug in H2 # does not appear because P2 is created by applying # H2 and squashing H5 into it. diff --git a/t/t6111-rev-list-treesame.sh b/t/t6111-rev-list-treesame.sh new file mode 100755 index 0000000000..88b84dfa73 --- /dev/null +++ b/t/t6111-rev-list-treesame.sh @@ -0,0 +1,196 @@ +#!/bin/sh +# +# ,---E--. *H----------. * marks !TREESAME parent paths +# / \ / \* +# *A--*B---D--*F-*G---------K-*L-*M +# \ /* \ / +# `-C-' `-*I-*J +# +# A creates "file", B and F change it. +# Odd merge G takes the old version from B. +# I changes it, but J reverts it, so K is TREESAME to both parents. +# H and L both change "file", and M merges those changes. + +test_description='TREESAME and limiting' + +. ./test-lib.sh + +note () { + git tag "$1" +} + +unnote () { + git name-rev --tags --stdin | sed -e "s|$_x40 (tags/\([^)]*\))\([ ]\)|\1\2|g" +} + +test_expect_success setup ' + test_commit "Initial file" file "Hi there" A && + git branch other-branch && + + test_commit "file=Hello" file "Hello" B && + git branch third-branch && + + git checkout other-branch && + test_commit "Added other" other "Hello" C && + + git checkout master && + test_merge D other-branch && + + git checkout third-branch && + test_commit "Third file" third "Nothing" E && + + git checkout master && + test_commit "file=Blah" file "Blah" F && + + test_tick && git merge --no-commit third-branch && + git checkout third-branch file && + git commit && + note G && + git branch fiddler-branch && + + git checkout -b part2-branch && + test_commit "file=Part 2" file "Part 2" H && + + git checkout fiddler-branch && + test_commit "Bad commit" file "Silly" I && + + test_tick && git revert I && note J && + + git checkout master && + test_tick && git merge --no-ff fiddler-branch && + note K + + test_commit "file=Part 1" file "Part 1" L && + + test_tick && test_must_fail git merge part2-branch && + test_commit M file "Parts 1+2" +' + +check_outcome () { + outcome=$1 + shift + + case "$1" in + *"("*) + FMT="%P %H | %s" + munge_actual=" + s/^\([^ ]*\) \([^ ]*\) .*/(\1)\2/ + s/ //g + s/()// + " + ;; + *) + FMT="%H | %s" + munge_actual="s/^\([^ ]*\) .*/\1/" + ;; + esac && + printf "%s\n" $1 >expect && + shift + + param="$*" && + test_expect_$outcome "log $param" ' + git log --format="$FMT" $param | + unnote >actual && + sed -e "$munge_actual" <actual >check && + test_cmp expect check || { + cat actual + false + } + ' +} + +check_result () { + check_outcome success "$@" +} + +# Odd merge G drops a change in F. Important that G is listed in all +# except the most basic list. Achieving this means normal merge D will also be +# shown in normal full-history, as we can't distinguish unless we do a +# simplification pass. After simplification, D is dropped but G remains. +# Also, merge simplification of G should not drop the parent B that the default +# simple history follows. +check_result 'M L K J I H G F E D C B A' +check_result '(LH)M (K)L (GJ)K (I)J (G)I (G)H (FE)G (D)F (B)E (BC)D (A)C (A)B A' +check_result 'M H L K J I G E F D C B A' --topo-order +check_result 'M L H B A' -- file +check_result '(LH)M (B)L (B)H (A)B A' --parents -- file +check_result 'M L J I H G F D B A' --full-history -- file +check_result '(LH)M (K)L (GJ)K (I)J (G)I (G)H (FB)G (D)F (BA)D (A)B A' --full-history --parents -- file +check_result '(LH)M (G)H (J)L (I)J (G)I (FB)G (B)F (A)B A' --simplify-merges -- file +check_result 'M L K G F D B A' --first-parent +check_result 'M L G F B A' --first-parent -- file + +# Check that odd merge G remains shown when F is the bottom. +check_result 'M L K J I H G E' F..M +check_result 'M H L K J I G E' F..M --topo-order +check_result 'M L H' F..M -- file +check_result '(LH)M (B)L (B)H' --parents F..M -- file +check_result 'M L J I H G' F..M --full-history -- file +check_result '(LH)M (K)L (GJ)K (I)J (G)I (G)H (FB)G' F..M --full-history --parents -- file +check_result '(LH)M (G)H (J)L (I)J (G)I (FB)G' F..M --simplify-merges -- file +check_result 'M L K J I H G' F..M --ancestry-path +check_result 'M L J I H G' F..M --ancestry-path -- file +check_result '(LH)M (K)L (GJ)K (I)J (G)I (G)H (FE)G' F..M --ancestry-path --parents -- file +check_result '(LH)M (G)H (J)L (I)J (G)I (FE)G' F..M --ancestry-path --simplify-merges -- file +check_result 'M L K G' F..M --first-parent +check_result 'M L G' F..M --first-parent -- file + +# Note that G is pruned when E is the bottom, even if it's the same commit list +# If we want history since E, then we're quite happy to ignore G that took E. +check_result 'M L K J I H G' E..M --ancestry-path +check_result 'M L J I H' E..M --ancestry-path -- file +check_result '(LH)M (K)L (EJ)K (I)J (E)I (E)H' E..M --ancestry-path --parents -- file +check_result '(LH)M (E)H (J)L (I)J (E)I' E..M --ancestry-path --simplify-merges -- file + +# Should still be able to ignore I-J branch in simple log, despite limiting +# to G. +check_result 'M L K J I H' G..M +check_result 'M H L K J I' G..M --topo-order +check_result 'M L H' G..M -- file +check_result '(LH)M (G)L (G)H' G..M --parents -- file +check_result 'M L J I H' G..M --full-history -- file +check_result 'M L K J I H' G..M --full-history --parents -- file +check_result 'M H L J I' G..M --simplify-merges -- file +check_result 'M L K J I H' G..M --ancestry-path +check_result 'M L J I H' G..M --ancestry-path -- file +check_result 'M L K J I H' G..M --ancestry-path --parents -- file +check_result 'M H L J I' G..M --ancestry-path --simplify-merges -- file + +# B..F should be able to simplify the merge D from irrelevant side branch C. +# Default log should also be free to follow B-D, and ignore C. +# But --full-history shouldn't drop D on its own - without simplification, +# we can't decide if the merge from INTERESTING commit C was sensible. +check_result 'F D C' B..F +check_result 'F' B..F -- file +check_result '(B)F' B..F --parents -- file +check_result 'F D' B..F --full-history -- file +check_result '(D)F (BA)D' B..F --full-history --parents -- file +check_result '(B)F' B..F --simplify-merges -- file +check_result 'F D' B..F --ancestry-path +check_result 'F' B..F --ancestry-path -- file +check_result 'F' B..F --ancestry-path --parents -- file +check_result 'F' B..F --ancestry-path --simplify-merges -- file +check_result 'F D' B..F --first-parent +check_result 'F' B..F --first-parent -- file + +# E...F should be equivalent to E F ^B, and be able to drop D as above. +check_result 'F' E F ^B -- file # includes D +check_result 'F' E...F -- file # includes D + +# Any sort of full history of C..F should show D, as it's the connection to C, +# and it differs from it. +check_result 'F D B' C..F +check_result 'F B' C..F -- file +check_result '(B)F (A)B' C..F --parents -- file +check_result 'F D B' C..F --full-history -- file +check_result '(D)F (BC)D (A)B' C..F --full-history --parents -- file +check_result '(D)F (BC)D (A)B' C..F --simplify-merges -- file +check_result 'F D' C..F --ancestry-path +check_result 'F D' C..F --ancestry-path -- file +check_result 'F D' C..F --ancestry-path --parents -- file +check_result 'F D' C..F --ancestry-path --simplify-merges -- file +check_result 'F D B' C..F --first-parent +check_result 'F B' C..F --first-parent -- file + + +test_done diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh index f67aa6ff6a..c0e5b2a627 100755 --- a/t/t6120-describe.sh +++ b/t/t6120-describe.sh @@ -110,6 +110,9 @@ check_describe tags/e --all HEAD^^^ check_describe B-0-* --long HEAD^^2^ check_describe A-3-* --long HEAD^^2 +check_describe c-7-* --tags +check_describe e-3-* --first-parent --tags + : >err.expect check_describe A --all A^0 test_expect_success 'no warning was displayed for A' ' @@ -171,4 +174,28 @@ check_describe "test2-lightweight-*" --tags --match="test2-*" check_describe "test2-lightweight-*" --long --tags --match="test2-*" HEAD^ +test_expect_success 'name-rev with exact tags' ' + echo A >expect && + tag_object=$(git rev-parse refs/tags/A) && + git name-rev --tags --name-only $tag_object >actual && + test_cmp expect actual && + + echo "A^0" >expect && + tagged_commit=$(git rev-parse "refs/tags/A^0") && + git name-rev --tags --name-only $tagged_commit >actual && + test_cmp expect actual +' + +test_expect_success 'describe --contains with the exact tags' ' + echo "A^0" >expect && + tag_object=$(git rev-parse refs/tags/A) && + git describe --contains $tag_object >actual && + test_cmp expect actual && + + echo "A^0" >expect && + tagged_commit=$(git rev-parse "refs/tags/A^0") && + git describe --contains $tagged_commit >actual && + test_cmp expect actual +' + test_done diff --git a/t/t6130-pathspec-noglob.sh b/t/t6130-pathspec-noglob.sh new file mode 100755 index 0000000000..39ef61994f --- /dev/null +++ b/t/t6130-pathspec-noglob.sh @@ -0,0 +1,68 @@ +#!/bin/sh + +test_description='test globbing (and noglob) of pathspec limiting' +. ./test-lib.sh + +test_expect_success 'create commits with glob characters' ' + test_commit unrelated bar && + test_commit vanilla foo && + # insert file "f*" in the commit, but in a way that avoids + # the name "f*" in the worktree, because it is not allowed + # on Windows (the tests below do not depend on the presence + # of the file in the worktree) + git update-index --add --cacheinfo 100644 "$(git rev-parse HEAD:foo)" "f*" && + test_tick && + git commit -m star && + test_commit bracket "f[o][o]" +' + +test_expect_success 'vanilla pathspec matches literally' ' + echo vanilla >expect && + git log --format=%s -- foo >actual && + test_cmp expect actual +' + +test_expect_success 'star pathspec globs' ' + cat >expect <<-\EOF && + bracket + star + vanilla + EOF + git log --format=%s -- "f*" >actual && + test_cmp expect actual +' + +test_expect_success 'bracket pathspec globs and matches literal brackets' ' + cat >expect <<-\EOF && + bracket + vanilla + EOF + git log --format=%s -- "f[o][o]" >actual && + test_cmp expect actual +' + +test_expect_success 'no-glob option matches literally (vanilla)' ' + echo vanilla >expect && + git --literal-pathspecs log --format=%s -- foo >actual && + test_cmp expect actual +' + +test_expect_success 'no-glob option matches literally (star)' ' + echo star >expect && + git --literal-pathspecs log --format=%s -- "f*" >actual && + test_cmp expect actual +' + +test_expect_success 'no-glob option matches literally (bracket)' ' + echo bracket >expect && + git --literal-pathspecs log --format=%s -- "f[o][o]" >actual && + test_cmp expect actual +' + +test_expect_success 'no-glob environment variable works' ' + echo star >expect && + GIT_LITERAL_PATHSPECS=1 git log --format=%s -- "f*" >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh index 992c2a0467..54b5744cc5 100755 --- a/t/t6200-fmt-merge-msg.sh +++ b/t/t6200-fmt-merge-msg.sh @@ -112,8 +112,8 @@ test_expect_success '[merge] summary/log configuration' ' Common #1 EOF - git config merge.log true && - test_might_fail git config --unset-all merge.summary && + test_config merge.log true && + test_unconfig merge.summary && git checkout master && test_tick && @@ -121,8 +121,8 @@ test_expect_success '[merge] summary/log configuration' ' git fmt-merge-msg <.git/FETCH_HEAD >actual1 && - test_might_fail git config --unset-all merge.log && - git config merge.summary true && + test_unconfig merge.log && + test_config merge.summary true && git checkout master && test_tick && @@ -134,11 +134,6 @@ test_expect_success '[merge] summary/log configuration' ' test_cmp expected actual2 ' -test_expect_success 'setup: clear [merge] configuration' ' - test_might_fail git config --unset-all merge.log && - test_might_fail git config --unset-all merge.summary -' - test_expect_success 'setup FETCH_HEAD' ' git checkout master && test_tick && @@ -180,6 +175,24 @@ test_expect_success 'merge.log=5 shows all 5 commits' ' test_cmp expected actual ' +test_expect_success '--log=5 with custom comment character' ' + cat >expected <<-EOF && + Merge branch ${apos}left${apos} + + x By Another Author (3) and A U Thor (2) + x Via Another Committer + * left: + Left #5 + Left #4 + Left #3 + Common #2 + Common #1 + EOF + + git -c core.commentchar="x" fmt-merge-msg --log=5 <.git/FETCH_HEAD >actual && + test_cmp expected actual +' + test_expect_success 'merge.log=0 disables shortlog' ' echo "Merge branch ${apos}left${apos}" >expected git -c merge.log=0 fmt-merge-msg <.git/FETCH_HEAD >actual && @@ -248,14 +261,14 @@ test_expect_success 'fmt-merge-msg -m' ' Common #1 EOF - test_might_fail git config --unset merge.log && - test_might_fail git config --unset merge.summary && + test_unconfig merge.log && + test_unconfig merge.summary && git checkout master && git fetch "$(pwd)" left && git fmt-merge-msg -m "Sync with left" <.git/FETCH_HEAD >actual && git fmt-merge-msg --log -m "Sync with left" \ <.git/FETCH_HEAD >actual.log && - git config merge.log true && + test_config merge.log true && git fmt-merge-msg -m "Sync with left" \ <.git/FETCH_HEAD >actual.log-config && git fmt-merge-msg --no-log -m "Sync with left" \ @@ -290,29 +303,29 @@ test_expect_success 'setup: expected shortlog for two branches' ' ' test_expect_success 'shortlog for two branches' ' - git config merge.log true && - test_might_fail git config --unset-all merge.summary && + test_config merge.log true && + test_unconfig merge.summary && git checkout master && test_tick && git fetch . left right && git fmt-merge-msg <.git/FETCH_HEAD >actual1 && - test_might_fail git config --unset-all merge.log && - git config merge.summary true && + test_unconfig merge.log && + test_config merge.summary true && git checkout master && test_tick && git fetch . left right && git fmt-merge-msg <.git/FETCH_HEAD >actual2 && - git config merge.log yes && - test_might_fail git config --unset-all merge.summary && + test_config merge.log yes && + test_unconfig merge.summary && git checkout master && test_tick && git fetch . left right && git fmt-merge-msg <.git/FETCH_HEAD >actual3 && - test_might_fail git config --unset-all merge.log && - git config merge.summary yes && + test_unconfig merge.log && + test_config merge.summary yes && git checkout master && test_tick && git fetch . left right && @@ -325,8 +338,8 @@ test_expect_success 'shortlog for two branches' ' ' test_expect_success 'merge-msg -F' ' - test_might_fail git config --unset-all merge.log && - git config merge.summary yes && + test_unconfig merge.log && + test_config merge.summary yes && git checkout master && test_tick && git fetch . left right && @@ -335,8 +348,8 @@ test_expect_success 'merge-msg -F' ' ' test_expect_success 'merge-msg -F in subdirectory' ' - test_might_fail git config --unset-all merge.log && - git config merge.summary yes && + test_unconfig merge.log && + test_config merge.summary yes && git checkout master && test_tick && git fetch . left right && @@ -350,8 +363,8 @@ test_expect_success 'merge-msg -F in subdirectory' ' ' test_expect_success 'merge-msg with nothing to merge' ' - test_might_fail git config --unset-all merge.log && - git config merge.summary yes && + test_unconfig merge.log && + test_config merge.summary yes && >empty && @@ -376,8 +389,8 @@ test_expect_success 'merge-msg tag' ' Common #1 EOF - test_might_fail git config --unset-all merge.log && - git config merge.summary yes && + test_unconfig merge.log && + test_config merge.summary yes && git checkout master && test_tick && @@ -406,8 +419,8 @@ test_expect_success 'merge-msg two tags' ' Common #1 EOF - test_might_fail git config --unset-all merge.log && - git config merge.summary yes && + test_unconfig merge.log && + test_config merge.summary yes && git checkout master && test_tick && @@ -436,8 +449,8 @@ test_expect_success 'merge-msg tag and branch' ' Common #1 EOF - test_might_fail git config --unset-all merge.log && - git config merge.summary yes && + test_unconfig merge.log && + test_config merge.summary yes && git checkout master && test_tick && @@ -464,6 +477,8 @@ test_expect_success 'merge-msg lots of commits' ' echo " ..." } >expected && + test_config merge.summary yes && + git checkout master && test_tick && git fetch . long && @@ -472,4 +487,43 @@ test_expect_success 'merge-msg lots of commits' ' test_cmp expected actual ' +test_expect_success 'merge-msg with "merging" an annotated tag' ' + test_config merge.log true && + + git checkout master^0 && + git commit --allow-empty -m "One step ahead" && + git tag -a -m "An annotated one" annote HEAD && + + git checkout master && + git fetch . annote && + + git fmt-merge-msg <.git/FETCH_HEAD >actual && + { + cat <<-\EOF + Merge tag '\''annote'\'' + + An annotated one + + * tag '\''annote'\'': + One step ahead + EOF + } >expected && + test_cmp expected actual && + + test_when_finished "git reset --hard" && + annote=$(git rev-parse annote) && + git merge --no-commit $annote && + { + cat <<-EOF + Merge tag '\''$annote'\'' + + An annotated one + + * tag '\''$annote'\'': + One step ahead + EOF + } >expected && + test_cmp expected .git/MERGE_MSG +' + test_done diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh index a845b154e4..101816e718 100755 --- a/t/t7001-mv.sh +++ b/t/t7001-mv.sh @@ -218,13 +218,13 @@ test_expect_success 'git mv should not change sha1 of moved cache entry' ' rm -f dirty dirty2 -test_expect_success SYMLINKS 'git mv should overwrite symlink to a file' ' +test_expect_success 'git mv should overwrite symlink to a file' ' rm -fr .git && git init && echo 1 >moved && - ln -s moved symlink && - git add moved symlink && + test_ln_s_add moved symlink && + git add moved && test_must_fail git mv moved symlink && git mv -f moved symlink && ! test -e moved && @@ -237,22 +237,26 @@ test_expect_success SYMLINKS 'git mv should overwrite symlink to a file' ' rm -f moved symlink -test_expect_success SYMLINKS 'git mv should overwrite file with a symlink' ' +test_expect_success 'git mv should overwrite file with a symlink' ' rm -fr .git && git init && echo 1 >moved && - ln -s moved symlink && - git add moved symlink && + test_ln_s_add moved symlink && + git add moved && test_must_fail git mv symlink moved && git mv -f symlink moved && ! test -e symlink && - test -h moved && git update-index --refresh && git diff-files --quiet ' +test_expect_success SYMLINKS 'check moved symlink' ' + + test -h moved +' + rm -f moved symlink test_done diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh index 4d13e10de1..9496736a89 100755 --- a/t/t7003-filter-branch.sh +++ b/t/t7003-filter-branch.sh @@ -64,6 +64,20 @@ test_expect_success 'correct GIT_DIR while using -d' ' grep drepo "$TRASHDIR/backup-refs" ' +test_expect_success 'tree-filter works with -d' ' + git init drepo-tree && + ( + cd drepo-tree && + test_commit one && + git filter-branch -d "$TRASHDIR/dfoo" \ + --tree-filter "echo changed >one.t" && + echo changed >expect && + git cat-file blob HEAD:one.t >actual && + test_cmp expect actual && + test_cmp one.t actual + ) +' + test_expect_success 'Fail if commit filter fails' ' test_must_fail git filter-branch -f --commit-filter "exit 1" HEAD ' @@ -167,10 +181,11 @@ test_expect_success 'author information is preserved' ' test_tick && GIT_AUTHOR_NAME="B V Uips" git commit -m bvuips && git branch preserved-author && - git filter-branch -f --msg-filter "cat; \ + (sane_unset GIT_AUTHOR_NAME && + git filter-branch -f --msg-filter "cat; \ test \$GIT_COMMIT != $(git rev-parse master) || \ echo Hallo" \ - preserved-author && + preserved-author) && test 1 = $(git rev-list --author="B V Uips" preserved-author | wc -l) ' diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index f5a79b13ae..c8d6e9f88c 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -104,6 +104,18 @@ test_expect_success 'creating a tag using HEAD directly should succeed' ' tag_exists myhead ' +test_expect_success '--force can create a tag with the name of one existing' ' + tag_exists mytag && + git tag --force mytag && + tag_exists mytag' + +test_expect_success '--force is moot with a non-existing tag name' ' + git tag newtag >expect && + git tag --force forcetag >actual && + test_cmp expect actual +' +git tag -d newtag forcetag + # deleting tags: test_expect_success 'trying to delete an unknown tag should fail' ' diff --git a/t/t7011-skip-worktree-reading.sh b/t/t7011-skip-worktree-reading.sh index 8f3b54d826..88d60c1ce2 100755 --- a/t/t7011-skip-worktree-reading.sh +++ b/t/t7011-skip-worktree-reading.sh @@ -91,12 +91,12 @@ test_expect_success 'update-index --remove' ' test_cmp expected 1 ' -test_expect_success 'ls-files --delete' ' +test_expect_success 'ls-files --deleted' ' setup_absent && test -z "$(git ls-files -d)" ' -test_expect_success 'ls-files --delete' ' +test_expect_success 'ls-files --deleted' ' setup_dirty && test -z "$(git ls-files -d)" ' diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh index f4f38a5e73..52ef06b000 100755 --- a/t/t7060-wtstatus.sh +++ b/t/t7060-wtstatus.sh @@ -5,6 +5,7 @@ test_description='basic work tree status reporting' . ./test-lib.sh test_expect_success setup ' + git config --global advice.statusuoption false && test_commit A && test_commit B oneside added && git checkout A^0 && diff --git a/t/t7061-wtstatus-ignore.sh b/t/t7061-wtstatus-ignore.sh new file mode 100755 index 0000000000..460789b4d8 --- /dev/null +++ b/t/t7061-wtstatus-ignore.sh @@ -0,0 +1,265 @@ +#!/bin/sh + +test_description='git-status ignored files' + +. ./test-lib.sh + +cat >expected <<\EOF +?? .gitignore +?? actual +?? expected +?? untracked/ +EOF + +test_expect_success 'status untracked directory with --ignored' ' + echo "ignored" >.gitignore && + mkdir untracked && + : >untracked/ignored && + : >untracked/uncommitted && + git status --porcelain --ignored >actual && + test_cmp expected actual +' + +cat >expected <<\EOF +?? .gitignore +?? actual +?? expected +?? untracked/uncommitted +!! untracked/ignored +EOF + +test_expect_success 'status untracked directory with --ignored -u' ' + git status --porcelain --ignored -u >actual && + test_cmp expected actual +' +cat >expected <<\EOF +?? untracked/uncommitted +!! untracked/ignored +EOF + +test_expect_success 'status prefixed untracked directory with --ignored' ' + git status --porcelain --ignored untracked/ >actual && + test_cmp expected actual +' + +cat >expected <<\EOF +?? untracked/uncommitted +!! untracked/ignored +EOF + +test_expect_success 'status prefixed untracked sub-directory with --ignored -u' ' + git status --porcelain --ignored -u untracked/ >actual && + test_cmp expected actual +' + +cat >expected <<\EOF +?? .gitignore +?? actual +?? expected +!! ignored/ +EOF + +test_expect_success 'status ignored directory with --ignore' ' + rm -rf untracked && + mkdir ignored && + : >ignored/uncommitted && + git status --porcelain --ignored >actual && + test_cmp expected actual +' + +cat >expected <<\EOF +?? .gitignore +?? actual +?? expected +!! ignored/uncommitted +EOF + +test_expect_success 'status ignored directory with --ignore -u' ' + git status --porcelain --ignored -u >actual && + test_cmp expected actual +' + +cat >expected <<\EOF +?? .gitignore +?? actual +?? expected +EOF + +test_expect_success 'status empty untracked directory with --ignore' ' + rm -rf ignored && + mkdir untracked-ignored && + mkdir untracked-ignored/test && + git status --porcelain --ignored >actual && + test_cmp expected actual +' + +cat >expected <<\EOF +?? .gitignore +?? actual +?? expected +EOF + +test_expect_success 'status empty untracked directory with --ignore -u' ' + git status --porcelain --ignored -u >actual && + test_cmp expected actual +' + +cat >expected <<\EOF +?? .gitignore +?? actual +?? expected +!! untracked-ignored/ +EOF + +test_expect_success 'status untracked directory with ignored files with --ignore' ' + : >untracked-ignored/ignored && + : >untracked-ignored/test/ignored && + git status --porcelain --ignored >actual && + test_cmp expected actual +' + +cat >expected <<\EOF +?? .gitignore +?? actual +?? expected +!! untracked-ignored/ignored +!! untracked-ignored/test/ignored +EOF + +test_expect_success 'status untracked directory with ignored files with --ignore -u' ' + git status --porcelain --ignored -u >actual && + test_cmp expected actual +' + +cat >expected <<\EOF +?? .gitignore +?? actual +?? expected +EOF + +test_expect_success 'status ignored tracked directory with --ignore' ' + rm -rf untracked-ignored && + mkdir tracked && + : >tracked/committed && + git add tracked/committed && + git commit -m. && + echo "tracked" >.gitignore && + git status --porcelain --ignored >actual && + test_cmp expected actual +' + +cat >expected <<\EOF +?? .gitignore +?? actual +?? expected +EOF + +test_expect_success 'status ignored tracked directory with --ignore -u' ' + git status --porcelain --ignored -u >actual && + test_cmp expected actual +' + +cat >expected <<\EOF +?? .gitignore +?? actual +?? expected +EOF + +test_expect_success 'status ignored tracked directory and ignored file with --ignore' ' + echo "committed" >>.gitignore && + git status --porcelain --ignored >actual && + test_cmp expected actual +' + +cat >expected <<\EOF +?? .gitignore +?? actual +?? expected +EOF + +test_expect_success 'status ignored tracked directory and ignored file with --ignore -u' ' + git status --porcelain --ignored -u >actual && + test_cmp expected actual +' + +cat >expected <<\EOF +?? .gitignore +?? actual +?? expected +!! tracked/uncommitted +EOF + +test_expect_success 'status ignored tracked directory and uncommitted file with --ignore' ' + echo "tracked" >.gitignore && + : >tracked/uncommitted && + git status --porcelain --ignored >actual && + test_cmp expected actual +' + +cat >expected <<\EOF +?? .gitignore +?? actual +?? expected +!! tracked/uncommitted +EOF + +test_expect_success 'status ignored tracked directory and uncommitted file with --ignore -u' ' + git status --porcelain --ignored -u >actual && + test_cmp expected actual +' + +cat >expected <<\EOF +?? .gitignore +?? actual +?? expected +!! tracked/ignored/ +EOF + +test_expect_success 'status ignored tracked directory with uncommitted file in untracked subdir with --ignore' ' + rm -rf tracked/uncommitted && + mkdir tracked/ignored && + : >tracked/ignored/uncommitted && + git status --porcelain --ignored >actual && + test_cmp expected actual +' + +cat >expected <<\EOF +?? .gitignore +?? actual +?? expected +!! tracked/ignored/uncommitted +EOF + +test_expect_success 'status ignored tracked directory with uncommitted file in untracked subdir with --ignore -u' ' + git status --porcelain --ignored -u >actual && + test_cmp expected actual +' + +cat >expected <<\EOF +?? .gitignore +?? actual +?? expected +!! tracked/ignored/uncommitted +EOF + +test_expect_success 'status ignored tracked directory with uncommitted file in tracked subdir with --ignore' ' + : >tracked/ignored/committed && + git add -f tracked/ignored/committed && + git commit -m. && + git status --porcelain --ignored >actual && + test_cmp expected actual +' + +cat >expected <<\EOF +?? .gitignore +?? actual +?? expected +!! tracked/ignored/uncommitted +EOF + +test_expect_success 'status ignored tracked directory with uncommitted file in tracked subdir with --ignore -u' ' + git status --porcelain --ignored -u >actual && + test_cmp expected actual +' + +test_done diff --git a/t/t7062-wtstatus-ignorecase.sh b/t/t7062-wtstatus-ignorecase.sh new file mode 100755 index 0000000000..73709dbeee --- /dev/null +++ b/t/t7062-wtstatus-ignorecase.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +test_description='git-status with core.ignorecase=true' + +. ./test-lib.sh + +test_expect_success 'status with hash collisions' ' + # note: "V/", "V/XQANY/" and "WURZAUP/" produce the same hash code + # in name-hash.c::hash_name + mkdir V && + mkdir V/XQANY && + mkdir WURZAUP && + touch V/XQANY/test && + git config core.ignorecase true && + git add . && + # test is successful if git status completes (no endless loop) + git status +' + +test_done diff --git a/t/t7102-reset.sh b/t/t7102-reset.sh index b096dc88c2..8d4b50d1b5 100755 --- a/t/t7102-reset.sh +++ b/t/t7102-reset.sh @@ -9,6 +9,19 @@ Documented tests for git reset' . ./test-lib.sh +commit_msg () { + # String "modify 2nd file (changed)" partly in German + # (translated with Google Translate), + # encoded in UTF-8, used as a commit log message below. + msg="modify 2nd file (ge\303\244ndert)\n" + if test -n "$1" + then + printf "$msg" | iconv -f utf-8 -t "$1" + else + printf "$msg" + fi +} + test_expect_success 'creating initial files and commits' ' test_tick && echo "1st file" >first && @@ -28,7 +41,8 @@ test_expect_success 'creating initial files and commits' ' echo "1st line 2nd file" >secondfile && echo "2nd line 2nd file" >>secondfile && - git commit -a -m "modify 2nd file" + git -c "i18n.commitEncoding=iso8859-1" commit -a -m "$(commit_msg iso8859-1)" && + head5=$(git rev-parse --verify HEAD) ' # git log --pretty=oneline # to see those SHA1 involved @@ -43,6 +57,20 @@ check_changes () { done | test_cmp .cat_expect - } +test_expect_success 'reset --hard message' ' + hex=$(git log -1 --format="%h") && + git reset --hard > .actual && + echo HEAD is now at $hex $(commit_msg) > .expected && + test_cmp .expected .actual +' + +test_expect_success 'reset --hard message (iso8859-1 logoutputencoding)' ' + hex=$(git log -1 --format="%h") && + git -c "i18n.logOutputEncoding=iso8859-1" reset --hard > .actual && + echo HEAD is now at $hex $(commit_msg iso8859-1) > .expected && + test_cmp .expected .actual +' + >.diff_expect >.cached_expect cat >.cat_expect <<EOF @@ -56,7 +84,7 @@ test_expect_success 'giving a non existing revision should fail' ' test_must_fail git reset --mixed aaaaaa && test_must_fail git reset --soft aaaaaa && test_must_fail git reset --hard aaaaaa && - check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc + check_changes $head5 ' test_expect_success 'reset --soft with unmerged index should fail' ' @@ -74,7 +102,7 @@ test_expect_success \ test_must_fail git reset --hard -- first && test_must_fail git reset --soft HEAD^ -- first && test_must_fail git reset --hard HEAD^ -- first && - check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc + check_changes $head5 ' test_expect_success 'giving unrecognized options should fail' ' @@ -86,7 +114,7 @@ test_expect_success 'giving unrecognized options should fail' ' test_must_fail git reset --soft -o && test_must_fail git reset --hard --other && test_must_fail git reset --hard -o && - check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc + check_changes $head5 ' test_expect_success \ @@ -110,7 +138,7 @@ test_expect_success \ git checkout master && git branch -D branch1 branch2 && - check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc + check_changes $head5 ' test_expect_success \ @@ -133,27 +161,27 @@ test_expect_success \ git checkout master && git branch -D branch3 branch4 && - check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc + check_changes $head5 ' test_expect_success \ 'resetting to HEAD with no changes should succeed and do nothing' ' git reset --hard && - check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc && + check_changes $head5 && git reset --hard HEAD && - check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc && + check_changes $head5 && git reset --soft && - check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc && + check_changes $head5 && git reset --soft HEAD && - check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc && + check_changes $head5 && git reset --mixed && - check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc && + check_changes $head5 && git reset --mixed HEAD && - check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc && + check_changes $head5 && git reset && - check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc && + check_changes $head5 && git reset HEAD && - check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc + check_changes $head5 ' >.diff_expect @@ -176,7 +204,7 @@ test_expect_success '--soft reset only should show changes in diff --cached' ' git reset --soft HEAD^ && check_changes d1a4bc3abce4829628ae2dcb0d60ef3d1a78b1c4 && test "$(git rev-parse ORIG_HEAD)" = \ - 3ec39651e7f44ea531a5de18a9fa791c0fd370fc + $head5 ' >.diff_expect @@ -191,9 +219,10 @@ test_expect_success \ 'changing files and redo the last commit should succeed' ' echo "3rd line 2nd file" >>secondfile && git commit -a -C ORIG_HEAD && - check_changes 3d3b7be011a58ca0c179ae45d94e6c83c0b0cd0d && + head4=$(git rev-parse --verify HEAD) && + check_changes $head4 && test "$(git rev-parse ORIG_HEAD)" = \ - 3ec39651e7f44ea531a5de18a9fa791c0fd370fc + $head5 ' >.diff_expect @@ -210,7 +239,7 @@ test_expect_success \ git reset --hard HEAD~2 && check_changes ddaefe00f1da16864591c61fdc7adb5d7cd6b74e && test "$(git rev-parse ORIG_HEAD)" = \ - 3d3b7be011a58ca0c179ae45d94e6c83c0b0cd0d + $head4 ' >.diff_expect @@ -302,8 +331,8 @@ test_expect_success 'redoing the last two commits should succeed' ' echo "1st line 2nd file" >secondfile && echo "2nd line 2nd file" >>secondfile && - git commit -a -m "modify 2nd file" && - check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc + git -c "i18n.commitEncoding=iso8859-1" commit -a -m "$(commit_msg iso8859-1)" && + check_changes $head5 ' >.diff_expect @@ -325,10 +354,11 @@ test_expect_success '--hard reset to HEAD should clear a failed merge' ' git checkout branch2 && echo "3rd line in branch2" >>secondfile && git commit -a -m "change in branch2" && + head3=$(git rev-parse --verify HEAD) && test_must_fail git pull . branch1 && git reset --hard && - check_changes 77abb337073fb4369a7ad69ff6f5ec0e4d6b54bb + check_changes $head3 ' >.diff_expect @@ -341,15 +371,15 @@ EOF test_expect_success \ '--hard reset to ORIG_HEAD should clear a fast-forward merge' ' git reset --hard HEAD^ && - check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc && + check_changes $head5 && git pull . branch1 && git reset --hard ORIG_HEAD && - check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc && + check_changes $head5 && git checkout master && git branch -D branch1 branch2 && - check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc + check_changes $head5 ' cat > expect << EOF @@ -388,7 +418,8 @@ test_expect_success 'test --mixed <paths>' ' echo 4 > file4 && echo 5 > file1 && git add file1 file3 file4 && - test_must_fail git reset HEAD -- file1 file2 file3 && + git reset HEAD -- file1 file2 file3 && + test_must_fail git diff --quiet && git diff > output && test_cmp output expect && git diff --cached > output && @@ -402,7 +433,8 @@ test_expect_success 'test resetting the index at give paths' ' >sub/file2 && git update-index --add sub/file1 sub/file2 && T=$(git write-tree) && - test_must_fail git reset HEAD sub/file2 && + git reset HEAD sub/file2 && + test_must_fail git diff --quiet && U=$(git write-tree) && echo "$T" && echo "$U" && @@ -440,7 +472,8 @@ test_expect_success 'resetting specific path that is unmerged' ' echo "100644 $F3 3 file2" } | git update-index --index-info && git ls-files -u && - test_must_fail git reset HEAD file2 && + git reset HEAD file2 && + test_must_fail git diff --quiet && git diff-index --exit-code --cached HEAD ' @@ -449,10 +482,11 @@ test_expect_success 'disambiguation (1)' ' git reset --hard && >secondfile && git add secondfile && - test_must_fail git reset secondfile && + git reset secondfile && + test_must_fail git diff --quiet -- secondfile && test -z "$(git diff --cached --name-only)" && test -f secondfile && - test ! -s secondfile + test_must_be_empty secondfile ' @@ -474,7 +508,8 @@ test_expect_success 'disambiguation (3)' ' >secondfile && git add secondfile && rm -f secondfile && - test_must_fail git reset HEAD secondfile && + git reset HEAD secondfile && + test_must_fail git diff --quiet && test -z "$(git diff --cached --name-only)" && test ! -f secondfile @@ -486,9 +521,18 @@ test_expect_success 'disambiguation (4)' ' >secondfile && git add secondfile && rm -f secondfile && - test_must_fail git reset -- secondfile && + git reset -- secondfile && + test_must_fail git diff --quiet && test -z "$(git diff --cached --name-only)" && test ! -f secondfile ' +test_expect_success 'reset with paths accepts tree' ' + # for simpler tests, drop last commit containing added files + git reset --hard HEAD^ && + git reset HEAD^^{tree} -- . && + git diff --cached HEAD^ --exit-code && + git diff HEAD --exit-code +' + test_done diff --git a/t/t7106-reset-unborn-branch.sh b/t/t7106-reset-unborn-branch.sh new file mode 100755 index 0000000000..8062cf502b --- /dev/null +++ b/t/t7106-reset-unborn-branch.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +test_description='git reset should work on unborn branch' +. ./test-lib.sh + +test_expect_success 'setup' ' + echo a >a && + echo b >b +' + +test_expect_success 'reset' ' + git add a b && + git reset && + test "$(git ls-files)" = "" +' + +test_expect_success 'reset HEAD' ' + rm .git/index && + git add a b && + test_must_fail git reset HEAD +' + +test_expect_success 'reset $file' ' + rm .git/index && + git add a b && + git reset a && + test "$(git ls-files)" = "b" +' + +test_expect_success 'reset -p' ' + rm .git/index && + git add a && + echo y | git reset -p && + test "$(git ls-files)" = "" +' + +test_expect_success 'reset --soft is a no-op' ' + rm .git/index && + git add a && + git reset --soft + test "$(git ls-files)" = "a" +' + +test_expect_success 'reset --hard' ' + rm .git/index && + git add a && + git reset --hard && + test "$(git ls-files)" = "" && + test_path_is_missing a +' + +test_done diff --git a/t/t7201-co.sh b/t/t7201-co.sh index be9672e5a0..0c9ec0ad44 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -431,6 +431,7 @@ test_expect_success 'detach a symbolic link HEAD' ' test_expect_success \ 'checkout with --track fakes a sensible -b <name>' ' + git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" && git update-ref refs/remotes/origin/koala/bear renamer && git checkout --track origin/koala/bear && diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh index ccfb54de7a..710be90489 100755 --- a/t/t7300-clean.sh +++ b/t/t7300-clean.sh @@ -298,6 +298,23 @@ test_expect_success 'git clean -d -x' ' ' +test_expect_success 'git clean -d -x with ignored tracked directory' ' + + mkdir -p build docs && + touch a.out src/part3.c docs/manual.txt obj.o build/lib.so && + git clean -d -x -e src && + test -f Makefile && + test -f README && + test -f src/part1.c && + test -f src/part2.c && + test ! -f a.out && + test -f src/part3.c && + test ! -d docs && + test ! -f obj.o && + test ! -d build + +' + test_expect_success 'git clean -X' ' mkdir -p build docs && @@ -332,6 +349,23 @@ test_expect_success 'git clean -d -X' ' ' +test_expect_success 'git clean -d -X with ignored tracked directory' ' + + mkdir -p build docs && + touch a.out src/part3.c docs/manual.txt obj.o build/lib.so && + git clean -d -X -e src && + test -f Makefile && + test -f README && + test -f src/part1.c && + test -f src/part2.c && + test -f a.out && + test ! -f src/part3.c && + test -f docs/manual.txt && + test ! -f obj.o && + test ! -d build + +' + test_expect_success 'clean.requireForce defaults to true' ' git config --unset clean.requireForce && diff --git a/t/t7301-clean-interactive.sh b/t/t7301-clean-interactive.sh new file mode 100755 index 0000000000..4e6055d06a --- /dev/null +++ b/t/t7301-clean-interactive.sh @@ -0,0 +1,439 @@ +#!/bin/sh + +test_description='git clean -i basic tests' + +. ./test-lib.sh + +test_expect_success 'setup' ' + + mkdir -p src && + touch src/part1.c Makefile && + echo build >.gitignore && + echo \*.o >>.gitignore && + git add . && + git commit -m setup && + touch src/part2.c README && + git add . + +' + +test_expect_success 'git clean -i (clean)' ' + + mkdir -p build docs && + touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \ + docs/manual.txt obj.o build/lib.so && + echo c | git clean -i && + test -f Makefile && + test -f README && + test -f src/part1.c && + test -f src/part2.c && + test ! -f a.out && + test -f docs/manual.txt && + test ! -f src/part3.c && + test ! -f src/part3.h && + test ! -f src/part4.c && + test ! -f src/part4.h && + test -f obj.o && + test -f build/lib.so + +' + +test_expect_success 'git clean -i (quit)' ' + + mkdir -p build docs && + touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \ + docs/manual.txt obj.o build/lib.so && + echo q | git clean -i && + test -f Makefile && + test -f README && + test -f src/part1.c && + test -f src/part2.c && + test -f a.out && + test -f docs/manual.txt && + test -f src/part3.c && + test -f src/part3.h && + test -f src/part4.c && + test -f src/part4.h && + test -f obj.o && + test -f build/lib.so + +' + +test_expect_success 'git clean -i (Ctrl+D)' ' + + mkdir -p build docs && + touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \ + docs/manual.txt obj.o build/lib.so && + echo "\04" | git clean -i && + test -f Makefile && + test -f README && + test -f src/part1.c && + test -f src/part2.c && + test -f a.out && + test -f docs/manual.txt && + test -f src/part3.c && + test -f src/part3.h && + test -f src/part4.c && + test -f src/part4.h && + test -f obj.o && + test -f build/lib.so + +' + +test_expect_success 'git clean -id (filter all)' ' + + mkdir -p build docs && + touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \ + docs/manual.txt obj.o build/lib.so && + (echo f; echo "*"; echo; echo c) | \ + git clean -id && + test -f Makefile && + test -f README && + test -f src/part1.c && + test -f src/part2.c && + test -f a.out && + test -f docs/manual.txt && + test -f src/part3.c && + test -f src/part3.h && + test -f src/part4.c && + test -f src/part4.h && + test -f obj.o && + test -f build/lib.so + +' + +test_expect_success 'git clean -id (filter patterns)' ' + + mkdir -p build docs && + touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \ + docs/manual.txt obj.o build/lib.so && + (echo f; echo "part3.* *.out"; echo; echo c) | \ + git clean -id && + test -f Makefile && + test -f README && + test -f src/part1.c && + test -f src/part2.c && + test -f a.out && + test ! -f docs/manual.txt && + test -f src/part3.c && + test -f src/part3.h && + test ! -f src/part4.c && + test ! -f src/part4.h && + test -f obj.o && + test -f build/lib.so + +' + +test_expect_success 'git clean -id (filter patterns 2)' ' + + mkdir -p build docs && + touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \ + docs/manual.txt obj.o build/lib.so && + (echo f; echo "* !*.out"; echo; echo c) | \ + git clean -id && + test -f Makefile && + test -f README && + test -f src/part1.c && + test -f src/part2.c && + test ! -f a.out && + test -f docs/manual.txt && + test -f src/part3.c && + test -f src/part3.h && + test -f src/part4.c && + test -f src/part4.h && + test -f obj.o && + test -f build/lib.so + +' + +test_expect_success 'git clean -id (select - all)' ' + + mkdir -p build docs && + touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \ + docs/manual.txt obj.o build/lib.so && + (echo s; echo "*"; echo; echo c) | \ + git clean -id && + test -f Makefile && + test -f README && + test -f src/part1.c && + test -f src/part2.c && + test ! -f a.out && + test ! -f docs/manual.txt && + test ! -f src/part3.c && + test ! -f src/part3.h && + test ! -f src/part4.c && + test ! -f src/part4.h && + test -f obj.o && + test -f build/lib.so + +' + +test_expect_success 'git clean -id (select - none)' ' + + mkdir -p build docs && + touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \ + docs/manual.txt obj.o build/lib.so && + (echo s; echo; echo c) | \ + git clean -id && + test -f Makefile && + test -f README && + test -f src/part1.c && + test -f src/part2.c && + test -f a.out && + test -f docs/manual.txt && + test -f src/part3.c && + test -f src/part3.h && + test -f src/part4.c && + test -f src/part4.h && + test -f obj.o && + test -f build/lib.so + +' + +test_expect_success 'git clean -id (select - number)' ' + + mkdir -p build docs && + touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \ + docs/manual.txt obj.o build/lib.so && + (echo s; echo 3; echo; echo c) | \ + git clean -id && + test -f Makefile && + test -f README && + test -f src/part1.c && + test -f src/part2.c && + test -f a.out && + test -f docs/manual.txt && + test ! -f src/part3.c && + test -f src/part3.h && + test -f src/part4.c && + test -f src/part4.h && + test -f obj.o && + test -f build/lib.so + +' + +test_expect_success 'git clean -id (select - number 2)' ' + + mkdir -p build docs && + touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \ + docs/manual.txt obj.o build/lib.so && + (echo s; echo 2 3; echo 5; echo; echo c) | \ + git clean -id && + test -f Makefile && + test -f README && + test -f src/part1.c && + test -f src/part2.c && + test -f a.out && + test ! -f docs/manual.txt && + test ! -f src/part3.c && + test -f src/part3.h && + test ! -f src/part4.c && + test -f src/part4.h && + test -f obj.o && + test -f build/lib.so + +' + +test_expect_success 'git clean -id (select - number 3)' ' + + mkdir -p build docs && + touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \ + docs/manual.txt obj.o build/lib.so && + (echo s; echo 3,4 5; echo; echo c) | \ + git clean -id && + test -f Makefile && + test -f README && + test -f src/part1.c && + test -f src/part2.c && + test -f a.out && + test -f docs/manual.txt && + test ! -f src/part3.c && + test ! -f src/part3.h && + test ! -f src/part4.c && + test -f src/part4.h && + test -f obj.o && + test -f build/lib.so + +' + +test_expect_success 'git clean -id (select - range)' ' + + mkdir -p build docs && + touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \ + docs/manual.txt obj.o build/lib.so && + (echo s; echo 1,3-4; echo 2; echo; echo c) | \ + git clean -id && + test -f Makefile && + test -f README && + test -f src/part1.c && + test -f src/part2.c && + test ! -f a.out && + test ! -f src/part3.c && + test ! -f src/part3.h && + test -f src/part4.c && + test -f src/part4.h && + test ! -f docs/manual.txt && + test -f obj.o && + test -f build/lib.so + +' + +test_expect_success 'git clean -id (select - range 2)' ' + + mkdir -p build docs && + touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \ + docs/manual.txt obj.o build/lib.so && + (echo s; echo 4- 1; echo; echo c) | \ + git clean -id && + test -f Makefile && + test -f README && + test -f src/part1.c && + test -f src/part2.c && + test ! -f a.out && + test -f docs/manual.txt && + test -f src/part3.c && + test ! -f src/part3.h && + test ! -f src/part4.c && + test ! -f src/part4.h && + test -f obj.o && + test -f build/lib.so + +' + +test_expect_success 'git clean -id (inverse select)' ' + + mkdir -p build docs && + touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \ + docs/manual.txt obj.o build/lib.so && + (echo s; echo "*"; echo -5- 1 -2; echo; echo c) | \ + git clean -id && + test -f Makefile && + test -f README && + test -f src/part1.c && + test -f src/part2.c && + test ! -f a.out && + test -f docs/manual.txt && + test ! -f src/part3.c && + test ! -f src/part3.h && + test -f src/part4.c && + test -f src/part4.h && + test -f obj.o && + test -f build/lib.so + +' + +test_expect_success 'git clean -id (ask)' ' + + mkdir -p build docs && + touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \ + docs/manual.txt obj.o build/lib.so && + (echo a; echo Y; echo y; echo no; echo yes; echo bad; echo) | \ + git clean -id && + test -f Makefile && + test -f README && + test -f src/part1.c && + test -f src/part2.c && + test ! -f a.out && + test ! -f docs/manual.txt && + test -f src/part3.c && + test ! -f src/part3.h && + test -f src/part4.c && + test -f src/part4.h && + test -f obj.o && + test -f build/lib.so + +' + +test_expect_success 'git clean -id (ask - Ctrl+D)' ' + + mkdir -p build docs && + touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \ + docs/manual.txt obj.o build/lib.so && + (echo a; echo Y; echo no; echo yes; echo "\04") | \ + git clean -id && + test -f Makefile && + test -f README && + test -f src/part1.c && + test -f src/part2.c && + test ! -f a.out && + test -f docs/manual.txt && + test ! -f src/part3.c && + test -f src/part3.h && + test -f src/part4.c && + test -f src/part4.h && + test -f obj.o && + test -f build/lib.so + +' + +test_expect_success 'git clean -id with prefix and path (filter)' ' + + mkdir -p build docs && + touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \ + docs/manual.txt obj.o build/lib.so && + (cd build/ && \ + (echo f; echo "docs"; echo "*.h"; echo ; echo c) | \ + git clean -id ..) && + test -f Makefile && + test -f README && + test -f src/part1.c && + test -f src/part2.c && + test ! -f a.out && + test -f docs/manual.txt && + test ! -f src/part3.c && + test -f src/part3.h && + test ! -f src/part4.c && + test -f src/part4.h && + test -f obj.o && + test -f build/lib.so + +' + +test_expect_success 'git clean -id with prefix and path (select by name)' ' + + mkdir -p build docs && + touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \ + docs/manual.txt obj.o build/lib.so && + (cd build/ && \ + (echo s; echo "../docs/"; echo "../src/part3.c"; \ + echo "../src/part4.c"; echo; echo c) | \ + git clean -id ..) && + test -f Makefile && + test -f README && + test -f src/part1.c && + test -f src/part2.c && + test -f a.out && + test ! -f docs/manual.txt && + test ! -f src/part3.c && + test -f src/part3.h && + test ! -f src/part4.c && + test -f src/part4.h && + test -f obj.o && + test -f build/lib.so + +' + +test_expect_success 'git clean -id with prefix and path (ask)' ' + + mkdir -p build docs && + touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \ + docs/manual.txt obj.o build/lib.so && + (cd build/ && \ + (echo a; echo Y; echo y; echo no; echo yes; echo bad; echo) | \ + git clean -id ..) && + test -f Makefile && + test -f README && + test -f src/part1.c && + test -f src/part2.c && + test ! -f a.out && + test ! -f docs/manual.txt && + test -f src/part3.c && + test ! -f src/part3.h && + test -f src/part4.c && + test -f src/part4.h && + test -f obj.o && + test -f build/lib.so + +' + +test_done diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index 5397037491..5ee97b003a 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -78,7 +78,7 @@ test_expect_success 'submodule add' ' ( cd addtest && git submodule add -q "$submodurl" submod >actual && - test ! -s actual && + test_must_be_empty actual && echo "gitdir: ../.git/modules/submod" >expect && test_cmp expect submod/.git && ( @@ -133,6 +133,7 @@ test_expect_success 'submodule add --branch' ' ( cd addtest && git submodule add -b initial "$submodurl" submod-branch && + test "initial" = "$(git config -f .gitmodules submodule.submod-branch.branch)" && git submodule init ) && @@ -211,6 +212,32 @@ test_expect_success 'submodule add with ./, /.. and // in path' ' test_cmp empty untracked ' +test_expect_success 'submodule add in subdirectory' ' + echo "refs/heads/master" >expect && + >empty && + + mkdir addtest/sub && + ( + cd addtest/sub && + git submodule add "$submodurl" ../realsubmod3 && + git submodule init + ) && + + rm -f heads head untracked && + inspect addtest/realsubmod3 ../.. && + test_cmp expect heads && + test_cmp expect head && + test_cmp empty untracked +' + +test_expect_success 'submodule add in subdirectory with relative path should fail' ' + ( + cd addtest/sub && + test_must_fail git submodule add ../../ submod3 2>../../output.err + ) && + test_i18ngrep toplevel output.err +' + test_expect_success 'setup - add an example entry to .gitmodules' ' GIT_CONFIG=.gitmodules \ git config submodule.example.url git://example.com/init.git @@ -307,7 +334,7 @@ test_expect_success 'update should work when path is an empty dir' ' mkdir init && git submodule update -q >update.out && - test ! -s update.out && + test_must_be_empty update.out && inspect init && test_cmp expect head-sha1 @@ -318,6 +345,26 @@ test_expect_success 'status should be "up-to-date" after update' ' grep "^ $rev1" list ' +test_expect_success 'status "up-to-date" from subdirectory' ' + mkdir -p sub && + ( + cd sub && + git submodule status >../list + ) && + grep "^ $rev1" list && + grep "\\.\\./init" list +' + +test_expect_success 'status "up-to-date" from subdirectory with path' ' + mkdir -p sub && + ( + cd sub && + git submodule status ../init >../list + ) && + grep "^ $rev1" list && + grep "\\.\\./init" list +' + test_expect_success 'status should be "modified" after submodule commit' ' ( cd init && @@ -398,6 +445,25 @@ test_expect_success 'update --init' ' git rev-parse --resolve-git-dir init/.git ' +test_expect_success 'update --init from subdirectory' ' + mv init init2 && + git config -f .gitmodules submodule.example.url "$(pwd)/init2" && + git config --remove-section submodule.example && + test_must_fail git config submodule.example.url && + + mkdir -p sub && + ( + cd sub && + git submodule update ../init >update.out && + cat update.out && + test_i18ngrep "not initialized" update.out && + test_must_fail git rev-parse --resolve-git-dir ../init/.git && + + git submodule update --init ../init + ) && + git rev-parse --resolve-git-dir init/.git +' + test_expect_success 'do not add files from a submodule' ' git reset --hard && @@ -681,4 +747,236 @@ test_expect_success 'moving the superproject does not break submodules' ' ) ' +test_expect_success 'submodule add --name allows to replace a submodule with another at the same path' ' + ( + cd addtest2 && + ( + cd repo && + echo "$submodurl/repo" >expect && + git config remote.origin.url >actual && + test_cmp expect actual && + echo "gitdir: ../.git/modules/repo" >expect && + test_cmp expect .git + ) && + rm -rf repo && + git rm repo && + git submodule add -q --name repo_new "$submodurl/bare.git" repo >actual && + test_must_be_empty actual && + echo "gitdir: ../.git/modules/submod" >expect && + test_cmp expect submod/.git && + ( + cd repo && + echo "$submodurl/bare.git" >expect && + git config remote.origin.url >actual && + test_cmp expect actual && + echo "gitdir: ../.git/modules/repo_new" >expect && + test_cmp expect .git + ) && + echo "repo" >expect && + git config -f .gitmodules submodule.repo.path >actual && + test_cmp expect actual && + git config -f .gitmodules submodule.repo_new.path >actual && + test_cmp expect actual&& + echo "$submodurl/repo" >expect && + git config -f .gitmodules submodule.repo.url >actual && + test_cmp expect actual && + echo "$submodurl/bare.git" >expect && + git config -f .gitmodules submodule.repo_new.url >actual && + test_cmp expect actual && + echo "$submodurl/repo" >expect && + git config submodule.repo.url >actual && + test_cmp expect actual && + echo "$submodurl/bare.git" >expect && + git config submodule.repo_new.url >actual && + test_cmp expect actual + ) +' + +test_expect_success 'submodule add with an existing name fails unless forced' ' + ( + cd addtest2 && + rm -rf repo && + git rm repo && + test_must_fail git submodule add -q --name repo_new "$submodurl/repo.git" repo && + test ! -d repo && + echo "repo" >expect && + git config -f .gitmodules submodule.repo_new.path >actual && + test_cmp expect actual&& + echo "$submodurl/bare.git" >expect && + git config -f .gitmodules submodule.repo_new.url >actual && + test_cmp expect actual && + echo "$submodurl/bare.git" >expect && + git config submodule.repo_new.url >actual && + test_cmp expect actual && + git submodule add -f -q --name repo_new "$submodurl/repo.git" repo && + test -d repo && + echo "repo" >expect && + git config -f .gitmodules submodule.repo_new.path >actual && + test_cmp expect actual&& + echo "$submodurl/repo.git" >expect && + git config -f .gitmodules submodule.repo_new.url >actual && + test_cmp expect actual && + echo "$submodurl/repo.git" >expect && + git config submodule.repo_new.url >actual && + test_cmp expect actual + ) +' + +test_expect_success 'set up a second submodule' ' + git submodule add ./init2 example2 && + git commit -m "submodule example2 added" +' + +test_expect_success 'submodule deinit should remove the whole submodule section from .git/config' ' + git config submodule.example.foo bar && + git config submodule.example2.frotz nitfol && + git submodule deinit init && + test -z "$(git config --get-regexp "submodule\.example\.")" && + test -n "$(git config --get-regexp "submodule\.example2\.")" && + test -f example2/.git && + rmdir init +' + +test_expect_success 'submodule deinit from subdirectory' ' + git submodule update --init && + git config submodule.example.foo bar && + mkdir -p sub && + ( + cd sub && + git submodule deinit ../init >../output + ) && + grep "\\.\\./init" output && + test -z "$(git config --get-regexp "submodule\.example\.")" && + test -n "$(git config --get-regexp "submodule\.example2\.")" && + test -f example2/.git && + rmdir init +' + +test_expect_success 'submodule deinit . deinits all initialized submodules' ' + git submodule update --init && + git config submodule.example.foo bar && + git config submodule.example2.frotz nitfol && + test_must_fail git submodule deinit && + git submodule deinit . >actual && + test -z "$(git config --get-regexp "submodule\.example\.")" && + test -z "$(git config --get-regexp "submodule\.example2\.")" && + test_i18ngrep "Cleared directory .init" actual && + test_i18ngrep "Cleared directory .example2" actual && + rmdir init example2 +' + +test_expect_success 'submodule deinit deinits a submodule when its work tree is missing or empty' ' + git submodule update --init && + rm -rf init example2/* example2/.git && + git submodule deinit init example2 >actual && + test -z "$(git config --get-regexp "submodule\.example\.")" && + test -z "$(git config --get-regexp "submodule\.example2\.")" && + test_i18ngrep ! "Cleared directory .init" actual && + test_i18ngrep "Cleared directory .example2" actual && + rmdir init +' + +test_expect_success 'submodule deinit fails when the submodule contains modifications unless forced' ' + git submodule update --init && + echo X >>init/s && + test_must_fail git submodule deinit init && + test -n "$(git config --get-regexp "submodule\.example\.")" && + test -f example2/.git && + git submodule deinit -f init >actual && + test -z "$(git config --get-regexp "submodule\.example\.")" && + test_i18ngrep "Cleared directory .init" actual && + rmdir init +' + +test_expect_success 'submodule deinit fails when the submodule contains untracked files unless forced' ' + git submodule update --init && + echo X >>init/untracked && + test_must_fail git submodule deinit init && + test -n "$(git config --get-regexp "submodule\.example\.")" && + test -f example2/.git && + git submodule deinit -f init >actual && + test -z "$(git config --get-regexp "submodule\.example\.")" && + test_i18ngrep "Cleared directory .init" actual && + rmdir init +' + +test_expect_success 'submodule deinit fails when the submodule HEAD does not match unless forced' ' + git submodule update --init && + ( + cd init && + git checkout HEAD^ + ) && + test_must_fail git submodule deinit init && + test -n "$(git config --get-regexp "submodule\.example\.")" && + test -f example2/.git && + git submodule deinit -f init >actual && + test -z "$(git config --get-regexp "submodule\.example\.")" && + test_i18ngrep "Cleared directory .init" actual && + rmdir init +' + +test_expect_success 'submodule deinit is silent when used on an uninitialized submodule' ' + git submodule update --init && + git submodule deinit init >actual && + test_i18ngrep "Submodule .example. (.*) unregistered for path .init" actual && + test_i18ngrep "Cleared directory .init" actual && + git submodule deinit init >actual && + test_i18ngrep ! "Submodule .example. (.*) unregistered for path .init" actual && + test_i18ngrep "Cleared directory .init" actual && + git submodule deinit . >actual && + test_i18ngrep ! "Submodule .example. (.*) unregistered for path .init" actual && + test_i18ngrep "Submodule .example2. (.*) unregistered for path .example2" actual && + test_i18ngrep "Cleared directory .init" actual && + git submodule deinit . >actual && + test_i18ngrep ! "Submodule .example. (.*) unregistered for path .init" actual && + test_i18ngrep ! "Submodule .example2. (.*) unregistered for path .example2" actual && + test_i18ngrep "Cleared directory .init" actual && + rmdir init example2 +' + +test_expect_success 'submodule deinit fails when submodule has a .git directory even when forced' ' + git submodule update --init && + ( + cd init && + rm .git && + cp -R ../.git/modules/example .git && + GIT_WORK_TREE=. git config --unset core.worktree + ) && + test_must_fail git submodule deinit init && + test_must_fail git submodule deinit -f init && + test -d init/.git && + test -n "$(git config --get-regexp "submodule\.example\.")" +' + +test_expect_success 'submodule with UTF-8 name' ' + svname=$(printf "\303\245 \303\244\303\266") && + mkdir "$svname" && + ( + cd "$svname" && + git init && + >sub && + git add sub && + git commit -m "init sub" + ) && + test_config core.precomposeunicode true && + git submodule add ./"$svname" && + git submodule >&2 && + test -n "$(git submodule | grep "$svname")" +' + +test_expect_success 'submodule add clone shallow submodule' ' + mkdir super && + pwd=$(pwd) + ( + cd super && + git init && + git submodule add --depth=1 file://"$pwd"/example2 submodule && + ( + cd submodule && + test 1 = $(git log --oneline | wc -l) + ) + ) +' + + test_done diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 30b429e7dc..ac2434c0db 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -45,6 +45,42 @@ EOF test_cmp expected actual " +test_expect_success 'added submodule (subdirectory)' " + mkdir sub && + ( + cd sub && + git submodule summary >../actual + ) && + cat >expected <<-EOF && +* ../sm1 0000000...$head1 (2): + > Add foo2 + +EOF + test_cmp expected actual +" + +test_expect_success 'added submodule (subdirectory only)' " + ( + cd sub && + git submodule summary . >../actual + ) && + >expected && + test_cmp expected actual +" + +test_expect_success 'added submodule (subdirectory with explicit path)' " + ( + cd sub && + git submodule summary ../sm1 >../actual + ) && + cat >expected <<-EOF && +* ../sm1 0000000...$head1 (2): + > Add foo2 + +EOF + test_cmp expected actual +" + commit_file sm1 && head2=$(add_file sm1 foo3) @@ -76,8 +112,8 @@ head3=$( ) test_expect_success 'modified submodule(backward)' " - git submodule summary >actual && - cat >expected <<-EOF && + git submodule summary >actual && + cat >expected <<-EOF && * sm1 $head2...$head3 (2): < Add foo3 < Add foo2 @@ -89,8 +125,8 @@ EOF head4=$(add_file sm1 foo4 foo5) && head4_full=$(GIT_DIR=sm1/.git git rev-parse --verify HEAD) test_expect_success 'modified submodule(backward and forward)' " - git submodule summary >actual && - cat >expected <<-EOF && + git submodule summary >actual && + cat >expected <<-EOF && * sm1 $head2...$head4 (4): > Add foo5 > Add foo4 @@ -102,15 +138,15 @@ EOF " test_expect_success '--summary-limit' " - git submodule summary -n 3 >actual && - cat >expected <<-EOF && + git submodule summary -n 3 >actual && + cat >expected <<-EOF && * sm1 $head2...$head4 (4): > Add foo5 > Add foo4 < Add foo3 EOF - test_cmp expected actual + test_cmp expected actual " commit_file sm1 && @@ -122,8 +158,8 @@ rm -f sm1 && mv sm1-bak sm1 test_expect_success 'typechanged submodule(submodule->blob), --cached' " - git submodule summary --cached >actual && - cat >expected <<-EOF && + git submodule summary --cached >actual && + cat >expected <<-EOF && * sm1 $head4(submodule)->$head5(blob) (3): < Add foo5 @@ -132,59 +168,59 @@ EOF " test_expect_success 'typechanged submodule(submodule->blob), --files' " - git submodule summary --files >actual && - cat >expected <<-EOF && + git submodule summary --files >actual && + cat >expected <<-EOF && * sm1 $head5(blob)->$head4(submodule) (3): > Add foo5 EOF - test_i18ncmp actual expected + test_i18ncmp actual expected " rm -rf sm1 && git checkout-index sm1 test_expect_success 'typechanged submodule(submodule->blob)' " - git submodule summary >actual && - cat >expected <<-EOF && + git submodule summary >actual && + cat >expected <<-EOF && * sm1 $head4(submodule)->$head5(blob): EOF - test_i18ncmp actual expected + test_i18ncmp actual expected " rm -f sm1 && test_create_repo sm1 && head6=$(add_file sm1 foo6 foo7) test_expect_success 'nonexistent commit' " - git submodule summary >actual && - cat >expected <<-EOF && + git submodule summary >actual && + cat >expected <<-EOF && * sm1 $head4...$head6: Warn: sm1 doesn't contain commit $head4_full EOF - test_i18ncmp actual expected + test_i18ncmp actual expected " commit_file test_expect_success 'typechanged submodule(blob->submodule)' " - git submodule summary >actual && - cat >expected <<-EOF && + git submodule summary >actual && + cat >expected <<-EOF && * sm1 $head5(blob)->$head6(submodule) (2): > Add foo7 EOF - test_i18ncmp expected actual + test_i18ncmp expected actual " commit_file sm1 && rm -rf sm1 test_expect_success 'deleted submodule' " - git submodule summary >actual && - cat >expected <<-EOF && + git submodule summary >actual && + cat >expected <<-EOF && * sm1 $head6...0000000: EOF - test_cmp expected actual + test_cmp expected actual " test_create_repo sm2 && @@ -192,43 +228,43 @@ head7=$(add_file sm2 foo8 foo9) && git add sm2 test_expect_success 'multiple submodules' " - git submodule summary >actual && - cat >expected <<-EOF && + git submodule summary >actual && + cat >expected <<-EOF && * sm1 $head6...0000000: * sm2 0000000...$head7 (2): > Add foo9 EOF - test_cmp expected actual + test_cmp expected actual " test_expect_success 'path filter' " - git submodule summary sm2 >actual && - cat >expected <<-EOF && + git submodule summary sm2 >actual && + cat >expected <<-EOF && * sm2 0000000...$head7 (2): > Add foo9 EOF - test_cmp expected actual + test_cmp expected actual " commit_file sm2 test_expect_success 'given commit' " - git submodule summary HEAD^ >actual && - cat >expected <<-EOF && + git submodule summary HEAD^ >actual && + cat >expected <<-EOF && * sm1 $head6...0000000: * sm2 0000000...$head7 (2): > Add foo9 EOF - test_cmp expected actual + test_cmp expected actual " test_expect_success '--for-status' " - git submodule summary --for-status HEAD^ >actual && - test_i18ncmp actual - <<EOF + git submodule summary --for-status HEAD^ >actual && + test_i18ncmp actual - <<EOF # Submodule changes to be committed: # # * sm1 $head6...0000000: @@ -240,14 +276,14 @@ EOF " test_expect_success 'fail when using --files together with --cached' " - test_must_fail git submodule summary --files --cached + test_must_fail git submodule summary --files --cached " test_expect_success 'should not fail in an empty repo' " - git init xyzzy && - cd xyzzy && - git submodule summary >output 2>&1 && - test_cmp output /dev/null + git init xyzzy && + cd xyzzy && + git submodule summary >output 2>&1 && + test_cmp output /dev/null " test_done diff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh index f919c8d34d..8e32f19007 100755 --- a/t/t7402-submodule-rebase.sh +++ b/t/t7402-submodule-rebase.sh @@ -3,7 +3,7 @@ # Copyright (c) 2008 Johannes Schindelin # -test_description='Test rebasing and stashing with dirty submodules' +test_description='Test rebasing, stashing, etc. with submodules' . ./test-lib.sh @@ -20,7 +20,8 @@ test_expect_success setup ' echo second line >> file && (cd submodule && git pull) && test_tick && - git commit -m file-and-submodule -a + git commit -m file-and-submodule -a && + git branch added-submodule ' @@ -89,4 +90,29 @@ test_expect_success 'stash with a dirty submodule' ' ' +test_expect_success 'rebasing submodule that should conflict' ' + git reset --hard && + git checkout added-submodule && + git add submodule && + test_tick && + git commit -m third && + ( + cd submodule && + git commit --allow-empty -m extra + ) && + git add submodule && + test_tick && + git commit -m fourth && + + test_must_fail git rebase --onto HEAD^^ HEAD^ HEAD^0 && + git ls-files -s submodule >actual && + ( + cd submodule && + echo "160000 $(git rev-parse HEAD^) 1 submodule" && + echo "160000 $(git rev-parse HEAD^^) 2 submodule" && + echo "160000 $(git rev-parse HEAD) 3 submodule" + ) >expect && + test_cmp expect actual +' + test_done diff --git a/t/t7403-submodule-sync.sh b/t/t7403-submodule-sync.sh index 524d5c1b21..79bc135bf6 100755 --- a/t/t7403-submodule-sync.sh +++ b/t/t7403-submodule-sync.sh @@ -11,165 +11,338 @@ These tests exercise the "git submodule sync" subcommand. . ./test-lib.sh test_expect_success setup ' - echo file > file && + echo file >file && git add file && test_tick && git commit -m upstream && git clone . super && git clone super submodule && - (cd super && - git submodule add ../submodule submodule && - test_tick && - git commit -m "submodule" + ( + cd submodule && + git submodule add ../submodule sub-submodule && + test_tick && + git commit -m "sub-submodule" + ) && + ( + cd super && + git submodule add ../submodule submodule && + test_tick && + git commit -m "submodule" ) && git clone super super-clone && - (cd super-clone && git submodule update --init) && + ( + cd super-clone && + git submodule update --init --recursive + ) && git clone super empty-clone && - (cd empty-clone && git submodule init) && + ( + cd empty-clone && + git submodule init + ) && git clone super top-only-clone && git clone super relative-clone && - (cd relative-clone && git submodule update --init) + ( + cd relative-clone && + git submodule update --init --recursive + ) && + git clone super recursive-clone && + ( + cd recursive-clone && + git submodule update --init --recursive + ) ' test_expect_success 'change submodule' ' - (cd submodule && - echo second line >> file && - test_tick && - git commit -a -m "change submodule" + ( + cd submodule && + echo second line >>file && + test_tick && + git commit -a -m "change submodule" ) ' +reset_submodule_urls () { + local root + root=$(pwd) && + ( + cd super-clone/submodule && + git config remote.origin.url "$root/submodule" + ) && + ( + cd super-clone/submodule/sub-submodule && + git config remote.origin.url "$root/submodule" + ) +} + test_expect_success 'change submodule url' ' - (cd super && - cd submodule && - git checkout master && - git pull + ( + cd super && + cd submodule && + git checkout master && + git pull ) && mv submodule moved-submodule && - (cd super && - git config -f .gitmodules submodule.submodule.url ../moved-submodule && - test_tick && - git commit -a -m moved-submodule + ( + cd moved-submodule && + git config -f .gitmodules submodule.sub-submodule.url ../moved-submodule && + test_tick && + git commit -a -m moved-sub-submodule + ) && + ( + cd super && + git config -f .gitmodules submodule.submodule.url ../moved-submodule && + test_tick && + git commit -a -m moved-submodule ) ' test_expect_success '"git submodule sync" should update submodule URLs' ' - (cd super-clone && - git pull --no-recurse-submodules && - git submodule sync + ( + cd super-clone && + git pull --no-recurse-submodules && + git submodule sync ) && - test -d "$(cd super-clone/submodule && - git config remote.origin.url + test -d "$( + cd super-clone/submodule && + git config remote.origin.url + )" && + test ! -d "$( + cd super-clone/submodule/sub-submodule && + git config remote.origin.url )" && - (cd super-clone/submodule && - git checkout master && - git pull + ( + cd super-clone/submodule && + git checkout master && + git pull ) && - (cd super-clone && - test -d "$(git config submodule.submodule.url)" + ( + cd super-clone && + test -d "$(git config submodule.submodule.url)" + ) +' + +test_expect_success '"git submodule sync --recursive" should update all submodule URLs' ' + ( + cd super-clone && + ( + cd submodule && + git pull --no-recurse-submodules + ) && + git submodule sync --recursive + ) && + test -d "$( + cd super-clone/submodule && + git config remote.origin.url + )" && + test -d "$( + cd super-clone/submodule/sub-submodule && + git config remote.origin.url + )" && + ( + cd super-clone/submodule/sub-submodule && + git checkout master && + git pull + ) +' + +test_expect_success 'reset submodule URLs' ' + reset_submodule_urls super-clone +' + +test_expect_success '"git submodule sync" should update submodule URLs - subdirectory' ' + ( + cd super-clone && + git pull --no-recurse-submodules && + mkdir -p sub && + cd sub && + git submodule sync >../../output + ) && + grep "\\.\\./submodule" output && + test -d "$( + cd super-clone/submodule && + git config remote.origin.url + )" && + test ! -d "$( + cd super-clone/submodule/sub-submodule && + git config remote.origin.url + )" && + ( + cd super-clone/submodule && + git checkout master && + git pull + ) && + ( + cd super-clone && + test -d "$(git config submodule.submodule.url)" + ) +' + +test_expect_success '"git submodule sync --recursive" should update all submodule URLs - subdirectory' ' + ( + cd super-clone && + ( + cd submodule && + git pull --no-recurse-submodules + ) && + mkdir -p sub && + cd sub && + git submodule sync --recursive >../../output + ) && + grep "\\.\\./submodule/sub-submodule" output && + test -d "$( + cd super-clone/submodule && + git config remote.origin.url + )" && + test -d "$( + cd super-clone/submodule/sub-submodule && + git config remote.origin.url + )" && + ( + cd super-clone/submodule/sub-submodule && + git checkout master && + git pull ) ' test_expect_success '"git submodule sync" should update known submodule URLs' ' - (cd empty-clone && - git pull && - git submodule sync && - test -d "$(git config submodule.submodule.url)" + ( + cd empty-clone && + git pull && + git submodule sync && + test -d "$(git config submodule.submodule.url)" ) ' test_expect_success '"git submodule sync" should not vivify uninteresting submodule' ' - (cd top-only-clone && - git pull && - git submodule sync && - test -z "$(git config submodule.submodule.url)" && - git submodule sync submodule && - test -z "$(git config submodule.submodule.url)" + ( + cd top-only-clone && + git pull && + git submodule sync && + test -z "$(git config submodule.submodule.url)" && + git submodule sync submodule && + test -z "$(git config submodule.submodule.url)" ) ' 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" - ) + ( + 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" + ( + 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" + ) && + ( + cd submodule/sub-submodule && + test "$(git config remote.origin.url)" != "../../foo/submodule" + ) ) +' + +test_expect_success '"git submodule sync --recursive" propagates changes in origin' ' + ( + cd recursive-clone && + git remote set-url origin foo/bar && + git submodule sync --recursive && + ( + cd submodule && + #actual foo/submodule + test "$(git config remote.origin.url)" = "../foo/submodule" + ) && + ( + cd submodule/sub-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" - ) + ( + 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" - ) + ( + 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" - ) + ( + 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" - ) + ( + 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" - ) + ( + 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" + ) ) ' diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh index 15426530e4..b192f936bc 100755 --- a/t/t7406-submodule-update.sh +++ b/t/t7406-submodule-update.sh @@ -80,6 +80,21 @@ test_expect_success 'submodule update detaching the HEAD ' ' ) ' +test_expect_success 'submodule update from subdirectory' ' + (cd super/submodule && + git reset --hard HEAD~1 + ) && + mkdir super/sub && + (cd super/sub && + (cd ../submodule && + compare_head + ) && + git submodule update ../submodule && + cd ../submodule && + ! compare_head + ) +' + apos="'"; test_expect_success 'submodule update does not fetch already present commits' ' (cd submodule && @@ -135,6 +150,37 @@ test_expect_success 'submodule update --force forcibly checks out submodules' ' ) ' +test_expect_success 'submodule update --remote should fetch upstream changes' ' + (cd submodule && + echo line4 >> file && + git add file && + test_tick && + git commit -m "upstream line4" + ) && + (cd super && + git submodule update --remote --force submodule && + cd submodule && + test "$(git log -1 --oneline)" = "$(GIT_DIR=../../submodule/.git git log -1 --oneline)" + ) +' + +test_expect_success 'local config should override .gitmodules branch' ' + (cd submodule && + git checkout -b test-branch && + echo line5 >> file && + git add file && + test_tick && + git commit -m "upstream line5" && + git checkout master + ) && + (cd super && + git config submodule.submodule.branch test-branch && + git submodule update --remote --force submodule && + cd submodule && + test "$(git log -1 --oneline)" = "$(GIT_DIR=../../submodule/.git git log -1 --oneline test-branch)" + ) +' + test_expect_success 'submodule update --rebase staying on master' ' (cd super/submodule && git checkout master @@ -248,6 +294,35 @@ test_expect_success 'submodule update - checkout in .git/config' ' ) ' +test_expect_success 'submodule update - command in .git/config' ' + (cd super && + git config submodule.submodule.update "!git checkout" + ) && + (cd super/submodule && + git reset --hard HEAD^ + ) && + (cd super && + (cd submodule && + compare_head + ) && + git submodule update submodule && + cd submodule && + ! compare_head + ) +' + +test_expect_success 'submodule update - command in .git/config catches failure' ' + (cd super && + git config submodule.submodule.update "!false" + ) && + (cd super/submodule && + git reset --hard HEAD^ + ) && + (cd super && + test_must_fail git submodule update submodule + ) +' + test_expect_success 'submodule init picks up rebase' ' (cd super && git config -f .gitmodules submodule.rebasing.update rebase && @@ -565,14 +640,14 @@ test_expect_success 'submodule add places git-dir in superprojects git-dir recur git log > ../../../expected ) && git commit -m "added subsubmodule" && - git push + git push origin : ) && (cd .git/modules/deeper/submodule/modules/subsubmodule && git log > ../../../../../actual ) && git add deeper/submodule && git commit -m "update submodule" && - git push && + git push origin : && test_cmp actual expected ) ' @@ -612,7 +687,8 @@ test_expect_success 'submodule update places git-dir in superprojects git-dir re rm -rf super_update_r2 && git clone super_update_r super_update_r2 && (cd super_update_r2 && - git submodule update --init --recursive && + git submodule update --init --recursive >actual && + test_i18ngrep "Submodule path .submodule/subsubmodule.: checked out" actual && (cd submodule/subsubmodule && git log > ../../expected ) && @@ -627,14 +703,16 @@ test_expect_success 'submodule add properly re-creates deeper level submodules' (cd super && git reset --hard master && rm -rf deeper/ && - git submodule add ../submodule deeper/submodule + git submodule add --force ../submodule deeper/submodule ) ' test_expect_success 'submodule update properly revives a moved submodule' ' (cd super && + H=$(git rev-parse --short HEAD) && git commit -am "pre move" && - git status >expect&& + H2=$(git rev-parse --short HEAD) && + git status | sed "s/$H/XXX/" >expect && H=$(cd submodule2; git rev-parse HEAD) && git rm --cached submodule2 && rm -rf submodule2 && @@ -643,7 +721,7 @@ test_expect_success 'submodule update properly revives a moved submodule' ' git config -f .gitmodules submodule.submodule2.path "moved/sub module" git commit -am "post move" && git submodule update && - git status >actual && + git status | sed "s/$H2/XXX/" >actual && test_cmp expect actual ) ' @@ -651,14 +729,24 @@ test_expect_success 'submodule update properly revives a moved submodule' ' 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 - ) + (cd linkto && + git clone "$TRASH_DIRECTORY"/super_update_r2 super && + (cd super && + git submodule update --init --recursive + ) ) ' +test_expect_success 'submodule update clone shallow submodule' ' + git clone cloned super3 && + pwd=$(pwd) + (cd super3 && + sed -e "s#url = ../#url = file://$pwd/#" <.gitmodules >.gitmodules.tmp && + mv -f .gitmodules.tmp .gitmodules && + git submodule update --init --depth=3 + (cd submodule && + test 1 = $(git log --oneline | wc -l) + ) + ) +' test_done diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index 9b69fe2e14..91d4fd1fac 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -80,6 +80,22 @@ test_expect_success 'test basic "submodule foreach" usage' ' test_i18ncmp expect actual ' +cat >expect <<EOF +Entering '../sub1' +$pwd/clone-foo1-../sub1-$sub1sha1 +Entering '../sub3' +$pwd/clone-foo3-../sub3-$sub3sha1 +EOF + +test_expect_success 'test "submodule foreach" from subdirectory' ' + mkdir clone/sub && + ( + cd clone/sub && + git submodule foreach "echo \$toplevel-\$name-\$sm_path-\$sha1" >../../actual + ) && + test_i18ncmp expect actual +' + test_expect_success 'setup nested submodules' ' git clone submodule nested1 && git clone submodule nested2 && @@ -226,14 +242,14 @@ test_expect_success 'test "status --recursive"' ' test_cmp expect actual ' -sed -e "/nested1 /s/.*/+$nested1sha1 nested1 (file2~1)/;/sub[1-3]/d" < expect > expect2 +sed -e "/nested2 /s/.*/+$nested2sha1 nested1\/nested2 (file2~1)/;/sub[1-3]/d" < expect > expect2 mv -f expect2 expect test_expect_success 'ensure "status --cached --recursive" preserves the --cached flag' ' ( cd clone3 && ( - cd nested1 && + cd nested1/nested2 && test_commit file2 ) && git submodule status --cached --recursive -- nested1 > ../actual diff --git a/t/t7409-submodule-detached-worktree.sh b/t/t7409-submodule-detached-worktree.sh index 2fec13dcd3..c20717181e 100755 --- a/t/t7409-submodule-detached-worktree.sh +++ b/t/t7409-submodule-detached-worktree.sh @@ -23,7 +23,9 @@ test_expect_success 'submodule on detached working tree' ' mkdir home && ( cd home && - export GIT_WORK_TREE="$(pwd)" GIT_DIR="$(pwd)/.dotfiles" && + GIT_WORK_TREE="$(pwd)" && + GIT_DIR="$(pwd)/.dotfiles" && + export GIT_WORK_TREE GIT_DIR && git clone --bare ../remote .dotfiles && git submodule add ../bundle1 .vim/bundle/sogood && test_commit "sogood" && @@ -39,7 +41,9 @@ test_expect_success 'submodule on detached working tree' ' ( cd home2 && git clone --bare ../remote .dotfiles && - export GIT_WORK_TREE="$(pwd)" GIT_DIR="$(pwd)/.dotfiles" && + GIT_WORK_TREE="$(pwd)" && + GIT_DIR="$(pwd)/.dotfiles" && + export GIT_WORK_TREE GIT_DIR && git checkout master && git submodule update --init && ( @@ -55,7 +59,8 @@ test_expect_success 'submodule on detached working pointed by core.worktree' ' mkdir home3 && ( cd home3 && - export GIT_DIR="$(pwd)/.dotfiles" && + GIT_DIR="$(pwd)/.dotfiles" && + export GIT_DIR && git clone --bare ../remote "$GIT_DIR" && git config core.bare false && git config core.worktree .. && @@ -66,7 +71,8 @@ test_expect_success 'submodule on detached working pointed by core.worktree' ' ) && ( cd home && - export GIT_DIR="$(pwd)/.dotfiles" && + GIT_DIR="$(pwd)/.dotfiles" && + export GIT_DIR && git config core.bare false && git config core.worktree .. && git pull && diff --git a/t/t7500-commit.sh b/t/t7500-commit.sh index 1c908f4d39..bdc1f29503 100755 --- a/t/t7500-commit.sh +++ b/t/t7500-commit.sh @@ -13,9 +13,9 @@ commit_msg_is () { expect=commit_msg_is.expect actual=commit_msg_is.actual - printf "%s" "$(git log --pretty=format:%s%b -1)" >$expect && - printf "%s" "$1" >$actual && - test_i18ncmp $expect $actual + printf "%s" "$(git log --pretty=format:%s%b -1)" >"$actual" && + printf "%s" "$1" >"$expect" && + test_i18ncmp "$expect" "$actual" } # A sanity check to see if commit is working at all. @@ -36,8 +36,7 @@ test_expect_success 'nonexistent template file should return error' ' ' test_expect_success 'nonexistent template file in config should return error' ' - git config commit.template "$PWD"/notexist && - test_when_finished "git config --unset commit.template" && + test_config commit.template "$PWD"/notexist && ( GIT_EDITOR="echo hello >\"\$1\"" && export GIT_EDITOR && @@ -93,14 +92,13 @@ test_expect_success '-t option should be short for --template' ' test_expect_success 'config-specified template should commit' ' echo "new template" > "$TEMPLATE" && - git config commit.template "$TEMPLATE" && + test_config commit.template "$TEMPLATE" && echo "more content" >> foo && git add foo && ( test_set_editor "$TEST_DIRECTORY"/t7500/add-content && git commit ) && - git config --unset commit.template && commit_msg_is "new templatecommit message" ' diff --git a/t/t7500/add-content-and-comment b/t/t7500/add-content-and-comment new file mode 100755 index 0000000000..c4dccff13a --- /dev/null +++ b/t/t7500/add-content-and-comment @@ -0,0 +1,5 @@ +#!/bin/sh +echo "commit message" >> "$1" +echo "# comment" >> "$1" +exit 0 + diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh index 195e7477d8..99ce36f5ef 100755 --- a/t/t7501-commit.sh +++ b/t/t7501-commit.sh @@ -524,4 +524,17 @@ test_expect_success 'commit a file whose name is a dash' ' test_i18ngrep " changed, 5 insertions" output ' +test_expect_success '--only works on to-be-born branch' ' + # This test relies on having something in the index, as it + # would not otherwise actually prove much. So check this. + test -n "$(git ls-files)" && + git checkout --orphan orphan && + echo foo >newfile && + git add newfile && + git commit --only newfile -m"--only on unborn branch" && + echo newfile >expected && + git ls-tree -r --name-only HEAD >actual && + test_cmp expected actual +' + test_done diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh index deb187eb7b..6313da2cdd 100755 --- a/t/t7502-commit.sh +++ b/t/t7502-commit.sh @@ -4,6 +4,15 @@ test_description='git commit porcelain-ish' . ./test-lib.sh +commit_msg_is () { + expect=commit_msg_is.expect + actual=commit_msg_is.actual + + printf "%s" "$(git log --pretty=format:%s%b -1)" >$actual && + printf "%s" "$1" >$expect && + test_i18ncmp $expect $actual +} + # Arguments: [<prefix] [<commit message>] [<commit options>] check_summary_oneline() { test_tick && @@ -162,23 +171,30 @@ test_expect_success 'verbose' ' test_expect_success 'verbose respects diff config' ' - git config color.diff always && + test_config color.diff always && git status -v >actual && - grep "\[1mdiff --git" actual && - git config --unset color.diff + grep "\[1mdiff --git" actual +' + +mesg_with_comment_and_newlines=' +# text + +' + +test_expect_success 'prepare file with comment line and trailing newlines' ' + printf "%s" "$mesg_with_comment_and_newlines" >expect ' -test_expect_success 'cleanup commit messages (verbatim,-t)' ' +test_expect_success 'cleanup commit messages (verbatim option,-t)' ' echo >>negative && - { echo;echo "# text";echo; } >expect && - git commit --cleanup=verbatim -t expect -a && - git cat-file -p HEAD |sed -e "1,/^\$/d" |head -n 3 >actual && + git commit --cleanup=verbatim --no-status -t expect -a && + git cat-file -p HEAD |sed -e "1,/^\$/d" >actual && test_cmp expect actual ' -test_expect_success 'cleanup commit messages (verbatim,-F)' ' +test_expect_success 'cleanup commit messages (verbatim option,-F)' ' echo >>negative && git commit --cleanup=verbatim -F expect -a && @@ -187,16 +203,16 @@ test_expect_success 'cleanup commit messages (verbatim,-F)' ' ' -test_expect_success 'cleanup commit messages (verbatim,-m)' ' +test_expect_success 'cleanup commit messages (verbatim option,-m)' ' echo >>negative && - git commit --cleanup=verbatim -m "$(cat expect)" -a && + git commit --cleanup=verbatim -m "$mesg_with_comment_and_newlines" -a && git cat-file -p HEAD |sed -e "1,/^\$/d">actual && test_cmp expect actual ' -test_expect_success 'cleanup commit messages (whitespace,-F)' ' +test_expect_success 'cleanup commit messages (whitespace option,-F)' ' echo >>negative && { echo;echo "# text";echo; } >text && @@ -207,7 +223,7 @@ test_expect_success 'cleanup commit messages (whitespace,-F)' ' ' -test_expect_success 'cleanup commit messages (strip,-F)' ' +test_expect_success 'cleanup commit messages (strip option,-F)' ' echo >>negative && { echo;echo "# text";echo sample;echo; } >text && @@ -218,7 +234,7 @@ test_expect_success 'cleanup commit messages (strip,-F)' ' ' -test_expect_success 'cleanup commit messages (strip,-F,-e)' ' +test_expect_success 'cleanup commit messages (strip option,-F,-e)' ' echo >>negative && { echo;echo sample;echo; } >text && @@ -231,10 +247,79 @@ echo "sample # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit." >expect -test_expect_success 'cleanup commit messages (strip,-F,-e): output' ' +test_expect_success 'cleanup commit messages (strip option,-F,-e): output' ' test_i18ncmp expect actual ' +test_expect_success 'cleanup commit message (fail on invalid cleanup mode option)' ' + test_must_fail git commit --cleanup=non-existent +' + +test_expect_success 'cleanup commit message (fail on invalid cleanup mode configuration)' ' + test_must_fail git -c commit.cleanup=non-existent commit +' + +test_expect_success 'cleanup commit message (no config and no option uses default)' ' + echo content >>file && + git add file && + ( + test_set_editor "$TEST_DIRECTORY"/t7500/add-content-and-comment && + git commit --no-status + ) && + commit_msg_is "commit message" +' + +test_expect_success 'cleanup commit message (option overrides default)' ' + echo content >>file && + git add file && + ( + test_set_editor "$TEST_DIRECTORY"/t7500/add-content-and-comment && + git commit --cleanup=whitespace --no-status + ) && + commit_msg_is "commit message # comment" +' + +test_expect_success 'cleanup commit message (config overrides default)' ' + echo content >>file && + git add file && + ( + test_set_editor "$TEST_DIRECTORY"/t7500/add-content-and-comment && + git -c commit.cleanup=whitespace commit --no-status + ) && + commit_msg_is "commit message # comment" +' + +test_expect_success 'cleanup commit message (option overrides config)' ' + echo content >>file && + git add file && + ( + test_set_editor "$TEST_DIRECTORY"/t7500/add-content-and-comment && + git -c commit.cleanup=whitespace commit --cleanup=default + ) && + commit_msg_is "commit message" +' + +test_expect_success 'cleanup commit message (default, -m)' ' + echo content >>file && + git add file && + git commit -m "message #comment " && + commit_msg_is "message #comment" +' + +test_expect_success 'cleanup commit message (whitespace option, -m)' ' + echo content >>file && + git add file && + git commit --cleanup=whitespace --no-status -m "message #comment " && + commit_msg_is "message #comment" +' + +test_expect_success 'cleanup commit message (whitespace config, -m)' ' + echo content >>file && + git add file && + git -c commit.cleanup=whitespace commit --no-status -m "message #comment " && + commit_msg_is "message #comment" +' + test_expect_success 'message shows author when it is not equal to committer' ' echo >>negative && git commit -e -m "sample" -a && @@ -243,16 +328,6 @@ test_expect_success 'message shows author when it is not equal to committer' ' .git/COMMIT_EDITMSG ' -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 AUTOIDENT 'message shows committer when it is automatic' ' echo >>negative && @@ -271,7 +346,7 @@ echo editor started > "$(pwd)/.git/result" exit 0 EOF -test_expect_success NOAUTOIDENT 'do not fire editor when committer is bogus' ' +test_expect_success !AUTOIDENT 'do not fire editor when committer is bogus' ' >.git/result >expect && @@ -286,6 +361,23 @@ test_expect_success NOAUTOIDENT 'do not fire editor when committer is bogus' ' test_cmp expect .git/result ' +test_expect_success 'do not fire editor if -m <msg> was given' ' + echo tick >file && + git add file && + echo "editor not started" >.git/result && + (GIT_EDITOR="\"$(pwd)/.git/FAKE_EDITOR\"" git commit -m tick) && + test "$(cat .git/result)" = "editor not started" +' + +test_expect_success 'do not fire editor if -m "" was given' ' + echo tock >file && + git add file && + echo "editor not started" >.git/result && + (GIT_EDITOR="\"$(pwd)/.git/FAKE_EDITOR\"" \ + git commit -m "" --allow-empty-message) && + test "$(cat .git/result)" = "editor not started" +' + test_expect_success 'do not fire editor in the presence of conflicts' ' git clean -f && @@ -349,6 +441,18 @@ test_expect_success 'A single-liner subject with a token plus colon is not a foo ' +test_expect_success 'commit -s places sob on third line after two empty lines' ' + git commit -s --allow-empty --allow-empty-message && + cat <<-EOF >expect && + + + Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> + + EOF + sed -e "/^#/d" -e "s/^:.*//" .git/COMMIT_EDITMSG >actual && + test_cmp expect actual +' + write_script .git/FAKE_EDITOR <<\EOF mv "$1" "$1.orig" ( @@ -359,16 +463,6 @@ EOF echo '## Custom template' >template -clear_config () { - ( - git config --unset-all "$1" - case $? in - 0|5) exit 0 ;; - *) exit 1 ;; - esac - ) -} - try_commit () { git reset --hard && echo >>negative && @@ -384,67 +478,57 @@ try_commit () { try_commit_status_combo () { test_expect_success 'commit' ' - clear_config commit.status && try_commit "" && test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG ' test_expect_success 'commit' ' - clear_config commit.status && try_commit "" && test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG ' test_expect_success 'commit --status' ' - clear_config commit.status && try_commit --status && test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG ' test_expect_success 'commit --no-status' ' - clear_config commit.status && try_commit --no-status && test_i18ngrep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG ' test_expect_success 'commit with commit.status = yes' ' - clear_config commit.status && - git config commit.status yes && + test_config commit.status yes && try_commit "" && test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG ' test_expect_success 'commit with commit.status = no' ' - clear_config commit.status && - git config commit.status no && + test_config commit.status no && try_commit "" && test_i18ngrep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG ' test_expect_success 'commit --status with commit.status = yes' ' - clear_config commit.status && - git config commit.status yes && + test_config commit.status yes && try_commit --status && test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG ' test_expect_success 'commit --no-status with commit.status = yes' ' - clear_config commit.status && - git config commit.status yes && + test_config commit.status yes && try_commit --no-status && test_i18ngrep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG ' test_expect_success 'commit --status with commit.status = no' ' - clear_config commit.status && - git config commit.status no && + test_config commit.status no && try_commit --status && test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG ' test_expect_success 'commit --no-status with commit.status = no' ' - clear_config commit.status && - git config commit.status no && + test_config commit.status no && try_commit --no-status && test_i18ngrep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG ' @@ -457,4 +541,10 @@ use_template="-t template" try_commit_status_combo +test_expect_success 'commit --status with custom comment character' ' + test_config core.commentchar ";" && + try_commit --status && + test_i18ngrep "^; Changes to be committed:" .git/COMMIT_EDITMSG +' + test_done diff --git a/t/t7505-prepare-commit-msg-hook.sh b/t/t7505-prepare-commit-msg-hook.sh index 5b4b694f18..357375151d 100755 --- a/t/t7505-prepare-commit-msg-hook.sh +++ b/t/t7505-prepare-commit-msg-hook.sh @@ -167,5 +167,19 @@ test_expect_success 'with failing hook (--no-verify)' ' ' +test_expect_success 'with failing hook (merge)' ' + + git checkout -B other HEAD@{1} && + echo "more" >> file && + git add file && + rm -f "$HOOK" && + git commit -m other && + write_script "$HOOK" <<-EOF + exit 1 + EOF + git checkout - && + test_must_fail git merge other + +' test_done diff --git a/t/t7508-status.sh b/t/t7508-status.sh index e313ef196e..ac3d0fe445 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -8,6 +8,7 @@ test_description='git status' . ./test-lib.sh test_expect_success 'status -h in broken repository' ' + git config --global advice.statusuoption false && mkdir broken && test_when_finished "rm -fr broken" && ( @@ -130,8 +131,7 @@ cat >expect <<\EOF EOF test_expect_success 'status (advice.statusHints false)' ' - test_when_finished "git config --unset advice.statusHints" && - git config advice.statusHints false && + test_config advice.statusHints false && git status >output && test_i18ncmp expect output @@ -331,8 +331,7 @@ test_expect_success 'status -uno' ' ' test_expect_success 'status (status.showUntrackedFiles no)' ' - git config status.showuntrackedfiles no - test_when_finished "git config --unset status.showuntrackedfiles" && + test_config status.showuntrackedfiles no && git status >output && test_i18ncmp expect output ' @@ -347,12 +346,11 @@ cat >expect <<EOF # # Untracked files not listed EOF -git config advice.statusHints false test_expect_success 'status -uno (advice.statusHints false)' ' + test_config advice.statusHints false && git status -uno >output && test_i18ncmp expect output ' -git config --unset advice.statusHints cat >expect << EOF M dir1/modified @@ -399,8 +397,7 @@ test_expect_success 'status -unormal' ' ' test_expect_success 'status (status.showUntrackedFiles normal)' ' - git config status.showuntrackedfiles normal - test_when_finished "git config --unset status.showuntrackedfiles" && + test_config status.showuntrackedfiles normal git status >output && test_i18ncmp expect output ' @@ -458,8 +455,7 @@ test_expect_success 'status -uall' ' ' test_expect_success 'status (status.showUntrackedFiles all)' ' - git config status.showuntrackedfiles all - test_when_finished "git config --unset status.showuntrackedfiles" && + test_config status.showuntrackedfiles all git status >output && test_i18ncmp expect output ' @@ -484,10 +480,9 @@ test_expect_success 'status -s -uall' ' test_cmp expect output ' test_expect_success 'status -s (status.showUntrackedFiles all)' ' - git config status.showuntrackedfiles all + test_config status.showuntrackedfiles all && git status -s >output && rm -rf dir3 && - git config --unset status.showuntrackedfiles && test_cmp expect output ' @@ -587,15 +582,13 @@ cat >expect <<\EOF EOF test_expect_success 'status with color.ui' ' - git config color.ui always && - test_when_finished "git config --unset color.ui" && + test_config color.ui always && git status | test_decode_color >output && test_i18ncmp expect output ' test_expect_success 'status with color.status' ' - git config color.status always && - test_when_finished "git config --unset color.status" && + test_config color.status always && git status | test_decode_color >output && test_i18ncmp expect output ' @@ -719,8 +712,7 @@ EOF test_expect_success 'status without relative paths' ' - git config status.relativePaths false && - test_when_finished "git config --unset status.relativePaths" && + test_config status.relativePaths false && (cd dir1 && git status) >output && test_i18ncmp expect output @@ -739,8 +731,7 @@ EOF test_expect_success 'status -s without relative paths' ' - git config status.relativePaths false && - test_when_finished "git config --unset status.relativePaths" && + test_config status.relativePaths false && (cd dir1 && git status -s) >output && test_cmp expect output @@ -1037,15 +1028,14 @@ test_expect_success '--ignore-submodules=untracked suppresses submodules with un ' test_expect_success '.gitmodules ignore=untracked suppresses submodules with untracked content' ' - git config diff.ignoreSubmodules dirty && + test_config diff.ignoreSubmodules dirty && git status >output && test_i18ncmp expect output && git config --add -f .gitmodules submodule.subname.ignore untracked && git config --add -f .gitmodules submodule.subname.path sm && git status >output && test_i18ncmp expect output && - git config -f .gitmodules --remove-section submodule.subname && - git config --unset diff.ignoreSubmodules + git config -f .gitmodules --remove-section submodule.subname ' test_expect_success '.git/config ignore=untracked suppresses submodules with untracked content' ' @@ -1065,15 +1055,14 @@ test_expect_success '--ignore-submodules=dirty suppresses submodules with untrac ' test_expect_success '.gitmodules ignore=dirty suppresses submodules with untracked content' ' - git config diff.ignoreSubmodules dirty && + test_config diff.ignoreSubmodules dirty && git status >output && ! test -s actual && git config --add -f .gitmodules submodule.subname.ignore dirty && git config --add -f .gitmodules submodule.subname.path sm && git status >output && test_i18ncmp expect output && - git config -f .gitmodules --remove-section submodule.subname && - git config --unset diff.ignoreSubmodules + git config -f .gitmodules --remove-section submodule.subname ' test_expect_success '.git/config ignore=dirty suppresses submodules with untracked content' ' @@ -1254,6 +1243,54 @@ test_expect_success ".git/config ignore=dirty doesn't suppress submodule summary ' cat > expect << EOF +; On branch master +; Changes to be committed: +; (use "git reset HEAD <file>..." to unstage) +; +; modified: sm +; +; 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 +; modified: sm (new commits) +; +; Submodule changes to be committed: +; +; * sm $head...$new_head (1): +; > Add bar +; +; Submodules changed but not updated: +; +; * sm $new_head...$head2 (1): +; > 2nd commit +; +; Untracked files: +; (use "git add <file>..." to include in what will be committed) +; +; .gitmodules +; dir1/untracked +; dir2/modified +; dir2/untracked +; expect +; output +; untracked +EOF + +test_expect_success "status (core.commentchar with submodule summary)" ' + test_config core.commentchar ";" && + git status >output && + test_i18ncmp expect output +' + +test_expect_success "status (core.commentchar with two chars with submodule summary)" ' + test_config core.commentchar ";;" && + git status >output && + test_i18ncmp expect output +' + +cat > expect << EOF # On branch master # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) @@ -1298,4 +1335,66 @@ test_expect_failure '.git/config ignore=all suppresses submodule summary' ' git config -f .gitmodules --remove-section submodule.subname ' +test_expect_success 'setup of test environment' ' + git config status.showUntrackedFiles no && + git status -s >expected_short && + git status --no-short >expected_noshort +' + +test_expect_success '"status.short=true" same as "-s"' ' + git -c status.short=true status >actual && + test_cmp expected_short actual +' + +test_expect_success '"status.short=true" weaker than "--no-short"' ' + git -c status.short=true status --no-short >actual && + test_cmp expected_noshort actual +' + +test_expect_success '"status.short=false" same as "--no-short"' ' + git -c status.short=false status >actual && + test_cmp expected_noshort actual +' + +test_expect_success '"status.short=false" weaker than "-s"' ' + git -c status.short=false status -s >actual && + test_cmp expected_short actual +' + +test_expect_success '"status.branch=true" same as "-b"' ' + git status -sb >expected_branch && + git -c status.branch=true status -s >actual && + test_cmp expected_branch actual +' + +test_expect_success '"status.branch=true" different from "--no-branch"' ' + git status -s --no-branch >expected_nobranch && + git -c status.branch=true status -s >actual && + test_must_fail test_cmp expected_nobranch actual +' + +test_expect_success '"status.branch=true" weaker than "--no-branch"' ' + git -c status.branch=true status -s --no-branch >actual && + test_cmp expected_nobranch actual +' + +test_expect_success '"status.branch=true" weaker than "--porcelain"' ' + git -c status.branch=true status --porcelain >actual && + test_cmp expected_nobranch actual +' + +test_expect_success '"status.branch=false" same as "--no-branch"' ' + git -c status.branch=false status -s >actual && + test_cmp expected_nobranch actual +' + +test_expect_success '"status.branch=false" weaker than "-b"' ' + git -c status.branch=false status -sb >actual && + test_cmp expected_branch actual +' + +test_expect_success 'Restore default test environment' ' + git config --unset status.showUntrackedFiles +' + test_done diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh index b3f6eb9c68..31a798fda2 100755 --- a/t/t7512-status-help.sh +++ b/t/t7512-status-help.sh @@ -5,7 +5,7 @@ # Grenoble INP Ensimag # -test_description='git status advices' +test_description='git status advice' . ./test-lib.sh @@ -14,6 +14,7 @@ test_description='git status advices' set_fake_editor test_expect_success 'prepare for conflicts' ' + git config --global advice.statusuoption false && test_commit init main.txt init && git branch conflicts && test_commit on_master main.txt on_master && @@ -73,10 +74,11 @@ test_expect_success 'prepare for rebase conflicts' ' test_expect_success 'status when rebase in progress before resolving conflicts' ' test_when_finished "git rebase --abort" && + ONTO=$(git rev-parse --short HEAD^^) && test_must_fail git rebase HEAD^ --onto HEAD^^ && - cat >expected <<-\EOF && - # Not currently on any branch. - # You are currently rebasing. + cat >expected <<-EOF && + # rebase in progress; onto $ONTO + # You are currently rebasing branch '\''rebase_conflicts'\'' on '\''$ONTO'\''. # (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) @@ -97,12 +99,13 @@ test_expect_success 'status when rebase in progress before resolving conflicts' test_expect_success 'status when rebase in progress before rebase --continue' ' git reset --hard rebase_conflicts && test_when_finished "git rebase --abort" && + ONTO=$(git rev-parse --short HEAD^^) && 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. + cat >expected <<-EOF && + # rebase in progress; onto $ONTO + # You are currently rebasing branch '\''rebase_conflicts'\'' on '\''$ONTO'\''. # (all conflicts fixed: run "git rebase --continue") # # Changes to be committed: @@ -130,10 +133,11 @@ test_expect_success 'prepare for rebase_i_conflicts' ' test_expect_success 'status during rebase -i when conflicts unresolved' ' test_when_finished "git rebase --abort" && + ONTO=$(git rev-parse --short rebase_i_conflicts) && test_must_fail git rebase -i rebase_i_conflicts && - cat >expected <<-\EOF && - # Not currently on any branch. - # You are currently rebasing. + cat >expected <<-EOF && + # rebase in progress; onto $ONTO + # You are currently rebasing branch '\''rebase_i_conflicts_second'\'' on '\''$ONTO'\''. # (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) @@ -154,11 +158,12 @@ test_expect_success 'status during rebase -i when conflicts unresolved' ' test_expect_success 'status during rebase -i after resolving conflicts' ' git reset --hard rebase_i_conflicts_second && test_when_finished "git rebase --abort" && + ONTO=$(git rev-parse --short rebase_i_conflicts) && 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. + cat >expected <<-EOF && + # rebase in progress; onto $ONTO + # You are currently rebasing branch '\''rebase_i_conflicts_second'\'' on '\''$ONTO'\''. # (all conflicts fixed: run "git rebase --continue") # # Changes to be committed: @@ -182,10 +187,11 @@ test_expect_success 'status when rebasing -i in edit mode' ' FAKE_LINES="1 edit 2" && export FAKE_LINES && test_when_finished "git rebase --abort" && + ONTO=$(git rev-parse --short HEAD~2) && git rebase -i HEAD~2 && - cat >expected <<-\EOF && - # Not currently on any branch. - # You are currently editing a commit during a rebase. + cat >expected <<-EOF && + # rebase in progress; onto $ONTO + # You are currently editing a commit while rebasing branch '\''rebase_i_edit'\'' on '\''$ONTO'\''. # (use "git commit --amend" to amend the current commit) # (use "git rebase --continue" once you are satisfied with your changes) # @@ -206,11 +212,12 @@ test_expect_success 'status when splitting a commit' ' FAKE_LINES="1 edit 2 3" && export FAKE_LINES && test_when_finished "git rebase --abort" && + ONTO=$(git rev-parse --short HEAD~3) && 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. + cat >expected <<-EOF && + # rebase in progress; onto $ONTO + # You are currently splitting a commit while rebasing branch '\''split_commit'\'' on '\''$ONTO'\''. # (Once your working directory is clean, run "git rebase --continue") # # Changes not staged for commit: @@ -236,11 +243,12 @@ test_expect_success 'status after editing the last commit with --amend during a FAKE_LINES="1 2 edit 3" && export FAKE_LINES && test_when_finished "git rebase --abort" && + ONTO=$(git rev-parse --short HEAD~3) && 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. + cat >expected <<-EOF && + # rebase in progress; onto $ONTO + # You are currently editing a commit while rebasing branch '\''amend_last'\'' on '\''$ONTO'\''. # (use "git commit --amend" to amend the current commit) # (use "git rebase --continue" once you are satisfied with your changes) # @@ -265,11 +273,12 @@ 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" && + ONTO=$(git rev-parse --short HEAD~3) && 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. + cat >expected <<-EOF && + # rebase in progress; onto $ONTO + # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''. # (use "git commit --amend" to amend the current commit) # (use "git rebase --continue" once you are satisfied with your changes) # @@ -285,12 +294,13 @@ test_expect_success 'status: (continue first edit) second edit and split' ' FAKE_LINES="edit 1 edit 2 3" && export FAKE_LINES && test_when_finished "git rebase --abort" && + ONTO=$(git rev-parse --short HEAD~3) && 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. + cat >expected <<-EOF && + # rebase in progress; onto $ONTO + # You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''. # (Once your working directory is clean, run "git rebase --continue") # # Changes not staged for commit: @@ -311,12 +321,13 @@ test_expect_success 'status: (continue first edit) second edit and amend' ' FAKE_LINES="edit 1 edit 2 3" && export FAKE_LINES && test_when_finished "git rebase --abort" && + ONTO=$(git rev-parse --short HEAD~3) && 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. + cat >expected <<-EOF && + # rebase in progress; onto $ONTO + # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''. # (use "git commit --amend" to amend the current commit) # (use "git rebase --continue" once you are satisfied with your changes) # @@ -332,12 +343,13 @@ test_expect_success 'status: (amend first edit) second edit' ' FAKE_LINES="edit 1 edit 2 3" && export FAKE_LINES && test_when_finished "git rebase --abort" && + ONTO=$(git rev-parse --short HEAD~3) && 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. + cat >expected <<-EOF && + # rebase in progress; onto $ONTO + # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''. # (use "git commit --amend" to amend the current commit) # (use "git rebase --continue" once you are satisfied with your changes) # @@ -353,13 +365,14 @@ test_expect_success 'status: (amend first edit) second edit and split' ' FAKE_LINES="edit 1 edit 2 3" && export FAKE_LINES && test_when_finished "git rebase --abort" && + ONTO=$(git rev-parse --short HEAD~3) && 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. + cat >expected <<-EOF && + # rebase in progress; onto $ONTO + # You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''. # (Once your working directory is clean, run "git rebase --continue") # # Changes not staged for commit: @@ -380,13 +393,14 @@ test_expect_success 'status: (amend first edit) second edit and amend' ' FAKE_LINES="edit 1 edit 2 3" && export FAKE_LINES && test_when_finished "git rebase --abort" && + ONTO=$(git rev-parse --short HEAD~3) && 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. + cat >expected <<-EOF && + # rebase in progress; onto $ONTO + # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''. # (use "git commit --amend" to amend the current commit) # (use "git rebase --continue" once you are satisfied with your changes) # @@ -402,14 +416,15 @@ test_expect_success 'status: (split first edit) second edit' ' FAKE_LINES="edit 1 edit 2 3" && export FAKE_LINES && test_when_finished "git rebase --abort" && + ONTO=$(git rev-parse --short HEAD~3) && 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. + cat >expected <<-EOF && + # rebase in progress; onto $ONTO + # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''. # (use "git commit --amend" to amend the current commit) # (use "git rebase --continue" once you are satisfied with your changes) # @@ -425,15 +440,16 @@ test_expect_success 'status: (split first edit) second edit and split' ' FAKE_LINES="edit 1 edit 2 3" && export FAKE_LINES && test_when_finished "git rebase --abort" && + ONTO=$(git rev-parse --short HEAD~3) && 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. + cat >expected <<-EOF && + # rebase in progress; onto $ONTO + # You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''. # (Once your working directory is clean, run "git rebase --continue") # # Changes not staged for commit: @@ -454,15 +470,16 @@ test_expect_success 'status: (split first edit) second edit and amend' ' FAKE_LINES="edit 1 edit 2 3" && export FAKE_LINES && test_when_finished "git rebase --abort" && + ONTO=$(git rev-parse --short HEAD~3) && 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. + cat >expected <<-EOF && + # rebase in progress; onto $ONTO + # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''. # (use "git commit --amend" to amend the current commit) # (use "git rebase --continue" once you are satisfied with your changes) # @@ -490,7 +507,7 @@ test_expect_success 'status in an am session: file already exists' ' 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") + # (fix conflicts and then run "git am --continue") # (use "git am --skip" to skip this patch) # (use "git am --abort" to restore the original branch) # @@ -512,7 +529,7 @@ test_expect_success 'status in an am session: file does not exist' ' 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") + # (fix conflicts and then run "git am --continue") # (use "git am --skip" to skip this patch) # (use "git am --abort" to restore the original branch) # @@ -556,9 +573,10 @@ test_expect_success 'status when bisecting' ' git bisect start && git bisect bad && git bisect good one_bisect && - cat >expected <<-\EOF && - # Not currently on any branch. - # You are currently bisecting. + TGT=$(git rev-parse --short two_bisect) && + cat >expected <<-EOF && + # HEAD detached at $TGT + # You are currently bisecting, started from branch '\''bisect'\''. # (use "git bisect reset" to get back to the original branch) # nothing to commit (use -u to show untracked files) @@ -577,10 +595,11 @@ test_expect_success 'status when rebase conflicts with statushints disabled' ' test_commit two_statushints main.txt two && test_commit three_statushints main.txt three && test_when_finished "git rebase --abort" && + ONTO=$(git rev-parse --short HEAD^^) && test_must_fail git rebase HEAD^ --onto HEAD^^ && - cat >expected <<-\EOF && - # Not currently on any branch. - # You are currently rebasing. + cat >expected <<-EOF && + # rebase in progress; onto $ONTO + # You are currently rebasing branch '\''statushints_disabled'\'' on '\''$ONTO'\''. # # Unmerged paths: # both modified: main.txt @@ -610,7 +629,8 @@ test_expect_success 'status when cherry-picking before resolving conflicts' ' cat >expected <<-\EOF && # On branch cherry_branch # You are currently cherry-picking. - # (fix conflicts and run "git commit") + # (fix conflicts and run "git cherry-pick --continue") + # (use "git cherry-pick --abort" to cancel the cherry-pick operation) # # Unmerged paths: # (use "git add <file>..." to mark resolution) @@ -633,7 +653,8 @@ test_expect_success 'status when cherry-picking after resolving conflicts' ' cat >expected <<-\EOF && # On branch cherry_branch # You are currently cherry-picking. - # (all conflicts fixed: run "git commit") + # (all conflicts fixed: run "git cherry-pick --continue") + # (use "git cherry-pick --abort" to cancel the cherry-pick operation) # # Changes to be committed: # @@ -645,5 +666,81 @@ test_expect_success 'status when cherry-picking after resolving conflicts' ' test_i18ncmp expected actual ' +test_expect_success 'status showing detached at and from a tag' ' + test_commit atag tagging && + git checkout atag && + cat >expected <<-\EOF + # HEAD detached at atag + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual && + + git reset --hard HEAD^ && + cat >expected <<-\EOF + # HEAD detached from atag + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + +test_expect_success 'status while reverting commit (conflicts)' ' + git checkout master && + echo before >to-revert.txt && + test_commit before to-revert.txt && + echo old >to-revert.txt && + test_commit old to-revert.txt && + echo new >to-revert.txt && + test_commit new to-revert.txt && + TO_REVERT=$(git rev-parse --short HEAD^) && + test_must_fail git revert $TO_REVERT && + cat >expected <<-EOF + # On branch master + # You are currently reverting commit $TO_REVERT. + # (fix conflicts and run "git revert --continue") + # (use "git revert --abort" to cancel the revert operation) + # + # Unmerged paths: + # (use "git reset HEAD <file>..." to unstage) + # (use "git add <file>..." to mark resolution) + # + # both modified: to-revert.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + +test_expect_success 'status while reverting commit (conflicts resolved)' ' + echo reverted >to-revert.txt && + git add to-revert.txt && + cat >expected <<-EOF + # On branch master + # You are currently reverting commit $TO_REVERT. + # (all conflicts fixed: run "git revert --continue") + # (use "git revert --abort" to cancel the revert operation) + # + # Changes to be committed: + # (use "git reset HEAD <file>..." to unstage) + # + # modified: to-revert.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 after reverting commit' ' + git revert --continue && + cat >expected <<-\EOF + # On branch master + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' test_done diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh index 5e19598fe7..10aa028017 100755 --- a/t/t7600-merge.sh +++ b/t/t7600-merge.sh @@ -56,7 +56,8 @@ create_merge_msgs () { echo && git log --no-merges ^HEAD c2 c3 } >squash.1-5-9 && - echo >msg.nolog && + : >msg.nologff && + echo >msg.nolognoff && { echo "* tag 'c3':" && echo " commit 3" && @@ -244,8 +245,7 @@ test_expect_success 'merges with --ff-only' ' test_expect_success 'merges with merge.ff=only' ' git reset --hard c1 && test_tick && - test_when_finished "git config --unset merge.ff" && - git config merge.ff only && + test_config merge.ff "only" && test_must_fail git merge c2 && test_must_fail git merge c3 && test_must_fail git merge c2 c3 && @@ -316,7 +316,7 @@ test_expect_success 'merge c1 with c2 (squash)' ' test_debug 'git log --graph --decorate --oneline --all' -test_expect_success 'unsuccesful merge of c1 with c2 (squash, ff-only)' ' +test_expect_success 'unsuccessful merge of c1 with c2 (squash, ff-only)' ' git reset --hard c1 && test_must_fail git merge --squash --ff-only c2 ' @@ -336,7 +336,7 @@ test_debug 'git log --graph --decorate --oneline --all' test_expect_success 'merge c1 with c2 (no-commit in config)' ' git reset --hard c1 && - git config branch.master.mergeoptions "--no-commit" && + test_config branch.master.mergeoptions "--no-commit" && git merge c2 && verify_merge file result.1-5 && verify_head $c1 && @@ -346,12 +346,11 @@ test_expect_success 'merge c1 with c2 (no-commit in config)' ' test_debug 'git log --graph --decorate --oneline --all' test_expect_success 'merge c1 with c2 (log in config)' ' - git config branch.master.mergeoptions "" && git reset --hard c1 && git merge --log c2 && git show -s --pretty=tformat:%s%n%b >expect && - git config branch.master.mergeoptions --log && + test_config branch.master.mergeoptions "--log" && git reset --hard c1 && git merge c2 && git show -s --pretty=tformat:%s%n%b >actual && @@ -360,17 +359,12 @@ test_expect_success 'merge c1 with c2 (log in config)' ' ' test_expect_success 'merge c1 with c2 (log in config gets overridden)' ' - test_when_finished "git config --remove-section branch.master" && - test_when_finished "git config --remove-section merge" && - test_might_fail git config --remove-section branch.master && - test_might_fail git config --remove-section merge && - git reset --hard c1 && git merge c2 && git show -s --pretty=tformat:%s%n%b >expect && - git config branch.master.mergeoptions "--no-log" && - git config merge.log true && + test_config branch.master.mergeoptions "--no-log" && + test_config merge.log "true" && git reset --hard c1 && git merge c2 && git show -s --pretty=tformat:%s%n%b >actual && @@ -380,7 +374,7 @@ test_expect_success 'merge c1 with c2 (log in config gets overridden)' ' test_expect_success 'merge c1 with c2 (squash in config)' ' git reset --hard c1 && - git config branch.master.mergeoptions "--squash" && + test_config branch.master.mergeoptions "--squash" && git merge c2 && verify_merge file result.1-5 && verify_head $c1 && @@ -392,7 +386,7 @@ test_debug 'git log --graph --decorate --oneline --all' test_expect_success 'override config option -n with --summary' ' git reset --hard c1 && - git config branch.master.mergeoptions "-n" && + test_config branch.master.mergeoptions "-n" && test_tick && git merge --summary c2 >diffstat.txt && verify_merge file result.1-5 msg.1-5 && @@ -406,7 +400,7 @@ test_expect_success 'override config option -n with --summary' ' test_expect_success 'override config option -n with --stat' ' git reset --hard c1 && - git config branch.master.mergeoptions "-n" && + test_config branch.master.mergeoptions "-n" && test_tick && git merge --stat c2 >diffstat.txt && verify_merge file result.1-5 msg.1-5 && @@ -422,7 +416,7 @@ test_debug 'git log --graph --decorate --oneline --all' test_expect_success 'override config option --stat' ' git reset --hard c1 && - git config branch.master.mergeoptions "--stat" && + test_config branch.master.mergeoptions "--stat" && test_tick && git merge -n c2 >diffstat.txt && verify_merge file result.1-5 msg.1-5 && @@ -438,7 +432,7 @@ test_debug 'git log --graph --decorate --oneline --all' test_expect_success 'merge c1 with c2 (override --no-commit)' ' git reset --hard c1 && - git config branch.master.mergeoptions "--no-commit" && + test_config branch.master.mergeoptions "--no-commit" && test_tick && git merge --commit c2 && verify_merge file result.1-5 msg.1-5 && @@ -449,7 +443,7 @@ test_debug 'git log --graph --decorate --oneline --all' test_expect_success 'merge c1 with c2 (override --squash)' ' git reset --hard c1 && - git config branch.master.mergeoptions "--squash" && + test_config branch.master.mergeoptions "--squash" && test_tick && git merge --no-squash c2 && verify_merge file result.1-5 msg.1-5 && @@ -460,7 +454,6 @@ test_debug 'git log --graph --decorate --oneline --all' test_expect_success 'merge c0 with c1 (no-ff)' ' git reset --hard c0 && - git config branch.master.mergeoptions "" && test_tick && git merge --no-ff c1 && verify_merge file result.1 && @@ -471,10 +464,9 @@ test_debug 'git log --graph --decorate --oneline --all' test_expect_success 'merge c0 with c1 (merge.ff=false)' ' git reset --hard c0 && - git config merge.ff false && + test_config merge.ff "false" && test_tick && git merge c1 && - git config --remove-section merge && verify_merge file result.1 && verify_parents $c0 $c1 ' @@ -482,22 +474,19 @@ test_debug 'git log --graph --decorate --oneline --all' test_expect_success 'combine branch.master.mergeoptions with merge.ff' ' git reset --hard c0 && - git config branch.master.mergeoptions --ff && - git config merge.ff false && + test_config branch.master.mergeoptions "--ff" && + test_config merge.ff "false" && test_tick && git merge c1 && - git config --remove-section "branch.master" && - git config --remove-section "merge" && verify_merge file result.1 && verify_parents "$c0" ' test_expect_success 'tolerate unknown values for merge.ff' ' git reset --hard c0 && - git config merge.ff something-new && + test_config merge.ff "something-new" && test_tick && git merge c1 2>message && - git config --remove-section "merge" && verify_head "$c1" && test_cmp empty message ' @@ -508,14 +497,20 @@ test_expect_success 'combining --squash and --no-ff is refused' ' test_must_fail git merge --no-ff --squash c1 ' -test_expect_success 'combining --ff-only and --no-ff is refused' ' - test_must_fail git merge --ff-only --no-ff c1 && - test_must_fail git merge --no-ff --ff-only c1 +test_expect_success 'option --ff-only overwrites --no-ff' ' + git merge --no-ff --ff-only c1 && + test_must_fail git merge --no-ff --ff-only c2 +' + +test_expect_success 'option --no-ff overrides merge.ff=only config' ' + git reset --hard c0 && + test_config merge.ff only && + git merge --no-ff c1 ' test_expect_success 'merge c0 with c1 (ff overrides no-ff)' ' git reset --hard c0 && - git config branch.master.mergeoptions "--no-ff" && + test_config branch.master.mergeoptions "--no-ff" && git merge --ff c1 && verify_merge file result.1 && verify_head $c1 @@ -525,14 +520,20 @@ test_expect_success 'merge log message' ' git reset --hard c0 && git merge --no-log c2 && git show -s --pretty=format:%b HEAD >msg.act && - test_cmp msg.nolog msg.act && + test_cmp msg.nologff msg.act && + + git reset --hard c0 && + test_config branch.master.mergeoptions "--no-ff" && + git merge --no-log c2 && + git show -s --pretty=format:%b HEAD >msg.act && + test_cmp msg.nolognoff msg.act && git merge --log c3 && git show -s --pretty=format:%b HEAD >msg.act && test_cmp msg.log msg.act && git reset --hard HEAD^ && - git config merge.log yes && + test_config merge.log "yes" && git merge c3 && git show -s --pretty=format:%b HEAD >msg.act && test_cmp msg.log msg.act @@ -542,7 +543,6 @@ test_debug 'git log --graph --decorate --oneline --all' test_expect_success 'merge c1 with c0, c2, c0, and c1' ' git reset --hard c1 && - git config branch.master.mergeoptions "" && test_tick && git merge c0 c2 c0 c1 && verify_merge file result.1-5 && @@ -553,7 +553,6 @@ test_debug 'git log --graph --decorate --oneline --all' test_expect_success 'merge c1 with c0, c2, c0, and c1' ' git reset --hard c1 && - git config branch.master.mergeoptions "" && test_tick && git merge c0 c2 c0 c1 && verify_merge file result.1-5 && @@ -564,7 +563,6 @@ test_debug 'git log --graph --decorate --oneline --all' test_expect_success 'merge c1 with c1 and c2' ' git reset --hard c1 && - git config branch.master.mergeoptions "" && test_tick && git merge c1 c2 && verify_merge file result.1-5 && diff --git a/t/t7601-merge-pull-config.sh b/t/t7601-merge-pull-config.sh index b44b293950..25dac79889 100755 --- a/t/t7601-merge-pull-config.sh +++ b/t/t7601-merge-pull-config.sh @@ -109,7 +109,7 @@ test_expect_success 'setup conflicted merge' ' ' # First do the merge with resolve and recursive then verify that -# recusive is choosen. +# recusive is chosen. test_expect_success 'merge picks up the best result' ' git config --unset-all pull.twohead && diff --git a/t/t7607-merge-overwrite.sh b/t/t7607-merge-overwrite.sh index 6547eb8f54..758a623cdb 100755 --- a/t/t7607-merge-overwrite.sh +++ b/t/t7607-merge-overwrite.sh @@ -141,11 +141,10 @@ test_expect_success SYMLINKS 'will not overwrite untracked symlink in leading pa test_path_is_missing .git/MERGE_HEAD ' -test_expect_success SYMLINKS 'will not be confused by symlink in leading path' ' +test_expect_success 'will not be confused by symlink in leading path' ' git reset --hard c0 && rm -rf sub && - ln -s sub2 sub && - git add sub && + test_ln_s_add sub2 sub && git commit -m ln && git checkout sub ' diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh index bc38737b2a..d526b1d96a 100755 --- a/t/t7610-mergetool.sh +++ b/t/t7610-mergetool.sh @@ -237,7 +237,7 @@ test_expect_success 'mergetool takes partial path' ' git submodule update -N && test_must_fail git merge master && - #shouldnt need these lines + #should not need these lines #( yes "d" | git mergetool file11 >/dev/null 2>&1 ) && #( yes "d" | git mergetool file12 >/dev/null 2>&1 ) && #( yes "l" | git mergetool submod >/dev/null 2>&1 ) && diff --git a/t/t7612-merge-verify-signatures.sh b/t/t7612-merge-verify-signatures.sh new file mode 100755 index 0000000000..21a0bf8fb8 --- /dev/null +++ b/t/t7612-merge-verify-signatures.sh @@ -0,0 +1,61 @@ +#!/bin/sh + +test_description='merge signature verification tests' +. ./test-lib.sh +. "$TEST_DIRECTORY/lib-gpg.sh" + +test_expect_success GPG 'create signed commits' ' + echo 1 >file && git add file && + test_tick && git commit -m initial && + git tag initial && + + git checkout -b side-signed && + echo 3 >elif && git add elif && + test_tick && git commit -S -m "signed on side" && + git checkout initial && + + git checkout -b side-unsigned && + echo 3 >foo && git add foo && + test_tick && git commit -m "unsigned on side" && + git checkout initial && + + git checkout -b side-bad && + echo 3 >bar && git add bar && + test_tick && git commit -S -m "bad on side" && + git cat-file commit side-bad >raw && + sed -e "s/bad/forged bad/" raw >forged && + git hash-object -w -t commit forged >forged.commit && + git checkout initial && + + git checkout -b side-untrusted && + echo 3 >baz && git add baz && + test_tick && git commit -SB7227189 -m "untrusted on side" + + git checkout master +' + +test_expect_success GPG 'merge unsigned commit with verification' ' + test_must_fail git merge --ff-only --verify-signatures side-unsigned 2>mergeerror && + test_i18ngrep "does not have a GPG signature" mergeerror +' + +test_expect_success GPG 'merge commit with bad signature with verification' ' + test_must_fail git merge --ff-only --verify-signatures $(cat forged.commit) 2>mergeerror && + test_i18ngrep "has a bad GPG signature" mergeerror +' + +test_expect_success GPG 'merge commit with untrusted signature with verification' ' + test_must_fail git merge --ff-only --verify-signatures side-untrusted 2>mergeerror && + test_i18ngrep "has an untrusted GPG signature" mergeerror +' + +test_expect_success GPG 'merge signed commit with verification' ' + git merge --verbose --ff-only --verify-signatures side-signed >mergeoutput && + test_i18ngrep "has a good GPG signature" mergeoutput +' + +test_expect_success GPG 'merge commit with bad signature without verification' ' + git merge $(cat forged.commit) +' + +test_done diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh index eb1d3f85b5..2418528487 100755 --- a/t/t7800-difftool.sh +++ b/t/t7800-difftool.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2009, 2010 David Aguilar +# Copyright (c) 2009, 2010, 2012, 2013 David Aguilar # test_description='git-difftool @@ -10,47 +10,19 @@ Testing basic diff tool invocation . ./test-lib.sh -remove_config_vars() +difftool_test_setup () { - # Unset all config variables used by git-difftool - git config --unset diff.tool - git config --unset diff.guitool - git config --unset difftool.test-tool.cmd - git config --unset difftool.prompt - git config --unset merge.tool - git config --unset mergetool.test-tool.cmd - git config --unset mergetool.prompt - return 0 + test_config diff.tool test-tool && + test_config difftool.test-tool.cmd 'cat "$LOCAL"' && + test_config difftool.bogus-tool.cmd false } -restore_test_defaults() -{ - # Restores the test defaults used by several tests - remove_config_vars - unset GIT_DIFF_TOOL - unset GIT_DIFFTOOL_PROMPT - unset GIT_DIFFTOOL_NO_PROMPT - git config diff.tool test-tool && - git config difftool.test-tool.cmd 'cat $LOCAL' - git config difftool.bogus-tool.cmd false -} - -prompt_given() +prompt_given () { prompt="$1" test "$prompt" = "Launch 'test-tool' [Y/n]: branch" } -stdin_contains() -{ - grep >/dev/null "$1" -} - -stdin_doesnot_contain() -{ - ! stdin_contains "$1" -} - # Create a file on master and change it on branch test_expect_success PERL 'setup' ' echo master >file && @@ -65,249 +37,237 @@ test_expect_success PERL 'setup' ' # Configure a custom difftool.<tool>.cmd and use it test_expect_success PERL 'custom commands' ' - restore_test_defaults && - git config difftool.test-tool.cmd "cat \$REMOTE" && + difftool_test_setup && + test_config difftool.test-tool.cmd "cat \"\$REMOTE\"" && + echo master >expect && + git difftool --no-prompt branch >actual && + test_cmp expect actual && - diff=$(git difftool --no-prompt branch) && - test "$diff" = "master" && - - restore_test_defaults && - diff=$(git difftool --no-prompt branch) && - test "$diff" = "branch" + test_config difftool.test-tool.cmd "cat \"\$LOCAL\"" && + echo branch >expect && + git difftool --no-prompt branch >actual && + test_cmp expect actual ' -# Ensures that a custom difftool.<tool>.cmd overrides built-ins -test_expect_success PERL 'custom commands override built-ins' ' - restore_test_defaults && - git config difftool.defaults.cmd "cat \$REMOTE" && - - diff=$(git difftool --tool defaults --no-prompt branch) && - test "$diff" = "master" && - - git config --unset difftool.defaults.cmd +test_expect_success PERL 'custom tool commands override built-ins' ' + test_config difftool.vimdiff.cmd "cat \"\$REMOTE\"" && + echo master >expect && + git difftool --tool vimdiff --no-prompt branch >actual && + test_cmp expect actual ' -# Ensures that git-difftool ignores bogus --tool values test_expect_success PERL 'difftool ignores bad --tool values' ' - diff=$(git difftool --no-prompt --tool=bad-tool branch) - test "$?" = 1 && - test "$diff" = "" + : >expect && + test_expect_code 1 \ + git difftool --no-prompt --tool=bad-tool branch >actual && + test_cmp expect actual ' test_expect_success PERL 'difftool forwards arguments to diff' ' + difftool_test_setup && >for-diff && git add for-diff && echo changes>for-diff && git add for-diff && - diff=$(git difftool --cached --no-prompt -- for-diff) && - test "$diff" = "" && + : >expect && + git difftool --cached --no-prompt -- for-diff >actual && + test_cmp expect actual && 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 && - git config diff.guitool test-tool && + difftool_test_setup && + test_config merge.tool bogus-tool && + test_config diff.tool bogus-tool && + test_config diff.guitool test-tool && - diff=$(git difftool --no-prompt --gui branch) && - test "$diff" = "branch" && - - restore_test_defaults + echo branch >expect && + git difftool --no-prompt --gui branch >actual && + test_cmp expect actual ' 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" && + difftool_test_setup && + : >expect && + git difftool --no-prompt --gui --no-gui >actual && + test_cmp expect actual && - restore_test_defaults + test_config merge.tool bogus-tool && + test_config diff.tool bogus-tool && + test_config diff.guitool test-tool && + echo branch >expect && + git difftool --no-prompt --no-gui --gui branch >actual && + test_cmp expect actual ' test_expect_success PERL 'difftool --gui works without configured diff.guitool' ' - git config diff.tool test-tool && - - diff=$(git difftool --no-prompt --gui branch) && - test "$diff" = "branch" && - - restore_test_defaults + difftool_test_setup && + echo branch >expect && + git difftool --no-prompt --gui branch >actual && + test_cmp expect actual ' # Specify the diff tool using $GIT_DIFF_TOOL test_expect_success PERL 'GIT_DIFF_TOOL variable' ' - test_might_fail git config --unset diff.tool && - GIT_DIFF_TOOL=test-tool && - export GIT_DIFF_TOOL && - - diff=$(git difftool --no-prompt branch) && - test "$diff" = "branch" && - - restore_test_defaults + difftool_test_setup && + git config --unset diff.tool && + echo branch >expect && + GIT_DIFF_TOOL=test-tool git difftool --no-prompt branch >actual && + test_cmp expect actual ' # Test the $GIT_*_TOOL variables and ensure # that $GIT_DIFF_TOOL always wins unless --tool is specified test_expect_success PERL 'GIT_DIFF_TOOL overrides' ' - git config diff.tool bogus-tool && - git config merge.tool bogus-tool && + difftool_test_setup && + test_config diff.tool bogus-tool && + test_config merge.tool bogus-tool && - GIT_DIFF_TOOL=test-tool && - export GIT_DIFF_TOOL && + echo branch >expect && + GIT_DIFF_TOOL=test-tool git difftool --no-prompt branch >actual && + test_cmp expect actual && - diff=$(git difftool --no-prompt branch) && - test "$diff" = "branch" && - - GIT_DIFF_TOOL=bogus-tool && - export GIT_DIFF_TOOL && - - diff=$(git difftool --no-prompt --tool=test-tool branch) && - test "$diff" = "branch" && - - restore_test_defaults + test_config diff.tool bogus-tool && + test_config merge.tool bogus-tool && + GIT_DIFF_TOOL=bogus-tool \ + git difftool --no-prompt --tool=test-tool branch >actual && + test_cmp expect actual ' # Test that we don't have to pass --no-prompt to difftool # when $GIT_DIFFTOOL_NO_PROMPT is true test_expect_success PERL 'GIT_DIFFTOOL_NO_PROMPT variable' ' - GIT_DIFFTOOL_NO_PROMPT=true && - export GIT_DIFFTOOL_NO_PROMPT && - - diff=$(git difftool branch) && - test "$diff" = "branch" && - - restore_test_defaults + difftool_test_setup && + echo branch >expect && + GIT_DIFFTOOL_NO_PROMPT=true git difftool branch >actual && + test_cmp expect actual ' # git-difftool supports the difftool.prompt variable. # Test that GIT_DIFFTOOL_PROMPT can override difftool.prompt = false test_expect_success PERL 'GIT_DIFFTOOL_PROMPT variable' ' - git config difftool.prompt false && - GIT_DIFFTOOL_PROMPT=true && - export GIT_DIFFTOOL_PROMPT && - - prompt=$(echo | git difftool branch | tail -1) && - prompt_given "$prompt" && - - restore_test_defaults + difftool_test_setup && + test_config difftool.prompt false && + echo >input && + GIT_DIFFTOOL_PROMPT=true git difftool branch <input >output && + prompt=$(tail -1 <output) && + prompt_given "$prompt" ' # Test that we don't have to pass --no-prompt when difftool.prompt is false test_expect_success PERL 'difftool.prompt config variable is false' ' - git config difftool.prompt false && - - diff=$(git difftool branch) && - test "$diff" = "branch" && - - restore_test_defaults + difftool_test_setup && + test_config difftool.prompt false && + echo branch >expect && + git difftool branch >actual && + test_cmp expect actual ' # Test that we don't have to pass --no-prompt when mergetool.prompt is false test_expect_success PERL 'difftool merge.prompt = false' ' + difftool_test_setup && test_might_fail git config --unset difftool.prompt && - git config mergetool.prompt false && - - diff=$(git difftool branch) && - test "$diff" = "branch" && - - restore_test_defaults + test_config mergetool.prompt false && + echo branch >expect && + git difftool branch >actual && + test_cmp expect actual ' # Test that the -y flag can override difftool.prompt = true test_expect_success PERL 'difftool.prompt can overridden with -y' ' - git config difftool.prompt true && - - diff=$(git difftool -y branch) && - test "$diff" = "branch" && - - restore_test_defaults + difftool_test_setup && + test_config difftool.prompt true && + echo branch >expect && + git difftool -y branch >actual && + test_cmp expect actual ' # Test that the --prompt flag can override difftool.prompt = false test_expect_success PERL 'difftool.prompt can overridden with --prompt' ' - git config difftool.prompt false && - - prompt=$(echo | git difftool --prompt branch | tail -1) && - prompt_given "$prompt" && - - restore_test_defaults + difftool_test_setup && + test_config difftool.prompt false && + echo >input && + git difftool --prompt branch <input >output && + prompt=$(tail -1 <output) && + prompt_given "$prompt" ' # Test that the last flag passed on the command-line wins test_expect_success PERL 'difftool last flag wins' ' - diff=$(git difftool --prompt --no-prompt branch) && - test "$diff" = "branch" && - - restore_test_defaults && - - prompt=$(echo | git difftool --no-prompt --prompt branch | tail -1) && - prompt_given "$prompt" && - - restore_test_defaults + difftool_test_setup && + echo branch >expect && + git difftool --prompt --no-prompt branch >actual && + test_cmp expect actual && + echo >input && + git difftool --no-prompt --prompt branch <input >output && + prompt=$(tail -1 <output) && + prompt_given "$prompt" ' # git-difftool falls back to git-mergetool config variables # so test that behavior here test_expect_success PERL 'difftool + mergetool config variables' ' - remove_config_vars && - git config merge.tool test-tool && - git config mergetool.test-tool.cmd "cat \$LOCAL" && - - diff=$(git difftool --no-prompt branch) && - test "$diff" = "branch" && + test_config merge.tool test-tool && + test_config mergetool.test-tool.cmd "cat \$LOCAL" && + echo branch >expect && + git difftool --no-prompt branch >actual && + test_cmp expect actual && # set merge.tool to something bogus, diff.tool to test-tool - git config merge.tool bogus-tool && - git config diff.tool test-tool && - - diff=$(git difftool --no-prompt branch) && - test "$diff" = "branch" && - - restore_test_defaults + test_config merge.tool bogus-tool && + test_config diff.tool test-tool && + git difftool --no-prompt branch >actual && + test_cmp expect actual ' test_expect_success PERL 'difftool.<tool>.path' ' - git config difftool.tkdiff.path echo && - diff=$(git difftool --tool=tkdiff --no-prompt branch) && - git config --unset difftool.tkdiff.path && - lines=$(echo "$diff" | grep file | wc -l) && - test "$lines" -eq 1 && - - restore_test_defaults + test_config difftool.tkdiff.path echo && + git difftool --tool=tkdiff --no-prompt branch >output && + lines=$(grep file output | wc -l) && + test "$lines" -eq 1 ' test_expect_success PERL 'difftool --extcmd=cat' ' - diff=$(git difftool --no-prompt --extcmd=cat branch) && - test "$diff" = branch"$LF"master + echo branch >expect && + echo master >>expect && + git difftool --no-prompt --extcmd=cat branch >actual && + test_cmp expect actual ' test_expect_success PERL 'difftool --extcmd cat' ' - diff=$(git difftool --no-prompt --extcmd cat branch) && - test "$diff" = branch"$LF"master + echo branch >expect && + echo master >>expect && + git difftool --no-prompt --extcmd=cat branch >actual && + test_cmp expect actual ' test_expect_success PERL 'difftool -x cat' ' - diff=$(git difftool --no-prompt -x cat branch) && - test "$diff" = branch"$LF"master + echo branch >expect && + echo master >>expect && + git difftool --no-prompt -x cat branch >actual && + test_cmp expect actual ' test_expect_success PERL 'difftool --extcmd echo arg1' ' - diff=$(git difftool --no-prompt --extcmd sh\ -c\ \"echo\ \$1\" branch) && - test "$diff" = file + echo file >expect && + git difftool --no-prompt \ + --extcmd sh\ -c\ \"echo\ \$1\" branch >actual && + test_cmp expect actual ' test_expect_success PERL 'difftool --extcmd cat arg1' ' - diff=$(git difftool --no-prompt --extcmd sh\ -c\ \"cat\ \$1\" branch) && - test "$diff" = master + echo master >expect && + git difftool --no-prompt \ + --extcmd sh\ -c\ \"cat\ \$1\" branch >actual && + test_cmp expect actual ' test_expect_success PERL 'difftool --extcmd cat arg2' ' - diff=$(git difftool --no-prompt --extcmd sh\ -c\ \"cat\ \$2\" branch) && - test "$diff" = branch + echo branch >expect && + git difftool --no-prompt \ + --extcmd sh\ -c\ \"cat\ \$2\" branch >actual && + test_cmp expect actual ' # Create a second file on master and a different version on branch @@ -324,26 +284,26 @@ test_expect_success PERL 'setup with 2 files different' ' ' test_expect_success PERL 'say no to the first file' ' - diff=$( (echo n; echo) | git difftool -x cat branch ) && - - echo "$diff" | stdin_contains m2 && - echo "$diff" | stdin_contains br2 && - echo "$diff" | stdin_doesnot_contain master && - echo "$diff" | stdin_doesnot_contain branch + (echo n && echo) >input && + git difftool -x cat branch <input >output && + grep m2 output && + grep br2 output && + ! grep master output && + ! grep branch output ' test_expect_success PERL 'say no to the second file' ' - diff=$( (echo; echo n) | git difftool -x cat branch ) && - - echo "$diff" | stdin_contains master && - echo "$diff" | stdin_contains branch && - echo "$diff" | stdin_doesnot_contain m2 && - echo "$diff" | stdin_doesnot_contain br2 + (echo && echo n) >input && + git difftool -x cat branch <input >output && + grep master output && + grep branch output && + ! grep m2 output && + ! grep br2 output ' test_expect_success PERL 'difftool --tool-help' ' - tool_help=$(git difftool --tool-help) && - echo "$tool_help" | stdin_contains tool + git difftool --tool-help >output && + grep tool output ' test_expect_success PERL 'setup change in subdirectory' ' @@ -354,34 +314,123 @@ test_expect_success PERL 'setup change in subdirectory' ' git commit -m "added sub/sub" && echo test >>file && echo test >>sub/sub && - git add . && + git add file sub/sub && 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 +run_dir_diff_test () { + test_expect_success PERL "$1 --no-symlinks" " + symlinks=--no-symlinks && + $2 + " + test_expect_success PERL,SYMLINKS "$1 --symlinks" " + symlinks=--symlinks && + $2 + " +} + +run_dir_diff_test 'difftool -d' ' + git difftool -d $symlinks --extcmd ls branch >output && + grep sub output && + grep file output ' -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 +run_dir_diff_test 'difftool --dir-diff' ' + git difftool --dir-diff $symlinks --extcmd ls branch >output && + grep sub output && + grep file output ' -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 +run_dir_diff_test 'difftool --dir-diff ignores --prompt' ' + git difftool --dir-diff $symlinks --prompt --extcmd ls branch >output && + grep sub output && + grep file output ' -test_expect_success PERL 'difftool --dir-diff from subdirectory' ' +run_dir_diff_test '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 + git difftool --dir-diff $symlinks --extcmd ls branch >output && + grep sub output && + grep file output + ) +' + +run_dir_diff_test 'difftool --dir-diff when worktree file is missing' ' + test_when_finished git reset --hard && + rm file2 && + git difftool --dir-diff $symlinks --extcmd ls branch master >output && + grep file2 output +' + +write_script .git/CHECK_SYMLINKS <<\EOF +for f in file file2 sub/sub +do + echo "$f" + readlink "$2/$f" +done >actual +EOF + +test_expect_success PERL,SYMLINKS 'difftool --dir-diff --symlink without unstaged changes' ' + cat >expect <<-EOF && + file + $(pwd)/file + file2 + $(pwd)/file2 + sub/sub + $(pwd)/sub/sub + EOF + git difftool --dir-diff --symlink \ + --extcmd "./.git/CHECK_SYMLINKS" branch HEAD && + test_cmp actual expect +' + +write_script modify-right-file <<\EOF +echo "new content" >"$2/file" +EOF + +run_dir_diff_test 'difftool --dir-diff syncs worktree with unstaged change' ' + test_when_finished git reset --hard && + echo "orig content" >file && + git difftool -d $symlinks --extcmd "$(pwd)/modify-right-file" branch && + echo "new content" >expect && + test_cmp expect file +' + +run_dir_diff_test 'difftool --dir-diff syncs worktree without unstaged change' ' + test_when_finished git reset --hard && + git difftool -d $symlinks --extcmd "$(pwd)/modify-right-file" branch && + echo "new content" >expect && + test_cmp expect file +' + +write_script modify-file <<\EOF +echo "new content" >file +EOF + +test_expect_success PERL 'difftool --no-symlinks does not overwrite working tree file ' ' + echo "orig content" >file && + git difftool --dir-diff --no-symlinks --extcmd "$(pwd)/modify-file" branch && + echo "new content" >expect && + test_cmp expect file +' + +write_script modify-both-files <<\EOF +echo "wt content" >file && +echo "tmp content" >"$2/file" && +echo "$2" >tmpdir +EOF + +test_expect_success PERL 'difftool --no-symlinks detects conflict ' ' + ( + TMPDIR=$TRASH_DIRECTORY && + export TMPDIR && + echo "orig content" >file && + test_must_fail git difftool --dir-diff --no-symlinks --extcmd "$(pwd)/modify-both-files" branch && + echo "wt content" >expect && + test_cmp expect file && + echo "tmp content" >expect && + test_cmp expect "$(cat tmpdir)/file" ) ' diff --git a/t/t7811-grep-open.sh b/t/t7811-grep-open.sh index a8957782cf..e1951a5cbb 100755 --- a/t/t7811-grep-open.sh +++ b/t/t7811-grep-open.sh @@ -125,11 +125,6 @@ test_expect_success 'modified file' ' test_cmp empty out ' -test_config() { - git config "$1" "$2" && - test_when_finished "git config --unset $1" -} - test_expect_success 'copes with color settings' ' rm -f actual && echo grep.h >expect && diff --git a/t/t8001-annotate.sh b/t/t8001-annotate.sh index 41962f04a7..72176e42c1 100755 --- a/t/t8001-annotate.sh +++ b/t/t8001-annotate.sh @@ -6,9 +6,9 @@ test_description='git annotate' PROG='git annotate' . "$TEST_DIRECTORY"/annotate-tests.sh -test_expect_success 'Annotating an old revision works' ' - git annotate file master >result && - awk "{ print \$3; }" <result >authors && +test_expect_success 'annotate old revision' ' + git annotate file master >actual && + awk "{ print \$3; }" <actual >authors && test 2 = $(grep A <authors | wc -l) && test 2 = $(grep B <authors | wc -l) ' diff --git a/t/t8002-blame.sh b/t/t8002-blame.sh index e2896cffc1..5cdf3f178e 100755 --- a/t/t8002-blame.sh +++ b/t/t8002-blame.sh @@ -7,8 +7,16 @@ PROG='git blame -c' . "$TEST_DIRECTORY"/annotate-tests.sh PROG='git blame -c -e' -test_expect_success 'Blame --show-email works' ' - check_count "<A@test.git>" 1 "<B@test.git>" 1 "<B1@test.git>" 1 "<B2@test.git>" 1 "<author@example.com>" 1 "<C@test.git>" 1 "<D@test.git>" 1 "<E at test dot git>" 1 +test_expect_success 'blame --show-email' ' + check_count \ + "<A@test.git>" 1 \ + "<B@test.git>" 1 \ + "<B1@test.git>" 1 \ + "<B2@test.git>" 1 \ + "<author@example.com>" 1 \ + "<C@test.git>" 1 \ + "<D@test.git>" 1 \ + "<E at test dot git>" 1 ' test_done diff --git a/t/t8003-blame-corner-cases.sh b/t/t8003-blame-corner-cases.sh index 230143cf31..e7cac1db55 100755 --- a/t/t8003-blame-corner-cases.sh +++ b/t/t8003-blame-corner-cases.sh @@ -175,6 +175,12 @@ test_expect_success 'blame -L with invalid end' ' grep "has only 2 lines" errors ' +test_expect_success 'blame parses <end> part of -L' ' + git blame -L1,1 tres >out && + cat out && + test $(wc -l < out) -eq 1 +' + test_expect_success 'indent of line numbers, nine lines' ' git blame nine_lines >actual && test $(grep -c " " actual) = 0 diff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh index bf6caa4dc3..7683515155 100755 --- a/t/t8006-blame-textconv.sh +++ b/t/t8006-blame-textconv.sh @@ -18,17 +18,13 @@ test_expect_success 'setup ' ' echo "bin: test number 0" >zero.bin && echo "bin: test 1" >one.bin && echo "bin: test number 2" >two.bin && - if test_have_prereq SYMLINKS; then - ln -s one.bin symlink.bin - fi && + test_ln_s_add one.bin symlink.bin && git add . && GIT_AUTHOR_NAME=Number1 git commit -a -m First --date="2010-01-01 18:00:00" && echo "bin: test 1 version 2" >one.bin && echo "bin: test number 2 version 2" >>two.bin && - if test_have_prereq SYMLINKS; then - rm symlink.bin && - ln -s two.bin symlink.bin - fi && + rm -f symlink.bin && + test_ln_s_add two.bin symlink.bin && GIT_AUTHOR_NAME=Number2 git commit -a -m Second --date="2010-01-01 20:00:00" ' @@ -135,7 +131,7 @@ test_expect_success SYMLINKS 'blame --textconv (on symlink)' ' # cp two.bin three.bin and make small tweak # (this will direct blame -C -C three.bin to consider two.bin and symlink.bin) -test_expect_success SYMLINKS 'make another new commit' ' +test_expect_success 'make another new commit' ' cat >three.bin <<\EOF && bin: test number 2 bin: test number 2 version 2 @@ -146,7 +142,7 @@ EOF GIT_AUTHOR_NAME=Number4 git commit -a -m Fourth --date="2010-01-01 23:00:00" ' -test_expect_success SYMLINKS 'blame on last commit (-C -C, symlink)' ' +test_expect_success 'blame on last commit (-C -C, symlink)' ' git blame -C -C three.bin >blame && find_blame <blame >result && cat >expected <<\EOF && diff --git a/t/t8007-cat-file-textconv.sh b/t/t8007-cat-file-textconv.sh index 78a0085e64..b95e102891 100755 --- a/t/t8007-cat-file-textconv.sh +++ b/t/t8007-cat-file-textconv.sh @@ -12,9 +12,7 @@ chmod +x helper test_expect_success 'setup ' ' echo "bin: test" >one.bin && - if test_have_prereq SYMLINKS; then - ln -s one.bin symlink.bin - fi && + test_ln_s_add one.bin symlink.bin && git add . && GIT_AUTHOR_NAME=Number1 git commit -a -m First --date="2010-01-01 18:00:00" && echo "bin: test version 2" >one.bin && @@ -72,14 +70,14 @@ test_expect_success 'cat-file --textconv on previous commit' ' test_cmp expected result ' -test_expect_success SYMLINKS 'cat-file without --textconv (symlink)' ' +test_expect_success 'cat-file without --textconv (symlink)' ' git cat-file blob :symlink.bin >result && printf "%s" "one.bin" >expected test_cmp expected result ' -test_expect_success SYMLINKS 'cat-file --textconv on index (symlink)' ' +test_expect_success 'cat-file --textconv on index (symlink)' ' ! git cat-file --textconv :symlink.bin 2>result && cat >expected <<\EOF && fatal: git cat-file --textconv: unable to run textconv on :symlink.bin @@ -87,7 +85,7 @@ EOF test_cmp expected result ' -test_expect_success SYMLINKS 'cat-file --textconv on HEAD (symlink)' ' +test_expect_success 'cat-file --textconv on HEAD (symlink)' ' ! git cat-file --textconv HEAD:symlink.bin 2>result && cat >expected <<EOF && fatal: git cat-file --textconv: unable to run textconv on HEAD:symlink.bin diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 035122808b..2813aa9a61 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -101,7 +101,7 @@ test_expect_success $PREREQ \ test_expect_success $PREREQ 'Send patches with --envelope-sender' ' clean_fake_sendmail && - git send-email --envelope-sender="Patch Contributer <patch@example.com>" --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors + git send-email --envelope-sender="Patch Contributor <patch@example.com>" --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors ' test_expect_success $PREREQ 'setup expect' ' @@ -171,6 +171,81 @@ Result: OK EOF " +test_suppress_self () { + test_commit $3 && + test_when_finished "git reset --hard HEAD^" && + + write_script cccmd-sed <<-EOF && + sed -n -e s/^cccmd--//p "\$1" + EOF + + git commit --amend --author="$1 <$2>" -F - && + clean_fake_sendmail && + git format-patch --stdout -1 >"suppress-self-$3.patch" && + + git send-email --from="$1 <$2>" \ + --to=nobody@example.com \ + --cc-cmd=./cccmd-sed \ + --suppress-cc=self \ + --smtp-server="$(pwd)/fake.sendmail" \ + suppress-self-$3.patch && + + mv msgtxt1 msgtxt1-$3 && + sed -e '/^$/q' msgtxt1-$3 >"msghdr1-$3" && + >"expected-no-cc-$3" && + + (grep '^Cc:' msghdr1-$3 >"actual-no-cc-$3"; + test_cmp expected-no-cc-$3 actual-no-cc-$3) +} + +test_suppress_self_unquoted () { + test_suppress_self "$1" "$2" "unquoted-$3" <<-EOF + test suppress-cc.self unquoted-$3 with name $1 email $2 + + unquoted-$3 + + cccmd--$1 <$2> + + Cc: $1 <$2> + Signed-off-by: $1 <$2> + EOF +} + +test_suppress_self_quoted () { + test_suppress_self "$1" "$2" "quoted-$3" <<-EOF + test suppress-cc.self quoted-$3 with name $1 email $2 + + quoted-$3 + + cccmd--"$1" <$2> + + Cc: $1 <$2> + Cc: "$1" <$2> + Signed-off-by: $1 <$2> + Signed-off-by: "$1" <$2> + EOF +} + +test_expect_success $PREREQ 'self name is suppressed' " + test_suppress_self_unquoted 'A U Thor' 'author@example.com' \ + 'self_name_suppressed' +" + +test_expect_success $PREREQ 'self name with dot is suppressed' " + test_suppress_self_quoted 'A U. Thor' 'author@example.com' \ + 'self_name_dot_suppressed' +" + +test_expect_success $PREREQ 'non-ascii self name is suppressed' " + test_suppress_self_quoted 'Füñný Nâmé' 'odd_?=mail@example.com' \ + 'non_ascii_self_suppressed' +" + +test_expect_success $PREREQ 'sanitized self name is suppressed' " + test_suppress_self_unquoted '\"A U. Thor\"' 'author@example.com' \ + 'self_name_sanitized_suppressed' +" + test_expect_success $PREREQ 'Show all headers' ' git send-email \ --dry-run \ @@ -191,17 +266,44 @@ test_expect_success $PREREQ 'Show all headers' ' test_expect_success $PREREQ 'Prompting works' ' clean_fake_sendmail && - (echo "Example <from@example.com>" - echo "to@example.com" + (echo "to@example.com" echo "" ) | GIT_SEND_EMAIL_NOTTY=1 git send-email \ --smtp-server="$(pwd)/fake.sendmail" \ $patches \ 2>errors && - grep "^From: Example <from@example.com>\$" msgtxt1 && + grep "^From: A U Thor <author@example.com>\$" msgtxt1 && grep "^To: to@example.com\$" msgtxt1 ' +test_expect_success $PREREQ,AUTOIDENT 'implicit ident is allowed' ' + clean_fake_sendmail && + (sane_unset GIT_AUTHOR_NAME && + sane_unset GIT_AUTHOR_EMAIL && + sane_unset GIT_COMMITTER_NAME && + sane_unset GIT_COMMITTER_EMAIL && + GIT_SEND_EMAIL_NOTTY=1 git send-email \ + --smtp-server="$(pwd)/fake.sendmail" \ + --to=to@example.com \ + $patches </dev/null 2>errors + ) +' + +test_expect_success $PREREQ,!AUTOIDENT 'broken implicit ident aborts send-email' ' + clean_fake_sendmail && + (sane_unset GIT_AUTHOR_NAME && + sane_unset GIT_AUTHOR_EMAIL && + sane_unset GIT_COMMITTER_NAME && + sane_unset GIT_COMMITTER_EMAIL && + GIT_SEND_EMAIL_NOTTY=1 && export GIT_SEND_EMAIL_NOTTY && + test_must_fail git send-email \ + --smtp-server="$(pwd)/fake.sendmail" \ + --to=to@example.com \ + $patches </dev/null 2>errors && + test_i18ngrep "tell me who you are" errors + ) +' + test_expect_success $PREREQ 'tocmd works' ' clean_fake_sendmail && cp $patches tocmd.patch && @@ -760,7 +862,7 @@ test_expect_success $PREREQ 'confirm detects EOF (auto causes failure)' ' test $ret = "0" ' -test_expect_success $PREREQ 'confirm doesnt loop forever' ' +test_expect_success $PREREQ 'confirm does not loop forever' ' CONFIRM=$(git config --get sendemail.confirm) && git config sendemail.confirm auto && GIT_SEND_EMAIL_NOTTY=1 && @@ -854,6 +956,89 @@ test_expect_success $PREREQ 'utf8 author is correctly passed on' ' grep "^From: Füñný Nâmé <odd_?=mail@example.com>" msgtxt1 ' +test_expect_success $PREREQ 'utf8 sender is not duplicated' ' + clean_fake_sendmail && + test_commit weird_sender && + 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="Füñný Nâmé <odd_?=mail@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + funny_name.patch && + grep "^From: " msgtxt1 >msgfrom && + test_line_count = 1 msgfrom +' + +test_expect_success $PREREQ 'sendemail.composeencoding works' ' + clean_fake_sendmail && + git config sendemail.composeencoding iso-8859-1 && + (echo "#!$SHELL_PATH" && + echo "echo utf8 body: à éìöú >>\"\$1\"" + ) >fake-editor-utf8 && + chmod +x fake-editor-utf8 && + GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \ + git send-email \ + --compose --subject foo \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches && + grep "^utf8 body" msgtxt1 && + grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1 +' + +test_expect_success $PREREQ '--compose-encoding works' ' + clean_fake_sendmail && + (echo "#!$SHELL_PATH" && + echo "echo utf8 body: à éìöú >>\"\$1\"" + ) >fake-editor-utf8 && + chmod +x fake-editor-utf8 && + GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \ + git send-email \ + --compose-encoding iso-8859-1 \ + --compose --subject foo \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches && + grep "^utf8 body" msgtxt1 && + grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1 +' + +test_expect_success $PREREQ '--compose-encoding overrides sendemail.composeencoding' ' + clean_fake_sendmail && + git config sendemail.composeencoding iso-8859-1 && + (echo "#!$SHELL_PATH" && + echo "echo utf8 body: à éìöú >>\"\$1\"" + ) >fake-editor-utf8 && + chmod +x fake-editor-utf8 && + GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \ + git send-email \ + --compose-encoding iso-8859-2 \ + --compose --subject foo \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches && + grep "^utf8 body" msgtxt1 && + grep "^Content-Type: text/plain; charset=iso-8859-2" msgtxt1 +' + +test_expect_success $PREREQ '--compose-encoding adds correct MIME for subject' ' + clean_fake_sendmail && + GIT_EDITOR="\"$(pwd)/fake-editor\"" \ + git send-email \ + --compose-encoding iso-8859-2 \ + --compose --subject utf8-sübjëct \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches && + grep "^fake edit" msgtxt1 && + grep "^Subject: =?iso-8859-2?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1 +' + test_expect_success $PREREQ 'detects ambiguous reference/file conflict' ' echo master > master && git add master && @@ -907,55 +1092,6 @@ test_expect_success $PREREQ 'threading but no chain-reply-to' ' grep "In-Reply-To: " stdout ' -test_expect_success $PREREQ 'warning with an implicit --chain-reply-to' ' - git send-email \ - --dry-run \ - --from="Example <nobody@example.com>" \ - --to=nobody@example.com \ - outdir/000?-*.patch 2>errors >out && - grep "no-chain-reply-to" errors -' - -test_expect_success $PREREQ 'no warning with an explicit --chain-reply-to' ' - git send-email \ - --dry-run \ - --from="Example <nobody@example.com>" \ - --to=nobody@example.com \ - --chain-reply-to \ - outdir/000?-*.patch 2>errors >out && - ! grep "no-chain-reply-to" errors -' - -test_expect_success $PREREQ 'no warning with an explicit --no-chain-reply-to' ' - git send-email \ - --dry-run \ - --from="Example <nobody@example.com>" \ - --to=nobody@example.com \ - --nochain-reply-to \ - outdir/000?-*.patch 2>errors >out && - ! grep "no-chain-reply-to" errors -' - -test_expect_success $PREREQ 'no warning with sendemail.chainreplyto = false' ' - git config sendemail.chainreplyto false && - git send-email \ - --dry-run \ - --from="Example <nobody@example.com>" \ - --to=nobody@example.com \ - outdir/000?-*.patch 2>errors >out && - ! grep "no-chain-reply-to" errors -' - -test_expect_success $PREREQ 'no warning with sendemail.chainreplyto = true' ' - git config sendemail.chainreplyto true && - git send-email \ - --dry-run \ - --from="Example <nobody@example.com>" \ - --to=nobody@example.com \ - outdir/000?-*.patch 2>errors >out && - ! grep "no-chain-reply-to" errors -' - test_expect_success $PREREQ 'sendemail.to works' ' git config --replace-all sendemail.to "Somebody <somebody@ex.com>" && git send-email \ @@ -1074,6 +1210,23 @@ EOF ' test_expect_success $PREREQ 'setup expect' ' +cat >expected <<EOF +Subject: subject goes here +EOF +' + +test_expect_success $PREREQ 'ASCII subject is not RFC2047 quoted' ' + clean_fake_sendmail && + echo bogus | + git send-email --from=author@example.com --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + --8bit-encoding=UTF-8 \ + email-using-8bit >stdout && + grep "Subject" msgtxt1 >actual && + test_cmp expected actual +' + +test_expect_success $PREREQ 'setup expect' ' cat >content-type-decl <<EOF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 diff --git a/t/t9010-svn-fe.sh b/t/t9010-svn-fe.sh index b7eed2489f..6dafe7e99a 100755 --- a/t/t9010-svn-fe.sh +++ b/t/t9010-svn-fe.sh @@ -54,14 +54,6 @@ text_no_props () { >empty -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 && diff --git a/t/t9020-remote-svn.sh b/t/t9020-remote-svn.sh new file mode 100755 index 0000000000..d9f6b73ab0 --- /dev/null +++ b/t/t9020-remote-svn.sh @@ -0,0 +1,89 @@ +#!/bin/sh + +test_description='tests remote-svn' + +. ./test-lib.sh + +MARKSPATH=.git/info/fast-import/remote-svn + +if ! test_have_prereq PYTHON +then + skip_all='skipping remote-svn tests, python not available' + test_done +fi + +# Override svnrdump with our simulator +PATH="$HOME:$PATH" +export PATH PYTHON_PATH GIT_BUILD_DIR + +write_script "$HOME/svnrdump" <<\EOF +exec "$PYTHON_PATH" "$GIT_BUILD_DIR/contrib/svn-fe/svnrdump_sim.py" "$@" +EOF + +init_git () { + rm -fr .git && + git init && + #git remote add svnsim testsvn::sim:///$TEST_DIRECTORY/t9020/example.svnrdump + # let's reuse an exisiting dump file!? + git remote add svnsim testsvn::sim://$TEST_DIRECTORY/t9154/svn.dump + git remote add svnfile testsvn::file://$TEST_DIRECTORY/t9154/svn.dump +} + +if test -e "$GIT_BUILD_DIR/git-remote-testsvn" +then + test_set_prereq REMOTE_SVN +fi + +test_debug ' + git --version + type git + type svnrdump +' + +test_expect_success REMOTE_SVN 'simple fetch' ' + init_git && + git fetch svnsim && + test_cmp .git/refs/svn/svnsim/master .git/refs/remotes/svnsim/master && + cp .git/refs/remotes/svnsim/master master.good +' + +test_debug ' + cat .git/refs/svn/svnsim/master + cat .git/refs/remotes/svnsim/master +' + +test_expect_success REMOTE_SVN 'repeated fetch, nothing shall change' ' + git fetch svnsim && + test_cmp master.good .git/refs/remotes/svnsim/master +' + +test_expect_success REMOTE_SVN 'fetch from a file:// url gives the same result' ' + git fetch svnfile +' + +test_expect_failure REMOTE_SVN 'the sha1 differ because the git-svn-id line in the commit msg contains the url' ' + test_cmp .git/refs/remotes/svnfile/master .git/refs/remotes/svnsim/master +' + +test_expect_success REMOTE_SVN 'mark-file regeneration' ' + # filter out any other marks, that can not be regenerated. Only up to 3 digit revisions are allowed here + grep ":[0-9]\{1,3\} " $MARKSPATH/svnsim.marks > $MARKSPATH/svnsim.marks.old && + rm $MARKSPATH/svnsim.marks && + git fetch svnsim && + test_cmp $MARKSPATH/svnsim.marks.old $MARKSPATH/svnsim.marks +' + +test_expect_success REMOTE_SVN 'incremental imports must lead to the same head' ' + SVNRMAX=3 && + export SVNRMAX && + init_git && + git fetch svnsim && + test_cmp .git/refs/svn/svnsim/master .git/refs/remotes/svnsim/master && + unset SVNRMAX && + git fetch svnsim && + test_cmp master.good .git/refs/remotes/svnsim/master +' + +test_debug 'git branch -a' + +test_done diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh index 749b75e8d4..4fea8d901b 100755 --- a/t/t9100-git-svn-basic.sh +++ b/t/t9100-git-svn-basic.sh @@ -306,5 +306,13 @@ test_expect_success 'git-svn works in a bare repository' ' git svn fetch ) && rm -rf bare-repo ' +test_expect_success 'git-svn works in in a repository with a gitdir: link' ' + mkdir worktree gitdir && + ( cd worktree && + git svn init "$svnrepo" && + git init --separate-git-dir ../gitdir && + git svn fetch ) && + rm -rf worktree gitdir + ' test_done diff --git a/t/t9114-git-svn-dcommit-merge.sh b/t/t9114-git-svn-dcommit-merge.sh index 3077851015..f524d2f383 100755 --- a/t/t9114-git-svn-dcommit-merge.sh +++ b/t/t9114-git-svn-dcommit-merge.sh @@ -48,7 +48,7 @@ test_expect_success 'setup svn repository' ' test_expect_success 'setup git mirror and merge' ' git svn init "$svnrepo" -t tags -T trunk -b branches && git svn fetch && - git checkout --track -b svn remotes/trunk && + git checkout -b svn remotes/trunk && git checkout -b merge && echo new file > new_file && git add new_file && diff --git a/t/t9147-git-svn-include-paths.sh b/t/t9147-git-svn-include-paths.sh new file mode 100755 index 0000000000..a90ff58629 --- /dev/null +++ b/t/t9147-git-svn-include-paths.sh @@ -0,0 +1,149 @@ +#!/bin/sh +# +# Copyright (c) 2013 Paul Walmsley - based on t9134 by Vitaly Shukela +# + +test_description='git svn property tests' +. ./lib-git-svn.sh + +test_expect_success 'setup test repository' ' + svn_cmd co "$svnrepo" s && + ( + cd s && + mkdir qqq www xxx && + echo test_qqq > qqq/test_qqq.txt && + echo test_www > www/test_www.txt && + echo test_xxx > xxx/test_xxx.txt && + svn_cmd add qqq && + svn_cmd add www && + svn_cmd add xxx && + svn_cmd commit -m "create some files" && + svn_cmd up && + echo hi >> www/test_www.txt && + svn_cmd commit -m "modify www/test_www.txt" && + svn_cmd up + ) +' + +test_expect_success 'clone an SVN repository with filter to include qqq directory' ' + git svn clone --include-paths="qqq" "$svnrepo" g && + echo test_qqq > expect && + for i in g/*/*.txt; do cat $i >> expect2; done && + test_cmp expect expect2 +' + + +test_expect_success 'init+fetch an SVN repository with included qqq directory' ' + git svn init "$svnrepo" c && + ( cd c && git svn fetch --include-paths="qqq" ) && + rm expect2 && + echo test_qqq > expect && + for i in c/*/*.txt; do cat $i >> expect2; done && + test_cmp expect expect2 +' + +test_expect_success 'verify include-paths config saved by clone' ' + ( + cd g && + git config --get svn-remote.svn.include-paths | fgrep "qqq" + ) +' + +test_expect_success 'SVN-side change outside of www' ' + ( + cd s && + echo b >> qqq/test_qqq.txt && + svn_cmd commit -m "SVN-side change outside of www" && + svn_cmd up && + svn_cmd log -v | fgrep "SVN-side change outside of www" + ) +' + +test_expect_success 'update git svn-cloned repo (config include)' ' + ( + cd g && + git svn rebase && + printf "test_qqq\nb\n" > expect && + for i in */*.txt; do cat $i >> expect2; done && + test_cmp expect2 expect && + rm expect expect2 + ) +' + +test_expect_success 'update git svn-cloned repo (option include)' ' + ( + cd c && + git svn rebase --include-paths="qqq" && + printf "test_qqq\nb\n" > expect && + for i in */*.txt; do cat $i >> expect2; done && + test_cmp expect2 expect && + rm expect expect2 + ) +' + +test_expect_success 'SVN-side change inside of ignored www' ' + ( + cd s && + echo zaq >> www/test_www.txt + svn_cmd commit -m "SVN-side change inside of www/test_www.txt" && + svn_cmd up && + svn_cmd log -v | fgrep "SVN-side change inside of www/test_www.txt" + ) +' + +test_expect_success 'update git svn-cloned repo (config include)' ' + ( + cd g && + git svn rebase && + printf "test_qqq\nb\n" > expect && + for i in */*.txt; do cat $i >> expect2; done && + test_cmp expect2 expect && + rm expect expect2 + ) +' + +test_expect_success 'update git svn-cloned repo (option include)' ' + ( + cd c && + git svn rebase --include-paths="qqq" && + printf "test_qqq\nb\n" > expect && + for i in */*.txt; do cat $i >> expect2; done && + test_cmp expect2 expect && + rm expect expect2 + ) +' + +test_expect_success 'SVN-side change in and out of included qqq' ' + ( + cd s && + echo cvf >> www/test_www.txt + echo ygg >> qqq/test_qqq.txt + svn_cmd commit -m "SVN-side change in and out of ignored www" && + svn_cmd up && + svn_cmd log -v | fgrep "SVN-side change in and out of ignored www" + ) +' + +test_expect_success 'update git svn-cloned repo again (config include)' ' + ( + cd g && + git svn rebase && + printf "test_qqq\nb\nygg\n" > expect && + for i in */*.txt; do cat $i >> expect2; done && + test_cmp expect2 expect && + rm expect expect2 + ) +' + +test_expect_success 'update git svn-cloned repo again (option include)' ' + ( + cd c && + git svn rebase --include-paths="qqq" && + printf "test_qqq\nb\nygg\n" > expect && + for i in */*.txt; do cat $i >> expect2; done && + test_cmp expect2 expect && + rm expect expect2 + ) +' + +test_done diff --git a/t/t9161-git-svn-mergeinfo-push.sh b/t/t9161-git-svn-mergeinfo-push.sh index 6ef0c0bde3..1eab7015c7 100755 --- a/t/t9161-git-svn-mergeinfo-push.sh +++ b/t/t9161-git-svn-mergeinfo-push.sh @@ -88,7 +88,6 @@ test_expect_success 'check reintegration mergeinfo' ' test "$mergeinfo" = "/branches/svnb1:2-4,7-9,13-18 /branches/svnb2:3,8,16-17 /branches/svnb3:4,9 -/branches/svnb4:5-6,10-12 /branches/svnb5:6,11" ' diff --git a/t/t9167-git-svn-cmd-branch-subproject.sh b/t/t9167-git-svn-cmd-branch-subproject.sh new file mode 100755 index 0000000000..53def876ed --- /dev/null +++ b/t/t9167-git-svn-cmd-branch-subproject.sh @@ -0,0 +1,48 @@ +#!/bin/sh +# +# Copyright (c) 2013 Tobias Schulte +# + +test_description='git svn branch for subproject clones' +. ./lib-git-svn.sh + +test_expect_success 'initialize svnrepo' ' + mkdir import && + ( + cd import && + mkdir -p trunk/project branches tags && + ( + cd trunk/project && + echo foo > foo + ) && + svn_cmd import -m "import for git-svn" . "$svnrepo" >/dev/null + ) && + rm -rf import && + svn_cmd co "$svnrepo"/trunk/project trunk/project && + ( + cd trunk/project && + echo bar >> foo && + svn_cmd ci -m "updated trunk" + ) && + rm -rf trunk +' + +test_expect_success 'import into git' ' + git svn init --trunk=trunk/project --branches=branches/*/project \ + --tags=tags/*/project "$svnrepo" && + git svn fetch && + git checkout remotes/trunk +' + +test_expect_success 'git svn branch tests' ' + test_must_fail git svn branch a && + git svn branch --parents a && + test_must_fail git svn branch -t tag1 && + git svn branch --parents -t tag1 && + test_must_fail git svn branch --tag tag2 && + git svn branch --parents --tag tag2 && + test_must_fail git svn tag tag3 && + git svn tag --parents tag3 +' + +test_done diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index b59be9a894..3fb3368903 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -19,14 +19,15 @@ then test_done fi -CVSROOT=$PWD/cvsroot +CVSROOT=$PWD/tmpcvsroot CVSWORK=$PWD/cvswork GIT_DIR=$PWD/.git export CVSROOT CVSWORK GIT_DIR rm -rf "$CVSROOT" "$CVSWORK" -mkdir "$CVSROOT" && + cvs init && +test -d "$CVSROOT" && cvs -Q co -d "$CVSWORK" . && echo >empty && git add empty && diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 2fcf269469..ac6f3b6af2 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -49,14 +49,6 @@ echo "$@"' >empty -test_expect_success 'setup: have pipes?' ' - rm -f frob && - if mkfifo frob - then - test_set_prereq PIPE - fi -' - ### ### series A ### diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh index 3e821f958b..34c2d8f49a 100755 --- a/t/t9350-fast-export.sh +++ b/t/t9350-fast-export.sh @@ -146,6 +146,12 @@ test_expect_success 'signed-tags=strip' ' ' +test_expect_success 'signed-tags=warn-strip' ' + git fast-export --signed-tags=warn-strip sign-your-name >output 2>err && + ! grep PGP output && + test -s err +' + test_expect_success 'setup submodule' ' git checkout -f master && @@ -303,7 +309,7 @@ test_expect_success 'dropping tag of filtered out object' ' ( cd limit-by-paths && git fast-export --tag-of-filtered-object=drop mytag -- there > output && - test_cmp output expected + test_cmp expected output ) ' @@ -320,7 +326,7 @@ test_expect_success 'rewriting tag of filtered out object' ' ( cd limit-by-paths && git fast-export --tag-of-filtered-object=rewrite mytag -- there > output && - test_cmp output expected + test_cmp expected output ) ' @@ -351,7 +357,7 @@ test_expect_failure 'no exact-ref revisions included' ' ( cd limit-by-paths && git fast-export master~2..master~1 > output && - test_cmp output expected + test_cmp expected output ) ' @@ -390,7 +396,7 @@ test_expect_success 'tree_tag-obj' 'git fast-export tree_tag-obj' test_expect_success 'tag-obj_tag' 'git fast-export tag-obj_tag' test_expect_success 'tag-obj_tag-obj' 'git fast-export tag-obj_tag-obj' -test_expect_success SYMLINKS 'directory becomes symlink' ' +test_expect_success 'directory becomes symlink' ' git init dirtosymlink && git init result && ( @@ -402,8 +408,7 @@ test_expect_success SYMLINKS 'directory becomes symlink' ' git add foo/world bar/world && git commit -q -mone && git rm -r foo && - ln -s bar foo && - git add foo && + test_ln_s_add bar foo && git commit -q -mtwo ) && ( @@ -440,4 +445,63 @@ test_expect_success 'fast-export quotes pathnames' ' ) ' +test_expect_success 'test bidirectionality' ' + >marks-cur && + >marks-new && + git init marks-test && + git fast-export --export-marks=marks-cur --import-marks=marks-cur --branches | \ + git --git-dir=marks-test/.git fast-import --export-marks=marks-new --import-marks=marks-new && + (cd marks-test && + git reset --hard && + echo Wohlauf > file && + git commit -a -m "back in time") && + git --git-dir=marks-test/.git fast-export --export-marks=marks-new --import-marks=marks-new --branches | \ + git fast-import --export-marks=marks-cur --import-marks=marks-cur +' + +cat > expected << EOF +blob +mark :13 +data 5 +bump + +commit refs/heads/master +mark :14 +author A U Thor <author@example.com> 1112912773 -0700 +committer C O Mitter <committer@example.com> 1112912773 -0700 +data 5 +bump +from :12 +M 100644 :13 file + +EOF + +test_expect_success 'avoid uninteresting refs' ' + > tmp-marks && + git fast-export --import-marks=tmp-marks \ + --export-marks=tmp-marks master > /dev/null && + git tag v1.0 && + git branch uninteresting && + echo bump > file && + git commit -a -m bump && + git fast-export --import-marks=tmp-marks \ + --export-marks=tmp-marks ^uninteresting ^v1.0 master > actual && + test_cmp expected actual +' + +cat > expected << EOF +reset refs/heads/master +from :14 + +EOF + +test_expect_success 'refs are updated even if no commits need to be exported' ' + > tmp-marks && + git fast-export --import-marks=tmp-marks \ + --export-marks=tmp-marks master > /dev/null && + git fast-export --import-marks=tmp-marks \ + --export-marks=tmp-marks master > actual && + test_cmp expected actual +' + test_done diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh index 806623e885..043138631b 100755 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@ -36,6 +36,7 @@ export CVSROOT CVS_SERVER rm -rf "$CVSWORK" "$SERVERDIR" test_expect_success 'setup' ' + git config push.default matching && echo >empty && git add empty && git commit -q -m "First Commit" && @@ -400,7 +401,7 @@ cat >expected.C <<EOF Line 0 ======= LINE 0 ->>>>>>> merge.3 +>>>>>>> merge.1.3 EOF for i in 1 2 3 4 5 6 7 8 @@ -505,6 +506,76 @@ test_expect_success 'cvs co -c (shows module database)' ' ' #------------ +# CVS LOG +#------------ + +# Known issues with git-cvsserver current log output: +# - Hard coded "lines: +2 -3" placeholder, instead of real numbers. +# - CVS normally does not internally add a blank first line +# nor a last line with nothing but a space to log messages. +# - The latest cvs 1.12.x server sends +0000 timezone (with some hidden "MT" +# tagging in the protocol), and if cvs 1.12.x client sees the MT tags, +# it converts to local time zone. git-cvsserver doesn't do the +0000 +# or the MT tags... +# - The latest 1.12.x releases add a "commitid:" field on to the end of the +# "date:" line (after "lines:"). Maybe we could stick git's commit id +# in it? Or does CVS expect a certain number of bits (too few for +# a full sha1)? +# +# Given the above, expect the following test to break if git-cvsserver's +# log output is improved. The test is just to ensure it doesn't +# accidentally get worse. + +sed -e 's/^x//' -e 's/SP$/ /' > "$WORKDIR/expect" <<EOF +x +xRCS file: $WORKDIR/gitcvs.git/master/merge,v +xWorking file: merge +xhead: 1.4 +xbranch: +xlocks: strict +xaccess list: +xsymbolic names: +xkeyword substitution: kv +xtotal revisions: 4; selected revisions: 4 +xdescription: +x---------------------------- +xrevision 1.4 +xdate: __DATE__; author: author; state: Exp; lines: +2 -3 +x +xMerge test (no-op) +xSP +x---------------------------- +xrevision 1.3 +xdate: __DATE__; author: author; state: Exp; lines: +2 -3 +x +xMerge test (conflict) +xSP +x---------------------------- +xrevision 1.2 +xdate: __DATE__; author: author; state: Exp; lines: +2 -3 +x +xMerge test (merge) +xSP +x---------------------------- +xrevision 1.1 +xdate: __DATE__; author: author; state: Exp; lines: +2 -3 +x +xMerge test (pre-merge) +xSP +x============================================================================= +EOF +expectStat="$?" + +cd "$WORKDIR" +test_expect_success 'cvs log' ' + cd cvswork && + test x"$expectStat" = x"0" && + GIT_CONFIG="$git_config" cvs log merge >../out && + sed -e "s%2[0-9][0-9][0-9]/[01][0-9]/[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]%__DATE__%" ../out > ../actual && + test_cmp ../expect ../actual +' + +#------------ # CVS ANNOTATE #------------ diff --git a/t/t9401-git-cvsserver-crlf.sh b/t/t9401-git-cvsserver-crlf.sh index ff6d6fb473..8c3db76301 100755 --- a/t/t9401-git-cvsserver-crlf.sh +++ b/t/t9401-git-cvsserver-crlf.sh @@ -38,6 +38,25 @@ not_present() { fi } +check_status_options() { + (cd "$1" && + GIT_CONFIG="$git_config" cvs -Q status "$2" > "${WORKDIR}/status.out" 2>&1 + ) + if [ x"$?" != x"0" ] ; then + echo "Error from cvs status: $1 $2" >> "${WORKDIR}/marked.log" + return 1; + fi + got="$(sed -n -e 's/^[ ]*Sticky Options:[ ]*//p' "${WORKDIR}/status.out")" + expect="$3" + if [ x"$expect" = x"" ] ; then + expect="(none)" + fi + test x"$got" = x"$expect" + stat=$? + echo "cvs status: $1 $2 $stat '$3' '$got'" >> "${WORKDIR}/marked.log" + return $stat +} + cvs >/dev/null 2>&1 if test $? -ne 1 then @@ -65,6 +84,7 @@ export CVSROOT CVS_SERVER rm -rf "$CVSWORK" "$SERVERDIR" test_expect_success 'setup' ' + git config push.default matching && echo "Simple text file" >textfile.c && echo "File with embedded NUL: Q <- there" | q_to_nul > binfile.bin && mkdir subdir && @@ -233,6 +253,22 @@ test_expect_success 'cvs co another copy (guess)' ' marked_as cvswork2/subdir newfile.c "" ' +test_expect_success 'cvs status - sticky options' ' + check_status_options cvswork2 textfile.c "" && + check_status_options cvswork2 binfile.bin -kb && + check_status_options cvswork2 .gitattributes "" && + check_status_options cvswork2 mixedUp.c -kb && + check_status_options cvswork2 multiline.c -kb && + check_status_options cvswork2 multilineTxt.c "" && + check_status_options cvswork2/subdir withCr.bin -kb && + check_status_options cvswork2 subdir/withCr.bin -kb && + check_status_options cvswork2/subdir file.h "" && + check_status_options cvswork2 subdir/file.h "" && + check_status_options cvswork2/subdir unspecified.other "" && + check_status_options cvswork2/subdir newfile.bin "" && + check_status_options cvswork2/subdir newfile.c "" +' + test_expect_success 'add text (guess)' ' (cd cvswork && echo "simpleText" > simpleText.c && diff --git a/t/t9402-git-cvsserver-refs.sh b/t/t9402-git-cvsserver-refs.sh new file mode 100755 index 0000000000..db69af2cff --- /dev/null +++ b/t/t9402-git-cvsserver-refs.sh @@ -0,0 +1,551 @@ +#!/bin/sh + +test_description='git-cvsserver and git refspecs + +tests ability for git-cvsserver to switch between and compare +tags, branches and other git refspecs' + +. ./test-lib.sh + +######### + +check_start_tree() { + rm -f "$WORKDIR/list.expected" + echo "start $1" >>"${WORKDIR}/check.log" +} + +check_file() { + sandbox="$1" + file="$2" + ver="$3" + GIT_DIR=$SERVERDIR git show "${ver}:${file}" \ + >"$WORKDIR/check.got" 2>"$WORKDIR/check.stderr" + test_cmp "$WORKDIR/check.got" "$sandbox/$file" + stat=$? + echo "check_file $sandbox $file $ver : $stat" >>"$WORKDIR/check.log" + echo "$file" >>"$WORKDIR/list.expected" + return $stat +} + +check_end_tree() { + sandbox="$1" && + find "$sandbox" -name CVS -prune -o -type f -print >"$WORKDIR/list.actual" && + sort <"$WORKDIR/list.expected" >expected && + sort <"$WORKDIR/list.actual" | sed -e "s%cvswork/%%" >actual && + test_cmp expected actual && + rm expected actual +} + +check_end_full_tree() { + sandbox="$1" && + sort <"$WORKDIR/list.expected" >expected && + find "$sandbox" -name CVS -prune -o -type f -print | + sed -e "s%$sandbox/%%" | sort >act1 && + test_cmp expected act1 && + git ls-tree --name-only -r "$2" | sort >act2 && + test_cmp expected act2 && + rm expected act1 act2 +} + +######### + +check_diff() { + diffFile="$1" + vOld="$2" + vNew="$3" + rm -rf diffSandbox + git clone -q -n . diffSandbox && + ( + cd diffSandbox && + git checkout "$vOld" && + git apply -p0 --index <"../$diffFile" && + git diff --exit-code "$vNew" + ) >check_diff_apply.out 2>&1 +} + +######### + +cvs >/dev/null 2>&1 +if test $? -ne 1 +then + skip_all='skipping git-cvsserver tests, cvs not found' + test_done +fi +if ! test_have_prereq PERL +then + skip_all='skipping git-cvsserver tests, perl not available' + test_done +fi +"$PERL_PATH" -e 'use DBI; use DBD::SQLite' >/dev/null 2>&1 || { + skip_all='skipping git-cvsserver tests, Perl SQLite interface unavailable' + test_done +} + +unset GIT_DIR GIT_CONFIG +WORKDIR=$(pwd) +SERVERDIR=$(pwd)/gitcvs.git +git_config="$SERVERDIR/config" +CVSROOT=":fork:$SERVERDIR" +CVSWORK="$(pwd)/cvswork" +CVS_SERVER=git-cvsserver +export CVSROOT CVS_SERVER + +rm -rf "$CVSWORK" "$SERVERDIR" +test_expect_success 'setup v1, b1' ' + echo "Simple text file" >textfile.c && + echo "t2" >t2 && + mkdir adir && + echo "adir/afile line1" >adir/afile && + echo "adir/afile line2" >>adir/afile && + echo "adir/afile line3" >>adir/afile && + echo "adir/afile line4" >>adir/afile && + echo "adir/a2file" >>adir/a2file && + mkdir adir/bdir && + echo "adir/bdir/bfile line 1" >adir/bdir/bfile && + echo "adir/bdir/bfile line 2" >>adir/bdir/bfile && + echo "adir/bdir/b2file" >adir/bdir/b2file && + git add textfile.c t2 adir && + git commit -q -m "First Commit (v1)" && + git tag v1 && + git branch b1 && + git clone -q --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 && + GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true && + GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log" +' + +rm -rf cvswork +test_expect_success 'cvs co v1' ' + cvs -f -Q co -r v1 -d cvswork master >cvs.log 2>&1 && + check_start_tree cvswork && + check_file cvswork textfile.c v1 && + check_file cvswork t2 v1 && + check_file cvswork adir/afile v1 && + check_file cvswork adir/a2file v1 && + check_file cvswork adir/bdir/bfile v1 && + check_file cvswork adir/bdir/b2file v1 && + check_end_tree cvswork +' + +rm -rf cvswork +test_expect_success 'cvs co b1' ' + cvs -f co -r b1 -d cvswork master >cvs.log 2>&1 && + check_start_tree cvswork && + check_file cvswork textfile.c v1 && + check_file cvswork t2 v1 && + check_file cvswork adir/afile v1 && + check_file cvswork adir/a2file v1 && + check_file cvswork adir/bdir/bfile v1 && + check_file cvswork adir/bdir/b2file v1 && + check_end_tree cvswork +' + +test_expect_success 'cvs co b1 [cvswork3]' ' + cvs -f co -r b1 -d cvswork3 master >cvs.log 2>&1 && + check_start_tree cvswork3 && + check_file cvswork3 textfile.c v1 && + check_file cvswork3 t2 v1 && + check_file cvswork3 adir/afile v1 && + check_file cvswork3 adir/a2file v1 && + check_file cvswork3 adir/bdir/bfile v1 && + check_file cvswork3 adir/bdir/b2file v1 && + check_end_full_tree cvswork3 v1 +' + +test_expect_success 'edit cvswork3 and save diff' ' + ( + cd cvswork3 && + sed -e "s/line1/line1 - data/" adir/afile >adir/afileNEW && + mv -f adir/afileNEW adir/afile && + echo "afile5" >adir/afile5 && + rm t2 && + cvs -f add adir/afile5 && + cvs -f rm t2 && + ! cvs -f diff -N -u >"$WORKDIR/cvswork3edit.diff" + ) +' + +test_expect_success 'setup v1.2 on b1' ' + git checkout b1 && + echo "new v1.2" >t3 && + rm t2 && + sed -e "s/line3/line3 - more data/" adir/afile >adir/afileNEW && + mv -f adir/afileNEW adir/afile && + rm adir/a2file && + echo "a3file" >>adir/a3file && + echo "bfile line 3" >>adir/bdir/bfile && + rm adir/bdir/b2file && + echo "b3file" >adir/bdir/b3file && + mkdir cdir && + echo "cdir/cfile" >cdir/cfile && + git add -A cdir adir t3 t2 && + git commit -q -m 'v1.2' && + git tag v1.2 && + git push --tags gitcvs.git b1:b1 +' + +test_expect_success 'cvs -f up (on b1 adir)' ' + ( cd cvswork/adir && cvs -f up -d ) >cvs.log 2>&1 && + check_start_tree cvswork && + check_file cvswork textfile.c v1 && + check_file cvswork t2 v1 && + check_file cvswork adir/afile v1.2 && + check_file cvswork adir/a3file v1.2 && + check_file cvswork adir/bdir/bfile v1.2 && + check_file cvswork adir/bdir/b3file v1.2 && + check_end_tree cvswork +' + +test_expect_success 'cvs up (on b1 /)' ' + ( cd cvswork && cvs -f up -d ) >cvs.log 2>&1 && + check_start_tree cvswork && + check_file cvswork textfile.c v1.2 && + check_file cvswork t3 v1.2 && + check_file cvswork adir/afile v1.2 && + check_file cvswork adir/a3file v1.2 && + check_file cvswork adir/bdir/bfile v1.2 && + check_file cvswork adir/bdir/b3file v1.2 && + check_file cvswork cdir/cfile v1.2 && + check_end_tree cvswork +' + +# Make sure "CVS/Tag" files didn't get messed up: +test_expect_success 'cvs up (on b1 /) (again; check CVS/Tag files)' ' + ( cd cvswork && cvs -f up -d ) >cvs.log 2>&1 && + check_start_tree cvswork && + check_file cvswork textfile.c v1.2 && + check_file cvswork t3 v1.2 && + check_file cvswork adir/afile v1.2 && + check_file cvswork adir/a3file v1.2 && + check_file cvswork adir/bdir/bfile v1.2 && + check_file cvswork adir/bdir/b3file v1.2 && + check_file cvswork cdir/cfile v1.2 && + check_end_tree cvswork +' + +# update to another version: +test_expect_success 'cvs up -r v1' ' + ( cd cvswork && cvs -f up -r v1 ) >cvs.log 2>&1 && + check_start_tree cvswork && + check_file cvswork textfile.c v1 && + check_file cvswork t2 v1 && + check_file cvswork adir/afile v1 && + check_file cvswork adir/a2file v1 && + check_file cvswork adir/bdir/bfile v1 && + check_file cvswork adir/bdir/b2file v1 && + check_end_tree cvswork +' + +test_expect_success 'cvs up' ' + ( cd cvswork && cvs -f up ) >cvs.log 2>&1 && + check_start_tree cvswork && + check_file cvswork textfile.c v1 && + check_file cvswork t2 v1 && + check_file cvswork adir/afile v1 && + check_file cvswork adir/a2file v1 && + check_file cvswork adir/bdir/bfile v1 && + check_file cvswork adir/bdir/b2file v1 && + check_end_tree cvswork +' + +test_expect_success 'cvs up (again; check CVS/Tag files)' ' + ( cd cvswork && cvs -f up -d ) >cvs.log 2>&1 && + check_start_tree cvswork && + check_file cvswork textfile.c v1 && + check_file cvswork t2 v1 && + check_file cvswork adir/afile v1 && + check_file cvswork adir/a2file v1 && + check_file cvswork adir/bdir/bfile v1 && + check_file cvswork adir/bdir/b2file v1 && + check_end_tree cvswork +' + +test_expect_success 'setup simple b2' ' + git branch b2 v1 && + git push --tags gitcvs.git b2:b2 +' + +test_expect_success 'cvs co b2 [into cvswork2]' ' + cvs -f co -r b2 -d cvswork2 master >cvs.log 2>&1 && + check_start_tree cvswork && + check_file cvswork textfile.c v1 && + check_file cvswork t2 v1 && + check_file cvswork adir/afile v1 && + check_file cvswork adir/a2file v1 && + check_file cvswork adir/bdir/bfile v1 && + check_file cvswork adir/bdir/b2file v1 && + check_end_tree cvswork +' + +test_expect_success 'root dir edit [cvswork2]' ' + ( + cd cvswork2 && echo "Line 2" >>textfile.c && + ! cvs -f diff -u >"$WORKDIR/cvsEdit1.diff" && + cvs -f commit -m "edit textfile.c" textfile.c + ) >cvsEdit1.log 2>&1 +' + +test_expect_success 'root dir rm file [cvswork2]' ' + ( + cd cvswork2 && + cvs -f rm -f t2 && + cvs -f diff -u >../cvsEdit2-empty.diff && + ! cvs -f diff -N -u >"$WORKDIR/cvsEdit2-N.diff" && + cvs -f commit -m "rm t2" + ) >cvsEdit2.log 2>&1 +' + +test_expect_success 'subdir edit/add/rm files [cvswork2]' ' + ( + cd cvswork2 && + sed -e "s/line 1/line 1 (v2)/" adir/bdir/bfile >adir/bdir/bfileNEW && + mv -f adir/bdir/bfileNEW adir/bdir/bfile && + rm adir/bdir/b2file && + cd adir && + cvs -f rm bdir/b2file && + echo "4th file" >bdir/b4file && + cvs -f add bdir/b4file && + ! cvs -f diff -N -u >"$WORKDIR/cvsEdit3.diff" && + git fetch gitcvs.git b2:b2 && + ( + cd .. && + ! cvs -f diff -u -N -r v1.2 >"$WORKDIR/cvsEdit3-v1.2.diff" && + ! cvs -f diff -u -N -r v1.2 -r v1 >"$WORKDIR/cvsEdit3-v1.2-v1.diff" + ) && + cvs -f commit -m "various add/rm/edit" + ) >cvs.log 2>&1 +' + +test_expect_success 'validate result of edits [cvswork2]' ' + git fetch gitcvs.git b2:b2 && + git tag v2 b2 && + git push --tags gitcvs.git b2:b2 && + check_start_tree cvswork2 && + check_file cvswork2 textfile.c v2 && + check_file cvswork2 adir/afile v2 && + check_file cvswork2 adir/a2file v2 && + check_file cvswork2 adir/bdir/bfile v2 && + check_file cvswork2 adir/bdir/b4file v2 && + check_end_full_tree cvswork2 v2 +' + +test_expect_success 'validate basic diffs saved during above cvswork2 edits' ' + test $(grep Index: cvsEdit1.diff | wc -l) = 1 && + test_must_be_empty cvsEdit2-empty.diff && + test $(grep Index: cvsEdit2-N.diff | wc -l) = 1 && + test $(grep Index: cvsEdit3.diff | wc -l) = 3 && + rm -rf diffSandbox && + git clone -q -n . diffSandbox && + ( + cd diffSandbox && + git checkout v1 && + git apply -p0 --index <"$WORKDIR/cvsEdit1.diff" && + git apply -p0 --index <"$WORKDIR/cvsEdit2-N.diff" && + git apply -p0 --directory=adir --index <"$WORKDIR/cvsEdit3.diff" && + git diff --exit-code v2 + ) >"check_diff_apply.out" 2>&1 +' + +test_expect_success 'validate v1.2 diff saved during last cvswork2 edit' ' + test $(grep Index: cvsEdit3-v1.2.diff | wc -l) = 9 && + check_diff cvsEdit3-v1.2.diff v1.2 v2 +' + +test_expect_success 'validate v1.2 v1 diff saved during last cvswork2 edit' ' + test $(grep Index: cvsEdit3-v1.2-v1.diff | wc -l) = 9 && + check_diff cvsEdit3-v1.2-v1.diff v1.2 v1 +' + +test_expect_success 'cvs up [cvswork2]' ' + ( cd cvswork2 && cvs -f up ) >cvs.log 2>&1 && + check_start_tree cvswork2 && + check_file cvswork2 textfile.c v2 && + check_file cvswork2 adir/afile v2 && + check_file cvswork2 adir/a2file v2 && + check_file cvswork2 adir/bdir/bfile v2 && + check_file cvswork2 adir/bdir/b4file v2 && + check_end_full_tree cvswork2 v2 +' + +test_expect_success 'cvs up -r b2 [back to cvswork]' ' + ( cd cvswork && cvs -f up -r b2 ) >cvs.log 2>&1 && + check_start_tree cvswork && + check_file cvswork textfile.c v2 && + check_file cvswork adir/afile v2 && + check_file cvswork adir/a2file v2 && + check_file cvswork adir/bdir/bfile v2 && + check_file cvswork adir/bdir/b4file v2 && + check_end_full_tree cvswork v2 +' + +test_expect_success 'cvs up -r b1' ' + ( cd cvswork && cvs -f up -r b1 ) >cvs.log 2>&1 && + check_start_tree cvswork && + check_file cvswork textfile.c v1.2 && + check_file cvswork t3 v1.2 && + check_file cvswork adir/afile v1.2 && + check_file cvswork adir/a3file v1.2 && + check_file cvswork adir/bdir/bfile v1.2 && + check_file cvswork adir/bdir/b3file v1.2 && + check_file cvswork cdir/cfile v1.2 && + check_end_full_tree cvswork v1.2 +' + +test_expect_success 'cvs up -A' ' + ( cd cvswork && cvs -f up -A ) >cvs.log 2>&1 && + check_start_tree cvswork && + check_file cvswork textfile.c v1 && + check_file cvswork t2 v1 && + check_file cvswork adir/afile v1 && + check_file cvswork adir/a2file v1 && + check_file cvswork adir/bdir/bfile v1 && + check_file cvswork adir/bdir/b2file v1 && + check_end_full_tree cvswork v1 +' + +test_expect_success 'cvs up (check CVS/Tag files)' ' + ( cd cvswork && cvs -f up ) >cvs.log 2>&1 && + check_start_tree cvswork && + check_file cvswork textfile.c v1 && + check_file cvswork t2 v1 && + check_file cvswork adir/afile v1 && + check_file cvswork adir/a2file v1 && + check_file cvswork adir/bdir/bfile v1 && + check_file cvswork adir/bdir/b2file v1 && + check_end_full_tree cvswork v1 +' + +# This is not really legal CVS, but it seems to work anyway: +test_expect_success 'cvs up -r heads/b1' ' + ( cd cvswork && cvs -f up -r heads/b1 ) >cvs.log 2>&1 && + check_start_tree cvswork && + check_file cvswork textfile.c v1.2 && + check_file cvswork t3 v1.2 && + check_file cvswork adir/afile v1.2 && + check_file cvswork adir/a3file v1.2 && + check_file cvswork adir/bdir/bfile v1.2 && + check_file cvswork adir/bdir/b3file v1.2 && + check_file cvswork cdir/cfile v1.2 && + check_end_full_tree cvswork v1.2 +' + +# But this should work even if CVS client checks -r more carefully: +test_expect_success 'cvs up -r heads_-s-b2 (cvsserver escape mechanism)' ' + ( cd cvswork && cvs -f up -r heads_-s-b2 ) >cvs.log 2>&1 && + check_start_tree cvswork && + check_file cvswork textfile.c v2 && + check_file cvswork adir/afile v2 && + check_file cvswork adir/a2file v2 && + check_file cvswork adir/bdir/bfile v2 && + check_file cvswork adir/bdir/b4file v2 && + check_end_full_tree cvswork v2 +' + +v1hash=$(git rev-parse v1) +test_expect_success 'cvs up -r $(git rev-parse v1)' ' + test -n "$v1hash" && + ( cd cvswork && cvs -f up -r "$v1hash" ) >cvs.log 2>&1 && + check_start_tree cvswork && + check_file cvswork textfile.c v1 && + check_file cvswork t2 v1 && + check_file cvswork adir/afile v1 && + check_file cvswork adir/a2file v1 && + check_file cvswork adir/bdir/bfile v1 && + check_file cvswork adir/bdir/b2file v1 && + check_end_full_tree cvswork v1 +' + +test_expect_success 'cvs diff -r v1 -u' ' + ( cd cvswork && cvs -f diff -r v1 -u ) >cvsDiff.out 2>cvs.log && + test_must_be_empty cvsDiff.out && + test_must_be_empty cvs.log +' + +test_expect_success 'cvs diff -N -r v2 -u' ' + ( cd cvswork && ! cvs -f diff -N -r v2 -u ) >cvsDiff.out 2>cvs.log && + test_must_be_empty cvs.log && + test -s cvsDiff.out && + check_diff cvsDiff.out v2 v1 >check_diff.out 2>&1 +' + +test_expect_success 'cvs diff -N -r v2 -r v1.2' ' + ( cd cvswork && ! cvs -f diff -N -r v2 -r v1.2 -u ) >cvsDiff.out 2>cvs.log && + test_must_be_empty cvs.log && + test -s cvsDiff.out && + check_diff cvsDiff.out v2 v1.2 >check_diff.out 2>&1 +' + +test_expect_success 'apply early [cvswork3] diff to b3' ' + git clone -q . gitwork3 && + ( + cd gitwork3 && + git checkout -b b3 v1 && + git apply -p0 --index <"$WORKDIR/cvswork3edit.diff" && + git commit -m "cvswork3 edits applied" + ) && + git fetch gitwork3 b3:b3 && + git tag v3 b3 +' + +test_expect_success 'check [cvswork3] diff' ' + ( cd cvswork3 && ! cvs -f diff -N -u ) >"$WORKDIR/cvsDiff.out" 2>cvs.log && + test_must_be_empty cvs.log && + test -s cvsDiff.out && + test $(grep Index: cvsDiff.out | wc -l) = 3 && + test_cmp cvsDiff.out cvswork3edit.diff && + check_diff cvsDiff.out v1 v3 >check_diff.out 2>&1 +' + +test_expect_success 'merge early [cvswork3] b3 with b1' ' + ( cd gitwork3 && git merge "message" HEAD b1 ) && + git fetch gitwork3 b3:b3 && + git tag v3merged b3 && + git push --tags gitcvs.git b3:b3 +' + +# This test would fail if cvsserver properly created a ".#afile"* file +# for the merge. +# TODO: Validate that the .# file was saved properly, and then +# delete/ignore it when checking the tree. +test_expect_success 'cvs up dirty [cvswork3]' ' + ( + cd cvswork3 && + cvs -f up && + ! cvs -f diff -N -u >"$WORKDIR/cvsDiff.out" + ) >cvs.log 2>&1 && + test -s cvsDiff.out && + test $(grep Index: cvsDiff.out | wc -l) = 2 && + check_start_tree cvswork3 && + check_file cvswork3 textfile.c v3merged && + check_file cvswork3 t3 v3merged && + check_file cvswork3 adir/afile v3merged && + check_file cvswork3 adir/a3file v3merged && + check_file cvswork3 adir/afile5 v3merged && + check_file cvswork3 adir/bdir/bfile v3merged && + check_file cvswork3 adir/bdir/b3file v3merged && + check_file cvswork3 cdir/cfile v3merged && + check_end_full_tree cvswork3 v3merged +' + +# TODO: test cvs status + +test_expect_success 'cvs commit [cvswork3]' ' + ( + cd cvswork3 && + cvs -f commit -m "dirty sandbox after auto-merge" + ) >cvs.log 2>&1 && + check_start_tree cvswork3 && + check_file cvswork3 textfile.c v3merged && + check_file cvswork3 t3 v3merged && + check_file cvswork3 adir/afile v3merged && + check_file cvswork3 adir/a3file v3merged && + check_file cvswork3 adir/afile5 v3merged && + check_file cvswork3 adir/bdir/bfile v3merged && + check_file cvswork3 adir/bdir/b3file v3merged && + check_file cvswork3 cdir/cfile v3merged && + check_end_full_tree cvswork3 v3merged && + git fetch gitcvs.git b3:b4 && + git tag v4.1 b4 && + git diff --exit-code v4.1 v3merged >check_diff_apply.out 2>&1 +' + +test_done diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh index 90bb6050c1..6fca19353d 100755 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@ -156,10 +156,10 @@ test_expect_success \ git commit -a -m "File renamed." && gitweb_run "p=.git;a=commitdiff"' -test_expect_success SYMLINKS \ +test_expect_success \ 'commitdiff(0): file to symlink' \ 'rm renamed_file && - ln -s file renamed_file && + test_ln_s_add file renamed_file && git commit -a -m "File to symlink." && gitweb_run "p=.git;a=commitdiff"' @@ -212,15 +212,14 @@ test_expect_success \ # ---------------------------------------------------------------------- # commitdiff testing (taken from t4114-apply-typechange.sh) -test_expect_success SYMLINKS 'setup typechange commits' ' +test_expect_success 'setup typechange commits' ' echo "hello world" > foo && echo "hi planet" > bar && git update-index --add foo bar && git commit -m initial && git branch initial && rm -f foo && - ln -s bar foo && - git update-index foo && + test_ln_s_add bar foo && git commit -m "foo symlinked to bar" && git branch foo-symlinked-to-bar && rm -f foo && @@ -361,11 +360,7 @@ test_expect_success \ echo "Changed" >> 04-rename-to && test_chmod +x 05-mode-change && rm -f 06-file-or-symlink && - if test_have_prereq SYMLINKS; then - ln -s 01-change 06-file-or-symlink - else - printf %s 01-change > 06-file-or-symlink - fi && + test_ln_s_add 01-change 06-file-or-symlink && echo "Changed and have mode changed" > 07-change-mode-change && test_chmod +x 07-change-mode-change && git commit -a -m "Large commit" && @@ -539,8 +534,7 @@ test_expect_success \ test_when_finished "GIT_COMMITTER_NAME=\"C O Mitter\"" && echo "ISO-8859-1" >> file && git add file && - git config i18n.commitencoding ISO-8859-1 && - test_when_finished "git config --unset i18n.commitencoding" && + test_config i18n.commitencoding ISO-8859-1 && git commit -F "$TEST_DIRECTORY"/t3900/ISO8859-1.txt && gitweb_run "p=.git;a=commit"' diff --git a/t/t9501-gitweb-standalone-http-status.sh b/t/t9501-gitweb-standalone-http-status.sh index ef86948d21..d3a5bac754 100755 --- a/t/t9501-gitweb-standalone-http-status.sh +++ b/t/t9501-gitweb-standalone-http-status.sh @@ -130,7 +130,8 @@ test_expect_success DATE_PARSER 'modification: feed last-modified' ' 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" && + HTTP_IF_MODIFIED_SINCE="Wed, 6 Apr 2005 22:14:13 +0000" && + export HTTP_IF_MODIFIED_SINCE && test_when_finished "unset HTTP_IF_MODIFIED_SINCE" && gitweb_run "p=.git;a=atom;h=master" && grep "Status: 200 OK" gitweb.headers @@ -138,7 +139,8 @@ test_expect_success DATE_PARSER 'modification: feed if-modified-since (modified) 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" && + HTTP_IF_MODIFIED_SINCE="Thu, 7 Apr 2005 22:14:13 +0000" && + export HTTP_IF_MODIFIED_SINCE && test_when_finished "unset HTTP_IF_MODIFIED_SINCE" && gitweb_run "p=.git;a=atom;h=master" && grep "Status: 304 Not Modified" gitweb.headers @@ -153,7 +155,8 @@ test_expect_success DATE_PARSER 'modification: snapshot last-modified' ' 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" && + HTTP_IF_MODIFIED_SINCE="Wed, 6 Apr 2005 22:14:13 +0000" && + export HTTP_IF_MODIFIED_SINCE && test_when_finished "unset HTTP_IF_MODIFIED_SINCE" && gitweb_run "p=.git;a=snapshot;h=master;sf=tgz" && grep "Status: 200 OK" gitweb.headers @@ -161,7 +164,8 @@ test_expect_success DATE_PARSER 'modification: snapshot if-modified-since (modif 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" && + HTTP_IF_MODIFIED_SINCE="Thu, 7 Apr 2005 22:14:13 +0000" && + export HTTP_IF_MODIFIED_SINCE && 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 @@ -170,7 +174,8 @@ 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" && + HTTP_IF_MODIFIED_SINCE="Wed, 6 Apr 2005 22:14:13 +0000" && + export HTTP_IF_MODIFIED_SINCE && test_when_finished "unset HTTP_IF_MODIFIED_SINCE" && gitweb_run "p=.git;a=snapshot;h=$ID;sf=tgz" && grep "Status: 200 OK" gitweb.headers && diff --git a/t/t9502-gitweb-standalone-parse-output.sh b/t/t9502-gitweb-standalone-parse-output.sh index 3a8e7d3f5a..86dfee2e4f 100755 --- a/t/t9502-gitweb-standalone-parse-output.sh +++ b/t/t9502-gitweb-standalone-parse-output.sh @@ -40,7 +40,7 @@ check_snapshot () { echo "basename=$basename" grep "filename=.*$basename.tar" gitweb.headers >/dev/null 2>&1 && "$TAR" tf gitweb.body >file_list && - ! grep -v "^$prefix/" file_list + ! grep -v -e "^$prefix$" -e "^$prefix/" -e "^pax_global_header$" file_list } test_expect_success setup ' diff --git a/t/t9604-cvsimport-timestamps.sh b/t/t9604-cvsimport-timestamps.sh new file mode 100755 index 0000000000..1fd51423ee --- /dev/null +++ b/t/t9604-cvsimport-timestamps.sh @@ -0,0 +1,71 @@ +#!/bin/sh + +test_description='git cvsimport timestamps' +. ./lib-cvs.sh + +setup_cvs_test_repository t9604 + +test_expect_success 'check timestamps are UTC (TZ=CST6CDT)' ' + + TZ=CST6CDT git cvsimport -p"-x" -C module-1 module && + git cvsimport -p"-x" -C module-1 module && + ( + cd module-1 && + git log --format="%s %ai" + ) >actual-1 && + cat >expect-1 <<-EOF && + Rev 16 2006-10-29 07:00:01 +0000 + Rev 15 2006-10-29 06:59:59 +0000 + Rev 14 2006-04-02 08:00:01 +0000 + Rev 13 2006-04-02 07:59:59 +0000 + Rev 12 2005-12-01 00:00:00 +0000 + Rev 11 2005-11-01 00:00:00 +0000 + Rev 10 2005-10-01 00:00:00 +0000 + Rev 9 2005-09-01 00:00:00 +0000 + Rev 8 2005-08-01 00:00:00 +0000 + Rev 7 2005-07-01 00:00:00 +0000 + Rev 6 2005-06-01 00:00:00 +0000 + Rev 5 2005-05-01 00:00:00 +0000 + Rev 4 2005-04-01 00:00:00 +0000 + Rev 3 2005-03-01 00:00:00 +0000 + Rev 2 2005-02-01 00:00:00 +0000 + Rev 1 2005-01-01 00:00:00 +0000 + EOF + test_cmp actual-1 expect-1 +' + +test_expect_success 'check timestamps with author-specific timezones' ' + + cat >cvs-authors <<-EOF && + user1=User One <user1@domain.org> + user2=User Two <user2@domain.org> CST6CDT + user3=User Three <user3@domain.org> EST5EDT + user4=User Four <user4@domain.org> MST7MDT + EOF + git cvsimport -p"-x" -A cvs-authors -C module-2 module && + ( + cd module-2 && + git log --format="%s %ai %an" + ) >actual-2 && + cat >expect-2 <<-EOF && + Rev 16 2006-10-29 01:00:01 -0600 User Two + Rev 15 2006-10-29 01:59:59 -0500 User Two + Rev 14 2006-04-02 03:00:01 -0500 User Two + Rev 13 2006-04-02 01:59:59 -0600 User Two + Rev 12 2005-11-30 17:00:00 -0700 User Four + Rev 11 2005-10-31 19:00:00 -0500 User Three + Rev 10 2005-09-30 19:00:00 -0500 User Two + Rev 9 2005-09-01 00:00:00 +0000 User One + Rev 8 2005-07-31 18:00:00 -0600 User Four + Rev 7 2005-06-30 20:00:00 -0400 User Three + Rev 6 2005-05-31 19:00:00 -0500 User Two + Rev 5 2005-05-01 00:00:00 +0000 User One + Rev 4 2005-03-31 17:00:00 -0700 User Four + Rev 3 2005-02-28 19:00:00 -0500 User Three + Rev 2 2005-01-31 18:00:00 -0600 User Two + Rev 1 2005-01-01 00:00:00 +0000 User One + EOF + test_cmp actual-2 expect-2 +' + +test_done diff --git a/t/t9604/cvsroot/.gitattributes b/t/t9604/cvsroot/.gitattributes new file mode 100644 index 0000000000..562b12e16e --- /dev/null +++ b/t/t9604/cvsroot/.gitattributes @@ -0,0 +1 @@ +* -whitespace diff --git a/t/t9604/cvsroot/CVSROOT/.gitignore b/t/t9604/cvsroot/CVSROOT/.gitignore new file mode 100644 index 0000000000..3bb9b34173 --- /dev/null +++ b/t/t9604/cvsroot/CVSROOT/.gitignore @@ -0,0 +1,2 @@ +history +val-tags diff --git a/t/t9604/cvsroot/module/a,v b/t/t9604/cvsroot/module/a,v new file mode 100644 index 0000000000..80658c3c8d --- /dev/null +++ b/t/t9604/cvsroot/module/a,v @@ -0,0 +1,264 @@ +head 1.16; +access; +symbols; +locks; strict; +comment @# @; + + +1.16 +date 2006.10.29.07.00.01; author user2; state Exp; +branches; +next 1.15; + +1.15 +date 2006.10.29.06.59.59; author user2; state Exp; +branches; +next 1.14; + +1.14 +date 2006.04.02.08.00.01; author user2; state Exp; +branches; +next 1.13; + +1.13 +date 2006.04.02.07.59.59; author user2; state Exp; +branches; +next 1.12; + +1.12 +date 2005.12.01.00.00.00; author user4; state Exp; +branches; +next 1.11; + +1.11 +date 2005.11.01.00.00.00; author user3; state Exp; +branches; +next 1.10; + +1.10 +date 2005.10.01.00.00.00; author user2; state Exp; +branches; +next 1.9; + +1.9 +date 2005.09.01.00.00.00; author user1; state Exp; +branches; +next 1.8; + +1.8 +date 2005.08.01.00.00.00; author user4; state Exp; +branches; +next 1.7; + +1.7 +date 2005.07.01.00.00.00; author user3; state Exp; +branches; +next 1.6; + +1.6 +date 2005.06.01.00.00.00; author user2; state Exp; +branches; +next 1.5; + +1.5 +date 2005.05.01.00.00.00; author user1; state Exp; +branches; +next 1.4; + +1.4 +date 2005.04.01.00.00.00; author user4; state Exp; +branches; +next 1.3; + +1.3 +date 2005.03.01.00.00.00; author user3; state Exp; +branches; +next 1.2; + +1.2 +date 2005.02.01.00.00.00; author user2; state Exp; +branches; +next 1.1; + +1.1 +date 2005.01.01.00.00.00; author user1; state Exp; +branches; +next ; + + +desc +@@ + + +1.16 +log +@Rev 16 +@ +text +@Rev 16 +@ + + +1.15 +log +@Rev 15 +@ +text +@d1 1 +a1 1 +Rev 15 +@ + + +1.14 +log +@Rev 14 +@ +text +@d1 1 +a1 1 +Rev 14 +@ + + +1.13 +log +@Rev 13 +@ +text +@d1 1 +a1 1 +Rev 13 +@ + + +1.12 +log +@Rev 12 +@ +text +@d1 1 +a1 1 +Rev 12 +@ + + +1.11 +log +@Rev 11 +@ +text +@d1 1 +a1 1 +Rev 11 +@ + + +1.10 +log +@Rev 10 +@ +text +@d1 1 +a1 1 +Rev 10 +@ + + +1.9 +log +@Rev 9 +@ +text +@d1 1 +a1 1 +Rev 9 +@ + + +1.8 +log +@Rev 8 +@ +text +@d1 1 +a1 1 +Rev 8 +@ + + +1.7 +log +@Rev 7 +@ +text +@d1 1 +a1 1 +Rev 7 +@ + + +1.6 +log +@Rev 6 +@ +text +@d1 1 +a1 1 +Rev 6 +@ + + +1.5 +log +@Rev 5 +@ +text +@d1 1 +a1 1 +Rev 5 +@ + + +1.4 +log +@Rev 4 +@ +text +@d1 1 +a1 1 +Rev 4 +@ + + +1.3 +log +@Rev 3 +@ +text +@d1 1 +a1 1 +Rev 3 +@ + + +1.2 +log +@Rev 2 +@ +text +@d1 1 +a1 1 +Rev 2 +@ + + +1.1 +log +@Rev 1 +@ +text +@d1 1 +a1 1 +Rev 1 +@ diff --git a/t/t9700/test.pl b/t/t9700/test.pl index 3b9b48408a..1140767b50 100755 --- a/t/t9700/test.pl +++ b/t/t9700/test.pl @@ -45,9 +45,9 @@ is($r->get_color("color.test.slot1", "red"), $ansi_green, "get_color"); # Failure cases for config: # Save and restore STDERR; we will probably extract this into a # "dies_ok" method and possibly move the STDERR handling to Git.pm. -open our $tmpstderr, ">&STDERR" or die "cannot save STDERR"; close STDERR; -eval { $r->config("test.dupstring") }; -ok($@, "config: duplicate entry in scalar context fails"); +open our $tmpstderr, ">&STDERR" or die "cannot save STDERR"; +open STDERR, ">", "/dev/null" or die "cannot redirect STDERR to /dev/null"; +is($r->config("test.dupstring"), "value2", "config: multivar"); eval { $r->config_bool("test.boolother") }; ok($@, "config_bool: non-boolean values fail"); open STDERR, ">&", $tmpstderr or die "cannot restore STDERR"; diff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh index b7ad716b09..665607c9cb 100755 --- a/t/t9800-git-p4-basic.sh +++ b/t/t9800-git-p4-basic.sh @@ -30,6 +30,11 @@ test_expect_success 'basic git p4 clone' ' ) ' +test_expect_success 'depot typo error' ' + test_must_fail git p4 clone --dest="$git" /depot 2>errs && + grep "Depot paths must start with" errs +' + test_expect_success 'git p4 clone @all' ' git p4 clone --dest="$git" //depot@all && test_when_finished cleanup_git && @@ -143,15 +148,29 @@ test_expect_success 'exit when p4 fails to produce marshaled output' ' ! test_i18ngrep Traceback errs ' -test_expect_success 'clone bare' ' +# Hide a file from p4d, make sure we catch its complaint. This won't fail in +# p4 changes, files, or describe; just in p4 print. If P4CLIENT is unset, the +# message will include "Librarian checkout". +test_expect_success 'exit gracefully for p4 server errors' ' + test_when_finished "mv \"$db\"/depot/file1,v,hidden \"$db\"/depot/file1,v" && + mv "$db"/depot/file1,v "$db"/depot/file1,v,hidden && + test_when_finished cleanup_git && + test_expect_code 1 git p4 clone --dest="$git" //depot@1 >out 2>err && + test_i18ngrep "Error from p4 print" err +' + +test_expect_success 'clone --bare should make a bare repository' ' rm -rf "$git" && git p4 clone --dest="$git" --bare //depot && test_when_finished cleanup_git && ( cd "$git" && - test ! -d .git && - bare=`git config --get core.bare` && - test "$bare" = true + test_path_is_missing .git && + git config --get --bool core.bare true && + git rev-parse --verify refs/remotes/p4/master && + git rev-parse --verify refs/remotes/p4/HEAD && + git rev-parse --verify refs/heads/master && + git rev-parse --verify HEAD ) ' @@ -172,6 +191,18 @@ test_expect_success 'initial import time from top change time' ' ) ' +test_expect_success 'unresolvable host in P4PORT should display error' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + P4PORT=nosuchhost:65537 && + export P4PORT && + test_expect_code 1 git p4 sync >out 2>err && + grep "connect to nosuchhost" err + ) +' + test_expect_success 'kill p4d' ' kill_p4d ' diff --git a/t/t9801-git-p4-branch.sh b/t/t9801-git-p4-branch.sh index 9730821c30..2bf142d09c 100755 --- a/t/t9801-git-p4-branch.sh +++ b/t/t9801-git-p4-branch.sh @@ -469,9 +469,11 @@ test_expect_success 'use-client-spec detect-branches skips branches setup' ' View: //depot/usecs/b1/... //depot/usecs/b3/... EOF - echo b3/b3-file3 >b3/b3-file3 && - p4 add b3/b3-file3 && - p4 submit -d "b3/b3-file3" + echo b3/b3-file3_1 >b3/b3-file3_1 && + echo b3/b3-file3_2 >b3/b3-file3_2 && + p4 add b3/b3-file3_1 && + p4 add b3/b3-file3_2 && + p4 submit -d "b3/b3-file3_1 b3/b3-file3_2" ) ' @@ -487,6 +489,21 @@ test_expect_success 'use-client-spec detect-branches skips branches' ' ) ' +test_expect_success 'use-client-spec detect-branches skips files in branches' ' + client_view "//depot/usecs/... //client/..." \ + "-//depot/usecs/b3/b3-file3_1 //client/b3/b3-file3_1" && + test_when_finished cleanup_git && + test_create_repo "$git" && + ( + cd "$git" && + git p4 sync --detect-branches --use-client-spec //depot/usecs@all && + git checkout -b master p4/usecs/b3 && + test_path_is_file b1-file1 && + test_path_is_file b3-file3_2 && + test_path_is_missing b3-file3_1 + ) +' + test_expect_success 'kill p4d' ' kill_p4d ' diff --git a/t/t9802-git-p4-filetype.sh b/t/t9802-git-p4-filetype.sh index 21924dfd7d..b0d1d94bf4 100755 --- a/t/t9802-git-p4-filetype.sh +++ b/t/t9802-git-p4-filetype.sh @@ -8,6 +8,123 @@ test_expect_success 'start p4d' ' start_p4d ' +# +# This series of tests checks newline handling Both p4 and +# git store newlines as \n, and have options to choose how +# newlines appear in checked-out files. +# +test_expect_success 'p4 client newlines, unix' ' + ( + cd "$cli" && + p4 client -o | sed "/LineEnd/s/:.*/:unix/" | p4 client -i && + printf "unix\ncrlf\n" >f-unix && + printf "unix\r\ncrlf\r\n" >f-unix-as-crlf && + p4 add -t text f-unix && + p4 submit -d f-unix && + + # LineEnd: unix; should be no change after sync + cp f-unix f-unix-orig && + p4 sync -f && + test_cmp f-unix-orig f-unix && + + # make sure stored in repo as unix newlines + # use sed to eat python-appened newline + p4 -G print //depot/f-unix | marshal_dump data 2 |\ + sed \$d >f-unix-p4-print && + test_cmp f-unix-orig f-unix-p4-print && + + # switch to win, make sure lf -> crlf + p4 client -o | sed "/LineEnd/s/:.*/:win/" | p4 client -i && + p4 sync -f && + test_cmp f-unix-as-crlf f-unix + ) +' + +test_expect_success 'p4 client newlines, win' ' + ( + cd "$cli" && + p4 client -o | sed "/LineEnd/s/:.*/:win/" | p4 client -i && + printf "win\r\ncrlf\r\n" >f-win && + printf "win\ncrlf\n" >f-win-as-lf && + p4 add -t text f-win && + p4 submit -d f-win && + + # LineEnd: win; should be no change after sync + cp f-win f-win-orig && + p4 sync -f && + test_cmp f-win-orig f-win && + + # make sure stored in repo as unix newlines + # use sed to eat python-appened newline + p4 -G print //depot/f-win | marshal_dump data 2 |\ + sed \$d >f-win-p4-print && + test_cmp f-win-as-lf f-win-p4-print && + + # switch to unix, make sure lf -> crlf + p4 client -o | sed "/LineEnd/s/:.*/:unix/" | p4 client -i && + p4 sync -f && + test_cmp f-win-as-lf f-win + ) +' + +test_expect_success 'ensure blobs store only lf newlines' ' + test_when_finished cleanup_git && + ( + cd "$git" && + git init && + git p4 sync //depot@all && + + # verify the files in .git are stored only with newlines + o=$(git ls-tree p4/master -- f-unix | cut -f1 | cut -d\ -f3) && + git cat-file blob $o >f-unix-blob && + test_cmp "$cli"/f-unix-orig f-unix-blob && + + o=$(git ls-tree p4/master -- f-win | cut -f1 | cut -d\ -f3) && + git cat-file blob $o >f-win-blob && + test_cmp "$cli"/f-win-as-lf f-win-blob && + + rm f-unix-blob f-win-blob + ) +' + +test_expect_success 'gitattributes setting eol=lf produces lf newlines' ' + test_when_finished cleanup_git && + ( + # checkout the files and make sure core.eol works as planned + cd "$git" && + git init && + echo "* eol=lf" >.gitattributes && + git p4 sync //depot@all && + git checkout -b master p4/master && + test_cmp "$cli"/f-unix-orig f-unix && + test_cmp "$cli"/f-win-as-lf f-win + ) +' + +test_expect_success 'gitattributes setting eol=crlf produces crlf newlines' ' + test_when_finished cleanup_git && + ( + # checkout the files and make sure core.eol works as planned + cd "$git" && + git init && + echo "* eol=crlf" >.gitattributes && + git p4 sync //depot@all && + git checkout -b master p4/master && + test_cmp "$cli"/f-unix-as-crlf f-unix && + test_cmp "$cli"/f-win-orig f-win + ) +' + +test_expect_success 'crlf cleanup' ' + ( + cd "$cli" && + rm f-unix-orig f-unix-as-crlf && + rm f-win-orig f-win-as-lf && + p4 client -o | sed "/LineEnd/s/:.*/:unix/" | p4 client -i && + p4 sync -f + ) +' + test_expect_success 'utf-16 file create' ' ( cd "$cli" && @@ -105,12 +222,13 @@ build_gendouble() { cat >gendouble.py <<-\EOF import sys import struct - import array - s = array.array("c", '\0' * 26) - struct.pack_into(">L", s, 0, 0x00051607) # AppleDouble - struct.pack_into(">L", s, 4, 0x00020000) # version 2 - s.tofile(sys.stdout) + s = struct.pack(">LL18s", + 0x00051607, # AppleDouble + 0x00020000, # version 2 + "" # pad to 26 bytes + ) + sys.stdout.write(s) EOF } diff --git a/t/t9806-git-p4-options.sh b/t/t9806-git-p4-options.sh index fa40cc8bb5..254d428b73 100755 --- a/t/t9806-git-p4-options.sh +++ b/t/t9806-git-p4-options.sh @@ -27,14 +27,102 @@ test_expect_success 'clone no --git-dir' ' test_must_fail git p4 clone --git-dir=xx //depot ' -test_expect_success 'clone --branch' ' +test_expect_success 'clone --branch should checkout master' ' git p4 clone --branch=refs/remotes/p4/sb --dest="$git" //depot && test_when_finished cleanup_git && ( cd "$git" && - git ls-files >files && - test_line_count = 0 files && - test_path_is_file .git/refs/remotes/p4/sb + git rev-parse refs/remotes/p4/sb >sb && + git rev-parse refs/heads/master >master && + test_cmp sb master && + git rev-parse HEAD >head && + test_cmp sb head + ) +' + +test_expect_success 'sync when no master branch prints a nice error' ' + test_when_finished cleanup_git && + git p4 clone --branch=refs/remotes/p4/sb --dest="$git" //depot@2 && + ( + cd "$git" && + test_must_fail git p4 sync 2>err && + grep "Error: no branch refs/remotes/p4/master" err + ) +' + +test_expect_success 'sync --branch builds the full ref name correctly' ' + test_when_finished cleanup_git && + ( + cd "$git" && + git init && + + git p4 sync --branch=b1 //depot && + git rev-parse --verify refs/remotes/p4/b1 && + git p4 sync --branch=p4/b2 //depot && + git rev-parse --verify refs/remotes/p4/b2 && + + git p4 sync --import-local --branch=h1 //depot && + git rev-parse --verify refs/heads/p4/h1 && + git p4 sync --import-local --branch=p4/h2 //depot && + git rev-parse --verify refs/heads/p4/h2 && + + git p4 sync --branch=refs/stuff //depot && + git rev-parse --verify refs/stuff + ) +' + +# engages --detect-branches code, which will do filename filtering so +# no sync to either b1 or b2 +test_expect_success 'sync when two branches but no master should noop' ' + test_when_finished cleanup_git && + ( + cd "$git" && + git init && + git p4 sync --branch=refs/remotes/p4/b1 //depot@2 && + git p4 sync --branch=refs/remotes/p4/b2 //depot@2 && + git p4 sync && + git show -s --format=%s refs/remotes/p4/b1 >show && + grep "Initial import" show && + git show -s --format=%s refs/remotes/p4/b2 >show && + grep "Initial import" show + ) +' + +test_expect_success 'sync --branch updates specific branch, no detection' ' + test_when_finished cleanup_git && + ( + cd "$git" && + git init && + git p4 sync --branch=b1 //depot@2 && + git p4 sync --branch=b2 //depot@2 && + git p4 sync --branch=b2 && + git show -s --format=%s refs/remotes/p4/b1 >show && + grep "Initial import" show && + git show -s --format=%s refs/remotes/p4/b2 >show && + grep "change 3" show + ) +' + +# allows using the refname "p4" as a short name for p4/master +test_expect_success 'clone creates HEAD symbolic reference' ' + git p4 clone --dest="$git" //depot && + test_when_finished cleanup_git && + ( + cd "$git" && + git rev-parse --verify refs/remotes/p4/master >master && + git rev-parse --verify p4 >p4 && + test_cmp master p4 + ) +' + +test_expect_success 'clone --branch creates HEAD symbolic reference' ' + git p4 clone --branch=refs/remotes/p4/sb --dest="$git" //depot && + test_when_finished cleanup_git && + ( + cd "$git" && + git rev-parse --verify refs/remotes/p4/sb >sb && + git rev-parse --verify p4 >p4 && + test_cmp sb p4 ) ' @@ -126,37 +214,58 @@ test_expect_success 'clone --use-client-spec' ' exec >/dev/null && test_must_fail git p4 clone --dest="$git" --use-client-spec ) && - cli2=$(test-path-utils real_path "$TRASH_DIRECTORY/cli2") && + # build a different client + cli2="$TRASH_DIRECTORY/cli2" && mkdir -p "$cli2" && test_when_finished "rmdir \"$cli2\"" && + test_when_finished cleanup_git && ( - cd "$cli2" && - p4 client -i <<-EOF - Client: client2 - Description: client2 - Root: $cli2 - View: //depot/sub/... //client2/bus/... - EOF - ) && - P4CLIENT=client2 && + # group P4CLIENT and cli changes in a sub-shell + P4CLIENT=client2 && + cli="$cli2" && + client_view "//depot/sub/... //client2/bus/..." && + git p4 clone --dest="$git" --use-client-spec //depot/... && + ( + cd "$git" && + test_path_is_file bus/dir/f4 && + test_path_is_missing file1 + ) && + cleanup_git && + # same thing again, this time with variable instead of option + ( + cd "$git" && + git init && + git config git-p4.useClientSpec true && + git p4 sync //depot/... && + git checkout -b master p4/master && + test_path_is_file bus/dir/f4 && + test_path_is_missing file1 + ) + ) +' + +test_expect_success 'submit works with no p4/master' ' test_when_finished cleanup_git && - git p4 clone --dest="$git" --use-client-spec //depot/... && + git p4 clone --branch=b1 //depot@1,2 --destination="$git" && ( cd "$git" && - test_path_is_file bus/dir/f4 && - test_path_is_missing file1 - ) && - cleanup_git && + test_commit submit-1-branch && + git config git-p4.skipSubmitEdit true && + git p4 submit --branch=b1 + ) +' - # same thing again, this time with variable instead of option +# The sync/rebase part post-submit will engage detect-branches +# machinery which will not do anything in this particular test. +test_expect_success 'submit works with two branches' ' + test_when_finished cleanup_git && + git p4 clone --branch=b1 //depot@1,2 --destination="$git" && ( cd "$git" && - git init && - git config git-p4.useClientSpec true && - git p4 sync //depot/... && - git checkout -b master p4/master && - test_path_is_file bus/dir/f4 && - test_path_is_missing file1 + git p4 sync --branch=b2 //depot@1,3 && + test_commit submit-2-branches && + git config git-p4.skipSubmitEdit true && + git p4 submit ) ' diff --git a/t/t9807-git-p4-submit.sh b/t/t9807-git-p4-submit.sh index 0ae048f29f..1fb7bc7cf9 100755 --- a/t/t9807-git-p4-submit.sh +++ b/t/t9807-git-p4-submit.sh @@ -17,6 +17,16 @@ test_expect_success 'init depot' ' ) ' +test_expect_failure 'is_cli_file_writeable function' ' + ( + cd "$cli" && + echo a >a && + is_cli_file_writeable a && + ! is_cli_file_writeable file1 && + rm a + ) +' + test_expect_success 'submit with no client dir' ' test_when_finished cleanup_git && git p4 clone --dest="$git" //depot && @@ -200,7 +210,7 @@ test_expect_success 'submit copy' ' ( cd "$cli" && test_path_is_file file5.ta && - test ! -w file5.ta + ! is_cli_file_writeable file5.ta ) ' @@ -219,7 +229,7 @@ test_expect_success 'submit rename' ' cd "$cli" && test_path_is_missing file6.t && test_path_is_file file6.ta && - test ! -w file6.ta + ! is_cli_file_writeable file6.ta ) ' diff --git a/t/t9808-git-p4-chdir.sh b/t/t9808-git-p4-chdir.sh index dc92e60cd6..11d2b5102c 100755 --- a/t/t9808-git-p4-chdir.sh +++ b/t/t9808-git-p4-chdir.sh @@ -42,6 +42,47 @@ test_expect_success 'P4CONFIG and relative dir clone' ' ) ' +# Common setup using .p4config to set P4CLIENT and P4PORT breaks +# if clone destination is relative. Make sure that chdir() expands +# the relative path in --dest to absolute. +test_expect_success 'p4 client root would be relative due to clone --dest' ' + test_when_finished cleanup_git && + ( + echo P4PORT=$P4PORT >git/.p4config && + P4CONFIG=.p4config && + export P4CONFIG && + unset P4PORT && + git p4 clone --dest="git" //depot + ) +' + +# When the p4 client Root is a symlink, make sure chdir() does not use +# getcwd() to convert it to a physical path. +test_expect_success SYMLINKS 'p4 client root symlink should stay symbolic' ' + physical="$TRASH_DIRECTORY/physical" && + symbolic="$TRASH_DIRECTORY/symbolic" && + test_when_finished "rm -rf \"$physical\"" && + test_when_finished "rm \"$symbolic\"" && + mkdir -p "$physical" && + ln -s "$physical" "$symbolic" && + test_when_finished cleanup_git && + ( + P4CLIENT=client-sym && + p4 client -i <<-EOF && + Client: $P4CLIENT + Description: $P4CLIENT + Root: $symbolic + LineEnd: unix + View: //depot/... //$P4CLIENT/... + EOF + git p4 clone --dest="$git" //depot && + cd "$git" && + test_commit file2 && + git config git-p4.skipSubmitEdit true && + git p4 submit + ) +' + test_expect_success 'kill p4d' ' kill_p4d ' diff --git a/t/t9809-git-p4-client-view.sh b/t/t9809-git-p4-client-view.sh index 281be29174..77f63492d9 100755 --- a/t/t9809-git-p4-client-view.sh +++ b/t/t9809-git-p4-client-view.sh @@ -196,7 +196,7 @@ test_expect_success 'exclusion single file' ' test_expect_success 'overlay wildcard' ' client_view "//depot/dir1/... //client/cli/..." \ - "+//depot/dir2/... //client/cli/...\n" && + "+//depot/dir2/... //client/cli/..." && files="cli/file11 cli/file12 cli/file21 cli/file22" && client_verify $files && test_when_finished cleanup_git && @@ -333,7 +333,7 @@ test_expect_success 'subdir clone, submit copy' ' ( cd "$cli" && test_path_is_file dir1/file11a && - test ! -w dir1/file11a + ! is_cli_file_writeable dir1/file11a ) ' @@ -353,7 +353,7 @@ test_expect_success 'subdir clone, submit rename' ' cd "$cli" && test_path_is_missing dir1/file13 && test_path_is_file dir1/file13a && - test ! -w dir1/file13a + ! is_cli_file_writeable dir1/file13a ) ' @@ -365,7 +365,10 @@ test_expect_success 'wildcard files submit back to p4, client-spec case' ' ( cd "$git" && echo git-wild-hash >dir1/git-wild#hash && - echo git-wild-star >dir1/git-wild\*star && + if test_have_prereq NOT_MINGW NOT_CYGWIN + then + echo git-wild-star >dir1/git-wild\*star + fi && echo git-wild-at >dir1/git-wild@at && echo git-wild-percent >dir1/git-wild%percent && git add dir1/git-wild* && @@ -376,7 +379,10 @@ test_expect_success 'wildcard files submit back to p4, client-spec case' ' ( cd "$cli" && test_path_is_file dir1/git-wild#hash && - test_path_is_file dir1/git-wild\*star && + if test_have_prereq NOT_MINGW NOT_CYGWIN + then + test_path_is_file dir1/git-wild\*star + fi && test_path_is_file dir1/git-wild@at && test_path_is_file dir1/git-wild%percent ) && diff --git a/t/t9810-git-p4-rcs.sh b/t/t9810-git-p4-rcs.sh index 0c2fc3ea1a..34fbc90005 100755 --- a/t/t9810-git-p4-rcs.sh +++ b/t/t9810-git-p4-rcs.sh @@ -26,10 +26,8 @@ test_expect_success 'init depot' ' 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 + sed "s/Revision/Revision: do not scrub me/" <filek >fileko && + sed "s/Id/Id: do not scrub me/" <fileko >file_text && p4 add -t text+k filek && p4 submit -d "filek" && p4 add -t text+ko fileko && @@ -88,7 +86,8 @@ test_expect_success 'edit far away from RCS lines' ' ( cd "$git" && git config git-p4.skipSubmitEdit true && - sed -i "s/^line7/line7 edit/" filek && + sed "s/^line7/line7 edit/" <filek >filek.tmp && + mv -f filek.tmp filek && git commit -m "filek line7 edit" filek && git p4 submit && scrub_k_check filek @@ -105,7 +104,8 @@ test_expect_success 'edit near RCS lines' ' cd "$git" && git config git-p4.skipSubmitEdit true && git config git-p4.attemptRCSCleanup true && - sed -i "s/^line4/line4 edit/" filek && + sed "s/^line4/line4 edit/" <filek >filek.tmp && + mv -f filek.tmp filek && git commit -m "filek line4 edit" filek && git p4 submit && scrub_k_check filek @@ -122,7 +122,8 @@ test_expect_success 'edit keyword lines' ' cd "$git" && git config git-p4.skipSubmitEdit true && git config git-p4.attemptRCSCleanup true && - sed -i "/Revision/d" filek && + sed "/Revision/d" <filek >filek.tmp && + mv -f filek.tmp filek && git commit -m "filek remove Revision line" filek && git p4 submit && scrub_k_check filek @@ -139,7 +140,8 @@ test_expect_success 'scrub ko files differently' ' cd "$git" && git config git-p4.skipSubmitEdit true && git config git-p4.attemptRCSCleanup true && - sed -i "s/^line4/line4 edit/" fileko && + sed "s/^line4/line4 edit/" <fileko >fileko.tmp && + mv -f fileko.tmp fileko && git commit -m "fileko line4 edit" fileko && git p4 submit && scrub_ko_check fileko && @@ -189,12 +191,14 @@ test_expect_success 'do not scrub plain text' ' cd "$git" && git config git-p4.skipSubmitEdit true && git config git-p4.attemptRCSCleanup true && - sed -i "s/^line4/line4 edit/" file_text && + sed "s/^line4/line4 edit/" <file_text >file_text.tmp && + mv -f file_text.tmp 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 && + sed "s/^line5/line5 p4 edit/" <file_text >file_text.tmp && + mv -f file_text.tmp file_text && p4 submit -d "file5 p4 edit" ) && echo s | test_expect_code 1 git p4 submit && diff --git a/t/t9812-git-p4-wildcards.sh b/t/t9812-git-p4-wildcards.sh index 143d413057..67633257f3 100755 --- a/t/t9812-git-p4-wildcards.sh +++ b/t/t9812-git-p4-wildcards.sh @@ -14,7 +14,10 @@ test_expect_success 'add p4 files with wildcards in the names' ' 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 && + if test_have_prereq NOT_MINGW NOT_CYGWIN + then + echo file-wild-star >file-wild\*star + fi && echo file-wild-at >file-wild@at && echo file-wild-percent >file-wild%percent && p4 add -f file-wild* && @@ -28,7 +31,10 @@ test_expect_success 'wildcard files git p4 clone' ' ( cd "$git" && test -f file-wild#hash && - test -f file-wild\*star && + if test_have_prereq NOT_MINGW NOT_CYGWIN + then + test -f file-wild\*star + fi && test -f file-wild@at && test -f file-wild%percent ) @@ -40,7 +46,10 @@ test_expect_success 'wildcard files submit back to p4, add' ' ( cd "$git" && echo git-wild-hash >git-wild#hash && - echo git-wild-star >git-wild\*star && + if test_have_prereq NOT_MINGW NOT_CYGWIN + then + echo git-wild-star >git-wild\*star + fi && echo git-wild-at >git-wild@at && echo git-wild-percent >git-wild%percent && git add git-wild* && @@ -51,7 +60,10 @@ test_expect_success 'wildcard files submit back to p4, add' ' ( cd "$cli" && test_path_is_file git-wild#hash && - test_path_is_file git-wild\*star && + if test_have_prereq NOT_MINGW NOT_CYGWIN + then + test_path_is_file git-wild\*star + fi && test_path_is_file git-wild@at && test_path_is_file git-wild%percent ) @@ -63,7 +75,10 @@ test_expect_success 'wildcard files submit back to p4, modify' ' ( cd "$git" && echo new-line >>git-wild#hash && - echo new-line >>git-wild\*star && + if test_have_prereq NOT_MINGW NOT_CYGWIN + then + echo new-line >>git-wild\*star + fi && echo new-line >>git-wild@at && echo new-line >>git-wild%percent && git add git-wild* && @@ -74,7 +89,10 @@ test_expect_success 'wildcard files submit back to p4, modify' ' ( cd "$cli" && test_line_count = 2 git-wild#hash && - test_line_count = 2 git-wild\*star && + if test_have_prereq NOT_MINGW NOT_CYGWIN + then + test_line_count = 2 git-wild\*star + fi && test_line_count = 2 git-wild@at && test_line_count = 2 git-wild%percent ) @@ -87,7 +105,7 @@ test_expect_success 'wildcard files submit back to p4, copy' ' cd "$git" && cp file2 git-wild-cp#hash && git add git-wild-cp#hash && - cp git-wild\*star file-wild-3 && + cp git-wild#hash file-wild-3 && git add file-wild-3 && git commit -m "wildcard copies" && git config git-p4.detectCopies true && @@ -134,7 +152,10 @@ test_expect_success 'wildcard files submit back to p4, delete' ' ( cd "$cli" && test_path_is_missing git-wild#hash && - test_path_is_missing git-wild\*star && + if test_have_prereq NOT_MINGW NOT_CYGWIN + then + test_path_is_missing git-wild\*star + fi && test_path_is_missing git-wild@at && test_path_is_missing git-wild%percent ) diff --git a/t/t9814-git-p4-rename.sh b/t/t9814-git-p4-rename.sh index 3bf1224ae0..be802e0e16 100755 --- a/t/t9814-git-p4-rename.sh +++ b/t/t9814-git-p4-rename.sh @@ -199,6 +199,41 @@ test_expect_success 'detect copies' ' ) ' +# See if configurables can be set, and in particular if the run.move.allow +# variable exists, which allows admins to disable the "p4 move" command. +test_expect_success 'p4 configure command and run.move.allow are available' ' + p4 configure show run.move.allow >out ; retval=$? && + test $retval = 0 && + { + egrep ^run.move.allow: out && + test_set_prereq P4D_HAVE_CONFIGURABLE_RUN_MOVE_ALLOW || + true + } || true +' + +# If move can be disabled, turn it off and test p4 move handling +test_expect_success P4D_HAVE_CONFIGURABLE_RUN_MOVE_ALLOW \ + 'do not use p4 move when administratively disabled' ' + test_when_finished "p4 configure set run.move.allow=1" && + p4 configure set run.move.allow=0 && + ( + cd "$cli" && + echo move-disallow-file >move-disallow-file && + p4 add move-disallow-file && + p4 submit -d "add move-disallow-file" + ) && + 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 move-disallow-file move-disallow-file-moved && + git commit -m "move move-disallow-file" && + git p4 submit + ) +' + test_expect_success 'kill p4d' ' kill_p4d ' diff --git a/t/t9815-git-p4-submit-fail.sh b/t/t9815-git-p4-submit-fail.sh index d2b7b3d98d..1243d96092 100755 --- a/t/t9815-git-p4-submit-fail.sh +++ b/t/t9815-git-p4-submit-fail.sh @@ -405,8 +405,8 @@ test_expect_success 'cleanup chmod after submit cancel' ' git p4 clone --dest="$git" //depot && ( cd "$git" && - chmod u+x text && - chmod u-x text+x && + test_chmod +x text && + test_chmod -x text+x && git add text text+x && git commit -m "chmod texts" && echo n | test_expect_code 1 git p4 submit @@ -415,10 +415,13 @@ test_expect_success 'cleanup chmod after submit cancel' ' cd "$cli" && test_path_is_file text && ! p4 fstat -T action text && - stat --format=%A text | egrep ^-r-- && test_path_is_file text+x && ! p4 fstat -T action text+x && - stat --format=%A text+x | egrep ^-r-x + if test_have_prereq NOT_CYGWIN + then + stat --format=%A text | egrep ^-r-- && + stat --format=%A text+x | egrep ^-r-x + fi ) ' diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index cbd0fb66f9..272a071e85 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -13,6 +13,25 @@ complete () return 0 } +# Be careful when updating this list: +# +# (1) The build tree may have build artifact from different branch, or +# the user's $PATH may have a random executable that may begin +# with "git-check" that are not part of the subcommands this build +# will ship, e.g. "check-ignore". The tests for completion for +# subcommand names tests how "check" is expanded; we limit the +# possible candidates to "checkout" and "check-attr" to make sure +# "check-attr", which is known by the filter function as a +# subcommand to be thrown out, while excluding other random files +# that happen to begin with "check" to avoid letting them get in +# the way. +# +# (2) A test makes sure that common subcommands are included in the +# completion for "git <TAB>", and a plumbing is excluded. "add", +# "filter-branch" and "ls-files" are listed for this. + +GIT_TESTING_COMMAND_COMPLETION='add checkout check-attr filter-branch ls-files' + . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" # We don't need this function to actually join words or do anything special. @@ -50,113 +69,281 @@ run_completion () local -a COMPREPLY _words local _cword _words=( $1 ) + test "${1: -1}" = ' ' && _words+=('') (( _cword = ${#_words[@]} - 1 )) __git_wrap__git_main && print_comp } +# Test high-level completion +# Arguments are: +# 1: typed text so far (cur) +# 2: expected completion test_completion () { - test $# -gt 1 && echo "$2" > expected - run_completion "$@" && + if test $# -gt 1 + then + printf '%s\n' "$2" >expected + else + sed -e 's/Z$//' >expected + fi && + run_completion "$1" && + test_cmp expected out +} + +# Test __gitcomp. +# The first argument is the typed text so far (cur); the rest are +# passed to __gitcomp. Expected output comes is read from the +# standard input, like test_completion(). +test_gitcomp () +{ + local -a COMPREPLY && + sed -e 's/Z$//' >expected && + cur="$1" && + shift && + __gitcomp "$@" && + print_comp && test_cmp expected out } -# Like test_completion, but reads expectation from stdin, -# which is convenient when it is multiline. We also process "_" into -# spaces to make test vectors more readable. -test_completion_long () +# Test __gitcomp_nl +# Arguments are: +# 1: current word (cur) +# -: the rest are passed to __gitcomp_nl +test_gitcomp_nl () { - tr _ " " >expected && - test_completion "$1" + local -a COMPREPLY && + sed -e 's/Z$//' >expected && + cur="$1" && + shift && + __gitcomp_nl "$@" && + print_comp && + test_cmp expected out } -newline=$'\n' +invalid_variable_name='${foo.bar}' + +actual="$TRASH_DIRECTORY/actual" + +test_expect_success 'setup for __gitdir tests' ' + mkdir -p subdir/subsubdir && + git init otherrepo +' + +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 "$(pwd -P)/.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 "$(pwd -P)/.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 "$(pwd -P)/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 "$(pwd -P)/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 "$(pwd -P)/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 '__gitcomp - trailing space - options' ' - sed -e "s/Z$//" >expected <<-\EOF && + test_gitcomp "--re" "--dry-run --reuse-message= --reedit-message= + --reset-author" <<-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 && + test_gitcomp "br" "branch. branch.autosetupmerge + branch.autosetuprebase browser." <<-\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 && + test_gitcomp "--strategy=re" "octopus ours recursive resolve subtree" \ + "" "re" <<-\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 && + test_gitcomp "branch.me" "remote merge mergeoptions rebase" \ + "branch.maint." "me" <<-\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 && + test_gitcomp "branch.me" "master maint next pu" "branch." \ + "ma" "." <<-\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 '__gitcomp - doesnt fail because of invalid variable name' ' + __gitcomp "$invalid_variable_name" +' + +read -r -d "" refs <<-\EOF +maint +master +next +pu +EOF + +test_expect_success '__gitcomp_nl - trailing space' ' + test_gitcomp_nl "m" "$refs" <<-EOF + maint Z + master Z + EOF +' + +test_expect_success '__gitcomp_nl - prefix' ' + test_gitcomp_nl "--fixup=m" "$refs" "--fixup=" "m" <<-EOF + --fixup=maint Z + --fixup=master Z + EOF +' + +test_expect_success '__gitcomp_nl - suffix' ' + test_gitcomp_nl "branch.ma" "$refs" "branch." "ma" "." <<-\EOF + branch.maint.Z + branch.master.Z + EOF +' + +test_expect_success '__gitcomp_nl - no suffix' ' + test_gitcomp_nl "ma" "$refs" "" "ma" "" <<-\EOF + maintZ + masterZ + EOF +' + +test_expect_success '__gitcomp_nl - doesnt fail because of invalid variable name' ' + __gitcomp_nl "$invalid_variable_name" ' test_expect_success 'basic' ' - run_completion "git \"\"" && + run_completion "git " && # built-in grep -q "^add \$" out && # script @@ -169,7 +356,7 @@ test_expect_success 'basic' ' ' test_expect_success 'double dash "git" itself' ' - sed -e "s/Z$//" >expected <<-\EOF && + test_completion "git --" <<-\EOF --paginate Z --no-pager Z --git-dir= @@ -178,17 +365,17 @@ test_expect_success 'double dash "git" itself' ' --exec-path Z --exec-path= --html-path Z + --man-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 && + test_completion "git checkout --" <<-\EOF --quiet Z --ours Z --theirs Z @@ -199,17 +386,15 @@ test_expect_success 'double dash "git checkout"' ' --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 && + test_completion "git --exe" <<-\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 " && @@ -226,7 +411,6 @@ test_expect_success 'general options plus command' ' 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 " && @@ -237,6 +421,11 @@ test_expect_success 'general options plus command' ' test_completion "git --no-replace-objects check" "checkout " ' +test_expect_success 'git --help completion' ' + test_completion "git --help ad" "add " && + test_completion "git --help core" "core-tutorial " +' + test_expect_success 'setup for ref completion' ' echo content >file1 && echo more >file2 && @@ -247,25 +436,25 @@ test_expect_success 'setup for ref completion' ' ' test_expect_success 'checkout completes ref names' ' - test_completion_long "git checkout m" <<-\EOF - master_ - mybranch_ - mytag_ + test_completion "git checkout m" <<-\EOF + master Z + mybranch Z + mytag Z EOF ' test_expect_success 'show completes all refs' ' - test_completion_long "git show m" <<-\EOF - master_ - mybranch_ - mytag_ + test_completion "git show m" <<-\EOF + master Z + mybranch Z + mytag Z EOF ' test_expect_success '<ref>: completes paths' ' - test_completion_long "git show mytag:f" <<-\EOF - file1_ - file2_ + test_completion "git show mytag:f" <<-\EOF + file1 Z + file2 Z EOF ' @@ -273,19 +462,101 @@ test_expect_success 'complete tree filename with spaces' ' echo content >"name with spaces" && git add . && git commit -m spaces && - test_completion_long "git show HEAD:nam" <<-\EOF - name with spaces_ + test_completion "git show HEAD:nam" <<-\EOF + name with spaces Z EOF ' -test_expect_failure 'complete tree filename with metacharacters' ' +test_expect_success 'complete tree filename with metacharacters' ' echo content >"name with \${meta}" && git add . && git commit -m meta && - test_completion_long "git show HEAD:nam" <<-\EOF - name with ${meta}_ - name with spaces_ + test_completion "git show HEAD:nam" <<-\EOF + name with ${meta} Z + name with spaces Z + EOF +' + +test_expect_success 'send-email' ' + test_completion "git send-email --cov" "--cover-letter " && + test_completion "git send-email ma" "master " +' + +test_expect_success 'complete files' ' + git init tmp && cd tmp && + test_when_finished "cd .. && rm -rf tmp" && + + echo "expected" > .gitignore && + echo "out" >> .gitignore && + + git add .gitignore && + test_completion "git commit " ".gitignore" && + + git commit -m ignore && + + touch new && + test_completion "git add " "new" && + + git add new && + git commit -a -m new && + test_completion "git add " "" && + + git mv new modified && + echo modify > modified && + test_completion "git add " "modified" && + + touch untracked && + + : TODO .gitignore should not be here && + test_completion "git rm " <<-\EOF && + .gitignore + modified EOF + + test_completion "git clean " "untracked" && + + : TODO .gitignore should not be here && + test_completion "git mv " <<-\EOF && + .gitignore + modified + EOF + + mkdir dir && + touch dir/file-in-dir && + git add dir/file-in-dir && + git commit -m dir && + + mkdir untracked-dir && + + : TODO .gitignore should not be here && + test_completion "git mv modified " <<-\EOF && + .gitignore + dir + modified + untracked + untracked-dir + EOF + + test_completion "git commit " "modified" && + + : TODO .gitignore should not be here && + test_completion "git ls-files " <<-\EOF + .gitignore + dir + modified + EOF + + touch momified && + test_completion "git add mom" "momified" +' + +test_expect_failure 'complete with tilde expansion' ' + git init tmp && cd tmp && + test_when_finished "cd .. && rm -rf tmp" && + + touch ~/tmp/file && + + test_completion "git add ~/tmp/" "~/tmp/file" ' test_done diff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh index f17c1f8b85..3c3e4e8c38 100755 --- a/t/t9903-bash-prompt.sh +++ b/t/t9903-bash-prompt.sh @@ -10,446 +10,558 @@ test_description='test git-specific bash prompt functions' . "$GIT_BUILD_DIR/contrib/completion/git-prompt.sh" actual="$TRASH_DIRECTORY/actual" +c_red='\\[\\e[31m\\]' +c_green='\\[\\e[32m\\]' +c_lblue='\\[\\e[1;34m\\]' +c_clear='\\[\\e[0m\\]' test_expect_success 'setup for prompt tests' ' - mkdir -p subdir/subsubdir && git init otherrepo && - echo 1 > file && + 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 && + echo 2 >file && git commit -m "second b1" file && - echo 3 > file && + echo 3 >file && git commit -m "third b1" file && git tag -a -m msg2 t2 && git checkout -b b2 master && - echo 0 > file && + echo 0 >file && git commit -m "second b2" file && + echo 00 >file && + git commit -m "another b2" file && + echo 000 >file && + git commit -m "yet another 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_expect_success 'prompt - branch name' ' + printf " (master)" >expected && + __git_ps1 >"$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_expect_success SYMLINKS 'prompt - branch name - symlink symref' ' + printf " (master)" >expected && + test_when_finished "git checkout master" && + test_config core.preferSymlinkRefs true && + git checkout master && + __git_ps1 >"$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_expect_success 'prompt - unborn branch' ' + printf " (unborn)" >expected && + git checkout --orphan unborn && + test_when_finished "git checkout master" && + __git_ps1 >"$actual" && test_cmp expected "$actual" ' test_expect_success 'prompt - detached head' ' - printf " ((%s...))" $(git log -1 --format="%h" b1^) > expected && + printf " ((%s...))" $(git log -1 --format="%h" --abbrev=13 b1^) >expected && + test_config core.abbrev 13 && git checkout b1^ && test_when_finished "git checkout master" && - __git_ps1 > "$actual" && + __git_ps1 >"$actual" && test_cmp expected "$actual" ' test_expect_success 'prompt - describe detached head - contains' ' - printf " ((t2~1))" > expected && + printf " ((t2~1))" >expected && git checkout b1^ && test_when_finished "git checkout master" && ( GIT_PS1_DESCRIBE_STYLE=contains && - __git_ps1 > "$actual" + __git_ps1 >"$actual" ) && test_cmp expected "$actual" ' test_expect_success 'prompt - describe detached head - branch' ' - printf " ((b1~1))" > expected && + printf " ((b1~1))" >expected && git checkout b1^ && test_when_finished "git checkout master" && ( GIT_PS1_DESCRIBE_STYLE=branch && - __git_ps1 > "$actual" + __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 && + 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" + __git_ps1 >"$actual" ) && test_cmp expected "$actual" ' test_expect_success 'prompt - describe detached head - default' ' - printf " ((t2))" > expected && + printf " ((t2))" >expected && git checkout --detach b1 && test_when_finished "git checkout master" && - __git_ps1 > "$actual" && + __git_ps1 >"$actual" && test_cmp expected "$actual" ' test_expect_success 'prompt - inside .git directory' ' - printf " (GIT_DIR!)" > expected && + printf " (GIT_DIR!)" >expected && ( cd .git && - __git_ps1 > "$actual" + __git_ps1 >"$actual" ) && test_cmp expected "$actual" ' test_expect_success 'prompt - deep inside .git directory' ' - printf " (GIT_DIR!)" > expected && + printf " (GIT_DIR!)" >expected && ( cd .git/refs/heads && - __git_ps1 > "$actual" + __git_ps1 >"$actual" ) && test_cmp expected "$actual" ' test_expect_success 'prompt - inside bare repository' ' - printf " (BARE:master)" > expected && + printf " (BARE:master)" >expected && git init --bare bare.git && test_when_finished "rm -rf bare.git" && ( cd bare.git && - __git_ps1 > "$actual" + __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 + printf " (b1|REBASE-i 2/3)" >expected + write_script fake_editor.sh <<-\EOF && + echo "exec echo" >"$1" + echo "edit $(git log -1 --format="%h")" >>"$1" + echo "exec echo" >>"$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" && + __git_ps1 >"$actual" && test_cmp expected "$actual" ' test_expect_success 'prompt - rebase merge' ' - printf " (b2|REBASE-m)" > expected && + printf " (b2|REBASE-m 1/3)" >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" && + __git_ps1 >"$actual" && test_cmp expected "$actual" ' test_expect_success 'prompt - rebase' ' - printf " ((t2)|REBASE)" > expected && + printf " (b2|REBASE 1/3)" >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" && + __git_ps1 >"$actual" && test_cmp expected "$actual" ' test_expect_success 'prompt - merge' ' - printf " (b1|MERGING)" > expected && + 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" && + __git_ps1 >"$actual" && test_cmp expected "$actual" ' test_expect_success 'prompt - cherry-pick' ' - printf " (master|CHERRY-PICKING)" > expected && + printf " (master|CHERRY-PICKING)" >expected && test_must_fail git cherry-pick b1 && test_when_finished "git reset --hard" && - __git_ps1 > "$actual" && + __git_ps1 >"$actual" && test_cmp expected "$actual" ' test_expect_success 'prompt - bisect' ' - printf " (master|BISECTING)" > expected && + printf " (master|BISECTING)" >expected && git bisect start && test_when_finished "git bisect reset" && - __git_ps1 > "$actual" && + __git_ps1 >"$actual" && test_cmp expected "$actual" ' test_expect_success 'prompt - dirty status indicator - clean' ' - printf " (master)" > expected && + printf " (master)" >expected && ( GIT_PS1_SHOWDIRTYSTATE=y && - __git_ps1 > "$actual" + __git_ps1 >"$actual" ) && test_cmp expected "$actual" ' test_expect_success 'prompt - dirty status indicator - dirty worktree' ' - printf " (master *)" > expected && - echo "dirty" > file && + printf " (master *)" >expected && + echo "dirty" >file && test_when_finished "git reset --hard" && ( GIT_PS1_SHOWDIRTYSTATE=y && - __git_ps1 > "$actual" + __git_ps1 >"$actual" ) && test_cmp expected "$actual" ' test_expect_success 'prompt - dirty status indicator - dirty index' ' - printf " (master +)" > expected && - echo "dirty" > file && + printf " (master +)" >expected && + echo "dirty" >file && test_when_finished "git reset --hard" && git add -u && ( GIT_PS1_SHOWDIRTYSTATE=y && - __git_ps1 > "$actual" + __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 && + printf " (master *+)" >expected && + echo "dirty index" >file && test_when_finished "git reset --hard" && git add -u && - echo "dirty worktree" > file && + echo "dirty worktree" >file && ( GIT_PS1_SHOWDIRTYSTATE=y && - __git_ps1 > "$actual" + __git_ps1 >"$actual" ) && test_cmp expected "$actual" ' test_expect_success 'prompt - dirty status indicator - before root commit' ' - printf " (master #)" > expected && + printf " (master #)" >expected && ( GIT_PS1_SHOWDIRTYSTATE=y && cd otherrepo && - __git_ps1 > "$actual" + __git_ps1 >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - shell variable unset with config disabled' ' + printf " (master)" >expected && + echo "dirty" >file && + test_when_finished "git reset --hard" && + test_config bash.showDirtyState false && + ( + sane_unset GIT_PS1_SHOWDIRTYSTATE && + __git_ps1 >"$actual" ) && test_cmp expected "$actual" ' -test_expect_success 'prompt - dirty status indicator - disabled by config' ' - printf " (master)" > expected && - echo "dirty" > file && +test_expect_success 'prompt - dirty status indicator - shell variable unset with config enabled' ' + printf " (master)" >expected && + echo "dirty" >file && + test_when_finished "git reset --hard" && + test_config bash.showDirtyState true && + ( + sane_unset GIT_PS1_SHOWDIRTYSTATE && + __git_ps1 >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - shell variable set with config disabled' ' + printf " (master)" >expected && + echo "dirty" >file && test_when_finished "git reset --hard" && test_config bash.showDirtyState false && ( GIT_PS1_SHOWDIRTYSTATE=y && - __git_ps1 > "$actual" + __git_ps1 >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - shell variable set with config enabled' ' + printf " (master *)" >expected && + echo "dirty" >file && + test_when_finished "git reset --hard" && + test_config bash.showDirtyState true && + ( + 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 && + printf " (GIT_DIR!)" >expected && + echo "dirty" >file && test_when_finished "git reset --hard" && ( GIT_PS1_SHOWDIRTYSTATE=y && cd .git && - __git_ps1 > "$actual" + __git_ps1 >"$actual" ) && test_cmp expected "$actual" ' test_expect_success 'prompt - stash status indicator - no stash' ' - printf " (master)" > expected && + printf " (master)" >expected && ( GIT_PS1_SHOWSTASHSTATE=y && - __git_ps1 > "$actual" + __git_ps1 >"$actual" ) && test_cmp expected "$actual" ' test_expect_success 'prompt - stash status indicator - stash' ' - printf " (master $)" > expected && + printf " (master $)" >expected && echo 2 >file && git stash && test_when_finished "git stash drop" && + git pack-refs --all && ( GIT_PS1_SHOWSTASHSTATE=y && - __git_ps1 > "$actual" + __git_ps1 >"$actual" ) && test_cmp expected "$actual" ' test_expect_success 'prompt - stash status indicator - not shown inside .git directory' ' - printf " (GIT_DIR!)" > expected && + printf " (GIT_DIR!)" >expected && echo 2 >file && git stash && test_when_finished "git stash drop" && ( GIT_PS1_SHOWSTASHSTATE=y && cd .git && - __git_ps1 > "$actual" + __git_ps1 >"$actual" ) && test_cmp expected "$actual" ' test_expect_success 'prompt - untracked files status indicator - no untracked files' ' - printf " (master)" > expected && + printf " (master)" >expected && ( GIT_PS1_SHOWUNTRACKEDFILES=y && cd otherrepo && - __git_ps1 > "$actual" + __git_ps1 >"$actual" ) && test_cmp expected "$actual" ' test_expect_success 'prompt - untracked files status indicator - untracked files' ' - printf " (master %%)" > expected && + printf " (master %%)" >expected && + ( + GIT_PS1_SHOWUNTRACKEDFILES=y && + __git_ps1 >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - untracked files status indicator - shell variable unset with config disabled' ' + printf " (master)" >expected && + test_config bash.showUntrackedFiles false && + ( + sane_unset GIT_PS1_SHOWUNTRACKEDFILES && + __git_ps1 >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - untracked files status indicator - shell variable unset with config enabled' ' + printf " (master)" >expected && + test_config bash.showUntrackedFiles true && + ( + sane_unset GIT_PS1_SHOWUNTRACKEDFILES && + __git_ps1 >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - untracked files status indicator - shell variable set with config disabled' ' + printf " (master)" >expected && + test_config bash.showUntrackedFiles false && ( GIT_PS1_SHOWUNTRACKEDFILES=y && - __git_ps1 > "$actual" + __git_ps1 >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - untracked files status indicator - shell variable set with config enabled' ' + printf " (master %%)" >expected && + test_config bash.showUntrackedFiles true && + ( + 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 && + printf " (GIT_DIR!)" >expected && ( GIT_PS1_SHOWUNTRACKEDFILES=y && cd .git && - __git_ps1 > "$actual" + __git_ps1 >"$actual" ) && test_cmp expected "$actual" ' test_expect_success 'prompt - format string starting with dash' ' - printf -- "-master" > expected && - __git_ps1 "-%s" > "$actual" && + printf -- "-master" >expected && + __git_ps1 "-%s" >"$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - pc mode' ' + printf "BEFORE: (master):AFTER" >expected && + printf "" >expected_output && + ( + __git_ps1 "BEFORE:" ":AFTER" >"$actual" && + test_cmp expected_output "$actual" && + printf "%s" "$PS1" >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - bash color pc mode - branch name' ' + printf "BEFORE: (${c_green}master${c_clear}):AFTER" >expected && + ( + GIT_PS1_SHOWCOLORHINTS=y && + __git_ps1 "BEFORE:" ":AFTER" >"$actual" + printf "%s" "$PS1" >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - bash color pc mode - detached head' ' + printf "BEFORE: (${c_red}(%s...)${c_clear}):AFTER" $(git log -1 --format="%h" b1^) >expected && + git checkout b1^ && + test_when_finished "git checkout master" && + ( + GIT_PS1_SHOWCOLORHINTS=y && + __git_ps1 "BEFORE:" ":AFTER" && + printf "%s" "$PS1" >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - bash color pc mode - dirty status indicator - dirty worktree' ' + printf "BEFORE: (${c_green}master${c_clear} ${c_red}*${c_clear}):AFTER" >expected && + echo "dirty" >file && + test_when_finished "git reset --hard" && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + GIT_PS1_SHOWCOLORHINTS=y && + __git_ps1 "BEFORE:" ":AFTER" && + printf "%s" "$PS1" >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - bash color pc mode - dirty status indicator - dirty index' ' + printf "BEFORE: (${c_green}master${c_clear} ${c_green}+${c_clear}):AFTER" >expected && + echo "dirty" >file && + test_when_finished "git reset --hard" && + git add -u && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + GIT_PS1_SHOWCOLORHINTS=y && + __git_ps1 "BEFORE:" ":AFTER" && + printf "%s" "$PS1" >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - bash color pc mode - dirty status indicator - dirty index and worktree' ' + printf "BEFORE: (${c_green}master${c_clear} ${c_red}*${c_green}+${c_clear}):AFTER" >expected && + echo "dirty index" >file && + test_when_finished "git reset --hard" && + git add -u && + echo "dirty worktree" >file && + ( + GIT_PS1_SHOWCOLORHINTS=y && + GIT_PS1_SHOWDIRTYSTATE=y && + __git_ps1 "BEFORE:" ":AFTER" && + printf "%s" "$PS1" >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - bash color pc mode - dirty status indicator - before root commit' ' + printf "BEFORE: (${c_green}master${c_clear} ${c_green}#${c_clear}):AFTER" >expected && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + GIT_PS1_SHOWCOLORHINTS=y && + cd otherrepo && + __git_ps1 "BEFORE:" ":AFTER" && + printf "%s" "$PS1" >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - bash color pc mode - inside .git directory' ' + printf "BEFORE: (${c_green}GIT_DIR!${c_clear}):AFTER" >expected && + echo "dirty" >file && + test_when_finished "git reset --hard" && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + GIT_PS1_SHOWCOLORHINTS=y && + cd .git && + __git_ps1 "BEFORE:" ":AFTER" && + printf "%s" "$PS1" >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - bash color pc mode - stash status indicator' ' + printf "BEFORE: (${c_green}master${c_clear} ${c_lblue}\$${c_clear}):AFTER" >expected && + echo 2 >file && + git stash && + test_when_finished "git stash drop" && + ( + GIT_PS1_SHOWSTASHSTATE=y && + GIT_PS1_SHOWCOLORHINTS=y && + __git_ps1 "BEFORE:" ":AFTER" && + printf "%s" "$PS1" >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - bash color pc mode - untracked files status indicator' ' + printf "BEFORE: (${c_green}master${c_clear} ${c_red}%%${c_clear}):AFTER" >expected && + ( + GIT_PS1_SHOWUNTRACKEDFILES=y && + GIT_PS1_SHOWCOLORHINTS=y && + __git_ps1 "BEFORE:" ":AFTER" && + printf "%s" "$PS1" >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - zsh color pc mode' ' + printf "BEFORE: (%%F{green}master%%f):AFTER" >expected && + ( + ZSH_VERSION=5.0.0 && + GIT_PS1_SHOWCOLORHINTS=y && + __git_ps1 "BEFORE:" ":AFTER" >"$actual" + printf "%s" "$PS1" >"$actual" + ) && test_cmp expected "$actual" ' diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index 8889ba5104..a7e9aacbb2 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -91,6 +91,10 @@ q_to_tab () { tr Q '\011' } +qz_to_tab_space () { + tr QZ '\011\040' +} + append_cr () { sed -e 's/$/Q/' | tr Q '\015' } @@ -135,12 +139,12 @@ test_pause () { fi } -# Call test_commit with the arguments "<message> [<file> [<contents>]]" +# Call test_commit with the arguments "<message> [<file> [<contents> [<tag>]]]" # # This will commit a file with the given contents and the given commit -# message. It will also add a tag with <message> as name. +# message, and tag the resulting commit with the given tag name. # -# Both <file> and <contents> default to <message>. +# <file>, <contents>, and <tag> all default to <message>. test_commit () { notick= && @@ -168,7 +172,7 @@ test_commit () { test_tick fi && git commit $signoff -m "$1" && - git tag "$1" + git tag "${4:-$1}" } # Call test_merge with the arguments "<message> <commit>", where <commit> @@ -275,6 +279,15 @@ test_have_prereq () { for prerequisite do + case "$prerequisite" in + !*) + negative_prereq=t + prerequisite=${prerequisite#!} + ;; + *) + negative_prereq= + esac + case " $lazily_tested_prereq " in *" $prerequisite "*) ;; @@ -294,10 +307,20 @@ test_have_prereq () { total_prereq=$(($total_prereq + 1)) case "$satisfied_prereq" in *" $prerequisite "*) + satisfied_this_prereq=t + ;; + *) + satisfied_this_prereq= + esac + + case "$satisfied_this_prereq,$negative_prereq" in + t,|,t) ok_prereq=$(($ok_prereq + 1)) ;; *) - # Keep a list of missing prerequisites + # Keep a list of missing prerequisites; restore + # the negative marker if necessary. + prerequisite=${negative_prereq:+!}$prerequisite if test -z "$missing_prereq" then missing_prereq=$prerequisite @@ -320,6 +343,7 @@ test_declared_prereq () { } test_expect_failure () { + test_start_ 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" @@ -334,10 +358,11 @@ test_expect_failure () { test_known_broken_failure_ "$1" fi fi - echo >&3 "" + test_finish_ } test_expect_success () { + test_start_ 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" @@ -352,7 +377,7 @@ test_expect_success () { test_failure_ "$@" fi fi - echo >&3 "" + test_finish_ } # test_external runs external test scripts that provide continuous @@ -517,6 +542,9 @@ test_must_fail () { elif test $exit_code = 127; then echo >&2 "test_must_fail: command not found: $*" return 1 + elif test $exit_code = 126; then + echo >&2 "test_must_fail: valgrind error: $*" + return 1 fi return 0 } @@ -583,6 +611,25 @@ test_cmp() { $GIT_TEST_CMP "$@" } +# Check if the file expected to be empty is indeed empty, and barfs +# otherwise. + +test_must_be_empty () { + if test -s "$1" + then + echo "'$1' is not empty, it contains:" + cat "$1" + return 1 + fi +} + +# Tests that its two parameters refer to the same revision +test_cmp_rev () { + git rev-parse --verify "$1" >expect.rev && + git rev-parse --verify "$2" >actual.rev && + test_cmp expect.rev actual.rev +} + # 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: @@ -646,3 +693,20 @@ test_create_repo () { mv .git/hooks .git/hooks-disabled ) || exit } + +# This function helps on symlink challenged file systems when it is not +# important that the file system entry is a symbolic link. +# Use test_ln_s_add instead of "ln -s x y && git add y" to add a +# symbolic link entry y to the index. + +test_ln_s_add () { + if test_have_prereq SYMLINKS + then + ln -s "$1" "$2" && + git update-index --add "$2" + else + printf '%s' "$1" >"$2" && + ln_s_obj=$(git hash-object -w "$2") && + git update-index --add --cacheinfo 120000 $ln_s_obj "$2" + fi +} diff --git a/t/test-lib.sh b/t/test-lib.sh index 489bc80fc1..1aa27bdbbf 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -54,8 +54,8 @@ done,*) # do not redirect again ;; *' --tee '*|*' --va'*) - mkdir -p test-results - BASE=test-results/$(basename "$0" .sh) + mkdir -p "$TEST_OUTPUT_DIRECTORY/test-results" + BASE="$TEST_OUTPUT_DIRECTORY/test-results/$(basename "$0" .sh)" (GIT_TEST_TEE_STARTED=done ${SHELL_PATH} "$0" "$@" 2>&1; echo $? > $BASE.exit) | tee $BASE.out test "$(cat $BASE.exit)" = 0 @@ -85,12 +85,14 @@ unset VISUAL EMAIL LANGUAGE COLUMNS $("$PERL_PATH" -e ' .*_TEST PROVE VALGRIND - PERF_AGGREGATING_LATER + UNZIP + PERF_ )); my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env); print join("\n", @vars); ') unset XDG_CONFIG_HOME +unset GITPERLLIB GIT_AUTHOR_EMAIL=author@example.com GIT_AUTHOR_NAME='A U Thor' GIT_COMMITTER_EMAIL=committer@example.com @@ -128,6 +130,7 @@ fi unset CDPATH unset GREP_OPTIONS +unset UNZIP case $(echo $GIT_TRACE |tr "[A-Z]" "[a-z]") in 1|2|true) @@ -182,6 +185,9 @@ do help=t; shift ;; -v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose) verbose=t; shift ;; + --verbose-only=*) + verbose_only=$(expr "z$1" : 'z[^=]*=\(.*\)') + shift ;; -q|--q|--qu|--qui|--quie|--quiet) # Ignore --quiet under a TAP::Harness. Saying how many tests # passed without the ok/not ok details is always an error. @@ -191,17 +197,45 @@ do --no-color) color=; shift ;; --va|--val|--valg|--valgr|--valgri|--valgrin|--valgrind) - valgrind=t; verbose=t; shift ;; + valgrind=memcheck + shift ;; + --valgrind=*) + valgrind=$(expr "z$1" : 'z[^=]*=\(.*\)') + shift ;; + --valgrind-only=*) + valgrind_only=$(expr "z$1" : 'z[^=]*=\(.*\)') + shift ;; + --valgrind-parallel=*) + valgrind_parallel=$(expr "z$1" : 'z[^=]*=\(.*\)') + shift ;; + --valgrind-only-stride=*) + valgrind_only_stride=$(expr "z$1" : 'z[^=]*=\(.*\)') + shift ;; + --valgrind-only-offset=*) + valgrind_only_offset=$(expr "z$1" : 'z[^=]*=\(.*\)') + shift ;; --tee) shift ;; # was handled already --root=*) root=$(expr "z$1" : 'z[^=]*=\(.*\)') shift ;; + --statusprefix=*) + statusprefix=$(expr "z$1" : 'z[^=]*=\(.*\)') + shift ;; *) echo "error: unknown test option '$1'" >&2; exit 1 ;; esac done +if test -n "$valgrind_only" || test -n "$valgrind_only_stride" +then + test -z "$valgrind" && valgrind=memcheck + test -z "$verbose" && verbose_only="$valgrind_only" +elif test -n "$valgrind" +then + verbose=t +fi + if test -n "$color" then say_color () { @@ -212,11 +246,13 @@ then error) tput bold; tput setaf 1;; # bold red skip) - tput bold; tput setaf 2;; # bold green + tput setaf 4;; # blue + warn) + tput setaf 3;; # brown/yellow pass) - tput setaf 2;; # green + tput setaf 2;; # green info) - tput setaf 3;; # brown + tput setaf 6;; # cyan *) test -n "$quiet" && return;; esac @@ -293,12 +329,12 @@ trap 'die' EXIT test_ok_ () { test_success=$(($test_success + 1)) - say_color "" "ok $test_count - $@" + say_color "" "${statusprefix}ok $test_count - $@" } test_failure_ () { test_failure=$(($test_failure + 1)) - say_color error "not ok - $test_count $1" + say_color error "${statusprefix}not ok $test_count - $1" shift echo "$@" | sed -e 's/^/# /' test "$immediate" = "" || { GIT_EXIT_OK=t; exit 1; } @@ -306,18 +342,83 @@ test_failure_ () { test_known_broken_ok_ () { test_fixed=$(($test_fixed+1)) - say_color "" "ok $test_count - $@ # TODO known breakage" + say_color error "${statusprefix}ok $test_count - $@ # TODO known breakage vanished" } test_known_broken_failure_ () { test_broken=$(($test_broken+1)) - say_color skip "not ok $test_count - $@ # TODO known breakage" + say_color warn "${statusprefix}not ok $test_count - $@ # TODO known breakage" } test_debug () { test "$debug" = "" || eval "$1" } +match_pattern_list () { + arg="$1" + shift + test -z "$*" && return 1 + for pattern_ + do + case "$arg" in + $pattern_) + return 0 + esac + done + return 1 +} + +maybe_teardown_verbose () { + test -z "$verbose_only" && return + exec 4>/dev/null 3>/dev/null + verbose= +} + +last_verbose=t +maybe_setup_verbose () { + test -z "$verbose_only" && return + if match_pattern_list $test_count $verbose_only || + { test -n "$valgrind_only_stride" && + expr $test_count "%" $valgrind_only_stride - $valgrind_only_offset = 0 >/dev/null; } + then + exec 4>&2 3>&1 + # Emit a delimiting blank line when going from + # non-verbose to verbose. Within verbose mode the + # delimiter is printed by test_expect_*. The choice + # of the initial $last_verbose is such that before + # test 1, we do not print it. + test -z "$last_verbose" && echo >&3 "" + verbose=t + else + exec 4>/dev/null 3>/dev/null + verbose= + fi + last_verbose=$verbose +} + +maybe_teardown_valgrind () { + test -z "$GIT_VALGRIND" && return + GIT_VALGRIND_ENABLED= +} + +maybe_setup_valgrind () { + test -z "$GIT_VALGRIND" && return + if test -z "$valgrind_only" && test -z "$valgrind_only_stride" + then + GIT_VALGRIND_ENABLED=t + return + fi + GIT_VALGRIND_ENABLED= + if match_pattern_list $test_count $valgrind_only + then + GIT_VALGRIND_ENABLED=t + elif test -n "$valgrind_only_stride" && + expr $test_count "%" $valgrind_only_stride - $valgrind_only_offset = 0 >/dev/null + then + GIT_VALGRIND_ENABLED=t + fi +} + test_eval_ () { # This is a separate function because some tests use # "return" to end a test_expect_success block early. @@ -327,8 +428,10 @@ test_eval_ () { test_run_ () { test_cleanup=: expecting_failure=$2 + setup_malloc_check test_eval_ "$1" eval_ret=$? + teardown_malloc_check if test -z "$immediate" || test $eval_ret = 0 || test -n "$expecting_failure" then @@ -343,17 +446,24 @@ test_run_ () { return "$eval_ret" } -test_skip () { +test_start_ () { test_count=$(($test_count+1)) + maybe_setup_verbose + maybe_setup_valgrind +} + +test_finish_ () { + echo >&3 "" + maybe_teardown_valgrind + maybe_teardown_verbose +} + +test_skip () { to_skip= - for skp in $GIT_SKIP_TESTS - do - case $this_test.$test_count in - $skp) - to_skip=t - break - esac - done + if match_pattern_list $this_test.$test_count $GIT_SKIP_TESTS + then + to_skip=t + fi if test -z "$to_skip" && test -n "$test_prereq" && ! test_have_prereq "$test_prereq" then @@ -367,8 +477,8 @@ test_skip () { of_prereq=" of $test_prereq" fi - say_color skip >&3 "skipping test: $@" - say_color skip "ok $test_count # skip $1 (missing $missing_prereq${of_prereq})" + say_color skip >&3 "${statusprefix}skipping test: $@" + say_color skip "${statusprefix}ok $test_count # skip $1 (missing $missing_prereq${of_prereq})" : true ;; *) @@ -385,11 +495,14 @@ test_at_end_hook_ () { test_done () { GIT_EXIT_OK=t + # Note: t0000 relies on $HARNESS_ACTIVE disabling the .counts + # output file if test -z "$HARNESS_ACTIVE" then test_results_dir="$TEST_OUTPUT_DIRECTORY/test-results" mkdir -p "$test_results_dir" - test_results_path="$test_results_dir/${0%.sh}-$$.counts" + base=${0##*/} + test_results_path="$test_results_dir/${base%.sh}-$$.counts" cat >>"$test_results_path" <<-EOF total $test_count @@ -403,13 +516,18 @@ test_done () { if test "$test_fixed" != 0 then - say_color pass "# fixed $test_fixed known breakage(s)" + say_color error "${statusprefix}# $test_fixed known breakage(s) vanished; please update test(s)" fi if test "$test_broken" != 0 then - say_color error "# still have $test_broken known breakage(s)" - msg="remaining $(($test_count-$test_broken)) test(s)" + say_color warn "${statusprefix}# still have $test_broken known breakage(s)" + fi + if test "$test_broken" != 0 || test "$test_fixed" != 0 + then + test_remaining=$(( $test_count - $test_broken - $test_fixed )) + msg="remaining $test_remaining test(s)" else + test_remaining=$test_count msg="$test_count test(s)" fi case "$test_failure" in @@ -423,11 +541,11 @@ test_done () { if test $test_external_has_tap -eq 0 then - if test $test_count -gt 0 + if test $test_remaining -gt 0 then - say_color pass "# passed all $msg" + say_color pass "${statusprefix}# passed all $msg" fi - say "1..$test_count$skip_all" + say "${statusprefix}1..$test_count$skip_all" fi test -d "$remove_trash" && @@ -441,8 +559,8 @@ test_done () { *) if test $test_external_has_tap -eq 0 then - say_color error "# failed $test_failure among $msg" - say "1..$test_count" + say_color error "${statusprefix}# failed $test_failure among $msg" + say "${statusprefix}1..$test_count" fi exit 1 ;; @@ -450,6 +568,9 @@ test_done () { esac } + +# Set up a directory that we can put in PATH which redirects all git +# calls to 'valgrind git ...'. if test -n "$valgrind" then make_symlink () { @@ -497,29 +618,43 @@ then make_symlink "$symlink_target" "$GIT_VALGRIND/bin/$base" || exit } - # override all git executables in TEST_DIRECTORY/.. - GIT_VALGRIND=$TEST_DIRECTORY/valgrind - mkdir -p "$GIT_VALGRIND"/bin - for file in $GIT_BUILD_DIR/git* $GIT_BUILD_DIR/test-* - do - make_valgrind_symlink $file - done - # special-case the mergetools loadables - make_symlink "$GIT_BUILD_DIR"/mergetools "$GIT_VALGRIND/bin/mergetools" - OLDIFS=$IFS - IFS=: - for path in $PATH - do - ls "$path"/git-* 2> /dev/null | - while read file + # In the case of --valgrind-parallel, we only need to do the + # wrapping once, in the main script. The worker children all + # have $valgrind_only_stride set, so we can skip based on that. + if test -z "$valgrind_only_stride" + then + # override all git executables in TEST_DIRECTORY/.. + GIT_VALGRIND=$TEST_DIRECTORY/valgrind + mkdir -p "$GIT_VALGRIND"/bin + for file in $GIT_BUILD_DIR/git* $GIT_BUILD_DIR/test-* do - make_valgrind_symlink "$file" + make_valgrind_symlink $file done - done - IFS=$OLDIFS + # special-case the mergetools loadables + make_symlink "$GIT_BUILD_DIR"/mergetools "$GIT_VALGRIND/bin/mergetools" + OLDIFS=$IFS + IFS=: + for path in $PATH + do + ls "$path"/git-* 2> /dev/null | + while read file + do + make_valgrind_symlink "$file" + done + done + IFS=$OLDIFS + fi PATH=$GIT_VALGRIND/bin:$PATH GIT_EXEC_PATH=$GIT_VALGRIND/bin export GIT_VALGRIND + GIT_VALGRIND_MODE="$valgrind" + export GIT_VALGRIND_MODE + GIT_VALGRIND_ENABLED=t + if test -n "$valgrind_only" || test -n "$valgrind_only_stride" + then + GIT_VALGRIND_ENABLED= + fi + export GIT_VALGRIND_ENABLED elif test -n "$GIT_TEST_INSTALLED" then GIT_EXEC_PATH=$($GIT_TEST_INSTALLED/git --exec-path) || @@ -582,14 +717,14 @@ then fi # Test repository -test="trash directory.$(basename "$0" .sh)" -test -n "$root" && test="$root/$test" -case "$test" in -/*) TRASH_DIRECTORY="$test" ;; - *) TRASH_DIRECTORY="$TEST_OUTPUT_DIRECTORY/$test" ;; +TRASH_DIRECTORY="trash directory.$(basename "$0" .sh)" +test -n "$root" && TRASH_DIRECTORY="$root/$TRASH_DIRECTORY" +case "$TRASH_DIRECTORY" in +/*) ;; # absolute path is good + *) TRASH_DIRECTORY="$TEST_OUTPUT_DIRECTORY/$TRASH_DIRECTORY" ;; esac test ! -z "$debug" || remove_trash=$TRASH_DIRECTORY -rm -fr "$test" || { +rm -fr "$TRASH_DIRECTORY" || { GIT_EXIT_OK=t echo >&5 "FATAL: Cannot prepare test area" exit 1 @@ -600,25 +735,57 @@ export HOME if test -z "$TEST_NO_CREATE_REPO" then - test_create_repo "$test" + test_create_repo "$TRASH_DIRECTORY" else - mkdir -p "$test" + mkdir -p "$TRASH_DIRECTORY" +fi + +# Gross hack to spawn N sub-instances of the tests in parallel, and +# summarize the results. Note that if this is enabled, the script +# terminates at the end of this 'if' block. +if test -n "$valgrind_parallel" +then + for i in $(test_seq 1 $valgrind_parallel) + do + root="$TRASH_DIRECTORY/vgparallel-$i" + mkdir "$root" + TEST_OUTPUT_DIRECTORY="$root" \ + ${SHELL_PATH} "$0" \ + --root="$root" --statusprefix="[$i] " \ + --valgrind="$valgrind" \ + --valgrind-only-stride="$valgrind_parallel" \ + --valgrind-only-offset="$i" & + pids="$pids $!" + done + trap "kill $pids" INT TERM HUP + wait $pids + trap - INT TERM HUP + for i in $(test_seq 1 $valgrind_parallel) + do + root="$TRASH_DIRECTORY/vgparallel-$i" + eval "$(cat "$root/test-results/$(basename "$0" .sh)"-*.counts | + sed 's/^\([a-z][a-z]*\) \([0-9][0-9]*\)/inner_\1=\2/')" + test_count=$(expr $test_count + $inner_total) + test_success=$(expr $test_success + $inner_success) + test_fixed=$(expr $test_fixed + $inner_fixed) + test_broken=$(expr $test_broken + $inner_broken) + test_failure=$(expr $test_failure + $inner_failed) + done + test_done 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 +cd -P "$TRASH_DIRECTORY" || exit 1 this_test=${0##*/} this_test=${this_test%%-*} -for skp in $GIT_SKIP_TESTS -do - case "$this_test" in - $skp) - say_color skip >&3 "skipping test $this_test altogether" - skip_all="skip all tests in $this_test" - test_done - esac -done +if match_pattern_list "$this_test" $GIT_SKIP_TESTS +then + say_color info >&3 "skipping test $this_test altogether" + skip_all="skip all tests in $this_test" + test_done +fi # Provide an implementation of the 'yes' utility yes () { @@ -656,19 +823,24 @@ case $(uname -s) in # backslashes in pathspec are converted to '/' # exec does not inherit the PID test_set_prereq MINGW + test_set_prereq NOT_CYGWIN test_set_prereq SED_STRIPS_CR + test_set_prereq GREP_STRIPS_CR ;; *CYGWIN*) test_set_prereq POSIXPERM test_set_prereq EXECKEEPSPID test_set_prereq NOT_MINGW + test_set_prereq CYGWIN test_set_prereq SED_STRIPS_CR + test_set_prereq GREP_STRIPS_CR ;; *) test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID test_set_prereq NOT_MINGW + test_set_prereq NOT_CYGWIN ;; esac @@ -714,6 +886,18 @@ test_i18ngrep () { fi } +test_lazy_prereq PIPE ' + # test whether the filesystem supports FIFOs + case $(uname -s) in + CYGWIN*) + false + ;; + *) + rm -f testfifo && mkfifo testfifo + ;; + esac +' + test_lazy_prereq SYMLINKS ' # test whether the filesystem supports symbolic links ln -s x y && test -h y @@ -738,6 +922,18 @@ test_lazy_prereq UTF8_NFD_TO_NFC ' esac ' +test_lazy_prereq AUTOIDENT ' + sane_unset GIT_AUTHOR_NAME && + sane_unset GIT_AUTHOR_EMAIL && + git var GIT_AUTHOR_IDENT +' + # When the tests are run as root, permission tests will report that # things are writable when they shouldn't be. test -w / || test_set_prereq SANITY + +GIT_UNZIP=${GIT_UNZIP:-unzip} +test_lazy_prereq UNZIP ' + "$GIT_UNZIP" -v + test $? -ne 127 +' diff --git a/t/test-terminal.perl b/t/test-terminal.perl index 10172aee18..1fb373f25b 100755 --- a/t/test-terminal.perl +++ b/t/test-terminal.perl @@ -31,7 +31,7 @@ sub finish_child { } elsif ($? & 127) { my $code = $? & 127; warn "died of signal $code"; - return $code - 128; + return $code + 128; } else { return $? >> 8; } diff --git a/t/valgrind/analyze.sh b/t/valgrind/analyze.sh index d8105d9fab..2ffc80f721 100755 --- a/t/valgrind/analyze.sh +++ b/t/valgrind/analyze.sh @@ -1,6 +1,10 @@ #!/bin/sh -out_prefix=$(dirname "$0")/../test-results/valgrind.out +# Get TEST_OUTPUT_DIRECTORY from GIT-BUILD-OPTIONS if it's there... +. "$(dirname "$0")/../../GIT-BUILD-OPTIONS" +# ... otherwise set it to the default value. +: ${TEST_OUTPUT_DIRECTORY=$(dirname "$0")/..} + output= count=0 total_count=0 @@ -115,7 +119,7 @@ handle_one () { finish_output } -for test_script in "$(dirname "$0")"/../test-results/*.out +for test_script in "$TEST_OUTPUT_DIRECTORY"/test-results/*.out do handle_one $test_script done diff --git a/t/valgrind/valgrind.sh b/t/valgrind/valgrind.sh index 582b4dca94..42153036dc 100755 --- a/t/valgrind/valgrind.sh +++ b/t/valgrind/valgrind.sh @@ -2,20 +2,30 @@ base=$(basename "$0") -TRACK_ORIGINS= +TOOL_OPTIONS='--leak-check=no' -VALGRIND_VERSION=$(valgrind --version) -VALGRIND_MAJOR=$(expr "$VALGRIND_VERSION" : '[^0-9]*\([0-9]*\)') -VALGRIND_MINOR=$(expr "$VALGRIND_VERSION" : '[^0-9]*[0-9]*\.\([0-9]*\)') -test 3 -gt "$VALGRIND_MAJOR" || -test 3 -eq "$VALGRIND_MAJOR" -a 4 -gt "$VALGRIND_MINOR" || -TRACK_ORIGINS=--track-origins=yes +test -z "$GIT_VALGRIND_ENABLED" && +exec "$GIT_VALGRIND"/../../"$base" "$@" + +case "$GIT_VALGRIND_MODE" in +memcheck-fast) + ;; +memcheck) + VALGRIND_VERSION=$(valgrind --version) + VALGRIND_MAJOR=$(expr "$VALGRIND_VERSION" : '[^0-9]*\([0-9]*\)') + VALGRIND_MINOR=$(expr "$VALGRIND_VERSION" : '[^0-9]*[0-9]*\.\([0-9]*\)') + test 3 -gt "$VALGRIND_MAJOR" || + test 3 -eq "$VALGRIND_MAJOR" -a 4 -gt "$VALGRIND_MINOR" || + TOOL_OPTIONS="$TOOL_OPTIONS --track-origins=yes" + ;; +*) + TOOL_OPTIONS="--tool=$GIT_VALGRIND_MODE" +esac exec valgrind -q --error-exitcode=126 \ - --leak-check=no \ - --suppressions="$GIT_VALGRIND/default.supp" \ --gen-suppressions=all \ - $TRACK_ORIGINS \ + --suppressions="$GIT_VALGRIND/default.supp" \ + $TOOL_OPTIONS \ --log-fd=4 \ --input-fd=4 \ $GIT_VALGRIND_OPTIONS \ |