diff options
Diffstat (limited to 't')
459 files changed, 26486 insertions, 5899 deletions
diff --git a/t/.gitattributes b/t/.gitattributes index 1b97c5465b..2d44088f56 100644 --- a/t/.gitattributes +++ b/t/.gitattributes @@ -1 +1,2 @@ t[0-9][0-9][0-9][0-9]/* -whitespace +t0110/url-* binary diff --git a/t/Git-SVN/00compile.t b/t/Git-SVN/00compile.t index c92fee453f..c92fee453f 100644..100755 --- a/t/Git-SVN/00compile.t +++ b/t/Git-SVN/00compile.t diff --git a/t/Git-SVN/Utils/add_path_to_url.t b/t/Git-SVN/Utils/add_path_to_url.t index bfbd87845f..bfbd87845f 100644..100755 --- a/t/Git-SVN/Utils/add_path_to_url.t +++ b/t/Git-SVN/Utils/add_path_to_url.t diff --git a/t/Git-SVN/Utils/can_compress.t b/t/Git-SVN/Utils/can_compress.t index d7b49b8d54..d7b49b8d54 100644..100755 --- a/t/Git-SVN/Utils/can_compress.t +++ b/t/Git-SVN/Utils/can_compress.t diff --git a/t/Git-SVN/Utils/canonicalize_url.t b/t/Git-SVN/Utils/canonicalize_url.t index 05795ab636..05795ab636 100644..100755 --- a/t/Git-SVN/Utils/canonicalize_url.t +++ b/t/Git-SVN/Utils/canonicalize_url.t diff --git a/t/Git-SVN/Utils/collapse_dotdot.t b/t/Git-SVN/Utils/collapse_dotdot.t index 1da1cce156..1da1cce156 100644..100755 --- a/t/Git-SVN/Utils/collapse_dotdot.t +++ b/t/Git-SVN/Utils/collapse_dotdot.t diff --git a/t/Git-SVN/Utils/fatal.t b/t/Git-SVN/Utils/fatal.t index 49e1438295..49e1438295 100644..100755 --- a/t/Git-SVN/Utils/fatal.t +++ b/t/Git-SVN/Utils/fatal.t diff --git a/t/Git-SVN/Utils/join_paths.t b/t/Git-SVN/Utils/join_paths.t index d4488e7162..d4488e7162 100644..100755 --- a/t/Git-SVN/Utils/join_paths.t +++ b/t/Git-SVN/Utils/join_paths.t 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,10 +334,17 @@ 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 - does not do so, whose path is specified with $PERL_PATH. + does not do so, whose path is specified with $PERL_PATH. Note that we + provide a "perl" function which uses $PERL_PATH under the hood, so + you do not need to worry when simply running perl in the test scripts + (but you do, for example, on a shebang line or in a sub script + created via "write_script"). - use sh without spelling it as "$SHELL_PATH", when the script can be misinterpreted by broken platform shell (e.g. Solaris). @@ -362,7 +391,7 @@ of the test_* functions (see the "Test harness library" section below), e.g.: test_expect_success PERL 'I need Perl' ' - "$PERL_PATH" -e "hlagh() if unf_unf()" + perl -e "hlagh() if unf_unf()" ' The advantage of skipping tests like this is that platforms that don't @@ -495,7 +524,7 @@ library for your script to use. test_external \ 'GitwebCache::*FileCache*' \ - "$PERL_PATH" "$TEST_DIRECTORY"/t9503/test_cache_interface.pl + perl "$TEST_DIRECTORY"/t9503/test_cache_interface.pl If the test is outputting its own TAP you should set the test_external_has_tap variable somewhere before calling the first @@ -511,7 +540,7 @@ library for your script to use. test_external_without_stderr \ 'Perl API' \ - "$PERL_PATH" "$TEST_DIRECTORY"/t9700/test.pl + perl "$TEST_DIRECTORY"/t9700/test.pl - test_expect_code <exit-code> <command> @@ -580,6 +609,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 ------------- @@ -590,11 +633,18 @@ See the prereq argument to the test_* functions in the "Test harness library" section above and the "test_have_prereq" function for how to use these, and "test_set_prereq" for how to define your own. - - PERL & PYTHON + - PYTHON + + Git wasn't compiled with NO_PYTHON=YesPlease. Wrap any tests that + need Python with this. + + - PERL - Git wasn't compiled with NO_PERL=YesPlease or - NO_PYTHON=YesPlease. Wrap any tests that need Perl or Python in - these. + Git wasn't compiled with NO_PERL=YesPlease. + + Even without the PERL prerequisite, tests can assume there is a + usable perl interpreter at $PERL_PATH, though it need not be + particularly modern. - POSIXPERM @@ -610,6 +660,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..304c7b7d87 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,513 @@ 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 merge 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 'blame huge graft' ' + test_when_finished "git checkout branch2" && + test_when_finished "rm -f .git/info/grafts" && + graft= && + for i in 0 1 2 + do + for j in 0 1 2 3 4 5 6 7 8 9 + do + git checkout --orphan "$i$j" && + printf "%s\n" "$i" "$j" >file && + test_tick && + GIT_AUTHOR_NAME=$i$j GIT_AUTHOR_EMAIL=$i$j@test.git \ + git commit -a -m "$i$j" && + commit=$(git rev-parse --verify HEAD) && + graft="$graft$commit " + done + done && + printf "%s " $graft >.git/info/grafts && + check_count -h 00 01 1 10 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' ' + test_must_fail $PROG -L-1 file +' + +test_expect_success 'blame -L 0' ' + test_must_fail $PROG -L0 file +' + +test_expect_success 'blame -L ,0' ' + test_must_fail $PROG -L,0 file +' + +test_expect_success 'blame -L ,+0' ' + test_must_fail $PROG -L,+0 file +' + +test_expect_success 'blame -L X,+0' ' + test_must_fail $PROG -L1,+0 file +' + +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 ,-0' ' + test_must_fail $PROG -L,-0 file +' + +test_expect_success 'blame -L X,-0' ' + test_must_fail $PROG -L1,-0 file +' + +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 +' + +# 'file' ends with an incomplete line, so 'wc' reports one fewer lines than +# git-blame sees, hence the last line is actually $(wc...)+1. +test_expect_success 'blame -L X (X == nlines)' ' + n=$(expr $(wc -l <file) + 1) && + check_count -L$n C 1 +' + +test_expect_success 'blame -L X (X == nlines + 1)' ' + n=$(expr $(wc -l <file) + 2) && + test_must_fail $PROG -L$n file +' + +test_expect_success 'blame -L X (X > nlines)' ' + test_must_fail $PROG -L12345 file +' + +test_expect_success 'blame -L ,Y (Y == nlines)' ' + n=$(expr $(wc -l <file) + 1) && + check_count -L,$n A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1 E 1 +' + +test_expect_success 'blame -L ,Y (Y == nlines + 1)' ' + n=$(expr $(wc -l <file) + 2) && + test_must_fail $PROG -L,$n file +' + +test_expect_success 'blame -L ,Y (Y > nlines)' ' + test_must_fail $PROG -L,12345 file +' + +test_expect_success 'blame -L multiple (disjoint)' ' + check_count -L2,3 -L6,7 A 1 B1 1 B2 1 "A U Thor" 1 +' + +test_expect_success 'blame -L multiple (disjoint: unordered)' ' + check_count -L6,7 -L2,3 A 1 B1 1 B2 1 "A U Thor" 1 +' + +test_expect_success 'blame -L multiple (adjacent)' ' + check_count -L2,3 -L4,5 A 1 B 1 B2 1 D 1 +' + +test_expect_success 'blame -L multiple (adjacent: unordered)' ' + check_count -L4,5 -L2,3 A 1 B 1 B2 1 D 1 +' + +test_expect_success 'blame -L multiple (overlapping)' ' + check_count -L2,4 -L3,5 A 1 B 1 B2 1 D 1 +' + +test_expect_success 'blame -L multiple (overlapping: unordered)' ' + check_count -L3,5 -L2,4 A 1 B 1 B2 1 D 1 +' + +test_expect_success 'blame -L multiple (superset/subset)' ' + check_count -L2,8 -L3,5 A 1 B 1 B1 1 B2 1 C 1 D 1 "A U Thor" 1 +' + +test_expect_success 'blame -L multiple (superset/subset: unordered)' ' + check_count -L3,5 -L2,8 A 1 B 1 B1 1 B2 1 C 1 D 1 "A U Thor" 1 +' + +test_expect_success 'blame -L /RE/ (relative)' ' + check_count -L3,3 -L/fox/ B1 1 B2 1 C 1 D 1 "A U Thor" 1 +' + +test_expect_success 'blame -L /RE/ (relative: no preceding range)' ' + check_count -L/dog/ A 1 B 1 B1 1 B2 1 C 1 D 1 "A U Thor" 1 +' + +test_expect_success 'blame -L /RE/ (relative: adjacent)' ' + check_count -L1,1 -L/dog/,+1 A 1 E 1 +' + +test_expect_success 'blame -L /RE/ (relative: not found)' ' + test_must_fail $PROG -L4,4 -L/dog/ file +' + +test_expect_success 'blame -L /RE/ (relative: end-of-file)' ' + test_must_fail $PROG -L, -L/$/ file +' + +test_expect_success 'blame -L ^/RE/ (absolute)' ' + check_count -L3,3 -L^/dog/,+2 A 1 B2 1 +' + +test_expect_success 'blame -L ^/RE/ (absolute: no preceding range)' ' + check_count -L^/dog/,+2 A 1 B2 1 +' + +test_expect_success 'blame -L ^/RE/ (absolute: not found)' ' + test_must_fail $PROG -L4,4 -L^/tambourine/ file +' + +test_expect_success 'blame -L ^/RE/ (absolute: end-of-file)' ' + n=$(expr $(wc -l <file) + 1) && + check_count -L$n -L^/$/,+2 A 1 C 1 E 1 +' + +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 "/}/ {x; s/$/Qputs(\"goodbye\");/; G;}" <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 :RE (relative)' ' + check_count -f hello.c -L3,3 -L:ma.. F 1 H 4 +' + +test_expect_success 'blame -L :RE (relative: no preceding range)' ' + check_count -f hello.c -L:ma.. F 4 G 1 +' + +test_expect_success 'blame -L :RE (relative: not found)' ' + test_must_fail $PROG -L3,3 -L:tambourine hello.c +' + +test_expect_success 'blame -L :RE (relative: end-of-file)' ' + test_must_fail $PROG -L, -L:main hello.c +' + +test_expect_success 'blame -L ^:RE (absolute)' ' + check_count -f hello.c -L3,3 -L^:ma.. F 4 G 1 +' + +test_expect_success 'blame -L ^:RE (absolute: no preceding range)' ' + check_count -f hello.c -L^:ma.. F 4 G 1 +' + +test_expect_success 'blame -L ^:RE (absolute: not found)' ' + test_must_fail $PROG -L4,4 -L^:tambourine hello.c +' + +test_expect_success 'blame -L ^:RE (absolute: end-of-file)' ' + n=$(printf "%d" $(wc -l <hello.c)) && + check_count -f hello.c -L$n -L^:ma.. F 4 G 1 H 1 +' + +test_expect_success 'setup incremental' ' + ( + GIT_AUTHOR_NAME=I && + export GIT_AUTHOR_NAME && + GIT_AUTHOR_EMAIL=I@test.git && + export GIT_AUTHOR_EMAIL && + >incremental && + git add incremental && + git commit -m "step 0" && + printf "partial" >>incremental && + git commit -a -m "step 0.5" && + echo >>incremental && + git commit -a -m "step 1" + ) +' + +test_expect_success 'blame empty' ' + check_count -h HEAD^^ -f incremental +' + +test_expect_success 'blame -L 0 empty' ' + test_must_fail $PROG -L0 incremental HEAD^^ +' + +test_expect_success 'blame -L 1 empty' ' + test_must_fail $PROG -L1 incremental HEAD^^ +' + +test_expect_success 'blame -L 2 empty' ' + test_must_fail $PROG -L2 incremental HEAD^^ +' + +test_expect_success 'blame half' ' + check_count -h HEAD^ -f incremental I 1 +' + +test_expect_success 'blame -L 0 half' ' + test_must_fail $PROG -L0 incremental HEAD^ +' + +test_expect_success 'blame -L 1 half' ' + check_count -h HEAD^ -f incremental -L1 I 1 +' + +test_expect_success 'blame -L 2 half' ' + test_must_fail $PROG -L2 incremental HEAD^ +' + +test_expect_success 'blame -L 3 half' ' + test_must_fail $PROG -L3 incremental HEAD^ +' + +test_expect_success 'blame full' ' + check_count -f incremental I 1 +' + +test_expect_success 'blame -L 0 full' ' + test_must_fail $PROG -L0 incremental +' + +test_expect_success 'blame -L 1 full' ' + check_count -f incremental -L1 I 1 +' + +test_expect_success 'blame -L 2 full' ' + test_must_fail $PROG -L2 incremental +' + +test_expect_success 'blame -L 3 full' ' + test_must_fail $PROG -L3 incremental +' + +test_expect_success 'blame -L' ' + test_must_fail $PROG -L file +' + +test_expect_success 'blame -L X,+' ' + test_must_fail $PROG -L1,+ file +' + +test_expect_success 'blame -L X,-' ' + test_must_fail $PROG -L1,- file +' + +test_expect_success 'blame -L X (non-numeric X)' ' + test_must_fail $PROG -LX file +' + +test_expect_success 'blame -L X,Y (non-numeric Y)' ' + test_must_fail $PROG -L1,Y file +' + +test_expect_success 'blame -L X,+N (non-numeric N)' ' + test_must_fail $PROG -L1,+N file +' + +test_expect_success 'blame -L X,-N (non-numeric N)' ' + test_must_fail $PROG -L1,-N file +' + +test_expect_success 'blame -L ,^/RE/' ' + test_must_fail $PROG -L1,^/99/ 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/gitweb-lib.sh b/t/gitweb-lib.sh index ae2dc4604f..d5dab5a94f 100644 --- a/t/gitweb-lib.sh +++ b/t/gitweb-lib.sh @@ -1,4 +1,5 @@ -#!/bin/sh +# Initialization and helpers for Gitweb tests, which source this +# shell library instead of test-lib.sh. # # Copyright (c) 2007 Jakub Narebski # @@ -36,7 +37,7 @@ EOF # You can set the GITWEB_TEST_INSTALLED environment variable to # the gitwebdir (the directory where gitweb is installed / deployed to) - # of an existing gitweb instalation to test that installation, + # of an existing gitweb installation to test that installation, # or simply to pathname of installed gitweb script. if test -n "$GITWEB_TEST_INSTALLED" ; then if test -d $GITWEB_TEST_INSTALLED; then @@ -69,7 +70,7 @@ gitweb_run () { # written to web server logs, so we are not interested in that: # we are interested only in properly formatted errors/warnings rm -f gitweb.log && - "$PERL_PATH" -- "$SCRIPT_NAME" \ + perl -- "$SCRIPT_NAME" \ >gitweb.output 2>gitweb.log && perl -w -e ' open O, ">gitweb.headers"; diff --git a/t/lib-bash.sh b/t/lib-bash.sh index 11397f747b..2be955fafb 100644 --- a/t/lib-bash.sh +++ b/t/lib-bash.sh @@ -1,7 +1,6 @@ -#!/bin/sh -# -# Ensures that tests are run under Bash; primarily intended for running tests -# of the completion script. +# Shell library sourced instead of ./test-lib.sh by tests that need +# to run under Bash; primarily intended for tests of the completion +# script. if test -n "$BASH" && test -z "$POSIXLY_CORRECT"; then # we are in full-on bash mode diff --git a/t/lib-credential.sh b/t/lib-credential.sh index 3c43ff11b3..957ae936e8 100755 --- a/t/lib-credential.sh +++ b/t/lib-credential.sh @@ -18,10 +18,6 @@ check() { cat stderr && false fi && - if test_have_prereq MINGW - then - dos2unix -q stderr - fi && test_cmp expect-stdout stdout && test_cmp expect-stderr stderr } diff --git a/t/lib-cvs.sh b/t/lib-cvs.sh index 44263ade25..5076718916 100644 --- a/t/lib-cvs.sh +++ b/t/lib-cvs.sh @@ -1,4 +1,4 @@ -#!/bin/sh +# Shell library sourced instead of ./test-lib.sh by cvsimport tests. . ./test-lib.sh diff --git a/t/lib-diff-alternative.sh b/t/lib-diff-alternative.sh index 75ffd9174f..8b4dbf22d2 100644 --- a/t/lib-diff-alternative.sh +++ b/t/lib-diff-alternative.sh @@ -1,4 +1,5 @@ -#!/bin/sh +# Helpers shared by the test scripts for diff algorithms (patience, +# histogram, etc). test_diff_frobnitz() { cat >file1 <<\EOF diff --git a/t/lib-gettext.sh b/t/lib-gettext.sh index 0f76f6cdc0..eec757f104 100644 --- a/t/lib-gettext.sh +++ b/t/lib-gettext.sh @@ -1,4 +1,5 @@ -#!/bin/sh +# Initialization and Icelandic locale for basic git i18n tests, +# which source this scriptlet instead of ./test-lib.sh. # # Copyright (c) 2010 Ævar Arnfjörð Bjarmason # @@ -14,12 +15,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-daemon.sh b/t/lib-git-daemon.sh index 87f0ad8f41..bc4b3412fb 100644 --- a/t/lib-git-daemon.sh +++ b/t/lib-git-daemon.sh @@ -1,12 +1,29 @@ -#!/bin/sh +# Shell library to run git-daemon in tests. Ends the test early if +# GIT_TEST_GIT_DAEMON is not set. +# +# Usage: +# +# . ./test-lib.sh +# . "$TEST_DIRECTORY"/lib-git-daemon.sh +# start_git_daemon +# +# test_expect_success '...' ' +# ... +# ' +# +# test_expect_success ... +# +# stop_git_daemon +# test_done -if test -z "$GIT_TEST_GIT_DAEMON" +test_tristate GIT_TEST_GIT_DAEMON +if test "$GIT_TEST_GIT_DAEMON" = false then - skip_all="git-daemon testing disabled (define GIT_TEST_GIT_DAEMON to enable)" + skip_all="git-daemon testing disabled (unset GIT_TEST_GIT_DAEMON to enable)" test_done fi -LIB_GIT_DAEMON_PORT=${LIB_GIT_DAEMON_PORT-'8121'} +LIB_GIT_DAEMON_PORT=${LIB_GIT_DAEMON_PORT-${this_test#t}} GIT_DAEMON_PID= GIT_DAEMON_DOCUMENT_ROOT_PATH="$PWD"/repo @@ -42,7 +59,8 @@ start_git_daemon() { kill "$GIT_DAEMON_PID" wait "$GIT_DAEMON_PID" trap 'die' EXIT - error "git daemon failed to start" + test_skip_or_die $GIT_TEST_GIT_DAEMON \ + "git daemon failed to start" fi } diff --git a/t/lib-git-p4.sh b/t/lib-git-p4.sh index 7061dce7e5..5aa8adcf9c 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. # @@ -28,20 +47,31 @@ P4DPORT=$((10669 + ($testid - $git_p4_test_start))) P4PORT=localhost:$P4DPORT P4CLIENT=client -P4EDITOR=: -export P4PORT P4CLIENT P4EDITOR +P4USER=author +P4EDITOR=true +unset P4CHARSET +export P4PORT P4CLIENT P4USER P4EDITOR P4CHARSET 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" +# git p4 submit generates a temp file, which will +# not get cleaned up if the submission fails. Don't +# clutter up /tmp on the test machine. +TMPDIR="$TRASH_DIRECTORY" +export TMPDIR + 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 @@ -73,19 +103,24 @@ start_p4d() { return 1 fi + # build a p4 user so author@example.com has an entry + p4_add_user author + # 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 } +p4_add_user() { + name=$1 && + p4 user -f -i <<-EOF + User: $name + Email: $name@example.com + FullName: Dr. $name + EOF +} + kill_p4d() { pid=$(cat "$pidfile") # it had better exist for the first kill @@ -123,13 +158,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..b0ec12ff6c 100644 --- a/t/lib-git-svn.sh +++ b/t/lib-git-svn.sh @@ -29,7 +29,7 @@ export svnrepo svnconf=$PWD/svnconf export svnconf -"$PERL_PATH" -w -e " +perl -w -e " use SVN::Core; use SVN::Repos; \$SVN::Core::VERSION gt '1.1.0' or exit(42); @@ -146,9 +146,9 @@ stop_httpd () { } convert_to_rev_db () { - "$PERL_PATH" -w -- - "$@" <<\EOF + perl -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..252cbf163b 100644 --- a/t/lib-httpd.sh +++ b/t/lib-httpd.sh @@ -1,11 +1,39 @@ -#!/bin/sh +# Shell library to run an HTTP server for use in tests. +# Ends the test early if httpd tests should not be run, +# for example because the user has not enabled them. +# +# Usage: +# +# . ./test-lib.sh +# . "$TEST_DIRECTORY"/lib-httpd.sh +# start_httpd +# +# test_expect_success '...' ' +# ... +# ' +# +# test_expect_success ... +# +# stop_httpd +# test_done +# +# Can be configured using the following variables. +# +# GIT_TEST_HTTPD enable HTTPD tests +# LIB_HTTPD_PATH web server path +# LIB_HTTPD_MODULE_PATH web server modules path +# LIB_HTTPD_PORT listening port +# LIB_HTTPD_DAV enable DAV +# LIB_HTTPD_SVN enable SVN +# LIB_HTTPD_SSL enable SSL # # Copyright (c) 2008 Clemens Buchacher <drizzd@aon.at> # -if test -z "$GIT_TEST_HTTPD" +test_tristate GIT_TEST_HTTPD +if test "$GIT_TEST_HTTPD" = false then - skip_all="Network testing disabled (define GIT_TEST_HTTPD to enable)" + skip_all="Network testing disabled (unset GIT_TEST_HTTPD to enable)" test_done fi @@ -37,7 +65,7 @@ case $(uname) in esac LIB_HTTPD_PATH=${LIB_HTTPD_PATH-"$DEFAULT_HTTPD_PATH"} -LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'8111'} +LIB_HTTPD_PORT=${LIB_HTTPD_PORT-${this_test#t}} TEST_PATH="$TEST_DIRECTORY"/lib-httpd HTTPD_ROOT_PATH="$PWD"/httpd @@ -49,8 +77,7 @@ GIT_VALGRIND_OPTIONS=$GIT_VALGRIND_OPTIONS; export GIT_VALGRIND_OPTIONS if ! test -x "$LIB_HTTPD_PATH" then - skip_all="skipping test, no web server found at '$LIB_HTTPD_PATH'" - test_done + test_skip_or_die $GIT_TEST_HTTPD "no web server found at '$LIB_HTTPD_PATH'" fi HTTPD_VERSION=`$LIB_HTTPD_PATH -v | \ @@ -62,24 +89,26 @@ then then if ! test $HTTPD_VERSION -ge 2 then - skip_all="skipping test, at least Apache version 2 is required" - test_done + test_skip_or_die $GIT_TEST_HTTPD \ + "at least Apache version 2 is required" fi if ! test -d "$DEFAULT_HTTPD_MODULE_PATH" then - skip_all="Apache module directory not found. Skipping tests." - test_done + test_skip_or_die $GIT_TEST_HTTPD \ + "Apache module directory not found" fi LIB_HTTPD_MODULE_PATH="$DEFAULT_HTTPD_MODULE_PATH" fi else - error "Could not identify web server at '$LIB_HTTPD_PATH'" + test_skip_or_die $GIT_TEST_HTTPD \ + "Could not identify web server at '$LIB_HTTPD_PATH'" 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" @@ -101,7 +130,7 @@ prepare_httpd() { HTTPD_DEST=127.0.0.1:$LIB_HTTPD_PORT HTTPD_URL=$HTTPD_PROTO://$HTTPD_DEST HTTPD_URL_USER=$HTTPD_PROTO://user%40host@$HTTPD_DEST - HTTPD_URL_USER_PASS=$HTTPD_PROTO://user%40host:user%40host@$HTTPD_DEST + HTTPD_URL_USER_PASS=$HTTPD_PROTO://user%40host:pass%40host@$HTTPD_DEST if test -n "$LIB_HTTPD_DAV" -o -n "$LIB_HTTPD_SVN" then @@ -127,9 +156,8 @@ start_httpd() { >&3 2>&4 if test $? -ne 0 then - skip_all="skipping test, web server setup failed" trap 'die' EXIT - test_done + test_skip_or_die $GIT_TEST_HTTPD "web server setup failed" fi } @@ -140,10 +168,11 @@ stop_httpd() { -f "$TEST_PATH/apache.conf" $HTTPD_PARA -k stop } -test_http_push_nonff() { +test_http_push_nonff () { REMOTE_REPO=$1 LOCAL_REPO=$2 BRANCH=$3 + EXPECT_CAS_RESULT=${4-failure} test_expect_success 'non-fast-forward push fails' ' cd "$REMOTE_REPO" && @@ -166,13 +195,37 @@ test_http_push_nonff() { test_expect_success 'non-fast-forward push shows help message' ' test_i18ngrep "Updates were rejected because" output ' + + test_expect_${EXPECT_CAS_RESULT} 'force with lease aka cas' ' + HEAD=$( cd "$REMOTE_REPO" && git rev-parse --verify HEAD ) && + test_when_finished '\'' + (cd "$REMOTE_REPO" && git update-ref HEAD "$HEAD") + '\'' && + ( + cd "$LOCAL_REPO" && + git push -v --force-with-lease=$BRANCH:$HEAD origin + ) && + git rev-parse --verify "$BRANCH" >expect && + ( + cd "$REMOTE_REPO" && git rev-parse --verify HEAD + ) >actual && + test_cmp expect actual + ' } setup_askpass_helper() { test_expect_success 'setup askpass helper' ' write_script "$TRASH_DIRECTORY/askpass" <<-\EOF && echo >>"$TRASH_DIRECTORY/askpass-query" "askpass: $*" && - cat "$TRASH_DIRECTORY/askpass-response" + case "$*" in + *Username*) + what=user + ;; + *Password*) + what=pass + ;; + esac && + cat "$TRASH_DIRECTORY/askpass-$what" EOF GIT_ASKPASS="$TRASH_DIRECTORY/askpass" && export GIT_ASKPASS && @@ -182,11 +235,13 @@ setup_askpass_helper() { set_askpass() { >"$TRASH_DIRECTORY/askpass-query" && - echo "$*" >"$TRASH_DIRECTORY/askpass-response" + echo "$1" >"$TRASH_DIRECTORY/askpass-user" && + echo "$2" >"$TRASH_DIRECTORY/askpass-pass" } expect_askpass() { - dest=$HTTPD_DEST + dest=$HTTPD_DEST${3+/$3} + { case "$1" in none) diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf index fe76e84b74..3a03e8263d 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 @@ -23,6 +22,13 @@ ErrorLog error.log <IfModule !mod_version.c> LoadModule version_module modules/mod_version.so </IfModule> +<IfModule !mod_headers.c> + LoadModule headers_module modules/mod_headers.so +</IfModule> + +<IfVersion < 2.4> +LockFile accept.lock +</IfVersion> <IfVersion < 2.1> <IfModule !mod_auth.c> @@ -40,6 +46,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 +85,24 @@ 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> +<LocationMatch /smart_cookies/> + SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH} + SetEnv GIT_HTTP_EXPORT_ALL + Header set Set-Cookie name=value +</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> @@ -72,6 +110,8 @@ ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1 RewriteEngine on RewriteRule ^/smart-redir-perm/(.*)$ /smart/$1 [R=301] RewriteRule ^/smart-redir-temp/(.*)$ /smart/$1 [R=302] +RewriteRule ^/smart-redir-auth/(.*)$ /auth/smart/$1 [R=301] +RewriteRule ^/smart-redir-limited/(.*)/info/refs$ /smart/$1/info/refs [R=301] <IfDefine SSL> LoadModule ssl_module modules/mod_ssl.so @@ -106,6 +146,21 @@ SSLEngine On 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-httpd/passwd b/t/lib-httpd/passwd index f2fbcad33e..99a34d6487 100644 --- a/t/lib-httpd/passwd +++ b/t/lib-httpd/passwd @@ -1 +1 @@ -user@host:nKpa8pZUHx/ic +user@host:xb4E8pqD81KQs diff --git a/t/lib-pack.sh b/t/lib-pack.sh new file mode 100644 index 0000000000..7509846571 --- /dev/null +++ b/t/lib-pack.sh @@ -0,0 +1,98 @@ +# Support routines for hand-crafting weird or malicious packs. +# +# You can make a complete pack like: +# +# pack_header 2 >foo.pack && +# pack_obj e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 >>foo.pack && +# pack_obj e68fe8129b546b101aee9510c5328e7f21ca1d18 >>foo.pack && +# pack_trailer foo.pack + +# Print the big-endian 4-byte octal representation of $1 +uint32_octal () { + n=$1 + printf '\\%o' $(($n / 16777216)); n=$((n % 16777216)) + printf '\\%o' $(($n / 65536)); n=$((n % 65536)) + printf '\\%o' $(($n / 256)); n=$((n % 256)) + printf '\\%o' $(($n )); +} + +# Print the big-endian 4-byte binary representation of $1 +uint32_binary () { + printf "$(uint32_octal "$1")" +} + +# Print a pack header, version 2, for a pack with $1 objects +pack_header () { + printf 'PACK' && + printf '\0\0\0\2' && + uint32_binary "$1" +} + +# Print the pack data for object $1, as a delta against object $2 (or as a full +# object if $2 is missing or empty). The output is suitable for including +# directly in the packfile, and represents the entirety of the object entry. +# Doing this on the fly (especially picking your deltas) is quite tricky, so we +# have hardcoded some well-known objects. See the case statements below for the +# complete list. +pack_obj () { + case "$1" in + # empty blob + e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) + case "$2" in + '') + printf '\060\170\234\003\0\0\0\0\1' + return + ;; + esac + ;; + + # blob containing "\7\76" + e68fe8129b546b101aee9510c5328e7f21ca1d18) + case "$2" in + '') + printf '\062\170\234\143\267\3\0\0\116\0\106' + return + ;; + 01d7713666f4de822776c7622c10f1b07de280dc) + printf '\165\1\327\161\66\146\364\336\202\47\166' && + printf '\307\142\54\20\361\260\175\342\200\334\170' && + printf '\234\143\142\142\142\267\003\0\0\151\0\114' + return + ;; + esac + ;; + + # blob containing "\7\0" + 01d7713666f4de822776c7622c10f1b07de280dc) + case "$2" in + '') + printf '\062\170\234\143\147\0\0\0\20\0\10' + return + ;; + e68fe8129b546b101aee9510c5328e7f21ca1d18) + printf '\165\346\217\350\22\233\124\153\20\32\356' && + printf '\225\20\305\62\216\177\41\312\35\30\170\234' && + printf '\143\142\142\142\147\0\0\0\53\0\16' + return + ;; + esac + ;; + esac + + echo >&2 "BUG: don't know how to print $1${2:+ (from $2)}" + return 1 +} + +# Compute and append pack trailer to "$1" +pack_trailer () { + test-sha1 -b <"$1" >trailer.tmp && + cat trailer.tmp >>"$1" && + rm -f trailer.tmp +} + +# Remove any existing packs to make sure that +# whatever we index next will be the pack that we +# actually use. +clear_packs () { + rm -f .git/objects/pack/* +} diff --git a/t/lib-pager.sh b/t/lib-pager.sh index ba03eab14f..3aa7a3ffd8 100644 --- a/t/lib-pager.sh +++ b/t/lib-pager.sh @@ -1,4 +1,4 @@ -#!/bin/sh +# Helpers for tests of git's choice of pager. test_expect_success 'determine default pager' ' test_might_fail git config --unset core.pager && diff --git a/t/lib-prereq-FILEMODE.sh b/t/lib-prereq-FILEMODE.sh deleted file mode 100644 index bce5a4c8bd..0000000000 --- a/t/lib-prereq-FILEMODE.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2010 Ævar Arnfjörð Bjarmason -# - -if test "$(git config --bool core.filemode)" = false -then - say 'filemode disabled on the filesystem' -else - test_set_prereq FILEMODE -fi diff --git a/t/lib-read-tree.sh b/t/lib-read-tree.sh index abc2c6f57f..b95f485606 100644 --- a/t/lib-read-tree.sh +++ b/t/lib-read-tree.sh @@ -1,43 +1,41 @@ -#!/bin/sh -# # Helper functions to check if read-tree would succeed/fail as expected with # and without the dry-run option. They also test that the dry-run does not # write the index and that together with -u it doesn't touch the work tree. # read_tree_must_succeed () { - git ls-files -s >pre-dry-run && - git read-tree -n "$@" && - git ls-files -s >post-dry-run && - test_cmp pre-dry-run post-dry-run && - git read-tree "$@" + git ls-files -s >pre-dry-run && + git read-tree -n "$@" && + git ls-files -s >post-dry-run && + test_cmp pre-dry-run post-dry-run && + git read-tree "$@" } read_tree_must_fail () { - git ls-files -s >pre-dry-run && - test_must_fail git read-tree -n "$@" && - git ls-files -s >post-dry-run && - test_cmp pre-dry-run post-dry-run && - test_must_fail git read-tree "$@" + git ls-files -s >pre-dry-run && + test_must_fail git read-tree -n "$@" && + git ls-files -s >post-dry-run && + test_cmp pre-dry-run post-dry-run && + test_must_fail git read-tree "$@" } read_tree_u_must_succeed () { - git ls-files -s >pre-dry-run && - git diff-files -p >pre-dry-run-wt && - git read-tree -n "$@" && - git ls-files -s >post-dry-run && - git diff-files -p >post-dry-run-wt && - test_cmp pre-dry-run post-dry-run && - test_cmp pre-dry-run-wt post-dry-run-wt && - git read-tree "$@" + git ls-files -s >pre-dry-run && + git diff-files -p >pre-dry-run-wt && + git read-tree -n "$@" && + git ls-files -s >post-dry-run && + git diff-files -p >post-dry-run-wt && + test_cmp pre-dry-run post-dry-run && + test_cmp pre-dry-run-wt post-dry-run-wt && + git read-tree "$@" } read_tree_u_must_fail () { - git ls-files -s >pre-dry-run && - git diff-files -p >pre-dry-run-wt && - test_must_fail git read-tree -n "$@" && - git ls-files -s >post-dry-run && - git diff-files -p >post-dry-run-wt && - test_cmp pre-dry-run post-dry-run && - test_cmp pre-dry-run-wt post-dry-run-wt && - test_must_fail git read-tree "$@" + git ls-files -s >pre-dry-run && + git diff-files -p >pre-dry-run-wt && + test_must_fail git read-tree -n "$@" && + git ls-files -s >post-dry-run && + git diff-files -p >post-dry-run-wt && + test_cmp pre-dry-run post-dry-run && + test_cmp pre-dry-run-wt post-dry-run-wt && + test_must_fail git read-tree "$@" } diff --git a/t/lib-rebase.sh b/t/lib-rebase.sh index 6ccf797091..6bd252212a 100644 --- a/t/lib-rebase.sh +++ b/t/lib-rebase.sh @@ -1,4 +1,4 @@ -#!/bin/sh +# Helper functions used by interactive rebase tests. # After setting the fake editor with this function, you can # @@ -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..3f2d873fec 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() -{ +# Replace unhelpful sha1 hashes with their symbolic equivalents +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/lib-terminal.sh b/t/lib-terminal.sh index 58d911d21b..51845491bb 100644 --- a/t/lib-terminal.sh +++ b/t/lib-terminal.sh @@ -1,6 +1,20 @@ -#!/bin/sh +# Helpers for terminal output tests. + +# Catch tests which should depend on TTY but forgot to. There's no need +# to aditionally check that the TTY prereq is set here. If the test declared +# it and we are running the test, then it must have been set. +test_terminal () { + if ! test_declared_prereq TTY + then + echo >&4 "test_terminal: need to declare TTY prerequisite" + return 127 + fi + perl "$TEST_DIRECTORY"/test-terminal.perl "$@" +} + +test_lazy_prereq TTY ' + test_have_prereq PERL && -test_expect_success PERL 'set up terminal for tests' ' # Reading from the pty master seems to get stuck _sometimes_ # on Mac OS X 10.5.0, using Perl 5.10.0 or 5.8.9. # @@ -15,21 +29,8 @@ test_expect_success PERL 'set up terminal for tests' ' # After 2000 iterations or so it hangs. # https://rt.cpan.org/Ticket/Display.html?id=65692 # - if test "$(uname -s)" = Darwin - then - : - elif - "$PERL_PATH" "$TEST_DIRECTORY"/test-terminal.perl \ - sh -c "test -t 1 && test -t 2" - then - test_set_prereq TTY && - test_terminal () { - if ! test_declared_prereq TTY - then - echo >&4 "test_terminal: need to declare TTY prerequisite" - return 127 - fi - "$PERL_PATH" "$TEST_DIRECTORY"/test-terminal.perl "$@" - } - fi + test "$(uname -s)" != Darwin && + + perl "$TEST_DIRECTORY"/test-terminal.perl \ + sh -c "test -t 1 && test -t 2" ' 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/p0001-rev-list.sh b/t/perf/p0001-rev-list.sh index 4f71a63b0a..16359d51ae 100755 --- a/t/perf/p0001-rev-list.sh +++ b/t/perf/p0001-rev-list.sh @@ -14,4 +14,16 @@ test_perf 'rev-list --all --objects' ' git rev-list --all --objects >/dev/null ' +test_expect_success 'create new unreferenced commit' ' + commit=$(git commit-tree HEAD^{tree} -p HEAD) +' + +test_perf 'rev-list $commit --not --all' ' + git rev-list $commit --not --all >/dev/null +' + +test_perf 'rev-list --objects $commit --not --all' ' + git rev-list --objects $commit --not --all >/dev/null +' + test_done 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/p4001-diff-no-index.sh b/t/perf/p4001-diff-no-index.sh new file mode 100755 index 0000000000..683be6984f --- /dev/null +++ b/t/perf/p4001-diff-no-index.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +test_description="Test diff --no-index performance" + +. ./perf-lib.sh + +test_perf_large_repo +test_checkout_worktree + +file1=$(git ls-files | tail -n 2 | head -1) +file2=$(git ls-files | tail -n 1 | head -1) + +test_expect_success "empty files, so they take no time to diff" " + echo >$file1 && + echo >$file2 +" + +test_perf "diff --no-index" " + git diff --no-index $file1 $file2 >/dev/null +" + +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/p5310-pack-bitmaps.sh b/t/perf/p5310-pack-bitmaps.sh new file mode 100755 index 0000000000..685d46f8b7 --- /dev/null +++ b/t/perf/p5310-pack-bitmaps.sh @@ -0,0 +1,57 @@ +#!/bin/sh + +test_description='Tests pack performance using bitmaps' +. ./perf-lib.sh + +test_perf_large_repo + +# note that we do everything through config, +# since we want to be able to compare bitmap-aware +# git versus non-bitmap git +test_expect_success 'setup bitmap config' ' + git config pack.writebitmaps true && + git config pack.writebitmaphashcache true +' + +test_perf 'repack to disk' ' + git repack -ad +' + +test_perf 'simulated clone' ' + git pack-objects --stdout --all </dev/null >/dev/null +' + +test_perf 'simulated fetch' ' + have=$(git rev-list HEAD~100 -1) && + { + echo HEAD && + echo ^$have + } | git pack-objects --revs --stdout >/dev/null +' + +test_expect_success 'create partial bitmap state' ' + # pick a commit to represent the repo tip in the past + cutoff=$(git rev-list HEAD~100 -1) && + orig_tip=$(git rev-parse HEAD) && + + # now kill off all of the refs and pretend we had + # just the one tip + rm -rf .git/logs .git/refs/* .git/packed-refs + git update-ref HEAD $cutoff + + # and then repack, which will leave us with a nice + # big bitmap pack of the "old" history, and all of + # the new history will be loose, as if it had been pushed + # up incrementally and exploded via unpack-objects + git repack -Ad + + # and now restore our original tip, as if the pushes + # had happened + git update-ref HEAD $orig_tip +' + +test_perf 'partial bitmap' ' + git pack-objects --stdout --all </dev/null >/dev/null +' + +test_done diff --git a/t/perf/perf-lib.sh b/t/perf/perf-lib.sh index a816fbcb76..a8c9574291 100644 --- a/t/perf/perf-lib.sh +++ b/t/perf/perf-lib.sh @@ -1,4 +1,6 @@ -#!/bin/sh +# Performance testing framework. Each perf script starts much like +# a normal test script, except it sources this library instead of +# test-lib.sh. See t/perf/README for documentation. # # Copyright (c) 2011 Thomas Rast # @@ -150,6 +152,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" @@ -160,7 +163,7 @@ test_perf () { echo "$test_count" >>"$perf_results_dir"/$base.subtests echo "$1" >"$perf_results_dir"/$base.$test_count.descr if test -z "$verbose"; then - echo -n "perf $test_count - $1:" + printf "%s" "perf $test_count - $1:" else echo "perf $test_count - $1:" fi @@ -169,7 +172,7 @@ test_perf () { if test_run_perf_ "$2" then if test -z "$verbose"; then - echo -n " $i" + printf " %s" "$i" else echo "* timing run $i/$GIT_PERF_REPEAT_COUNT:" fi @@ -187,7 +190,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..a2bb63ce8e 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -41,43 +41,235 @@ test_expect_success '.git/objects should have 3 subdirectories' ' test_expect_success 'success is reported like this' ' : ' -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 not running under a test harness, whether we + # are or not. The test-lib output depends on the setting of + # this variable, so we need a stable setting under which to run + # the sub-test. + sane_unset 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 && + TEST_OUTPUT_DIRECTORY=$(pwd) && + export TEST_OUTPUT_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 + > ok 1 - passing test + > Z + > expecting success: echo foo + > foo + > ok 2 - test with output + > Z + > expecting success: false + > 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 + > 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 +307,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 +351,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 +362,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 +422,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 +429,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 +441,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 +459,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 +483,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 +501,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 +523,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 +531,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 +565,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 +589,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/t0001-init.sh b/t/t0001-init.sh index ad66410564..9fb582b192 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -379,6 +379,10 @@ test_expect_success 'init with separate gitdir' ' test -d realgitdir/refs ' +test_expect_success 're-init on .git file' ' + ( cd newdir && git init ) +' + test_expect_success 're-init to update git link' ' ( cd newdir && diff --git a/t/t0002-gitfile.sh b/t/t0002-gitfile.sh index cb144258cc..37e9396e5d 100755 --- a/t/t0002-gitfile.sh +++ b/t/t0002-gitfile.sh @@ -7,7 +7,7 @@ Verify that plumbing commands work when .git is a file . ./test-lib.sh objpath() { - echo "$1" | sed -e 's|\(..\)|\1/|' + echo "$1" | sed -e 's|\(..\)|\1/|' } objck() { @@ -19,7 +19,6 @@ objck() { fi } - test_expect_success 'initial setup' ' REAL="$(pwd)/.real" && mv .git "$REAL" diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh index 807b8b88e2..f0fbb42554 100755 --- a/t/t0003-attributes.sh +++ b/t/t0003-attributes.sh @@ -13,7 +13,6 @@ attr_check () { test_line_count = 0 err } - test_expect_success 'setup' ' mkdir -p a/b/d a/c b && ( @@ -198,7 +197,8 @@ test_expect_success 'root subdir attribute test' ' test_expect_success 'negative patterns' ' echo "!f test=bar" >.gitattributes && - test_must_fail git check-attr test -- f + git check-attr test -- '"'"'!f'"'"' 2>errors && + test_i18ngrep "Negative patterns are ignored" errors ' test_expect_success 'patterns starting with exclamation' ' @@ -206,40 +206,95 @@ test_expect_success 'patterns starting with exclamation' ' 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 'using --git-dir and --work-tree' ' + mkdir unreal real && + git init real && + echo "file test=in-real" >real/.gitattributes && + ( + cd unreal && + attr_check file in-real "--git-dir ../real/.git --work-tree ../real" + ) +' + test_expect_success 'setup bare' ' - git clone --bare . bare.git && - cd bare.git + git clone --bare . bare.git ' test_expect_success 'bare repository: check that .gitattribute is ignored' ' ( - echo "f test=f" - echo "a/i test=a/i" - ) >.gitattributes && - attr_check f unspecified && - attr_check a/f unspecified && - attr_check a/c/f unspecified && - attr_check a/i unspecified && - attr_check subdir/a/i unspecified + cd bare.git && + ( + echo "f test=f" + echo "a/i test=a/i" + ) >.gitattributes && + attr_check f unspecified && + attr_check a/f unspecified && + attr_check a/c/f unspecified && + attr_check a/i unspecified && + attr_check subdir/a/i unspecified + ) ' test_expect_success 'bare repository: check that --cached honors index' ' - GIT_INDEX_FILE=../.git/index \ - git check-attr --cached --stdin --all <../stdin-all | - sort >actual && - test_cmp ../specified-all actual + ( + cd bare.git && + GIT_INDEX_FILE=../.git/index \ + git check-attr --cached --stdin --all <../stdin-all | + sort >actual && + test_cmp ../specified-all actual + ) ' test_expect_success 'bare repository: test info/attributes' ' ( - echo "f test=f" - echo "a/i test=a/i" - ) >info/attributes && - attr_check f f && - attr_check a/f f && - attr_check a/c/f f && - attr_check a/i a/i && - attr_check subdir/a/i unspecified + cd bare.git && + ( + echo "f test=f" + echo "a/i test=a/i" + ) >info/attributes && + attr_check f f && + attr_check a/f f && + attr_check a/c/f f && + attr_check a/i a/i && + attr_check subdir/a/i unspecified + ) ' test_done 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..63beb99828 --- /dev/null +++ b/t/t0008-ignores.sh @@ -0,0 +1,809 @@ +#!/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" +} + +broken_c_unquote () { + "$PERL_PATH" -pe 's/^"//; s/\\//; s/"$//; tr/\n/\0/' "$@" +} + +broken_c_unquote_verbose () { + "$PERL_PATH" -pe 's/ "/ /; s/\\//; s/"$//; tr/:\t\n/\0/' "$@" +} + +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 $no_index_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 $no_index_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. +# +# A parameter is used to determine if the tests are run with the +# normal case (using the index), or with the --no-index option. +# +# 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) +# - index option: --index or --no-index +test_expect_success_multiple () { + prereq= + if test $# -eq 5 + then + prereq=$1 + shift + fi + if test "$4" = "--index" + then + no_index_opt= + else + no_index_opt=$4 + 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${no_index_opt:+ with $no_index_opt}" ' + 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 + opts="${no_index_opt:+$no_index_opt }$quiet_opt" + test_expect_success $prereq "$testname${opts:+ with $opts}" " + 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="${no_index_opt:+$no_index_opt }$verbose_opt${non_matching_opt:+ $non_matching_opt}" + test_expect_success $prereq "$testname${opts:+ with $opts}" "$test_code" + done + done + verbose_opt= + non_matching_opt= + no_index_opt= +} + +test_expect_success_multi () { + test_expect_success_multiple "$@" "--index" +} + +test_expect_success_no_index_multi () { + test_expect_success_multiple "$@" "--no-index" +} + +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 unless the --no-index option is used. + +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_no_index_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_no_index_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_no_index_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_no_index_multi "existing tracked file $where shown as ignored" \ + ".gitignore:2:ignored-* ${subdir}ignored-but-in-index" \ + "test_check_ignore '${subdir}ignored-but-in-index'" + + 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_no_index_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' + " + + test_expect_success_no_index_multi "mix of file types $where" \ +":: ${subdir}non-existent +.gitignore:1:one ${subdir}one +:: ${subdir}not-ignored +.gitignore:2: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: pathspec '\''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: pathspec '\''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: Pathspec '\''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: Pathspec '\''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 + +broken_c_unquote stdin >stdin0 + +broken_c_unquote expected-default >expected-default0 + +broken_c_unquote_verbose expected-verbose >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 + +broken_c_unquote stdin >stdin0 + +broken_c_unquote expected-default >expected-default0 + +broken_c_unquote_verbose expected-verbose >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 whitespace handling + +test_expect_success 'trailing whitespace is ignored' ' + mkdir whitespace && + >whitespace/trailing && + >whitespace/untracked && + echo "whitespace/trailing " >ignore && + cat >expect <<EOF && +whitespace/untracked +EOF + : >err.expect && + git ls-files -o -X ignore whitespace >actual 2>err && + test_cmp expect actual && + test_cmp err.expect err +' + +test_expect_success !MINGW 'quoting allows trailing whitespace' ' + rm -rf whitespace && + mkdir whitespace && + >"whitespace/trailing " && + >whitespace/untracked && + echo "whitespace/trailing\\ \\ " >ignore && + echo whitespace/untracked >expect && + : >err.expect && + git ls-files -o -X ignore whitespace >actual 2>err && + test_cmp expect actual && + test_cmp err.expect err +' + +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/t0011-hashmap.sh b/t/t0011-hashmap.sh new file mode 100755 index 0000000000..391e2b6492 --- /dev/null +++ b/t/t0011-hashmap.sh @@ -0,0 +1,240 @@ +#!/bin/sh + +test_description='test hashmap and string hash functions' +. ./test-lib.sh + +test_hashmap() { + echo "$1" | test-hashmap $3 > actual && + echo "$2" > expect && + test_cmp expect actual +} + +test_expect_success 'hash functions' ' + +test_hashmap "hash key1" "2215982743 2215982743 116372151 116372151" && +test_hashmap "hash key2" "2215982740 2215982740 116372148 116372148" && +test_hashmap "hash fooBarFrotz" "1383912807 1383912807 3189766727 3189766727" && +test_hashmap "hash foobarfrotz" "2862305959 2862305959 3189766727 3189766727" + +' + +test_expect_success 'put' ' + +test_hashmap "put key1 value1 +put key2 value2 +put fooBarFrotz value3 +put foobarfrotz value4 +size" "NULL +NULL +NULL +NULL +64 4" + +' + +test_expect_success 'put (case insensitive)' ' + +test_hashmap "put key1 value1 +put key2 value2 +put fooBarFrotz value3 +size" "NULL +NULL +NULL +64 3" ignorecase + +' + +test_expect_success 'replace' ' + +test_hashmap "put key1 value1 +put key1 value2 +put fooBarFrotz value3 +put fooBarFrotz value4 +size" "NULL +value1 +NULL +value3 +64 2" + +' + +test_expect_success 'replace (case insensitive)' ' + +test_hashmap "put key1 value1 +put Key1 value2 +put fooBarFrotz value3 +put foobarfrotz value4 +size" "NULL +value1 +NULL +value3 +64 2" ignorecase + +' + +test_expect_success 'get' ' + +test_hashmap "put key1 value1 +put key2 value2 +put fooBarFrotz value3 +put foobarfrotz value4 +get key1 +get key2 +get fooBarFrotz +get notInMap" "NULL +NULL +NULL +NULL +value1 +value2 +value3 +NULL" + +' + +test_expect_success 'get (case insensitive)' ' + +test_hashmap "put key1 value1 +put key2 value2 +put fooBarFrotz value3 +get Key1 +get keY2 +get foobarfrotz +get notInMap" "NULL +NULL +NULL +value1 +value2 +value3 +NULL" ignorecase + +' + +test_expect_success 'add' ' + +test_hashmap "add key1 value1 +add key1 value2 +add fooBarFrotz value3 +add fooBarFrotz value4 +get key1 +get fooBarFrotz +get notInMap" "value2 +value1 +value4 +value3 +NULL" + +' + +test_expect_success 'add (case insensitive)' ' + +test_hashmap "add key1 value1 +add Key1 value2 +add fooBarFrotz value3 +add foobarfrotz value4 +get key1 +get Foobarfrotz +get notInMap" "value2 +value1 +value4 +value3 +NULL" ignorecase + +' + +test_expect_success 'remove' ' + +test_hashmap "put key1 value1 +put key2 value2 +put fooBarFrotz value3 +remove key1 +remove key2 +remove notInMap +size" "NULL +NULL +NULL +value1 +value2 +NULL +64 1" + +' + +test_expect_success 'remove (case insensitive)' ' + +test_hashmap "put key1 value1 +put key2 value2 +put fooBarFrotz value3 +remove Key1 +remove keY2 +remove notInMap +size" "NULL +NULL +NULL +value1 +value2 +NULL +64 1" ignorecase + +' + +test_expect_success 'iterate' ' + +test_hashmap "put key1 value1 +put key2 value2 +put fooBarFrotz value3 +iterate" "NULL +NULL +NULL +key2 value2 +key1 value1 +fooBarFrotz value3" + +' + +test_expect_success 'iterate (case insensitive)' ' + +test_hashmap "put key1 value1 +put key2 value2 +put fooBarFrotz value3 +iterate" "NULL +NULL +NULL +fooBarFrotz value3 +key2 value2 +key1 value1" ignorecase + +' + +test_expect_success 'grow / shrink' ' + + rm -f in && + rm -f expect && + for n in $(test_seq 51) + do + echo put key$n value$n >> in && + echo NULL >> expect + done && + echo size >> in && + echo 64 51 >> expect && + echo put key52 value52 >> in && + echo NULL >> expect + echo size >> in && + echo 256 52 >> expect && + for n in $(test_seq 12) + do + echo remove key$n >> in && + echo value$n >> expect + done && + echo size >> in && + echo 256 40 >> expect && + echo remove key40 >> in && + echo value40 >> expect && + echo size >> in && + echo 64 39 >> expect && + cat in | test-hashmap > out && + test_cmp expect out + +' + +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/t0021-conversion.sh b/t/t0021-conversion.sh index e50f0f742f..b92e6cb046 100755 --- a/t/t0021-conversion.sh +++ b/t/t0021-conversion.sh @@ -190,4 +190,18 @@ test_expect_success 'required filter clean failure' ' test_must_fail git add test.fc ' +test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE + +test_expect_success EXPENSIVE 'filter large file' ' + git config filter.largefile.smudge cat && + git config filter.largefile.clean cat && + for i in $(test_seq 1 2048); do printf "%1048576d" 1; done >2GB && + echo "2GB filter=largefile" >.gitattributes && + git add 2GB 2>err && + ! test -s err && + rm -f 2GB && + git checkout -- 2GB 2>err && + ! test -s err +' + test_done 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..6b3cedcf24 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,31 @@ 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 && + git config core.precomposeunicode false && + 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/t0056-git-C.sh b/t/t0056-git-C.sh new file mode 100755 index 0000000000..99c037703a --- /dev/null +++ b/t/t0056-git-C.sh @@ -0,0 +1,84 @@ +#!/bin/sh + +test_description='"-C <path>" option and its effects on other path-related options' + +. ./test-lib.sh + +test_expect_success '"git -C <path>" runs git from the directory <path>' ' + test_create_repo dir1 && + echo 1 >dir1/a.txt && + msg="initial in dir1" && + (cd dir1 && git add a.txt && git commit -m "$msg") && + echo "$msg" >expected && + git -C dir1 log --format=%s >actual && + test_cmp expected actual +' + +test_expect_success 'Multiple -C options: "-C dir1 -C dir2" is equivalent to "-C dir1/dir2"' ' + test_create_repo dir1/dir2 && + echo 1 >dir1/dir2/b.txt && + git -C dir1/dir2 add b.txt && + msg="initial in dir1/dir2" && + echo "$msg" >expected && + git -C dir1/dir2 commit -m "$msg" && + git -C dir1 -C dir2 log --format=%s >actual && + test_cmp expected actual +' + +test_expect_success 'Effect on --git-dir option: "-C c --git-dir=a.git" is equivalent to "--git-dir c/a.git"' ' + mkdir c && + mkdir c/a && + mkdir c/a.git && + (cd c/a.git && git init --bare) && + echo 1 >c/a/a.txt && + git --git-dir c/a.git --work-tree=c/a add a.txt && + git --git-dir c/a.git --work-tree=c/a commit -m "initial" && + git --git-dir=c/a.git log -1 --format=%s >expected && + git -C c --git-dir=a.git log -1 --format=%s >actual && + test_cmp expected actual +' + +test_expect_success 'Order should not matter: "--git-dir=a.git -C c" is equivalent to "-C c --git-dir=a.git"' ' + git -C c --git-dir=a.git log -1 --format=%s >expected && + git --git-dir=a.git -C c log -1 --format=%s >actual && + test_cmp expected actual +' + +test_expect_success 'Effect on --work-tree option: "-C c/a.git --work-tree=../a" is equivalent to "--work-tree=c/a --git-dir=c/a.git"' ' + rm c/a/a.txt && + git --git-dir=c/a.git --work-tree=c/a status >expected && + git -C c/a.git --work-tree=../a status >actual && + test_cmp expected actual +' + +test_expect_success 'Order should not matter: "--work-tree=../a -C c/a.git" is equivalent to "-C c/a.git --work-tree=../a"' ' + git -C c/a.git --work-tree=../a status >expected && + git --work-tree=../a -C c/a.git status >actual && + test_cmp expected actual +' + +test_expect_success 'Effect on --git-dir and --work-tree options - "-C c --git-dir=a.git --work-tree=a" is equivalent to "--git-dir=c/a.git --work-tree=c/a"' ' + git --git-dir=c/a.git --work-tree=c/a status >expected && + git -C c --git-dir=a.git --work-tree=a status >actual && + test_cmp expected actual +' + +test_expect_success 'Order should not matter: "-C c --git-dir=a.git --work-tree=a" is equivalent to "--git-dir=a.git -C c --work-tree=a"' ' + git -C c --git-dir=a.git --work-tree=a status >expected && + git --git-dir=a.git -C c --work-tree=a status >actual && + test_cmp expected actual +' + +test_expect_success 'Order should not matter: "-C c --git-dir=a.git --work-tree=a" is equivalent to "--git-dir=a.git --work-tree=a -C c"' ' + git -C c --git-dir=a.git --work-tree=a status >expected && + git --git-dir=a.git --work-tree=a -C c status >actual && + test_cmp expected actual +' + +test_expect_success 'Relative followed by fullpath: "-C ./here -C /there" is equivalent to "-C /there"' ' + echo "initial in dir1/dir2" >expected && + git -C dir1 -C "$(pwd)/dir1/dir2" log --format=%s >actual && + test_cmp expected actual +' + +test_done diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh index 4ef2345982..c0143a0a70 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 print_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 print_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,58 @@ test_expect_success SYMLINKS 'real path works on symlinks' ' test "$sym" = "$(test-path-utils real_path "$dir2/syml")" ' +test_expect_success SYMLINKS 'prefix_path works with absolute paths to work tree symlinks' ' + ln -s target symlink && + test "$(test-path-utils prefix_path prefix "$(pwd)/symlink")" = "symlink" +' + +test_expect_success 'prefix_path works with only absolute path to work tree' ' + echo "" >expected && + test-path-utils prefix_path prefix "$(pwd)" >actual && + test_cmp expected actual +' + +test_expect_success 'prefix_path rejects absolute path to dir with same beginning as work tree' ' + test_must_fail test-path-utils prefix_path prefix "$(pwd)a" +' + +test_expect_success SYMLINKS 'prefix_path works with absolute path to a symlink to work tree having same beginning as work tree' ' + git init repo && + ln -s repo repolink && + test "a" = "$(cd repo && test-path-utils prefix_path prefix "$(pwd)/../repolink/a")" +' + +relative_path /foo/a/b/c/ /foo/a/b/ c/ +relative_path /foo/a/b/c/ /foo/a/b c/ +relative_path /foo/a//b//c/ ///foo/a/b// c/ POSIX +relative_path /foo/a/b /foo/a/b ./ +relative_path /foo/a/b/ /foo/a/b ./ +relative_path /foo/a /foo/a/b ../ +relative_path / /foo/a/b/ ../../../ +relative_path /foo/a/c /foo/a/b/ ../c +relative_path /foo/a/c /foo/a/b ../c +relative_path /foo/x/y /foo/a/b/ ../../x/y +relative_path /foo/a/b "<empty>" /foo/a/b +relative_path /foo/a/b "<null>" /foo/a/b +relative_path foo/a/b/c/ foo/a/b/ c/ +relative_path foo/a/b/c/ foo/a/b c/ +relative_path foo/a/b//c foo/a//b c +relative_path foo/a/b/ foo/a/b/ ./ +relative_path foo/a/b/ foo/a/b ./ +relative_path foo/a foo/a/b ../ +relative_path foo/x/y foo/a/b ../../x/y +relative_path foo/a/c foo/a/b ../c +relative_path foo/a/b /foo/x/y foo/a/b +relative_path /foo/a/b foo/x/y /foo/a/b +relative_path d:/a/b D:/a/c ../b MINGW +relative_path C:/a/b D:/a/c C:/a/b MINGW +relative_path foo/a/b "<empty>" foo/a/b +relative_path foo/a/b "<null>" foo/a/b +relative_path "<empty>" /foo/a/b ./ +relative_path "<empty>" "<empty>" ./ +relative_path "<empty>" "<null>" ./ +relative_path "<null>" "<empty>" ./ +relative_path "<null>" "<null>" ./ +relative_path "<null>" /foo/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..5ed69a6f56 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" && @@ -25,6 +25,10 @@ test_expect_success POSIXPERM 'mktemp to unwritable directory prints filename' ' grep "cannotwrite/test" err ' +test_expect_success 'git_mkstemps_mode does not fail if fd 0 is not open' ' + git commit --allow-empty -m message <&- +' + test_expect_success 'check for a bug in the regex routines' ' # if this test fails, re-build git with NO_REGEX=1 test-regex 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/t0110-urlmatch-normalization.sh b/t/t0110-urlmatch-normalization.sh new file mode 100755 index 0000000000..8d6096d4d1 --- /dev/null +++ b/t/t0110-urlmatch-normalization.sh @@ -0,0 +1,177 @@ +#!/bin/sh + +test_description='urlmatch URL normalization' +. ./test-lib.sh + +# The base name of the test url files +tu="$TEST_DIRECTORY/t0110/url" + +# Note that only file: URLs should be allowed without a host + +test_expect_success 'url scheme' ' + ! test-urlmatch-normalization "" && + ! test-urlmatch-normalization "_" && + ! test-urlmatch-normalization "scheme" && + ! test-urlmatch-normalization "scheme:" && + ! test-urlmatch-normalization "scheme:/" && + ! test-urlmatch-normalization "scheme://" && + ! test-urlmatch-normalization "file" && + ! test-urlmatch-normalization "file:" && + ! test-urlmatch-normalization "file:/" && + test-urlmatch-normalization "file://" && + ! test-urlmatch-normalization "://acme.co" && + ! test-urlmatch-normalization "x_test://acme.co" && + ! test-urlmatch-normalization "-test://acme.co" && + ! test-urlmatch-normalization "0test://acme.co" && + ! test-urlmatch-normalization "+test://acme.co" && + ! test-urlmatch-normalization ".test://acme.co" && + ! test-urlmatch-normalization "schem%6e://" && + test-urlmatch-normalization "x-Test+v1.0://acme.co" && + test "$(test-urlmatch-normalization -p "AbCdeF://x.Y")" = "abcdef://x.y/" +' + +test_expect_success 'url authority' ' + ! test-urlmatch-normalization "scheme://user:pass@" && + ! test-urlmatch-normalization "scheme://?" && + ! test-urlmatch-normalization "scheme://#" && + ! test-urlmatch-normalization "scheme:///" && + ! test-urlmatch-normalization "scheme://:" && + ! test-urlmatch-normalization "scheme://:555" && + test-urlmatch-normalization "file://user:pass@" && + test-urlmatch-normalization "file://?" && + test-urlmatch-normalization "file://#" && + test-urlmatch-normalization "file:///" && + test-urlmatch-normalization "file://:" && + ! test-urlmatch-normalization "file://:555" && + test-urlmatch-normalization "scheme://user:pass@host" && + test-urlmatch-normalization "scheme://@host" && + test-urlmatch-normalization "scheme://%00@host" && + ! test-urlmatch-normalization "scheme://%%@host" && + ! test-urlmatch-normalization "scheme://host_" && + test-urlmatch-normalization "scheme://user:pass@host/" && + test-urlmatch-normalization "scheme://@host/" && + test-urlmatch-normalization "scheme://host/" && + test-urlmatch-normalization "scheme://host?x" && + test-urlmatch-normalization "scheme://host#x" && + test-urlmatch-normalization "scheme://host/@" && + test-urlmatch-normalization "scheme://host?@x" && + test-urlmatch-normalization "scheme://host#@x" && + test-urlmatch-normalization "scheme://[::1]" && + test-urlmatch-normalization "scheme://[::1]/" && + ! test-urlmatch-normalization "scheme://hos%41/" && + test-urlmatch-normalization "scheme://[invalid....:/" && + test-urlmatch-normalization "scheme://invalid....:]/" && + ! test-urlmatch-normalization "scheme://invalid....:[/" && + ! test-urlmatch-normalization "scheme://invalid....:[" +' + +test_expect_success 'url port checks' ' + test-urlmatch-normalization "xyz://q@some.host:" && + test-urlmatch-normalization "xyz://q@some.host:456/" && + ! test-urlmatch-normalization "xyz://q@some.host:0" && + ! test-urlmatch-normalization "xyz://q@some.host:0000000" && + test-urlmatch-normalization "xyz://q@some.host:0000001?" && + test-urlmatch-normalization "xyz://q@some.host:065535#" && + test-urlmatch-normalization "xyz://q@some.host:65535" && + ! test-urlmatch-normalization "xyz://q@some.host:65536" && + ! test-urlmatch-normalization "xyz://q@some.host:99999" && + ! test-urlmatch-normalization "xyz://q@some.host:100000" && + ! test-urlmatch-normalization "xyz://q@some.host:100001" && + test-urlmatch-normalization "http://q@some.host:80" && + test-urlmatch-normalization "https://q@some.host:443" && + test-urlmatch-normalization "http://q@some.host:80/" && + test-urlmatch-normalization "https://q@some.host:443?" && + ! test-urlmatch-normalization "http://q@:8008" && + ! test-urlmatch-normalization "http://:8080" && + ! test-urlmatch-normalization "http://:" && + test-urlmatch-normalization "xyz://q@some.host:456/" && + test-urlmatch-normalization "xyz://[::1]:456/" && + test-urlmatch-normalization "xyz://[::1]:/" && + ! test-urlmatch-normalization "xyz://[::1]:000/" && + ! test-urlmatch-normalization "xyz://[::1]:0%300/" && + ! test-urlmatch-normalization "xyz://[::1]:0x80/" && + ! test-urlmatch-normalization "xyz://[::1]:4294967297/" && + ! test-urlmatch-normalization "xyz://[::1]:030f/" +' + +test_expect_success 'url port normalization' ' + test "$(test-urlmatch-normalization -p "http://x:800")" = "http://x:800/" && + test "$(test-urlmatch-normalization -p "http://x:0800")" = "http://x:800/" && + test "$(test-urlmatch-normalization -p "http://x:00000800")" = "http://x:800/" && + test "$(test-urlmatch-normalization -p "http://x:065535")" = "http://x:65535/" && + test "$(test-urlmatch-normalization -p "http://x:1")" = "http://x:1/" && + test "$(test-urlmatch-normalization -p "http://x:80")" = "http://x/" && + test "$(test-urlmatch-normalization -p "http://x:080")" = "http://x/" && + test "$(test-urlmatch-normalization -p "http://x:000000080")" = "http://x/" && + test "$(test-urlmatch-normalization -p "https://x:443")" = "https://x/" && + test "$(test-urlmatch-normalization -p "https://x:0443")" = "https://x/" && + test "$(test-urlmatch-normalization -p "https://x:000000443")" = "https://x/" +' + +test_expect_success 'url general escapes' ' + ! test-urlmatch-normalization "http://x.y?%fg" && + test "$(test-urlmatch-normalization -p "X://W/%7e%41^%3a")" = "x://w/~A%5E%3A" && + test "$(test-urlmatch-normalization -p "X://W/:/?#[]@")" = "x://w/:/?#[]@" && + test "$(test-urlmatch-normalization -p "X://W/$&()*+,;=")" = "x://w/$&()*+,;=" && + test "$(test-urlmatch-normalization -p "X://W/'\''")" = "x://w/'\''" && + test "$(test-urlmatch-normalization -p "X://W?'\!'")" = "x://w/?'\!'" +' + +test_expect_success 'url high-bit escapes' ' + test "$(test-urlmatch-normalization -p "$(cat "$tu-1")")" = "x://q/%01%02%03%04%05%06%07%08%0E%0F%10%11%12" && + test "$(test-urlmatch-normalization -p "$(cat "$tu-2")")" = "x://q/%13%14%15%16%17%18%19%1B%1C%1D%1E%1F%7F" && + test "$(test-urlmatch-normalization -p "$(cat "$tu-3")")" = "x://q/%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F" && + test "$(test-urlmatch-normalization -p "$(cat "$tu-4")")" = "x://q/%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F" && + test "$(test-urlmatch-normalization -p "$(cat "$tu-5")")" = "x://q/%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF" && + test "$(test-urlmatch-normalization -p "$(cat "$tu-6")")" = "x://q/%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF" && + test "$(test-urlmatch-normalization -p "$(cat "$tu-7")")" = "x://q/%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF" && + test "$(test-urlmatch-normalization -p "$(cat "$tu-8")")" = "x://q/%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF" && + test "$(test-urlmatch-normalization -p "$(cat "$tu-9")")" = "x://q/%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF" && + test "$(test-urlmatch-normalization -p "$(cat "$tu-10")")" = "x://q/%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF" && + test "$(test-urlmatch-normalization -p "$(cat "$tu-11")")" = "x://q/%C2%80%DF%BF%E0%A0%80%EF%BF%BD%F0%90%80%80%F0%AF%BF%BD" +' + +test_expect_success 'url username/password escapes' ' + test "$(test-urlmatch-normalization -p "x://%41%62(^):%70+d@foo")" = "x://Ab(%5E):p+d@foo/" +' + +test_expect_success 'url normalized lengths' ' + test "$(test-urlmatch-normalization -l "Http://%4d%65:%4d^%70@The.Host")" = 25 && + test "$(test-urlmatch-normalization -l "http://%41:%42@x.y/%61/")" = 17 && + test "$(test-urlmatch-normalization -l "http://@x.y/^")" = 15 +' + +test_expect_success 'url . and .. segments' ' + test "$(test-urlmatch-normalization -p "x://y/.")" = "x://y/" && + test "$(test-urlmatch-normalization -p "x://y/./")" = "x://y/" && + test "$(test-urlmatch-normalization -p "x://y/a/.")" = "x://y/a" && + test "$(test-urlmatch-normalization -p "x://y/a/./")" = "x://y/a/" && + test "$(test-urlmatch-normalization -p "x://y/.?")" = "x://y/?" && + test "$(test-urlmatch-normalization -p "x://y/./?")" = "x://y/?" && + test "$(test-urlmatch-normalization -p "x://y/a/.?")" = "x://y/a?" && + test "$(test-urlmatch-normalization -p "x://y/a/./?")" = "x://y/a/?" && + test "$(test-urlmatch-normalization -p "x://y/a/./b/.././../c")" = "x://y/c" && + test "$(test-urlmatch-normalization -p "x://y/a/./b/../.././c/")" = "x://y/c/" && + test "$(test-urlmatch-normalization -p "x://y/a/./b/.././../c/././.././.")" = "x://y/" && + ! test-urlmatch-normalization "x://y/a/./b/.././../c/././.././.." && + test "$(test-urlmatch-normalization -p "x://y/a/./?/././..")" = "x://y/a/?/././.." && + test "$(test-urlmatch-normalization -p "x://y/%2e/")" = "x://y/" && + test "$(test-urlmatch-normalization -p "x://y/%2E/")" = "x://y/" && + test "$(test-urlmatch-normalization -p "x://y/a/%2e./")" = "x://y/" && + test "$(test-urlmatch-normalization -p "x://y/b/.%2E/")" = "x://y/" && + test "$(test-urlmatch-normalization -p "x://y/c/%2e%2E/")" = "x://y/" +' + +# http://@foo specifies an empty user name but does not specify a password +# http://foo specifies neither a user name nor a password +# So they should not be equivalent +test_expect_success 'url equivalents' ' + test-urlmatch-normalization "httP://x" "Http://X/" && + test-urlmatch-normalization "Http://%4d%65:%4d^%70@The.Host" "hTTP://Me:%4D^p@the.HOST:80/" && + ! test-urlmatch-normalization "https://@x.y/^" "httpS://x.y:443/^" && + test-urlmatch-normalization "https://@x.y/^" "httpS://@x.y:0443/^" && + test-urlmatch-normalization "https://@x.y/^/../abc" "httpS://@x.y:0443/abc" && + test-urlmatch-normalization "https://@x.y/^/.." "httpS://@x.y:0443/" +' + +test_done diff --git a/t/t0110/README b/t/t0110/README new file mode 100644 index 0000000000..ad4a50ecd8 --- /dev/null +++ b/t/t0110/README @@ -0,0 +1,9 @@ +The url data files in this directory contain URLs with characters +in the range 0x01-0x1f and 0x7f-0xff to test the proper normalization +of unprintable characters. + +A select few characters in the 0x01-0x1f range are skipped to help +avoid problems running the test itself. + +The urls are in test files in this directory rather than being +embedded in the test script for portability. diff --git a/t/t0110/url-1 b/t/t0110/url-1 new file mode 100644 index 0000000000..519019c5ce --- /dev/null +++ b/t/t0110/url-1 @@ -0,0 +1 @@ +x://q/ diff --git a/t/t0110/url-10 b/t/t0110/url-10 new file mode 100644 index 0000000000..b9965de6a5 --- /dev/null +++ b/t/t0110/url-10 @@ -0,0 +1 @@ +x://q/ðñòóôõö÷øùúûüýþÿ diff --git a/t/t0110/url-11 b/t/t0110/url-11 new file mode 100644 index 0000000000..f0a50f1009 --- /dev/null +++ b/t/t0110/url-11 @@ -0,0 +1 @@ +x://q/Â€ß¿à €ï¿½ð€€ð¯¿½ diff --git a/t/t0110/url-2 b/t/t0110/url-2 new file mode 100644 index 0000000000..43334b05b2 --- /dev/null +++ b/t/t0110/url-2 @@ -0,0 +1 @@ +x://q/ diff --git a/t/t0110/url-3 b/t/t0110/url-3 new file mode 100644 index 0000000000..7378c7bec2 --- /dev/null +++ b/t/t0110/url-3 @@ -0,0 +1 @@ +x://q/€‚ƒ„…†‡ˆ‰Š‹ŒŽ diff --git a/t/t0110/url-4 b/t/t0110/url-4 new file mode 100644 index 0000000000..220b198c97 --- /dev/null +++ b/t/t0110/url-4 @@ -0,0 +1 @@ +x://q/‘’“”•–—˜™š›œžŸ diff --git a/t/t0110/url-5 b/t/t0110/url-5 new file mode 100644 index 0000000000..1ccd927779 --- /dev/null +++ b/t/t0110/url-5 @@ -0,0 +1 @@ +x://q/ ¡¢£¤¥¦§¨©ª«¬®¯ diff --git a/t/t0110/url-6 b/t/t0110/url-6 new file mode 100644 index 0000000000..e8283aac6d --- /dev/null +++ b/t/t0110/url-6 @@ -0,0 +1 @@ +x://q/°±²³´µ¶·¸¹º»¼½¾¿ diff --git a/t/t0110/url-7 b/t/t0110/url-7 new file mode 100644 index 0000000000..fa7c10b615 --- /dev/null +++ b/t/t0110/url-7 @@ -0,0 +1 @@ +x://q/ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ diff --git a/t/t0110/url-8 b/t/t0110/url-8 new file mode 100644 index 0000000000..79a0ba836f --- /dev/null +++ b/t/t0110/url-8 @@ -0,0 +1 @@ +x://q/ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß diff --git a/t/t0110/url-9 b/t/t0110/url-9 new file mode 100644 index 0000000000..8b44bec48b --- /dev/null +++ b/t/t0110/url-9 @@ -0,0 +1 @@ +x://q/àáâãäåæçèéêëìíîï diff --git a/t/t0202-gettext-perl.sh b/t/t0202-gettext-perl.sh index 428ebb0080..a29d166e00 100755 --- a/t/t0202-gettext-perl.sh +++ b/t/t0202-gettext-perl.sh @@ -12,7 +12,7 @@ if ! test_have_prereq PERL; then test_done fi -"$PERL_PATH" -MTest::More -e 0 2>/dev/null || { +perl -MTest::More -e 0 2>/dev/null || { skip_all="Perl Test::More unavailable, skipping test" test_done } @@ -22,6 +22,6 @@ test_external_has_tap=1 test_external_without_stderr \ 'Perl Git::I18N API' \ - "$PERL_PATH" "$TEST_DIRECTORY"/t0202/test.pl + perl "$TEST_DIRECTORY"/t0202/test.pl test_done diff --git a/t/t0202/test.pl b/t/t0202/test.pl index 2c10cb4693..2c10cb4693 100644..100755 --- a/t/t0202/test.pl +++ b/t/t0202/test.pl 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/t1005-read-tree-reset.sh b/t/t1005-read-tree-reset.sh index f53de79e56..074568500a 100755 --- a/t/t1005-read-tree-reset.sh +++ b/t/t1005-read-tree-reset.sh @@ -8,84 +8,99 @@ test_description='read-tree -u --reset' # two-tree test test_expect_success 'setup' ' - git init && - mkdir df && - echo content >df/file && - git add df/file && - git commit -m one && - git ls-files >expect && - rm -rf df && - echo content >df && - git add df && - echo content >new && - git add new && - git commit -m two + git init && + mkdir df && + echo content >df/file && + git add df/file && + git commit -m one && + git ls-files >expect && + rm -rf df && + echo content >df && + git add df && + echo content >new && + git add new && + git commit -m two ' test_expect_success 'reset should work' ' - read_tree_u_must_succeed -u --reset HEAD^ && - git ls-files >actual && - test_cmp expect actual + read_tree_u_must_succeed -u --reset HEAD^ && + git ls-files >actual && + test_cmp expect actual ' test_expect_success 'reset should remove remnants from a failed merge' ' - read_tree_u_must_succeed --reset -u HEAD && - git ls-files -s >expect && - sha1=$(git rev-parse :new) && - ( - echo "100644 $sha1 1 old" - echo "100644 $sha1 3 old" - ) | git update-index --index-info && - >old && - git ls-files -s && - read_tree_u_must_succeed --reset -u HEAD && - git ls-files -s >actual && - ! test -f old + read_tree_u_must_succeed --reset -u HEAD && + git ls-files -s >expect && + sha1=$(git rev-parse :new) && + ( + echo "100644 $sha1 1 old" + echo "100644 $sha1 3 old" + ) | git update-index --index-info && + >old && + git ls-files -s && + read_tree_u_must_succeed --reset -u HEAD && + git ls-files -s >actual && + ! test -f old +' + +test_expect_success 'two-way reset should remove remnants too' ' + read_tree_u_must_succeed --reset -u HEAD && + git ls-files -s >expect && + sha1=$(git rev-parse :new) && + ( + echo "100644 $sha1 1 old" + echo "100644 $sha1 3 old" + ) | git update-index --index-info && + >old && + git ls-files -s && + read_tree_u_must_succeed --reset -u HEAD HEAD && + git ls-files -s >actual && + ! test -f old ' test_expect_success 'Porcelain reset should remove remnants too' ' - read_tree_u_must_succeed --reset -u HEAD && - git ls-files -s >expect && - sha1=$(git rev-parse :new) && - ( - echo "100644 $sha1 1 old" - echo "100644 $sha1 3 old" - ) | git update-index --index-info && - >old && - git ls-files -s && - git reset --hard && - git ls-files -s >actual && - ! test -f old + read_tree_u_must_succeed --reset -u HEAD && + git ls-files -s >expect && + sha1=$(git rev-parse :new) && + ( + echo "100644 $sha1 1 old" + echo "100644 $sha1 3 old" + ) | git update-index --index-info && + >old && + git ls-files -s && + git reset --hard && + git ls-files -s >actual && + ! test -f old ' test_expect_success 'Porcelain checkout -f should remove remnants too' ' - read_tree_u_must_succeed --reset -u HEAD && - git ls-files -s >expect && - sha1=$(git rev-parse :new) && - ( - echo "100644 $sha1 1 old" - echo "100644 $sha1 3 old" - ) | git update-index --index-info && - >old && - git ls-files -s && - git checkout -f && - git ls-files -s >actual && - ! test -f old + read_tree_u_must_succeed --reset -u HEAD && + git ls-files -s >expect && + sha1=$(git rev-parse :new) && + ( + echo "100644 $sha1 1 old" + echo "100644 $sha1 3 old" + ) | git update-index --index-info && + >old && + git ls-files -s && + git checkout -f && + git ls-files -s >actual && + ! test -f old ' test_expect_success 'Porcelain checkout -f HEAD should remove remnants too' ' - read_tree_u_must_succeed --reset -u HEAD && - git ls-files -s >expect && - sha1=$(git rev-parse :new) && - ( - echo "100644 $sha1 1 old" - echo "100644 $sha1 3 old" - ) | git update-index --index-info && - >old && - git ls-files -s && - git checkout -f HEAD && - git ls-files -s >actual && - ! test -f old + read_tree_u_must_succeed --reset -u HEAD && + git ls-files -s >expect && + sha1=$(git rev-parse :new) && + ( + echo "100644 $sha1 1 old" + echo "100644 $sha1 3 old" + ) | git update-index --index-info && + >old && + git ls-files -s && + git checkout -f HEAD && + git ls-files -s >actual && + ! test -f old ' test_done diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh index d8b7f2ffbc..a72e700ae4 100755 --- a/t/t1006-cat-file.sh +++ b/t/t1006-cat-file.sh @@ -36,66 +36,76 @@ $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 + ' + + test -z "$content" || + test_expect_success "--batch without type ($type)" ' + { + echo "$size" && + maybe_remove_timestamp "$content" $no_ts + } >expect && + echo $sha1 | git cat-file --batch="%(objectsize)" >actual.full && + maybe_remove_timestamp "$(cat actual.full)" $no_ts >actual && + test_cmp expect actual + ' + + test -z "$content" || + test_expect_success "--batch without size ($type)" ' + { + echo "$type" && + maybe_remove_timestamp "$content" $no_ts + } >expect && + echo $sha1 | git cat-file --batch="%(objecttype)" >actual.full && + maybe_remove_timestamp "$(cat actual.full)" $no_ts >actual && + test_cmp expect actual ' } @@ -110,15 +120,23 @@ test_expect_success "setup" ' run_tests 'blob' $hello_sha1 $hello_size "$hello_content" "$hello_content" +test_expect_success '--batch-check without %(rest) considers whole line' ' + echo "$hello_sha1 blob $hello_size" >expect && + git update-index --add --cacheinfo 100644 $hello_sha1 "white space" && + test_when_finished "git update-index --remove \"white space\"" && + echo ":white space" | git cat-file --batch-check >actual && + test_cmp expect actual +' + tree_sha1=$(git write-tree) tree_size=33 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 +153,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" \ @@ -201,6 +216,12 @@ test_expect_success "--batch-check for an emtpy line" ' test " missing" = "$(echo | git cat-file --batch-check)" ' +test_expect_success 'empty --batch-check notices missing object' ' + echo "$_z40 missing" >expect && + echo "$_z40" | git cat-file --batch-check="" >actual && + test_cmp expect actual +' + batch_input="$hello_sha1 $commit_sha1 $tag_sha1 @@ -241,4 +262,38 @@ test_expect_success "--batch-check with multiple sha1s gives correct format" ' "$(echo_without_newline "$batch_check_input" | git cat-file --batch-check)" ' +test_expect_success 'setup blobs which are likely to delta' ' + test-genrandom foo 10240 >foo && + { cat foo; echo plus; } >foo-plus && + git add foo foo-plus && + git commit -m foo && + cat >blobs <<-\EOF + HEAD:foo + HEAD:foo-plus + EOF +' + +test_expect_success 'confirm that neither loose blob is a delta' ' + cat >expect <<-EOF + $_z40 + $_z40 + EOF + git cat-file --batch-check="%(deltabase)" <blobs >actual && + test_cmp expect actual +' + +# To avoid relying too much on the current delta heuristics, +# we will check only that one of the two objects is a delta +# against the other, but not the order. We can do so by just +# asking for the base of both, and checking whether either +# sha1 appears in the output. +test_expect_success '%(deltabase) reports packed delta bases' ' + git repack -ad && + git cat-file --batch-check="%(deltabase)" <blobs >actual && + { + grep "$(git rev-parse HEAD:foo)" actual || + grep "$(git rev-parse HEAD:foo-plus)" actual + } +' + test_done diff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh index df573c4978..b946f87686 100755 --- a/t/t1010-mktree.sh +++ b/t/t1010-mktree.sh @@ -42,13 +42,13 @@ test_expect_success 'ls-tree piped to mktree (2)' ' ' test_expect_success 'ls-tree output in wrong order given to mktree (1)' ' - "$PERL_PATH" -e "print reverse <>" <top | + perl -e "print reverse <>" <top | git mktree >actual && test_cmp tree actual ' test_expect_success 'ls-tree output in wrong order given to mktree (2)' ' - "$PERL_PATH" -e "print reverse <>" <top.withsub | + perl -e "print reverse <>" <top.withsub | git mktree >actual && test_cmp tree.withsub actual ' 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/t1013-loose-object-format.sh b/t/t1013-loose-object-format.sh deleted file mode 100755 index fbf5f2fc00..0000000000 --- a/t/t1013-loose-object-format.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2011 Roberto Tyley -# - -test_description='Correctly identify and parse loose object headers - -There are two file formats for loose objects - the original standard -format, and the experimental format introduced with Git v1.4.3, later -deprecated with v1.5.3. Although Git no longer writes the -experimental format, objects in both formats must be read, with the -format for a given file being determined by the header. - -Detecting file format based on header is not entirely trivial, not -least because the first byte of a zlib-deflated stream will vary -depending on how much memory was allocated for the deflation window -buffer when the object was written out (for example 4KB on Android, -rather that 32KB on a normal PC). - -The loose objects used as test vectors have been generated with the -following Git versions: - -standard format: Git v1.7.4.1 -experimental format: Git v1.4.3 (legacyheaders=false) -standard format, deflated with 4KB window size: Agit/JGit on Android -' - -. ./test-lib.sh - -assert_blob_equals() { - printf "%s" "$2" >expected && - git cat-file -p "$1" >actual && - test_cmp expected actual -} - -test_expect_success setup ' - cp -R "$TEST_DIRECTORY/t1013/objects" .git/ && - git --version -' - -test_expect_success 'read standard-format loose objects' ' - git cat-file tag 8d4e360d6c70fbd72411991c02a09c442cf7a9fa && - git cat-file commit 6baee0540ea990d9761a3eb9ab183003a71c3696 && - git ls-tree 7a37b887a73791d12d26c0d3e39568a8fb0fa6e8 && - assert_blob_equals "257cc5642cb1a054f08cc83f2d943e56fd3ebe99" "foo$LF" -' - -test_expect_success 'read experimental-format loose objects' ' - git cat-file tag 76e7fa9941f4d5f97f64fea65a2cba436bc79cbb && - git cat-file commit 7875c6237d3fcdd0ac2f0decc7d3fa6a50b66c09 && - git ls-tree 95b1625de3ba8b2214d1e0d0591138aea733f64f && - assert_blob_equals "2e65efe2a145dda7ee51d1741299f848e5bf752e" "a" && - assert_blob_equals "9ae9e86b7bd6cb1472d9373702d8249973da0832" "ab" && - assert_blob_equals "85df50785d62d3b05ab03d9cbf7e4a0b49449730" "abcd" && - assert_blob_equals "1656f9233d999f61ef23ef390b9c71d75399f435" "abcdefgh" && - assert_blob_equals "1e72a6b2c4a577ab0338860fa9fe87f761fc9bbd" "abcdefghi" && - assert_blob_equals "70e6a83d8dcb26fc8bc0cf702e2ddeb6adca18fd" "abcdefghijklmnop" && - assert_blob_equals "bd15045f6ce8ff75747562173640456a394412c8" "abcdefghijklmnopqrstuvwx" -' - -test_expect_success 'read standard-format objects deflated with smaller window buffer' ' - git cat-file tag f816d5255855ac160652ee5253b06cd8ee14165a && - git cat-file tag 149cedb5c46929d18e0f118e9fa31927487af3b6 -' - -test_done diff --git a/t/t1013/objects/14/9cedb5c46929d18e0f118e9fa31927487af3b6 b/t/t1013/objects/14/9cedb5c46929d18e0f118e9fa31927487af3b6 Binary files differdeleted file mode 100644 index 472fd1458e..0000000000 --- a/t/t1013/objects/14/9cedb5c46929d18e0f118e9fa31927487af3b6 +++ /dev/null diff --git a/t/t1013/objects/16/56f9233d999f61ef23ef390b9c71d75399f435 b/t/t1013/objects/16/56f9233d999f61ef23ef390b9c71d75399f435 Binary files differdeleted file mode 100644 index c379d74ae2..0000000000 --- a/t/t1013/objects/16/56f9233d999f61ef23ef390b9c71d75399f435 +++ /dev/null diff --git a/t/t1013/objects/1e/72a6b2c4a577ab0338860fa9fe87f761fc9bbd b/t/t1013/objects/1e/72a6b2c4a577ab0338860fa9fe87f761fc9bbd Binary files differdeleted file mode 100644 index 93706305bc..0000000000 --- a/t/t1013/objects/1e/72a6b2c4a577ab0338860fa9fe87f761fc9bbd +++ /dev/null diff --git a/t/t1013/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99 b/t/t1013/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99 Binary files differdeleted file mode 100644 index bdcf704c9e..0000000000 --- a/t/t1013/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99 +++ /dev/null diff --git a/t/t1013/objects/2e/65efe2a145dda7ee51d1741299f848e5bf752e b/t/t1013/objects/2e/65efe2a145dda7ee51d1741299f848e5bf752e Binary files differdeleted file mode 100644 index ad62c43e41..0000000000 --- a/t/t1013/objects/2e/65efe2a145dda7ee51d1741299f848e5bf752e +++ /dev/null diff --git a/t/t1013/objects/6b/aee0540ea990d9761a3eb9ab183003a71c3696 b/t/t1013/objects/6b/aee0540ea990d9761a3eb9ab183003a71c3696 Binary files differdeleted file mode 100644 index 3d2f0337db..0000000000 --- a/t/t1013/objects/6b/aee0540ea990d9761a3eb9ab183003a71c3696 +++ /dev/null diff --git a/t/t1013/objects/70/e6a83d8dcb26fc8bc0cf702e2ddeb6adca18fd b/t/t1013/objects/70/e6a83d8dcb26fc8bc0cf702e2ddeb6adca18fd Binary files differdeleted file mode 100644 index b3f71a6ee5..0000000000 --- a/t/t1013/objects/70/e6a83d8dcb26fc8bc0cf702e2ddeb6adca18fd +++ /dev/null diff --git a/t/t1013/objects/76/e7fa9941f4d5f97f64fea65a2cba436bc79cbb b/t/t1013/objects/76/e7fa9941f4d5f97f64fea65a2cba436bc79cbb deleted file mode 100644 index af4e9a7b0c..0000000000 --- a/t/t1013/objects/76/e7fa9941f4d5f97f64fea65a2cba436bc79cbb +++ /dev/null @@ -1,2 +0,0 @@ -Âxœ%ÌA‚0@Ñ}O1{cSZ(˜ãνáÃthª”’ZŒÜÞ Ëÿ?
¦m×6dµiÉ9…¤Gå˜h´Ø¨ÁZR'Q¶…RŒ¡ˆ‚ø³p‘ç‚ÓqL9âÏ=g¸§sIÐoopÎÿ”eÏ«_1»€³¤$×ç*Si«ëNwpP•RBôûÅÁú -³‡[(ð®d-øÁL9á
\ No newline at end of file diff --git a/t/t1013/objects/78/75c6237d3fcdd0ac2f0decc7d3fa6a50b66c09 b/t/t1013/objects/78/75c6237d3fcdd0ac2f0decc7d3fa6a50b66c09 Binary files differdeleted file mode 100644 index 3dd28be5c6..0000000000 --- a/t/t1013/objects/78/75c6237d3fcdd0ac2f0decc7d3fa6a50b66c09 +++ /dev/null diff --git a/t/t1013/objects/7a/37b887a73791d12d26c0d3e39568a8fb0fa6e8 b/t/t1013/objects/7a/37b887a73791d12d26c0d3e39568a8fb0fa6e8 Binary files differdeleted file mode 100644 index 2b97b264c3..0000000000 --- a/t/t1013/objects/7a/37b887a73791d12d26c0d3e39568a8fb0fa6e8 +++ /dev/null diff --git a/t/t1013/objects/85/df50785d62d3b05ab03d9cbf7e4a0b49449730 b/t/t1013/objects/85/df50785d62d3b05ab03d9cbf7e4a0b49449730 Binary files differdeleted file mode 100644 index 6dff746876..0000000000 --- a/t/t1013/objects/85/df50785d62d3b05ab03d9cbf7e4a0b49449730 +++ /dev/null diff --git a/t/t1013/objects/8d/4e360d6c70fbd72411991c02a09c442cf7a9fa b/t/t1013/objects/8d/4e360d6c70fbd72411991c02a09c442cf7a9fa Binary files differdeleted file mode 100644 index cb41e92d07..0000000000 --- a/t/t1013/objects/8d/4e360d6c70fbd72411991c02a09c442cf7a9fa +++ /dev/null diff --git a/t/t1013/objects/95/b1625de3ba8b2214d1e0d0591138aea733f64f b/t/t1013/objects/95/b1625de3ba8b2214d1e0d0591138aea733f64f Binary files differdeleted file mode 100644 index 7ac46b4f70..0000000000 --- a/t/t1013/objects/95/b1625de3ba8b2214d1e0d0591138aea733f64f +++ /dev/null diff --git a/t/t1013/objects/9a/e9e86b7bd6cb1472d9373702d8249973da0832 b/t/t1013/objects/9a/e9e86b7bd6cb1472d9373702d8249973da0832 Binary files differdeleted file mode 100644 index 9d8316d4e5..0000000000 --- a/t/t1013/objects/9a/e9e86b7bd6cb1472d9373702d8249973da0832 +++ /dev/null diff --git a/t/t1013/objects/bd/15045f6ce8ff75747562173640456a394412c8 b/t/t1013/objects/bd/15045f6ce8ff75747562173640456a394412c8 Binary files differdeleted file mode 100644 index eebf23956e..0000000000 --- a/t/t1013/objects/bd/15045f6ce8ff75747562173640456a394412c8 +++ /dev/null diff --git a/t/t1013/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 b/t/t1013/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 Binary files differdeleted file mode 100644 index 134cf19379..0000000000 --- a/t/t1013/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +++ /dev/null diff --git a/t/t1013/objects/f8/16d5255855ac160652ee5253b06cd8ee14165a b/t/t1013/objects/f8/16d5255855ac160652ee5253b06cd8ee14165a deleted file mode 100644 index 26b75aec56..0000000000 --- a/t/t1013/objects/f8/16d5255855ac160652ee5253b06cd8ee14165a +++ /dev/null @@ -1 +0,0 @@ -H‰ÌÁ‚0€aÏ{ŠÞ
I»e&Æø*¥ˆG°ß^¸ýù¿ËDåÒ†wU‡Ò—¬S±4ªŠÆªž ,fÅ[ðßVAÛºÎüxÈÇö6[wtG§Lu¸?—¦²¼Ú×@‰"gì{†+by¾%M
\ No newline at end of file diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh index e23ac0e69d..6902320e81 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 ' @@ -148,7 +148,7 @@ test_expect_success 'GIT_PREFIX for built-ins' ' ( cd dir && printf "change" >two && - env GIT_EXTERNAL_DIFF=./diff git diff >../actual + GIT_EXTERNAL_DIFF=./diff git diff >../actual git checkout -- two ) && 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 3c96fda548..3e3f77b59b 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -475,15 +475,28 @@ ein.bahn=strasse EOF test_expect_success 'alternative GIT_CONFIG' ' - GIT_CONFIG=other-config git config -l >output && + GIT_CONFIG=other-config git config --list >output && test_cmp expect output ' test_expect_success 'alternative GIT_CONFIG (--file)' ' - git config --file other-config -l > output && + git config --file other-config --list >output && test_cmp expect output ' +test_expect_success 'alternative GIT_CONFIG (--file=-)' ' + git config --file - --list <other-config >output && + test_cmp expect output +' + +test_expect_success 'setting a value in stdin is an error' ' + test_must_fail git config --file - some.value foo +' + +test_expect_success 'editing stdin is an error' ' + test_must_fail git config --file - --edit +' + test_expect_success 'refer config from subdirectory' ' mkdir x && ( @@ -652,16 +665,23 @@ test_expect_success numbers ' test_cmp expect actual ' +test_expect_success '--int is at least 64 bits' ' + git config giga.watts 121g && + echo 129922760704 >expect && + git config --int --get giga.watts >actual && + test_cmp expect actual +' + test_expect_success 'invalid unit' ' git config aninvalid.unit "1auto" && 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 + cat >expect <<-\EOF + fatal: bad numeric config value '\''1auto'\'' for '\''aninvalid.unit'\'' in .git/config: invalid unit EOF test_must_fail git config --int --get aninvalid.unit 2>actual && - test_cmp actual expect + test_i18ncmp expect actual ' cat > expect << EOF @@ -954,24 +974,15 @@ test_expect_success SYMLINKS 'symlinked configuration' ' ' test_expect_success 'nonexistent configuration' ' - ( - GIT_CONFIG=doesnotexist && - export GIT_CONFIG && - test_must_fail git config --list && - test_must_fail git config test.xyzzy - ) + test_must_fail env GIT_CONFIG=doesnotexist git config --list && + test_must_fail env GIT_CONFIG=doesnotexist git config test.xyzzy ' test_expect_success SYMLINKS 'symlink to nonexistent configuration' ' ln -s doesnotexist linktonada && ln -s linktonada linktolinktonada && - ( - GIT_CONFIG=linktonada && - export GIT_CONFIG && - test_must_fail git config --list && - GIT_CONFIG=linktolinktonada && - test_must_fail git config --list - ) + test_must_fail env GIT_CONFIG=linktonada git config --list && + test_must_fail env GIT_CONFIG=linktolinktonada git config --list ' test_expect_success 'check split_cmdline return' " @@ -1087,4 +1098,64 @@ test_expect_success 'barf on incomplete string' ' grep " line 3 " error ' +test_expect_success 'urlmatch' ' + cat >.git/config <<-\EOF && + [http] + sslVerify + [http "https://weak.example.com"] + sslVerify = false + cookieFile = /tmp/cookie.txt + EOF + + echo true >expect && + git config --bool --get-urlmatch http.SSLverify https://good.example.com >actual && + test_cmp expect actual && + + echo false >expect && + git config --bool --get-urlmatch http.sslverify https://weak.example.com >actual && + test_cmp expect actual && + + { + echo http.cookiefile /tmp/cookie.txt && + echo http.sslverify false + } >expect && + git config --get-urlmatch HTTP https://weak.example.com >actual && + test_cmp expect actual +' + +# 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/t1303-wacky-config.sh b/t/t1303-wacky-config.sh index 46103a1591..3a2c81968c 100755 --- a/t/t1303-wacky-config.sh +++ b/t/t1303-wacky-config.sh @@ -3,17 +3,28 @@ test_description='Test wacky input to git config' . ./test-lib.sh +# Leaving off the newline is intentional! setup() { (printf "[section]\n" && printf " key = foo") >.git/config } +# 'check section.key value' verifies that the entry for section.key is +# 'value' check() { echo "$2" >expected git config --get "$1" >actual 2>&1 test_cmp actual expected } +# 'check section.key regex value' verifies that the entry for +# section.key *that matches 'regex'* is 'value' +check_regex() { + echo "$3" >expected + git config --get "$1" "$2" >actual 2>&1 + test_cmp actual expected +} + test_expect_success 'modify same key' ' setup && git config section.key bar && @@ -47,4 +58,57 @@ test_expect_success 'do not crash on special long config line' ' check section.key "$LONG_VALUE" ' +setup_many() { + setup && + # This time we want the newline so that we can tack on more + # entries. + echo >>.git/config && + # Semi-efficient way of concatenating 5^5 = 3125 lines. Note + # that because 'setup' already put one line, this means 3126 + # entries for section.key in the config file. + cat >5to1 <<-\EOF && + key = foo + key = foo + key = foo + key = foo + key = foo + EOF + cat 5to1 5to1 5to1 5to1 5to1 >5to2 && # 25 + cat 5to2 5to2 5to2 5to2 5to2 >5to3 && # 125 + cat 5to3 5to3 5to3 5to3 5to3 >5to4 && # 635 + cat 5to4 5to4 5to4 5to4 5to4 >>.git/config # 3125 +} + +test_expect_success 'get many entries' ' + setup_many && + git config --get-all section.key >actual && + test_line_count = 3126 actual +' + +test_expect_success 'get many entries by regex' ' + setup_many && + git config --get-regexp "sec.*ke." >actual && + test_line_count = 3126 actual +' + +test_expect_success 'add and replace one of many entries' ' + setup_many && + git config --add section.key bar && + check_regex section.key "b.*r" bar && + git config section.key beer "b.*r" && + check_regex section.key "b.*r" beer +' + +test_expect_success 'replace many entries' ' + setup_many && + git config --replace-all section.key bar && + check section.key bar +' + +test_expect_success 'unset many entries' ' + setup_many && + git config --unset-all section.key && + test_must_fail git config section.key +' + test_done diff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh index a70707620f..9ba2ba11c3 100755 --- a/t/t1305-config-include.sh +++ b/t/t1305-config-include.sh @@ -113,7 +113,7 @@ test_expect_success 'missing include files are ignored' ' test_expect_success 'absolute includes from command line work' ' echo "[test]one = 1" >one && echo 1 >expect && - git -c include.path="$PWD/one" config test.one >actual && + git -c include.path="$(pwd)/one" config test.one >actual && test_cmp expect actual ' @@ -122,6 +122,36 @@ test_expect_success 'relative includes from command line fail' ' test_must_fail git -c include.path=one config test.one ' +test_expect_success 'absolute includes from blobs work' ' + echo "[test]one = 1" >one && + echo "[include]path=$(pwd)/one" >blob && + blob=$(git hash-object -w blob) && + echo 1 >expect && + git config --blob=$blob test.one >actual && + test_cmp expect actual +' + +test_expect_success 'relative includes from blobs fail' ' + echo "[test]one = 1" >one && + echo "[include]path=one" >blob && + blob=$(git hash-object -w blob) && + test_must_fail git config --blob=$blob test.one +' + +test_expect_success 'absolute includes from stdin work' ' + echo "[test]one = 1" >one && + echo 1 >expect && + echo "[include]path=\"$(pwd)/one\"" | + git config --file - test.one >actual && + test_cmp expect actual +' + +test_expect_success 'relative includes from stdin line fail' ' + echo "[test]one = 1" >one && + echo "[include]path=one" | + test_must_fail git config --file - test.one +' + test_expect_success 'include cycles are detected' ' cat >.gitconfig <<-\EOF && [test]value = gitconfig 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/t1400-update-ref.sh b/t/t1400-update-ref.sh index e415ee0bbf..6ffd82fe32 100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -302,4 +302,636 @@ test_expect_success \ 'git cat-file blob master@{2005-05-26 23:42}:F (expect OTHER)' \ 'test OTHER = $(git cat-file blob "master@{2005-05-26 23:42}:F")' +a=refs/heads/a +b=refs/heads/b +c=refs/heads/c +E='""' +F='%s\0' +pws='path with space' + +test_expect_success 'stdin test setup' ' + echo "$pws" >"$pws" && + git add -- "$pws" && + git commit -m "$pws" +' + +test_expect_success '-z fails without --stdin' ' + test_must_fail git update-ref -z $m $m $m 2>err && + grep "usage: git update-ref" err +' + +test_expect_success 'stdin works with no input' ' + >stdin && + git update-ref --stdin <stdin && + git rev-parse --verify -q $m +' + +test_expect_success 'stdin fails on empty line' ' + echo "" >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: empty command in input" err +' + +test_expect_success 'stdin fails on only whitespace' ' + echo " " >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: whitespace before command: " err +' + +test_expect_success 'stdin fails on leading whitespace' ' + echo " create $a $m" >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: whitespace before command: create $a $m" err +' + +test_expect_success 'stdin fails on unknown command' ' + echo "unknown $a" >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: unknown command: unknown $a" err +' + +test_expect_success 'stdin fails on badly quoted input' ' + echo "create $a \"master" >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: badly quoted argument: \\\"master" err +' + +test_expect_success 'stdin fails on arguments not separated by space' ' + echo "create \"$a\"master" >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: expected SP but got: master" err +' + +test_expect_success 'stdin fails create with no ref' ' + echo "create " >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: create line missing <ref>" err +' + +test_expect_success 'stdin fails create with bad ref name' ' + echo "create ~a $m" >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: invalid ref format: ~a" err +' + +test_expect_success 'stdin fails create with no new value' ' + echo "create $a" >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: create $a missing <newvalue>" err +' + +test_expect_success 'stdin fails create with too many arguments' ' + echo "create $a $m $m" >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: create $a has extra input: $m" err +' + +test_expect_success 'stdin fails update with no ref' ' + echo "update " >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: update line missing <ref>" err +' + +test_expect_success 'stdin fails update with bad ref name' ' + echo "update ~a $m" >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: invalid ref format: ~a" err +' + +test_expect_success 'stdin fails update with no new value' ' + echo "update $a" >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: update $a missing <newvalue>" err +' + +test_expect_success 'stdin fails update with too many arguments' ' + echo "update $a $m $m $m" >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: update $a has extra input: $m" err +' + +test_expect_success 'stdin fails delete with no ref' ' + echo "delete " >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: delete line missing <ref>" err +' + +test_expect_success 'stdin fails delete with bad ref name' ' + echo "delete ~a $m" >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: invalid ref format: ~a" err +' + +test_expect_success 'stdin fails delete with too many arguments' ' + echo "delete $a $m $m" >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: delete $a has extra input: $m" err +' + +test_expect_success 'stdin fails verify with too many arguments' ' + echo "verify $a $m $m" >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: verify $a has extra input: $m" err +' + +test_expect_success 'stdin fails option with unknown name' ' + echo "option unknown" >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: option unknown: unknown" err +' + +test_expect_success 'stdin fails with duplicate refs' ' + cat >stdin <<-EOF && + create $a $m + create $b $m + create $a $m + EOF + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: Multiple updates for ref '"'"'$a'"'"' not allowed." err +' + +test_expect_success 'stdin create ref works' ' + echo "create $a $m" >stdin && + git update-ref --stdin <stdin && + git rev-parse $m >expect && + git rev-parse $a >actual && + test_cmp expect actual +' + +test_expect_success 'stdin update ref creates with zero old value' ' + echo "update $b $m $Z" >stdin && + git update-ref --stdin <stdin && + git rev-parse $m >expect && + git rev-parse $b >actual && + test_cmp expect actual && + git update-ref -d $b +' + +test_expect_success 'stdin update ref creates with empty old value' ' + echo "update $b $m $E" >stdin && + git update-ref --stdin <stdin && + git rev-parse $m >expect && + git rev-parse $b >actual && + test_cmp expect actual +' + +test_expect_success 'stdin create ref works with path with space to blob' ' + echo "create refs/blobs/pws \"$m:$pws\"" >stdin && + git update-ref --stdin <stdin && + git rev-parse "$m:$pws" >expect && + git rev-parse refs/blobs/pws >actual && + test_cmp expect actual && + git update-ref -d refs/blobs/pws +' + +test_expect_success 'stdin update ref fails with wrong old value' ' + echo "update $c $m $m~1" >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: Cannot lock the ref '"'"'$c'"'"'" err && + test_must_fail git rev-parse --verify -q $c +' + +test_expect_success 'stdin update ref fails with bad old value' ' + echo "update $c $m does-not-exist" >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: invalid old value for ref $c: does-not-exist" err && + test_must_fail git rev-parse --verify -q $c +' + +test_expect_success 'stdin create ref fails with bad new value' ' + echo "create $c does-not-exist" >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: invalid new value for ref $c: does-not-exist" err && + test_must_fail git rev-parse --verify -q $c +' + +test_expect_success 'stdin create ref fails with zero new value' ' + echo "create $c " >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: create $c given zero new value" err && + test_must_fail git rev-parse --verify -q $c +' + +test_expect_success 'stdin update ref works with right old value' ' + echo "update $b $m~1 $m" >stdin && + git update-ref --stdin <stdin && + git rev-parse $m~1 >expect && + git rev-parse $b >actual && + test_cmp expect actual +' + +test_expect_success 'stdin delete ref fails with wrong old value' ' + echo "delete $a $m~1" >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: Cannot lock the ref '"'"'$a'"'"'" err && + git rev-parse $m >expect && + git rev-parse $a >actual && + test_cmp expect actual +' + +test_expect_success 'stdin delete ref fails with zero old value' ' + echo "delete $a " >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: delete $a given zero old value" err && + git rev-parse $m >expect && + git rev-parse $a >actual && + test_cmp expect actual +' + +test_expect_success 'stdin update symref works option no-deref' ' + git symbolic-ref TESTSYMREF $b && + cat >stdin <<-EOF && + option no-deref + update TESTSYMREF $a $b + EOF + git update-ref --stdin <stdin && + git rev-parse TESTSYMREF >expect && + git rev-parse $a >actual && + test_cmp expect actual && + git rev-parse $m~1 >expect && + git rev-parse $b >actual && + test_cmp expect actual +' + +test_expect_success 'stdin delete symref works option no-deref' ' + git symbolic-ref TESTSYMREF $b && + cat >stdin <<-EOF && + option no-deref + delete TESTSYMREF $b + EOF + git update-ref --stdin <stdin && + test_must_fail git rev-parse --verify -q TESTSYMREF && + git rev-parse $m~1 >expect && + git rev-parse $b >actual && + test_cmp expect actual +' + +test_expect_success 'stdin delete ref works with right old value' ' + echo "delete $b $m~1" >stdin && + git update-ref --stdin <stdin && + test_must_fail git rev-parse --verify -q $b +' + +test_expect_success 'stdin update/create/verify combination works' ' + cat >stdin <<-EOF && + update $a $m + create $b $m + verify $c + EOF + git update-ref --stdin <stdin && + git rev-parse $m >expect && + git rev-parse $a >actual && + test_cmp expect actual && + git rev-parse $b >actual && + test_cmp expect actual && + test_must_fail git rev-parse --verify -q $c +' + +test_expect_success 'stdin update refs works with identity updates' ' + cat >stdin <<-EOF && + update $a $m $m + update $b $m $m + update $c $Z $E + EOF + git update-ref --stdin <stdin && + git rev-parse $m >expect && + git rev-parse $a >actual && + test_cmp expect actual && + git rev-parse $b >actual && + test_cmp expect actual && + test_must_fail git rev-parse --verify -q $c +' + +test_expect_success 'stdin update refs fails with wrong old value' ' + git update-ref $c $m && + cat >stdin <<-EOF && + update $a $m $m + update $b $m $m + update $c '' + EOF + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: Cannot lock the ref '"'"'$c'"'"'" err && + git rev-parse $m >expect && + git rev-parse $a >actual && + test_cmp expect actual && + git rev-parse $b >actual && + test_cmp expect actual && + git rev-parse $c >actual && + test_cmp expect actual +' + +test_expect_success 'stdin delete refs works with packed and loose refs' ' + git pack-refs --all && + git update-ref $c $m~1 && + cat >stdin <<-EOF && + delete $a $m + update $b $Z $m + update $c $E $m~1 + EOF + git update-ref --stdin <stdin && + test_must_fail git rev-parse --verify -q $a && + test_must_fail git rev-parse --verify -q $b && + test_must_fail git rev-parse --verify -q $c +' + +test_expect_success 'stdin -z works on empty input' ' + >stdin && + git update-ref -z --stdin <stdin && + git rev-parse --verify -q $m +' + +test_expect_success 'stdin -z fails on empty line' ' + echo "" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: whitespace before command: " err +' + +test_expect_success 'stdin -z fails on empty command' ' + printf $F "" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: empty command in input" err +' + +test_expect_success 'stdin -z fails on only whitespace' ' + printf $F " " >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: whitespace before command: " err +' + +test_expect_success 'stdin -z fails on leading whitespace' ' + printf $F " create $a" "$m" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: whitespace before command: create $a" err +' + +test_expect_success 'stdin -z fails on unknown command' ' + printf $F "unknown $a" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: unknown command: unknown $a" err +' + +test_expect_success 'stdin -z fails create with no ref' ' + printf $F "create " >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: create line missing <ref>" err +' + +test_expect_success 'stdin -z fails create with bad ref name' ' + printf $F "create ~a " "$m" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: invalid ref format: ~a " err +' + +test_expect_success 'stdin -z fails create with no new value' ' + printf $F "create $a" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: create $a missing <newvalue>" err +' + +test_expect_success 'stdin -z fails create with too many arguments' ' + printf $F "create $a" "$m" "$m" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: unknown command: $m" err +' + +test_expect_success 'stdin -z fails update with no ref' ' + printf $F "update " >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: update line missing <ref>" err +' + +test_expect_success 'stdin -z fails update with bad ref name' ' + printf $F "update ~a" "$m" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: invalid ref format: ~a" err +' + +test_expect_success 'stdin -z fails update with no new value' ' + printf $F "update $a" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: update $a missing <newvalue>" err +' + +test_expect_success 'stdin -z fails update with no old value' ' + printf $F "update $a" "$m" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: update $a missing \\[<oldvalue>\\] NUL" err +' + +test_expect_success 'stdin -z fails update with too many arguments' ' + printf $F "update $a" "$m" "$m" "$m" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: unknown command: $m" err +' + +test_expect_success 'stdin -z fails delete with no ref' ' + printf $F "delete " >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: delete line missing <ref>" err +' + +test_expect_success 'stdin -z fails delete with bad ref name' ' + printf $F "delete ~a" "$m" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: invalid ref format: ~a" err +' + +test_expect_success 'stdin -z fails delete with no old value' ' + printf $F "delete $a" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: delete $a missing \\[<oldvalue>\\] NUL" err +' + +test_expect_success 'stdin -z fails delete with too many arguments' ' + printf $F "delete $a" "$m" "$m" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: unknown command: $m" err +' + +test_expect_success 'stdin -z fails verify with too many arguments' ' + printf $F "verify $a" "$m" "$m" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: unknown command: $m" err +' + +test_expect_success 'stdin -z fails verify with no old value' ' + printf $F "verify $a" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: verify $a missing \\[<oldvalue>\\] NUL" err +' + +test_expect_success 'stdin -z fails option with unknown name' ' + printf $F "option unknown" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: option unknown: unknown" err +' + +test_expect_success 'stdin -z fails with duplicate refs' ' + printf $F "create $a" "$m" "create $b" "$m" "create $a" "$m" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: Multiple updates for ref '"'"'$a'"'"' not allowed." err +' + +test_expect_success 'stdin -z create ref works' ' + printf $F "create $a" "$m" >stdin && + git update-ref -z --stdin <stdin && + git rev-parse $m >expect && + git rev-parse $a >actual && + test_cmp expect actual +' + +test_expect_success 'stdin -z update ref creates with zero old value' ' + printf $F "update $b" "$m" "$Z" >stdin && + git update-ref -z --stdin <stdin && + git rev-parse $m >expect && + git rev-parse $b >actual && + test_cmp expect actual && + git update-ref -d $b +' + +test_expect_success 'stdin -z update ref creates with empty old value' ' + printf $F "update $b" "$m" "" >stdin && + git update-ref -z --stdin <stdin && + git rev-parse $m >expect && + git rev-parse $b >actual && + test_cmp expect actual +' + +test_expect_success 'stdin -z create ref works with path with space to blob' ' + printf $F "create refs/blobs/pws" "$m:$pws" >stdin && + git update-ref -z --stdin <stdin && + git rev-parse "$m:$pws" >expect && + git rev-parse refs/blobs/pws >actual && + test_cmp expect actual && + git update-ref -d refs/blobs/pws +' + +test_expect_success 'stdin -z update ref fails with wrong old value' ' + printf $F "update $c" "$m" "$m~1" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: Cannot lock the ref '"'"'$c'"'"'" err && + test_must_fail git rev-parse --verify -q $c +' + +test_expect_success 'stdin -z update ref fails with bad old value' ' + printf $F "update $c" "$m" "does-not-exist" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: invalid old value for ref $c: does-not-exist" err && + test_must_fail git rev-parse --verify -q $c +' + +test_expect_success 'stdin -z create ref fails with bad new value' ' + printf $F "create $c" "does-not-exist" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: invalid new value for ref $c: does-not-exist" err && + test_must_fail git rev-parse --verify -q $c +' + +test_expect_success 'stdin -z create ref fails with zero new value' ' + printf $F "create $c" "" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: create $c given zero new value" err && + test_must_fail git rev-parse --verify -q $c +' + +test_expect_success 'stdin -z update ref works with right old value' ' + printf $F "update $b" "$m~1" "$m" >stdin && + git update-ref -z --stdin <stdin && + git rev-parse $m~1 >expect && + git rev-parse $b >actual && + test_cmp expect actual +' + +test_expect_success 'stdin -z delete ref fails with wrong old value' ' + printf $F "delete $a" "$m~1" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: Cannot lock the ref '"'"'$a'"'"'" err && + git rev-parse $m >expect && + git rev-parse $a >actual && + test_cmp expect actual +' + +test_expect_success 'stdin -z delete ref fails with zero old value' ' + printf $F "delete $a" "$Z" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: delete $a given zero old value" err && + git rev-parse $m >expect && + git rev-parse $a >actual && + test_cmp expect actual +' + +test_expect_success 'stdin -z update symref works option no-deref' ' + git symbolic-ref TESTSYMREF $b && + printf $F "option no-deref" "update TESTSYMREF" "$a" "$b" >stdin && + git update-ref -z --stdin <stdin && + git rev-parse TESTSYMREF >expect && + git rev-parse $a >actual && + test_cmp expect actual && + git rev-parse $m~1 >expect && + git rev-parse $b >actual && + test_cmp expect actual +' + +test_expect_success 'stdin -z delete symref works option no-deref' ' + git symbolic-ref TESTSYMREF $b && + printf $F "option no-deref" "delete TESTSYMREF" "$b" >stdin && + git update-ref -z --stdin <stdin && + test_must_fail git rev-parse --verify -q TESTSYMREF && + git rev-parse $m~1 >expect && + git rev-parse $b >actual && + test_cmp expect actual +' + +test_expect_success 'stdin -z delete ref works with right old value' ' + printf $F "delete $b" "$m~1" >stdin && + git update-ref -z --stdin <stdin && + test_must_fail git rev-parse --verify -q $b +' + +test_expect_success 'stdin -z update/create/verify combination works' ' + printf $F "update $a" "$m" "" "create $b" "$m" "verify $c" "" >stdin && + git update-ref -z --stdin <stdin && + git rev-parse $m >expect && + git rev-parse $a >actual && + test_cmp expect actual && + git rev-parse $b >actual && + test_cmp expect actual && + test_must_fail git rev-parse --verify -q $c +' + +test_expect_success 'stdin -z update refs works with identity updates' ' + printf $F "update $a" "$m" "$m" "update $b" "$m" "$m" "update $c" "$Z" "" >stdin && + git update-ref -z --stdin <stdin && + git rev-parse $m >expect && + git rev-parse $a >actual && + test_cmp expect actual && + git rev-parse $b >actual && + test_cmp expect actual && + test_must_fail git rev-parse --verify -q $c +' + +test_expect_success 'stdin -z update refs fails with wrong old value' ' + git update-ref $c $m && + printf $F "update $a" "$m" "$m" "update $b" "$m" "$m" "update $c" "" "$Z" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: Cannot lock the ref '"'"'$c'"'"'" err && + git rev-parse $m >expect && + git rev-parse $a >actual && + test_cmp expect actual && + git rev-parse $b >actual && + test_cmp expect actual && + git rev-parse $c >actual && + test_cmp expect actual +' + +test_expect_success 'stdin -z delete refs works with packed and loose refs' ' + git pack-refs --all && + git update-ref $c $m~1 && + printf $F "delete $a" "$m" "update $b" "$Z" "$m" "update $c" "" "$m~1" >stdin && + git update-ref -z --stdin <stdin && + test_must_fail git rev-parse --verify -q $a && + test_must_fail git rev-parse --verify -q $b && + test_must_fail git rev-parse --verify -q $c +' + 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/t1411-reflog-show.sh b/t/t1411-reflog-show.sh index 9a105fe21f..6f47c0dd0e 100755 --- a/t/t1411-reflog-show.sh +++ b/t/t1411-reflog-show.sh @@ -144,4 +144,26 @@ test_expect_success 'empty reflog file' ' test_cmp expect actual ' +# This guards against the alternative of showing the diffs vs. the +# reflog ancestor. The reflog used is designed to list the commits +# more than once, so as to exercise the corresponding logic. +test_expect_success 'git log -g -p shows diffs vs. parents' ' + test_commit two && + git branch flipflop && + git update-ref refs/heads/flipflop -m flip1 HEAD^ && + git update-ref refs/heads/flipflop -m flop1 HEAD && + git update-ref refs/heads/flipflop -m flip2 HEAD^ && + git log -g -p flipflop >reflog && + grep -v ^Reflog reflog >actual && + git log -1 -p HEAD^ >log.one && + git log -1 -p HEAD >log.two && + ( + cat log.one; echo + cat log.two; echo + cat log.one; echo + cat log.two + ) >expect && + test_cmp expect actual +' + test_done diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh index 08aa24ca15..8c739c9613 100755 --- a/t/t1450-fsck.sh +++ b/t/t1450-fsck.sh @@ -142,6 +142,20 @@ test_expect_success '> in name is reported' ' grep "error in commit $new" out ' +# date is 2^64 + 1 +test_expect_success 'integer overflow in timestamps is reported' ' + git cat-file commit HEAD >basis && + sed "s/^\\(author .*>\\) [0-9]*/\\1 18446744073709551617/" \ + <basis >bad-timestamp && + new=$(git hash-object -t commit -w --stdin <bad-timestamp) && + test_when_finished "remove_object $new" && + git update-ref refs/heads/bogus "$new" && + test_when_finished "git update-ref -d refs/heads/bogus" && + git fsck 2>out && + cat out && + grep "error in commit $new.*integer overflow" out +' + test_expect_success 'tag pointing to nonexistent' ' cat >invalid-tag <<-\EOF && object ffffffffffffffffffffffffffffffffffffffff @@ -237,4 +251,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/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh index 13c88c9aae..922423e7d0 100755 --- a/t/t1502-rev-parse-parseopt.sh +++ b/t/t1502-rev-parse-parseopt.sh @@ -3,40 +3,64 @@ test_description='test git rev-parse --parseopt' . ./test-lib.sh -cat > expect <<\END_EXPECT -cat <<\EOF -usage: some-command [options] <args>... - - some-command does foo and bar! - - -h, --help show the help - --foo some nifty option --foo - --bar ... some cool option --bar with an argument - -An option group Header - -C[...] option C with an optional argument - -Extras - --extra1 line above used to cause a segfault but no longer does - -EOF +sed -e 's/^|//' >expect <<\END_EXPECT +|cat <<\EOF +|usage: some-command [options] <args>... +| +| some-command does foo and bar! +| +| -h, --help show the help +| --foo some nifty option --foo +| --bar ... some cool option --bar with an argument +| -b, --baz a short and long option +| +|An option group Header +| -C[...] option C with an optional argument +| -d, --data[=...] short and long option with an optional argument +| +|Argument hints +| -b <arg> short option required argument +| --bar2 <arg> long option required argument +| -e, --fuz <with-space> +| short and long option required argument +| -s[<some>] short option optional argument +| --long[=<data>] long option optional argument +| -g, --fluf[=<path>] short and long option optional argument +| --longest <very-long-argument-hint> +| a very long argument hint +| +|Extras +| --extra1 line above used to cause a segfault but no longer does +| +|EOF END_EXPECT -cat > optionspec << EOF -some-command [options] <args>... - -some-command does foo and bar! --- -h,help show the help - -foo some nifty option --foo -bar= some cool option --bar with an argument - - An option group Header -C? option C with an optional argument - -Extras -extra1 line above used to cause a segfault but no longer does +sed -e 's/^|//' >optionspec <<\EOF +|some-command [options] <args>... +| +|some-command does foo and bar! +|-- +|h,help show the help +| +|foo some nifty option --foo +|bar= some cool option --bar with an argument +|b,baz a short and long option +| +| An option group Header +|C? option C with an optional argument +|d,data? short and long option with an optional argument +| +| Argument hints +|b=arg short option required argument +|bar2=arg long option required argument +|e,fuz=with-space short and long option required argument +|s?some short option optional argument +|long?data long option optional argument +|g,fluf?path short and long option optional argument +|longest=very-long-argument-hint a very long argument hint +| +|Extras +|extra1 line above used to cause a segfault but no longer does EOF test_expect_success 'test --parseopt help output' ' @@ -45,16 +69,16 @@ test_expect_success 'test --parseopt help output' ' ' cat > expect <<EOF -set -- --foo --bar 'ham' -- 'arg' +set -- --foo --bar 'ham' -b -- 'arg' EOF test_expect_success 'test --parseopt' ' - git rev-parse --parseopt -- --foo --bar=ham arg < optionspec > output && + git rev-parse --parseopt -- --foo --bar=ham --baz arg < optionspec > output && test_cmp expect output ' test_expect_success 'test --parseopt with mixed options and arguments' ' - git rev-parse --parseopt -- --foo arg --bar=ham < optionspec > output && + git rev-parse --parseopt -- --foo arg --bar=ham --baz < optionspec > output && test_cmp expect output ' @@ -99,4 +123,36 @@ test_expect_success 'test --parseopt --keep-dashdash --stop-at-non-option withou test_cmp expect output ' +cat > expect <<EOF +set -- --foo --bar='z' --baz -C'Z' --data='A' -- 'arg' +EOF + +test_expect_success 'test --parseopt --stuck-long' ' + git rev-parse --parseopt --stuck-long -- --foo --bar=z -b arg -CZ -dA <optionspec >output && + test_cmp expect output +' + +cat > expect <<EOF +set -- --data='' -C --baz -- 'arg' +EOF + +test_expect_success 'test --parseopt --stuck-long and empty optional argument' ' + git rev-parse --parseopt --stuck-long -- --data= arg -C -b <optionspec >output && + test_cmp expect output +' + +cat > expect <<EOF +set -- --data --baz -- 'arg' +EOF + +test_expect_success 'test --parseopt --stuck-long and long option with unset optional argument' ' + git rev-parse --parseopt --stuck-long -- --data arg -b <optionspec >output && + test_cmp expect output +' + +test_expect_success 'test --parseopt --stuck-long and short option with unset optional argument' ' + git rev-parse --parseopt --stuck-long -- -d arg -b <optionspec >output && + test_cmp expect output +' + 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/t1506-rev-parse-diagnosis.sh b/t/t1506-rev-parse-diagnosis.sh index f950c10128..613d9bfe1b 100755 --- a/t/t1506-rev-parse-diagnosis.sh +++ b/t/t1506-rev-parse-diagnosis.sh @@ -196,4 +196,28 @@ test_expect_success 'dotdot is not an empty set' ' test_cmp expect actual ' +test_expect_success 'arg before dashdash must be a revision (missing)' ' + test_must_fail git rev-parse foobar -- 2>stderr && + test_i18ngrep "bad revision" stderr +' + +test_expect_success 'arg before dashdash must be a revision (file)' ' + >foobar && + test_must_fail git rev-parse foobar -- 2>stderr && + test_i18ngrep "bad revision" stderr +' + +test_expect_success 'arg before dashdash must be a revision (ambiguous)' ' + >foobar && + git update-ref refs/heads/foobar HEAD && + { + # we do not want to use rev-parse here, because + # we are testing it + cat .git/refs/heads/foobar && + printf "%s\n" -- + } >expect && + git rev-parse foobar -- >actual && + test_cmp expect actual +' + test_done diff --git a/t/t1507-rev-parse-upstream.sh b/t/t1507-rev-parse-upstream.sh index d6e576192f..178694ee63 100755 --- a/t/t1507-rev-parse-upstream.sh +++ b/t/t1507-rev-parse-upstream.sh @@ -17,6 +17,9 @@ test_expect_success 'setup' ' test_commit 4 && git branch --track my-side origin/side && git branch --track local-master master && + git branch --track fun@ny origin/side && + git branch --track @funny origin/side && + git branch --track funny@ origin/side && git remote add -t master master-only .. && git fetch master-only && git branch bad-upstream && @@ -54,6 +57,28 @@ test_expect_success 'my-side@{upstream} resolves to correct full name' ' test refs/remotes/origin/side = "$(full_name my-side@{u})" ' +test_expect_success 'upstream of branch with @ in middle' ' + full_name fun@ny@{u} >actual && + echo refs/remotes/origin/side >expect && + test_cmp expect actual +' + +test_expect_success 'upstream of branch with @ at start' ' + full_name @funny@{u} >actual && + echo refs/remotes/origin/side >expect && + test_cmp expect actual +' + +test_expect_success 'upstream of branch with @ at end' ' + full_name funny@@{u} >actual && + echo refs/remotes/origin/side >expect && + test_cmp expect actual +' + +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 +150,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 +158,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 +166,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 +174,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 +183,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 @@ -211,4 +231,20 @@ test_expect_success 'log -g other@{u}@{now}' ' test_cmp expect actual ' +test_expect_success '@{reflog}-parsing does not look beyond colon' ' + echo content >@{yesterday} && + git add @{yesterday} && + git commit -m "funny reflog file" && + git hash-object @{yesterday} >expect && + git rev-parse HEAD:@{yesterday} >actual +' + +test_expect_success '@{upstream}-parsing does not look beyond colon' ' + echo content >@{upstream} && + git add @{upstream} && + git commit -m "funny upstream file" && + git hash-object @{upstream} >expect && + git rev-parse HEAD:@{upstream} >actual +' + test_done diff --git a/t/t1508-at-combinations.sh b/t/t1508-at-combinations.sh index d5d6244178..078e1195df 100755 --- a/t/t1508-at-combinations.sh +++ b/t/t1508-at-combinations.sh @@ -4,17 +4,27 @@ 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 + elif test '$2' = 'ref' + then + git rev-parse --symbolic-full-name '$1' >actual + else + git cat-file -p '$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 } @@ -25,27 +35,64 @@ test_expect_success 'setup' ' git checkout -b upstream-branch && test_commit upstream-one && test_commit upstream-two && + git checkout -b @/at-test && + git checkout -b @@/at-test && + git checkout -b @at-test && git checkout -b old-branch && test_commit old-one && test_commit old-two && 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 +check "@@/at-test" ref refs/heads/@@/at-test +check "@/at-test" ref refs/heads/@/at-test +check "@at-test" ref refs/heads/@at-test 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_expect_success 'create path with @' ' + echo content >normal && + echo content >fun@ny && + git add normal fun@ny && + git commit -m "funny path" +' + +check "@:normal" blob content +check "@:fun@ny" blob content 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..e1b2a99f10 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 && @@ -758,9 +777,7 @@ test_expect_success '#30: core.worktree and core.bare conflict (gitfile version) setup_repo 30 "$here/30" gitfile true && ( cd 30 && - GIT_DIR=.git && - export GIT_DIR && - test_must_fail git symbolic-ref HEAD 2>result + test_must_fail env GIT_DIR=.git git symbolic-ref HEAD 2>result ) && grep "core.bare and core.worktree" 30/result ' diff --git a/t/t1511-rev-parse-caret.sh b/t/t1511-rev-parse-caret.sh index eaefc777bd..15973f2094 100755 --- a/t/t1511-rev-parse-caret.sh +++ b/t/t1511-rev-parse-caret.sh @@ -54,6 +54,13 @@ test_expect_success 'ref^{tree}' ' test_must_fail git rev-parse blob-tag^{tree} ' +test_expect_success 'ref^{tag}' ' + test_must_fail git rev-parse HEAD^{tag} && + git rev-parse commit-tag >expected && + git rev-parse commit-tag^{tag} >actual && + test_cmp expected actual +' + test_expect_success 'ref^{/.}' ' git rev-parse master >expected && git rev-parse master^{/.} >actual && 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/t1600-index.sh b/t/t1600-index.sh new file mode 100755 index 0000000000..079d241145 --- /dev/null +++ b/t/t1600-index.sh @@ -0,0 +1,76 @@ +#!/bin/sh + +test_description='index file specific tests' + +. ./test-lib.sh + +test_expect_success 'setup' ' + echo 1 >a +' + +test_expect_success 'bogus GIT_INDEX_VERSION issues warning' ' + ( + rm -f .git/index && + GIT_INDEX_VERSION=2bogus && + export GIT_INDEX_VERSION && + git add a 2>&1 | sed "s/[0-9]//" >actual.err && + sed -e "s/ Z$/ /" <<-\EOF >expect.err && + warning: GIT_INDEX_VERSION set, but the value is invalid. + Using version Z + EOF + test_i18ncmp expect.err actual.err + ) +' + +test_expect_success 'out of bounds GIT_INDEX_VERSION issues warning' ' + ( + rm -f .git/index && + GIT_INDEX_VERSION=1 && + export GIT_INDEX_VERSION && + git add a 2>&1 | sed "s/[0-9]//" >actual.err && + sed -e "s/ Z$/ /" <<-\EOF >expect.err && + warning: GIT_INDEX_VERSION set, but the value is invalid. + Using version Z + EOF + test_i18ncmp expect.err actual.err + ) +' + +test_expect_success 'no warning with bogus GIT_INDEX_VERSION and existing index' ' + ( + GIT_INDEX_VERSION=1 && + export GIT_INDEX_VERSION && + git add a 2>actual.err && + >expect.err && + test_i18ncmp expect.err actual.err + ) +' + +test_expect_success 'out of bounds index.version issues warning' ' + ( + sane_unset GIT_INDEX_VERSION && + rm -f .git/index && + git config --add index.version 1 && + git add a 2>&1 | sed "s/[0-9]//" >actual.err && + sed -e "s/ Z$/ /" <<-\EOF >expect.err && + warning: index.version set, but the value is invalid. + Using version Z + EOF + test_i18ncmp expect.err actual.err + ) +' + +test_expect_success 'GIT_INDEX_VERSION takes precedence over config' ' + ( + rm -f .git/index && + GIT_INDEX_VERSION=4 && + export GIT_INDEX_VERSION && + git config --add index.version 2 && + git add a 2>&1 && + echo 4 >expect && + test-index-version <.git/index >actual && + test_cmp expect 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/t2008-checkout-subdir.sh b/t/t2008-checkout-subdir.sh index 3e098ab31e..eadb9434ae 100755 --- a/t/t2008-checkout-subdir.sh +++ b/t/t2008-checkout-subdir.sh @@ -58,13 +58,13 @@ test_expect_success 'checkout with simple prefix' ' ' -# This is not expected to work as ls-files was not designed -# to deal with such. Enable it when ls-files is updated. -: test_expect_success 'checkout with complex relative path' ' - - rm file1 && - git checkout HEAD -- ../dir1/../dir1/file1 && test -f ./file1 - +test_expect_success 'checkout with complex relative path' ' + ( + cd dir1 && + rm file1 && + git checkout HEAD -- ../dir1/../dir1/file1 && + test "hello" = "$(cat file1)" + ) ' test_expect_success 'relative path outside tree should fail' \ diff --git a/t/t2010-checkout-ambiguous.sh b/t/t2010-checkout-ambiguous.sh index 7cc0a3582e..87bdf9c96b 100755 --- a/t/t2010-checkout-ambiguous.sh +++ b/t/t2010-checkout-ambiguous.sh @@ -47,4 +47,10 @@ test_expect_success 'disambiguate checking out from a tree-ish' ' git diff --exit-code --quiet ' +test_expect_success 'accurate error message with more than one ref' ' + test_must_fail git checkout HEAD master -- 2>actual && + grep 2 actual && + test_i18ngrep "one reference expected, 2 given" actual +' + test_done 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..6ecb559465 --- /dev/null +++ b/t/t2024-checkout-dwim.sh @@ -0,0 +1,188 @@ +#!/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 d_baz && + git checkout -b eggs && + test_commit d_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_expect_success 'checkout of branch with a file having the same name fails' ' + git checkout -B master && + test_might_fail git branch -D spam && + + >spam && + test_must_fail git checkout spam && + test_must_fail git rev-parse --verify refs/heads/spam && + test_branch master +' + +test_expect_success 'checkout <branch> -- succeeds, even if a file with the same name exists' ' + git checkout -B master && + test_might_fail git branch -D spam && + + >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_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/t2104-update-index-skip-worktree.sh b/t/t2104-update-index-skip-worktree.sh index 1d0879be06..29c1fb10ca 100755 --- a/t/t2104-update-index-skip-worktree.sh +++ b/t/t2104-update-index-skip-worktree.sh @@ -7,6 +7,8 @@ test_description='skip-worktree bit test' . ./test-lib.sh +test_set_index_version 3 + cat >expect.full <<EOF H 1 H 2 diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh index 4cdebda6a5..e16b15d3e5 100755 --- a/t/t2200-add-update.sh +++ b/t/t2200-add-update.sh @@ -80,11 +80,21 @@ test_expect_success 'change gets noticed' ' ' -test_expect_success SYMLINKS 'replace a file with a symlink' ' +test_expect_success 'non-qualified update in subdir updates from the root' ' + ( + cd dir1 && + echo even more >>sub2 && + git add -u + ) && + : >expect && + 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 +160,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 dc2f0458fd..b2798feef7 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 ' @@ -115,7 +115,7 @@ EOF git config core.excludesFile excludes-file -git status | grep "^# " > output +git -c status.displayCommentPrefix=true status | grep "^# " > output cat > expect << EOF # .gitignore @@ -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,10 +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/t3004-ls-files-basic.sh b/t/t3004-ls-files-basic.sh index 8d9bc3c2af..9c7adbdbe1 100755 --- a/t/t3004-ls-files-basic.sh +++ b/t/t3004-ls-files-basic.sh @@ -36,4 +36,21 @@ test_expect_success 'ls-files -h in corrupt repository' ' test_i18ngrep "[Uu]sage: git ls-files " broken/usage ' +test_expect_success SYMLINKS 'ls-files with absolute paths to symlinks' ' + mkdir subs && + ln -s nosuch link && + ln -s ../nosuch subs/link && + git add link subs/link && + git ls-files -s link subs/link >expect && + git ls-files -s "$(pwd)/link" "$(pwd)/subs/link" >actual && + test_cmp expect actual && + + ( + cd subs && + git ls-files -s link >../expect && + git ls-files -s "$(pwd)/link" >../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..6d3b828a95 100755 --- a/t/t3010-ls-files-killed-modified.sh +++ b/t/t3010-ls-files-killed-modified.sh @@ -11,6 +11,9 @@ 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 + pathx/ju - a file in a directory + submod1/ - a submodule + submod2/ - another submodule and the following on the filesystem: @@ -21,9 +24,12 @@ and the following on the filesystem: path4 - a file path5 - a symlink path6/file6 - a file in a directory + pathx/ju/nk - a file in a directory to be killed + 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 +39,91 @@ 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 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 \ - 'validate git ls-files -k output.' \ - '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 \ - 'validate git ls-files -m output.' \ - 'test_cmp .expected .output' +test_expect_success 'git update-index --add to add various paths.' ' + date >path0 && + test_ln_s_add xyzzy path1 && + mkdir path2 path3 pathx && + date >path2/file2 && + date >path3/file3 && + >pathx/ju && + : >path7 && + date >path8 && + : >path9 && + date >path10 && + git update-index --add -- path0 path?/file? pathx/ju 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.' ' + date >path2 && + if test_have_prereq SYMLINKS + then + ln -s frotz path3 && + ln -s nitfol path5 + else + date >path3 && + date >path5 + fi && + mkdir -p path0 path1 path6 pathx/ju && + date >path0/file0 && + date >path1/file1 && + date >path6/file6 && + date >path7 && + : >path8 && + : >path9 && + touch path10 && + >pathx/ju/nk && + cat >.expected <<-\EOF + path0/file0 + path1/file1 + path2 + path3 + pathx/ju/nk + EOF +' + +test_expect_success 'git ls-files -k output (w/o icase)' ' + git ls-files -k >.output + test_cmp .expected .output +' + +test_expect_success 'git ls-files -k output (w/ icase)' ' + git -c core.ignorecase=true ls-files -k >.output + test_cmp .expected .output +' + +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.' ' + cat >.expected <<-\EOF && + path0 + path1 + path2/file2 + path3/file3 + path7 + path8 + pathx/ju + submod1 + EOF + test_cmp .expected .output +' test_done diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh index a5e3da7e41..82e18548c3 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,13 @@ 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 + c7=$(git rev-parse --verify HEAD) && + 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' ' @@ -524,6 +518,52 @@ test_expect_success 'reset and bind merge' ' ' +test_expect_success 'merge-recursive w/ empty work tree - ours has rename' ' + ( + GIT_WORK_TREE="$PWD/ours-has-rename-work" && + export GIT_WORK_TREE && + GIT_INDEX_FILE="$PWD/ours-has-rename-index" && + export GIT_INDEX_FILE && + mkdir "$GIT_WORK_TREE" && + git read-tree -i -m $c7 && + git update-index --ignore-missing --refresh && + git merge-recursive $c0 -- $c7 $c3 && + git ls-files -s >actual-files + ) 2>actual-err && + >expected-err && + cat >expected-files <<-EOF && + 100644 $o3 0 b/c + 100644 $o0 0 c + 100644 $o0 0 d/e + 100644 $o0 0 e + EOF + test_cmp expected-files actual-files && + test_cmp expected-err actual-err +' + +test_expect_success 'merge-recursive w/ empty work tree - theirs has rename' ' + ( + GIT_WORK_TREE="$PWD/theirs-has-rename-work" && + export GIT_WORK_TREE && + GIT_INDEX_FILE="$PWD/theirs-has-rename-index" && + export GIT_INDEX_FILE && + mkdir "$GIT_WORK_TREE" && + git read-tree -i -m $c3 && + git update-index --ignore-missing --refresh && + git merge-recursive $c0 -- $c3 $c7 && + git ls-files -s >actual-files + ) 2>actual-err && + >expected-err && + cat >expected-files <<-EOF && + 100644 $o3 0 b/c + 100644 $o0 0 c + 100644 $o0 0 d/e + 100644 $o0 0 e + EOF + test_cmp expected-files actual-files && + test_cmp expected-err actual-err +' + test_expect_success 'merge removes empty directories' ' git reset --hard master && @@ -569,28 +609,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..ef509df351 --- /dev/null +++ b/t/t3070-wildmatch.sh @@ -0,0 +1,268 @@ +#!/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 +} + +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..ac31b711f2 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -7,20 +7,19 @@ 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 --man --help </dev/null >/dev/null 2>&1 && + test_path_is_missing .git/refs/heads/--help ' test_expect_success 'branch -h in broken repository' ' @@ -34,63 +33,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 +251,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 +285,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 +293,192 @@ 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/*:refs/remotes/local/* && + (git show-ref -q refs/remotes/local/master || git fetch local) && + git config remote.local.fetch refs/heads/s:refs/remotes/local/s && + 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.autosetupmerge 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 +486,48 @@ 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 +' + +test_expect_success '--set-upstream-to notices an error to set branch as own upstream' ' + git branch --set-upstream-to refs/heads/my13 my13 2>actual && + cat >expected <<-\EOF && + warning: Not setting branch my13 as its own upstream. + EOF + test_expect_code 1 git config branch.my13.remote && + test_expect_code 1 git config branch.my13.merge && + test_i18ncmp 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 +798,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 ' @@ -800,11 +859,7 @@ test_expect_success 'detect typo in branch name when using --edit-description' ' write_script editor <<-\EOF && echo "New contents" >"$1" EOF - ( - EDITOR=./editor && - export EDITOR && - test_must_fail git branch --edit-description no-such-branch - ) + test_must_fail env EDITOR=./editor git branch --edit-description no-such-branch ' test_expect_success 'refuse --edit-description on unborn branch for now' ' @@ -812,15 +867,46 @@ test_expect_success 'refuse --edit-description on unborn branch for now' ' echo "New contents" >"$1" EOF git checkout --orphan unborn && - ( - EDITOR=./editor && - export EDITOR && - test_must_fail git branch --edit-description - ) + test_must_fail env EDITOR=./editor git branch --edit-description ' test_expect_success '--merged catches invalid object names' ' test_must_fail git branch --merged 0000000000000000000000000000000000000000 ' +test_expect_success 'tracking with unexpected .fetch refspec' ' + rm -rf a b c d && + git init a && + ( + cd a && + test_commit a + ) && + git init b && + ( + cd b && + test_commit b + ) && + git init c && + ( + cd c && + test_commit c && + git remote add a ../a && + git remote add b ../b && + git fetch --all + ) && + git init d && + ( + cd d && + git remote add c ../c && + git config remote.c.fetch "+refs/remotes/*:refs/remotes/*" && + git fetch c && + git branch --track local/a/master remotes/a/master && + test "$(git config branch.local/a/master.remote)" = "c" && + test "$(git config branch.local/a/master.merge)" = "refs/remotes/a/master" && + git rev-parse --verify a >expect && + git rev-parse --verify local/a/master >actual && + test_cmp expect actual + ) +' + test_done 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/t3300-funny-names.sh b/t/t3300-funny-names.sh index 7480d6e7c2..9a146f1335 100755 --- a/t/t3300-funny-names.sh +++ b/t/t3300-funny-names.sh @@ -69,7 +69,7 @@ test_expect_success 'ls-files -z does not quote funny filename' ' tabs ," (dq) and spaces EOF git ls-files -z >ls-files.z && - "$PERL_PATH" -pe "y/\000/\012/" <ls-files.z >current && + perl -pe "y/\000/\012/" <ls-files.z >current && test_cmp expected current ' @@ -106,7 +106,7 @@ test_expect_success 'diff-index -z does not quote funny filename' ' tabs ," (dq) and spaces EOF git diff-index -z --name-status $t0 >diff-index.z && - "$PERL_PATH" -pe "y/\000/\012/" <diff-index.z >current && + perl -pe "y/\000/\012/" <diff-index.z >current && test_cmp expected current ' @@ -116,7 +116,7 @@ test_expect_success 'diff-tree -z does not quote funny filename' ' tabs ," (dq) and spaces EOF git diff-tree -z --name-status $t0 $t1 >diff-tree.z && - "$PERL_PATH" -pe y/\\000/\\012/ <diff-tree.z >current && + perl -pe y/\\000/\\012/ <diff-tree.z >current && test_cmp expected current ' diff --git a/t/t3301-notes.sh b/t/t3301-notes.sh index 16de05aff9..cfd67ff3df 100755 --- a/t/t3301-notes.sh +++ b/t/t3301-notes.sh @@ -17,7 +17,7 @@ GIT_EDITOR=./fake_editor.sh export GIT_EDITOR test_expect_success 'cannot annotate non-existing HEAD' ' - (MSG=3 && export MSG && test_must_fail git notes add) + test_must_fail env MSG=3 git notes add ' test_expect_success setup ' @@ -32,22 +32,16 @@ test_expect_success setup ' ' test_expect_success 'need valid notes ref' ' - (MSG=1 GIT_NOTES_REF=/ && export MSG GIT_NOTES_REF && - test_must_fail git notes add) && - (MSG=2 GIT_NOTES_REF=/ && export MSG GIT_NOTES_REF && - test_must_fail git notes show) + test_must_fail env MSG=1 GIT_NOTES_REF=/ git notes show && + test_must_fail env MSG=2 GIT_NOTES_REF=/ git notes show ' test_expect_success 'refusing to add notes in refs/heads/' ' - (MSG=1 GIT_NOTES_REF=refs/heads/bogus && - export MSG GIT_NOTES_REF && - test_must_fail git notes add) + test_must_fail env MSG=1 GIT_NOTES_REF=refs/heads/bogus git notes add ' test_expect_success 'refusing to edit notes in refs/remotes/' ' - (MSG=1 GIT_NOTES_REF=refs/remotes/bogus && - export MSG GIT_NOTES_REF && - test_must_fail git notes edit) + test_must_fail env MSG=1 GIT_NOTES_REF=refs/heads/bogus git notes edit ' # 1 indicates caught gracefully by die, 128 means git-show barked @@ -812,6 +806,33 @@ test_expect_success 'create note from non-existing note with "git notes add -C" test_must_fail git notes list HEAD ' +test_expect_success 'create note from non-blob with "git notes add -C" fails' ' + commit=$(git rev-parse --verify HEAD) && + tree=$(git rev-parse --verify HEAD:) && + test_must_fail git notes add -C $commit && + test_must_fail git notes add -C $tree && + test_must_fail git notes list HEAD +' + +cat > expect << EOF +commit 80d796defacd5db327b7a4e50099663902fbdc5c +Author: A U Thor <author@example.com> +Date: Thu Apr 7 15:20:13 2005 -0700 + + 8th + +Notes (other): + This is a blob object +EOF + +test_expect_success 'create note from blob with "git notes add -C" reuses blob id' ' + blob=$(echo "This is a blob object" | git hash-object -w --stdin) && + git notes add -C $blob && + git log -1 > actual && + test_cmp expect actual && + test "$(git notes list HEAD)" = "$blob" +' + cat > expect << EOF commit 016e982bad97eacdbda0fcbd7ce5b0ba87c81f1b Author: A U Thor <author@example.com> @@ -838,11 +859,7 @@ test_expect_success 'create note from non-existing note with "git notes add -c" git add a10 && test_tick && git commit -m 10th && - ( - MSG="yet another note" && - export MSG && - test_must_fail git notes add -c deadbeef - ) && + test_must_fail env MSG="yet another note" git notes add -c deadbeef && test_must_fail git notes list HEAD ' diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index 1de0ebda25..80e0a951ea 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,31 @@ 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 from ambiguous branch name' ' + git checkout -b topic side && + git rebase master ' -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 off of the previous branch using "-"' ' + git checkout master && + git checkout HEAD^ && + git rebase @{-1} >expect.messages && + git merge-base master HEAD >expect.forkpoint && -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) + git checkout master && + git checkout HEAD^ && + git rebase - >actual.messages && + git merge-base master HEAD >actual.forkpoint && + + test_cmp expect.forkpoint actual.forkpoint && + # the next one is dubious---we may want to say "-", + # instead of @{-1}, in the message + test_i18ncmp expect.messages actual.messages ' 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 +122,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 ' @@ -168,18 +151,28 @@ test_expect_success 'fail when upstream arg is missing and not configured' ' test_must_fail git rebase ' -test_expect_success 'default to @{upstream} when upstream arg is missing' ' +test_expect_success 'default to common base in @{upstream}s reflog if no upstream arg' ' + git checkout -b default-base master && git checkout -b default topic && git config branch.default.remote . && - git config branch.default.merge refs/heads/master && + git config branch.default.merge refs/heads/default-base && + git rebase && + git rev-parse --verify default-base >expect && + git rev-parse default~1 >actual && + test_cmp expect actual && + git checkout default-base && + git reset --hard HEAD^ && + git checkout default && git rebase && - test "$(git rev-parse default~1)" = "$(git rev-parse master)" + git rev-parse --verify default-base >expect && + git rev-parse default~1 >actual && + test_cmp expect actual ' 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..c0023a5b4f 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -29,14 +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 # in the expect2 file for the 'stop on conflicting pick' test. @@ -78,6 +70,7 @@ export SHELL test_expect_success 'rebase -i with the exec command' ' git checkout master && ( + set_fake_editor && FAKE_LINES="1 exec_>touch-one 2 exec_>touch-two exec_false exec_>touch-three 3 4 exec_>\"touch-file__name_with_spaces\";_>touch-after-semicolon 5" && @@ -99,6 +92,7 @@ test_expect_success 'rebase -i with the exec command' ' test_expect_success 'rebase -i with the exec command runs from tree root' ' git checkout master && mkdir subdir && (cd subdir && + set_fake_editor && FAKE_LINES="1 exec_>touch-subdir" \ git rebase -i HEAD^ ) && @@ -108,11 +102,8 @@ test_expect_success 'rebase -i with the exec command runs from tree root' ' test_expect_success 'rebase -i with the exec command checks tree cleanness' ' git checkout master && - ( - FAKE_LINES="exec_echo_foo_>file1 1" && - export FAKE_LINES && - test_must_fail git rebase -i HEAD^ - ) && + set_fake_editor && + test_must_fail env FAKE_LINES="exec_echo_foo_>file1 1" git rebase -i HEAD^ && test_cmp_rev master^ HEAD && git reset --hard && git rebase --continue @@ -121,16 +112,15 @@ test_expect_success 'rebase -i with the exec command checks tree cleanness' ' test_expect_success 'rebase -i with exec of inexistent command' ' git checkout master && test_when_finished "git rebase --abort" && - ( - FAKE_LINES="exec_this-command-does-not-exist 1" && - export FAKE_LINES && - test_must_fail git rebase -i HEAD^ >actual 2>&1 - ) && + set_fake_editor && + test_must_fail env FAKE_LINES="exec_this-command-does-not-exist 1" \ + git rebase -i HEAD^ >actual 2>&1 && ! grep "Maybe git-rebase is broken" actual ' test_expect_success 'no changes are a nop' ' git checkout branch2 && + set_fake_editor && git rebase -i F && test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch2" && test $(git rev-parse I) = $(git rev-parse HEAD) @@ -140,6 +130,7 @@ test_expect_success 'test the [branch] option' ' git checkout -b dead-end && git rm file6 && git commit -m "stop here" && + set_fake_editor && git rebase -i F branch2 && test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch2" && test $(git rev-parse I) = $(git rev-parse branch2) && @@ -148,6 +139,7 @@ test_expect_success 'test the [branch] option' ' test_expect_success 'test --onto <branch>' ' git checkout -b test-onto branch2 && + set_fake_editor && git rebase -i --onto branch1 F && test "$(git symbolic-ref -q HEAD)" = "refs/heads/test-onto" && test $(git rev-parse HEAD^) = $(git rev-parse branch1) && @@ -157,6 +149,7 @@ test_expect_success 'test --onto <branch>' ' test_expect_success 'rebase on top of a non-conflicting commit' ' git checkout branch1 && git tag original-branch1 && + set_fake_editor && git rebase -i branch2 && test file6 = $(git diff --name-only original-branch1) && test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch1" && @@ -169,6 +162,7 @@ test_expect_success 'reflog for the branch shows state before rebase' ' ' test_expect_success 'exchange two commits' ' + set_fake_editor && FAKE_LINES="2 1" git rebase -i HEAD~2 && test H = $(git cat-file commit HEAD^ | sed -ne \$p) && test G = $(git cat-file commit HEAD | sed -ne \$p) @@ -194,6 +188,7 @@ EOF test_expect_success 'stop on conflicting pick' ' git tag new-branch1 && + set_fake_editor && test_must_fail git rebase -i master && test "$(git rev-parse HEAD~3)" = "$(git rev-parse master)" && test_cmp expect .git/rebase-merge/patch && @@ -214,6 +209,7 @@ test_expect_success 'abort' ' test_expect_success 'abort with error when new base cannot be checked out' ' git rm --cached file1 && git commit -m "remove file in base" && + set_fake_editor && test_must_fail git rebase -i master > output 2>&1 && grep "The following untracked working tree files would be overwritten by checkout:" \ output && @@ -228,6 +224,7 @@ test_expect_success 'retain authorship' ' test_tick && GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" && git tag twerp && + set_fake_editor && git rebase -i --onto master HEAD^ && git show HEAD | grep "^Author: Twerp Snog" ' @@ -238,6 +235,7 @@ test_expect_success 'squash' ' test_tick && GIT_AUTHOR_NAME="Nitfol" git commit -m "nitfol" file7 && echo "******************************" && + set_fake_editor && FAKE_LINES="1 squash 2" EXPECT_HEADER_COUNT=2 \ git rebase -i --onto master HEAD~2 && test B = $(cat file7) && @@ -250,6 +248,7 @@ test_expect_success 'retain authorship when squashing' ' test_expect_success '-p handles "no changes" gracefully' ' HEAD=$(git rev-parse HEAD) && + set_fake_editor && git rebase -i -p HEAD^ && git update-index --refresh && git diff-files --quiet && @@ -259,6 +258,7 @@ test_expect_success '-p handles "no changes" gracefully' ' test_expect_failure 'exchange two commits with -p' ' git checkout H && + set_fake_editor && FAKE_LINES="2 1" git rebase -i -p HEAD~2 && test H = $(git cat-file commit HEAD^ | sed -ne \$p) && test G = $(git cat-file commit HEAD | sed -ne \$p) @@ -293,6 +293,7 @@ test_expect_success 'preserve merges with -p' ' git commit -m M file1 && git checkout -b to-be-rebased && test_tick && + set_fake_editor && git rebase -i -p --onto branch1 master && git update-index --refresh && git diff-files --quiet && @@ -307,6 +308,7 @@ test_expect_success 'preserve merges with -p' ' ' test_expect_success 'edit ancestor with -p' ' + set_fake_editor && FAKE_LINES="1 2 edit 3 4" git rebase -i -p HEAD~3 && echo 2 > unrelated-file && test_tick && @@ -320,6 +322,7 @@ test_expect_success 'edit ancestor with -p' ' test_expect_success '--continue tries to commit' ' test_tick && + set_fake_editor && test_must_fail git rebase -i --onto new-branch1 HEAD^ && echo resolved > file1 && git add file1 && @@ -331,6 +334,7 @@ test_expect_success '--continue tries to commit' ' test_expect_success 'verbose flag is heeded, even after --continue' ' git reset --hard master@{1} && test_tick && + set_fake_editor && test_must_fail git rebase -v -i --onto new-branch1 HEAD^ && echo resolved > file1 && git add file1 && @@ -340,6 +344,7 @@ test_expect_success 'verbose flag is heeded, even after --continue' ' test_expect_success 'multi-squash only fires up editor once' ' base=$(git rev-parse HEAD~4) && + set_fake_editor && FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="1 squash 2 squash 3 squash 4" \ EXPECT_HEADER_COUNT=4 \ git rebase -i $base && @@ -350,6 +355,7 @@ test_expect_success 'multi-squash only fires up editor once' ' test_expect_success 'multi-fixup does not fire up editor' ' git checkout -b multi-fixup E && base=$(git rev-parse HEAD~4) && + set_fake_editor && FAKE_COMMIT_AMEND="NEVER" FAKE_LINES="1 fixup 2 fixup 3 fixup 4" \ git rebase -i $base && test $base = $(git rev-parse HEAD^) && @@ -361,11 +367,8 @@ test_expect_success 'multi-fixup does not fire up editor' ' test_expect_success 'commit message used after conflict' ' git checkout -b conflict-fixup conflict-branch && base=$(git rev-parse HEAD~4) && - ( - FAKE_LINES="1 fixup 3 fixup 4" && - export FAKE_LINES && - test_must_fail git rebase -i $base - ) && + set_fake_editor && + test_must_fail env FAKE_LINES="1 fixup 3 fixup 4" git rebase -i $base && echo three > conflict && git add conflict && FAKE_COMMIT_AMEND="ONCE" EXPECT_HEADER_COUNT=2 \ @@ -379,11 +382,8 @@ test_expect_success 'commit message used after conflict' ' test_expect_success 'commit message retained after conflict' ' git checkout -b conflict-squash conflict-branch && base=$(git rev-parse HEAD~4) && - ( - FAKE_LINES="1 fixup 3 squash 4" && - export FAKE_LINES && - test_must_fail git rebase -i $base - ) && + set_fake_editor && + test_must_fail env FAKE_LINES="1 fixup 3 squash 4" git rebase -i $base && echo three > conflict && git add conflict && FAKE_COMMIT_AMEND="TWICE" EXPECT_HEADER_COUNT=2 \ @@ -405,6 +405,7 @@ EOF test_expect_success 'squash and fixup generate correct log messages' ' git checkout -b squash-fixup E && base=$(git rev-parse HEAD~4) && + set_fake_editor && FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="1 fixup 2 squash 3 fixup 4" \ EXPECT_HEADER_COUNT=4 \ git rebase -i $base && @@ -417,6 +418,7 @@ test_expect_success 'squash and fixup generate correct log messages' ' test_expect_success 'squash ignores comments' ' git checkout -b skip-comments E && base=$(git rev-parse HEAD~4) && + set_fake_editor && FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="# 1 # squash 2 # squash 3 # squash 4 #" \ EXPECT_HEADER_COUNT=4 \ git rebase -i $base && @@ -429,6 +431,7 @@ test_expect_success 'squash ignores comments' ' test_expect_success 'squash ignores blank lines' ' git checkout -b skip-blank-lines E && base=$(git rev-parse HEAD~4) && + set_fake_editor && FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="> 1 > squash 2 > squash 3 > squash 4 >" \ EXPECT_HEADER_COUNT=4 \ git rebase -i $base && @@ -441,6 +444,7 @@ test_expect_success 'squash ignores blank lines' ' test_expect_success 'squash works as expected' ' git checkout -b squash-works no-conflict-branch && one=$(git rev-parse HEAD~3) && + set_fake_editor && FAKE_LINES="1 squash 3 2" EXPECT_HEADER_COUNT=2 \ git rebase -i HEAD~3 && test $one = $(git rev-parse HEAD~2) @@ -449,11 +453,8 @@ test_expect_success 'squash works as expected' ' test_expect_success 'interrupted squash works as expected' ' git checkout -b interrupted-squash conflict-branch && one=$(git rev-parse HEAD~3) && - ( - FAKE_LINES="1 squash 3 2" && - export FAKE_LINES && - test_must_fail git rebase -i HEAD~3 - ) && + set_fake_editor && + test_must_fail env FAKE_LINES="1 squash 3 2" git rebase -i HEAD~3 && (echo one; echo two; echo four) > conflict && git add conflict && test_must_fail git rebase --continue && @@ -466,11 +467,8 @@ test_expect_success 'interrupted squash works as expected' ' test_expect_success 'interrupted squash works as expected (case 2)' ' git checkout -b interrupted-squash2 conflict-branch && one=$(git rev-parse HEAD~3) && - ( - FAKE_LINES="3 squash 1 2" && - export FAKE_LINES && - test_must_fail git rebase -i HEAD~3 - ) && + set_fake_editor && + test_must_fail env FAKE_LINES="3 squash 1 2" git rebase -i HEAD~3 && (echo one; echo four) > conflict && git add conflict && test_must_fail git rebase --continue && @@ -483,21 +481,14 @@ 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 && + set_fake_editor && FAKE_LINES="edit 1" git rebase -i HEAD^ && echo edited > file7 && git add file7 && @@ -510,20 +501,18 @@ test_expect_success '--continue tries to commit, even for "edit"' ' test_expect_success 'aborted --continue does not squash commits after "edit"' ' old=$(git rev-parse HEAD) && test_tick && + set_fake_editor && FAKE_LINES="edit 1" git rebase -i HEAD^ && echo "edited again" > file7 && git add file7 && - ( - FAKE_COMMIT_MESSAGE=" " && - export FAKE_COMMIT_MESSAGE && - test_must_fail git rebase --continue - ) && + test_must_fail env FAKE_COMMIT_MESSAGE=" " git rebase --continue && test $old = $(git rev-parse HEAD) && git rebase --abort ' test_expect_success 'auto-amend only edited commits after "edit"' ' test_tick && + set_fake_editor && FAKE_LINES="edit 1" git rebase -i HEAD^ && echo "edited again" > file7 && git add file7 && @@ -531,22 +520,15 @@ test_expect_success 'auto-amend only edited commits after "edit"' ' echo "and again" > file7 && git add file7 && test_tick && - ( - FAKE_COMMIT_MESSAGE="and again" && - export FAKE_COMMIT_MESSAGE && - test_must_fail git rebase --continue - ) && + test_must_fail env FAKE_COMMIT_MESSAGE="and again" git rebase --continue && git rebase --abort ' test_expect_success 'clean error after failed "exec"' ' test_tick && test_when_finished "git rebase --abort || :" && - ( - FAKE_LINES="1 exec_false" && - export FAKE_LINES && - test_must_fail git rebase -i HEAD^ - ) && + set_fake_editor && + test_must_fail env FAKE_LINES="1 exec_false" git rebase -i HEAD^ && echo "edited again" > file7 && git add file7 && test_must_fail git rebase --continue 2>error && @@ -557,6 +539,7 @@ test_expect_success 'rebase a detached HEAD' ' grandparent=$(git rev-parse HEAD~2) && git checkout $(git rev-parse HEAD) && test_tick && + set_fake_editor && FAKE_LINES="2 1" git rebase -i HEAD~2 && test $grandparent = $(git rev-parse HEAD~2) ' @@ -573,6 +556,7 @@ test_expect_success 'rebase a commit violating pre-commit' ' test_must_fail git commit -m doesnt-verify file1 && git commit -m doesnt-verify --no-verify file1 && test_tick && + set_fake_editor && FAKE_LINES=2 git rebase -i HEAD~2 ' @@ -594,6 +578,7 @@ test_expect_success 'rebase with a file named HEAD in worktree' ' git commit -m "Add body" ) && + set_fake_editor && FAKE_LINES="1 squash 2" git rebase -i to-be-rebased && test "$(git show -s --pretty=format:%an)" = "Squashed Away" @@ -605,6 +590,7 @@ test_expect_success 'do "noop" when there is nothing to cherry-pick' ' GIT_EDITOR=: git commit --amend \ --author="Somebody else <somebody@else.com>" && test $(git rev-parse branch3) != $(git rev-parse branch4) && + set_fake_editor && git rebase -i branch3 && test $(git rev-parse branch3) = $(git rev-parse branch4) @@ -629,10 +615,12 @@ test_expect_success 'submodule rebase setup' ' git commit -a -m "submodule second" ) && test_tick && + set_fake_editor && git commit -a -m "Three changes submodule" ' test_expect_success 'submodule rebase -i' ' + set_fake_editor && FAKE_LINES="1 squash 2 3" git rebase -i A ' @@ -650,6 +638,7 @@ test_expect_success 'submodule conflict setup' ' ' test_expect_success 'rebase -i continue with only submodule staged' ' + set_fake_editor && test_must_fail git rebase -i submodule-base && git add sub && git rebase --continue && @@ -659,6 +648,7 @@ test_expect_success 'rebase -i continue with only submodule staged' ' test_expect_success 'rebase -i continue with unstaged submodule' ' git checkout submodule-topic && git reset --hard && + set_fake_editor && test_must_fail git rebase -i submodule-base && git reset && git rebase --continue && @@ -671,6 +661,7 @@ test_expect_success 'avoid unnecessary reset' ' test-chmtime =123456789 file3 && git update-index --refresh && HEAD=$(git rev-parse HEAD) && + set_fake_editor && git rebase -i HEAD~4 && test $HEAD = $(git rev-parse HEAD) && MTIME=$(test-chmtime -v +0 file3 | sed 's/[^0-9].*$//') && @@ -679,6 +670,7 @@ test_expect_success 'avoid unnecessary reset' ' test_expect_success 'reword' ' git checkout -b reword-branch master && + set_fake_editor && FAKE_LINES="1 2 3 reword 4" FAKE_COMMIT_MESSAGE="E changed" git rebase -i A && git show HEAD | grep "E changed" && test $(git rev-parse master) != $(git rev-parse HEAD) && @@ -698,7 +690,8 @@ 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 && + set_fake_editor && + git rebase -i --onto n1 n2 && test "a note" = "$(git notes show HEAD)" ' @@ -711,6 +704,7 @@ EOF test_expect_success 'rebase -i can copy notes over a fixup' ' git reset --hard n3 && git notes add -m"an earlier note" n2 && + set_fake_editor && GIT_NOTES_REWRITE_MODE=concatenate FAKE_LINES="1 fixup 2" git rebase -i n1 && git notes show > output && test_cmp expect output @@ -720,6 +714,7 @@ test_expect_success 'rebase while detaching HEAD' ' git symbolic-ref HEAD && grandparent=$(git rev-parse HEAD~2) && test_tick && + set_fake_editor && FAKE_LINES="2 1" git rebase -i HEAD~2 HEAD^0 && test $grandparent = $(git rev-parse HEAD~2) && test_must_fail git symbolic-ref HEAD @@ -729,6 +724,7 @@ test_tick # Ensure that the rebased commits get a different timestamp. test_expect_success 'always cherry-pick with --no-ff' ' git checkout no-ff-branch && git tag original-no-ff-branch && + set_fake_editor && git rebase -i --no-ff A && touch empty && for p in 0 1 2 @@ -761,6 +757,7 @@ test_expect_success 'set up commits with funny messages' ' test_expect_success 'rebase-i history with funny messages' ' git rev-list A..funny >expect && test_tick && + set_fake_editor && FAKE_LINES="1 2 3 4" git rebase -i A && git rev-list A.. >actual && test_cmp expect actual @@ -777,6 +774,7 @@ test_expect_success 'prepare for rebase -i --exec' ' test_expect_success 'running "git rebase -i --exec git show HEAD"' ' + set_fake_editor && git rebase -i --exec "git show HEAD" HEAD~2 >actual && ( FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" && @@ -790,6 +788,7 @@ test_expect_success 'running "git rebase -i --exec git show HEAD"' ' test_expect_success 'running "git rebase --exec git show HEAD -i"' ' git reset --hard execute && + set_fake_editor && git rebase --exec "git show HEAD" -i HEAD~2 >actual && ( FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" && @@ -803,6 +802,7 @@ test_expect_success 'running "git rebase --exec git show HEAD -i"' ' test_expect_success 'running "git rebase -ix git show HEAD"' ' git reset --hard execute && + set_fake_editor && git rebase -ix "git show HEAD" HEAD~2 >actual && ( FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" && @@ -816,6 +816,7 @@ test_expect_success 'running "git rebase -ix git show HEAD"' ' test_expect_success 'rebase -ix with several <CMD>' ' git reset --hard execute && + set_fake_editor && git rebase -ix "git show HEAD; pwd" HEAD~2 >actual && ( FAKE_LINES="1 exec_git_show_HEAD;_pwd 2 exec_git_show_HEAD;_pwd" && @@ -829,6 +830,7 @@ test_expect_success 'rebase -ix with several <CMD>' ' test_expect_success 'rebase -ix with several instances of --exec' ' git reset --hard execute && + set_fake_editor && git rebase -i --exec "git show HEAD" --exec "pwd" HEAD~2 >actual && ( FAKE_LINES="1 exec_git_show_HEAD exec_pwd 2 @@ -850,6 +852,7 @@ test_expect_success 'rebase -ix with --autosquash' ' echo bis >bis.txt && git add bis.txt && git commit -m "fixup! two_exec" && + set_fake_editor && ( git checkout -b autosquash_actual && git rebase -i --exec "git show HEAD" --autosquash HEAD~4 >actual @@ -868,6 +871,7 @@ test_expect_success 'rebase -ix with --autosquash' ' test_expect_success 'rebase --exec without -i shows error message' ' git reset --hard execute && + set_fake_editor && test_must_fail git rebase --exec "git show HEAD" HEAD~2 2>actual && echo "The --exec option must be used with the --interactive option" >expected && test_i18ncmp expected actual @@ -876,6 +880,7 @@ test_expect_success 'rebase --exec without -i shows error message' ' test_expect_success 'rebase -i --exec without <CMD>' ' git reset --hard execute && + set_fake_editor && test_must_fail git rebase -i --exec 2>tmp && sed -e "1d" tmp >actual && test_must_fail git rebase -h >expected && @@ -885,6 +890,7 @@ test_expect_success 'rebase -i --exec without <CMD>' ' test_expect_success 'rebase -i --root re-order and drop commits' ' git checkout E && + set_fake_editor && FAKE_LINES="3 1 2 5" git rebase -i --root && test E = $(git cat-file commit HEAD | sed -ne \$p) && test B = $(git cat-file commit HEAD^ | sed -ne \$p) && @@ -898,6 +904,7 @@ test_expect_success 'rebase -i --root retain root commit author and message' ' echo B >file7 && git add file7 && GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" && + set_fake_editor && FAKE_LINES="2" git rebase -i --root && git cat-file commit HEAD | grep -q "^author Twerp Snog" && git cat-file commit HEAD | grep -q "^different author$" @@ -905,17 +912,15 @@ test_expect_success 'rebase -i --root retain root commit author and message' ' test_expect_success 'rebase -i --root temporary sentinel commit' ' git checkout B && - ( - FAKE_LINES="2" && - export FAKE_LINES && - test_must_fail git rebase -i --root - ) && + set_fake_editor && + test_must_fail env FAKE_LINES="2" git rebase -i --root && git cat-file commit HEAD | grep "^tree 4b825dc642cb" && git rebase --abort ' test_expect_success 'rebase -i --root fixup root commit' ' git checkout B && + set_fake_editor && FAKE_LINES="1 fixup 2" git rebase -i --root && test A = $(git cat-file commit HEAD | sed -ne \$p) && test B = $(git show HEAD:file1) && @@ -925,6 +930,7 @@ test_expect_success 'rebase -i --root fixup root commit' ' test_expect_success 'rebase --edit-todo does not works on non-interactive rebase' ' git reset --hard && git checkout conflict-branch && + set_fake_editor && test_must_fail git rebase --onto HEAD~2 HEAD~ && test_must_fail git rebase --edit-todo && git rebase --abort @@ -933,6 +939,7 @@ test_expect_success 'rebase --edit-todo does not works on non-interactive rebase test_expect_success 'rebase --edit-todo can be used to modify todo' ' git reset --hard && git checkout no-conflict-branch^0 && + set_fake_editor && FAKE_LINES="edit 1 2 3" git rebase -i HEAD~3 && FAKE_LINES="2 1" git rebase --edit-todo && git rebase --continue @@ -940,4 +947,88 @@ 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 && + set_fake_editor && + 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_expect_success 'rebase -i error on commits with \ in message' ' + current_head=$(git rev-parse HEAD) + test_when_finished "git rebase --abort; git reset --hard $current_head; rm -f error" && + test_commit TO-REMOVE will-conflict old-content && + test_commit "\temp" will-conflict new-content dummy && + test_must_fail env EDITOR=true git rebase -i HEAD^ --onto HEAD^^ 2>error && + test_expect_code 1 grep " emp" error +' + +test_expect_success 'short SHA-1 setup' ' + test_when_finished "git checkout master" && + git checkout --orphan collide && + git rm -rf . && + ( + unset test_tick && + test_commit collide1 collide && + test_commit --notick collide2 collide && + test_commit --notick collide3 collide + ) +' + +test_expect_success 'short SHA-1 collide' ' + test_when_finished "reset_rebase && git checkout master" && + git checkout collide && + ( + unset test_tick && + test_tick && + set_fake_editor && + FAKE_COMMIT_MESSAGE="collide2 ac4f2ee" \ + FAKE_LINES="reword 1 2" git rebase -i HEAD~2 + ) +' + 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..8c251c57a6 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 @@ -37,15 +29,7 @@ export GIT_AUTHOR_EMAIL # \ # 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 +# Clone 4 (same as Clone 3) test_expect_success 'setup for merge-preserving rebase' \ 'echo First > A && @@ -58,20 +42,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" && @@ -96,21 +66,21 @@ test_expect_success 'setup for merge-preserving rebase' \ git merge --no-ff topic2 ) && + git clone ./. clone4 && + ( + cd clone4 && + git checkout -b topic2 origin/topic && + echo Sixth > A && + git commit -a -m "Modify A3" && + git checkout -b topic origin/topic && + git merge --no-ff topic2 + ) && + git checkout topic && echo Fourth >> B && 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,14 +108,14 @@ test_expect_success 'rebase -p preserves no-ff merges' ' ) ' -test_expect_success 'rebase -p works when base inside second parent' ' +test_expect_success 'rebase -p ignores merge.log config' ' ( 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) + git -c merge.log=1 rebase -p origin/topic && + echo >expected && + git log --format="%b" -1 >current && + test_cmp expected current ) ' diff --git a/t/t3413-rebase-hook.sh b/t/t3413-rebase-hook.sh index 098b75507b..b6833e9a5f 100755 --- a/t/t3413-rebase-hook.sh +++ b/t/t3413-rebase-hook.sh @@ -118,11 +118,7 @@ test_expect_success 'pre-rebase hook stops rebase (1)' ' test_expect_success 'pre-rebase hook stops rebase (2)' ' git checkout test && git reset --hard side && - ( - EDITOR=: - export EDITOR - test_must_fail git rebase -i master - ) && + test_must_fail env EDITOR=: git rebase -i master && test "z$(git symbolic-ref HEAD)" = zrefs/heads/test && test 0 = $(git rev-list HEAD...side | wc -l) ' 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..51f3bbb8af 100755 --- a/t/t3501-revert-cherry-pick.sh +++ b/t/t3501-revert-cherry-pick.sh @@ -100,4 +100,45 @@ test_expect_success 'revert forbidden on dirty working tree' ' ' +test_expect_success 'cherry-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_expect_success 'cherry-pick "-" to pick from previous branch' ' + git checkout unborn && + test_commit to-pick actual content && + git checkout master && + git cherry-pick - && + echo content >expect && + test_cmp expect actual +' + +test_expect_success 'cherry-pick "-" is meaningless without checkout' ' + test_create_repo afresh && + ( + cd afresh && + test_commit one && + test_commit two && + test_commit three && + test_must_fail git cherry-pick - + ) +' + +test_expect_success 'cherry-pick "-" works with arguments' ' + git checkout -b side-branch && + test_commit change actual change && + git checkout master && + git cherry-pick -s - && + echo "Signed-off-by: C O Mitter <committer@example.com>" >expect && + git cat-file commit HEAD | grep ^Signed-off-by: >signoff && + test_cmp expect signoff && + echo change >expect && + test_cmp expect actual +' + 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..fb889ac6f0 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 'cherry-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..1e5b3948df 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 @@ -76,7 +74,7 @@ test_expect_success 'Setup rename with file on one side matching different dirna echo content > sub/file && echo foo > othersub/whatever && git add -A && - git commit -m "Common commmit" && + git commit -m "Common commit" && git rm -rf othersub && git mv sub/file othersub && 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 97254e8d33..3d305814b9 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -240,18 +240,15 @@ test_expect_success 'refresh index before checking if it is up-to-date' ' test_expect_success 'choking "git rm" should not let it die with cruft' ' git reset -q --hard && + test_when_finished "rm -f .git/index.lock && git reset -q --hard" && i=0 && while test $i -lt 12000 do - echo "100644 $_z40 0 some-file-$i" + echo "100644 1234567890123456789012345678901234567890 0 some-file-$i" i=$(( $i + 1 )) done | git update-index --index-info && - git rm -n "some-file-*" | :; - test -f .git/index.lock - status=$? - rm -f .git/index.lock - git reset -q --hard - test "$status" != 0 + git rm -n "some-file-*" | : && + test_path_is_missing .git/index.lock ' test_expect_success 'rm removes subdirectories recursively' ' @@ -263,6 +260,7 @@ test_expect_success 'rm removes subdirectories recursively' ' ' cat >expect <<EOF +M .gitmodules D submod EOF @@ -270,6 +268,15 @@ cat >expect.modified <<EOF M submod EOF +cat >expect.cached <<EOF +D submod +EOF + +cat >expect.both_deleted<<EOF +D .gitmodules +D 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 && @@ -281,16 +288,20 @@ test_expect_success 'rm removes empty submodules from work tree' ' git rm submod && test ! -e submod && git status -s -uno --ignore-submodules=none > actual && - test_cmp expect actual + test_cmp expect actual && + test_must_fail git config -f .gitmodules submodule.sub.url && + test_must_fail git config -f .gitmodules submodule.sub.path ' -test_expect_success 'rm removes removed submodule from index' ' +test_expect_success 'rm removes removed submodule from index and .gitmodules' ' 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_cmp expect actual && + test_must_fail git config -f .gitmodules submodule.sub.url && + test_must_fail git config -f .gitmodules submodule.sub.path ' test_expect_success 'rm removes work tree of unmodified submodules' ' @@ -299,9 +310,28 @@ test_expect_success 'rm 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_must_fail git config -f .gitmodules submodule.sub.url && + test_must_fail git config -f .gitmodules submodule.sub.path +' + +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 && @@ -316,6 +346,72 @@ test_expect_success 'rm of a populated submodule with different HEAD fails unles git rm -f submod && test ! -d submod && git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual && + test_must_fail git config -f .gitmodules submodule.sub.url && + test_must_fail git config -f .gitmodules submodule.sub.path +' + +test_expect_success 'rm --cached leaves work tree of populated submodules and .gitmodules alone' ' + git reset --hard && + git submodule update && + git rm --cached submod && + test -d submod && + test -f submod/.git && + git status -s -uno >actual && + test_cmp expect.cached actual && + git config -f .gitmodules submodule.sub.url && + git config -f .gitmodules submodule.sub.path +' + +test_expect_success 'rm --dry-run does not touch the submodule or .gitmodules' ' + git reset --hard && + git submodule update && + git rm -n submod && + test -f submod/.git && + git diff-index --exit-code HEAD +' + +test_expect_success 'rm does not complain when no .gitmodules file is found' ' + git reset --hard && + git submodule update && + git rm .gitmodules && + git rm submod >actual 2>actual.err && + ! test -s actual.err && + ! test -d submod && + ! test -f submod/.git && + git status -s -uno >actual && + test_cmp expect.both_deleted actual +' + +test_expect_success 'rm will error out on a modified .gitmodules file unless staged' ' + git reset --hard && + git submodule update && + git config -f .gitmodules foo.bar true && + test_must_fail git rm submod >actual 2>actual.err && + test -s actual.err && + test -d submod && + test -f submod/.git && + git diff-files --quiet -- submod && + git add .gitmodules && + git rm submod >actual 2>actual.err && + ! test -s actual.err && + ! test -d submod && + ! test -f submod/.git && + git status -s -uno >actual && + test_cmp expect actual +' + +test_expect_success 'rm issues a warning when section is not found in .gitmodules' ' + git reset --hard && + git submodule update && + git config -f .gitmodules --remove-section submodule.sub && + git add .gitmodules && + echo "warning: Could not find section in .gitmodules where path=submod" >expect.err && + git rm submod >actual 2>actual.err && + test_i18ncmp expect.err actual.err && + ! test -d submod && + ! test -f submod/.git && + git status -s -uno >actual && test_cmp expect actual ' @@ -410,7 +506,9 @@ test_expect_success 'rm of a conflicted populated submodule with different HEAD git rm -f submod && test ! -d submod && git status -s -uno --ignore-submodules=none > actual && - test_cmp expect actual + test_cmp expect actual && + test_must_fail git config -f .gitmodules submodule.sub.url && + test_must_fail git config -f .gitmodules submodule.sub.path ' test_expect_success 'rm of a conflicted populated submodule with modifications fails unless forced' ' @@ -429,7 +527,9 @@ test_expect_success 'rm of a conflicted populated submodule with modifications f git rm -f submod && test ! -d submod && git status -s -uno --ignore-submodules=none > actual && - test_cmp expect actual + test_cmp expect actual && + test_must_fail git config -f .gitmodules submodule.sub.url && + test_must_fail git config -f .gitmodules submodule.sub.path ' test_expect_success 'rm of a conflicted populated submodule with untracked files fails unless forced' ' @@ -457,7 +557,7 @@ test_expect_success 'rm of a conflicted populated submodule with a .git director git submodule update && (cd submod && rm .git && - cp -a ../.git/modules/sub .git && + cp -R ../.git/modules/sub .git && GIT_WORK_TREE=. git config --unset core.worktree ) && test_must_fail git merge conflict2 && @@ -491,7 +591,7 @@ test_expect_success 'rm of a populated submodule with a .git directory fails eve git submodule update && (cd submod && rm .git && - cp -a ../.git/modules/sub .git && + cp -R ../.git/modules/sub .git && GIT_WORK_TREE=. git config --unset core.worktree ) && test_must_fail git rm submod && @@ -589,7 +689,7 @@ test_expect_success 'rm of a populated nested submodule with a nested .git direc git submodule update --recursive && (cd submod/subsubmod && rm .git && - cp -a ../../.git/modules/sub/modules/sub .git && + cp -R ../../.git/modules/sub/modules/sub .git && GIT_WORK_TREE=. git config --unset core.worktree ) && test_must_fail git rm submod && @@ -605,4 +705,181 @@ test_expect_success 'rm of a populated nested submodule with a nested .git direc rm -rf submod ' +test_expect_success 'checking out a commit after submodule removal needs manual updates' ' + git commit -m "submodule removal" submod && + git checkout HEAD^ && + git submodule update && + git checkout -q HEAD^ 2>actual && + git checkout -q master 2>actual && + echo "warning: unable to rmdir submod: Directory not empty" >expected && + test_i18ncmp expected actual && + git status -s submod >actual && + echo "?? submod/" >expected && + test_cmp expected actual && + rm -rf submod && + git status -s -uno --ignore-submodules=none > actual && + ! test -s actual +' + +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..fe274e2fb1 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);; @@ -275,6 +272,25 @@ test_expect_success '"add non-existent" should fail' ' ! (git ls-files | grep "non-existent") ' +test_expect_success 'git add -A on empty repo does not error out' ' + rm -fr empty && + git init empty && + ( + cd empty && + git add -A . && + git add -A + ) +' + +test_expect_success '"git add ." in empty repo' ' + rm -fr empty && + git init empty && + ( + cd empty && + git add . + ) +' + test_expect_success 'git add --dry-run of existing changed file' " echo new >>track-this && git add --dry-run track-this >actual 2>&1 && diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh index 098a6ae4a0..24ddd8a704 100755 --- a/t/t3701-add-interactive.sh +++ b/t/t3701-add-interactive.sh @@ -2,20 +2,25 @@ test_description='add -i basic tests' . ./test-lib.sh -. "$TEST_DIRECTORY"/lib-prereq-FILEMODE.sh -test_expect_success PERL 'setup (initial)' ' +if ! test_have_prereq PERL +then + skip_all='skipping add -i tests, perl not available' + test_done +fi + +test_expect_success 'setup (initial)' ' echo content >file && git add file && echo more >>file && echo lines >>file ' -test_expect_success PERL 'status works (initial)' ' +test_expect_success 'status works (initial)' ' git add -i </dev/null >output && grep "+1/-0 *+2/-0 file" output ' -test_expect_success PERL 'setup expected' ' +test_expect_success 'setup expected' ' cat >expected <<EOF new file mode 100644 index 0000000..d95f3ad @@ -26,19 +31,19 @@ index 0000000..d95f3ad EOF ' -test_expect_success PERL 'diff works (initial)' ' +test_expect_success 'diff works (initial)' ' (echo d; echo 1) | git add -i >output && sed -ne "/new file/,/content/p" <output >diff && test_cmp expected diff ' -test_expect_success PERL 'revert works (initial)' ' +test_expect_success 'revert works (initial)' ' git add file && (echo r; echo 1) | git add -i && git ls-files >output && ! grep . output ' -test_expect_success PERL 'setup (commit)' ' +test_expect_success 'setup (commit)' ' echo baseline >file && git add file && git commit -m commit && @@ -47,12 +52,12 @@ test_expect_success PERL 'setup (commit)' ' echo more >>file && echo lines >>file ' -test_expect_success PERL 'status works (commit)' ' +test_expect_success 'status works (commit)' ' git add -i </dev/null >output && grep "+1/-0 *+2/-0 file" output ' -test_expect_success PERL 'setup expected' ' +test_expect_success 'setup expected' ' cat >expected <<EOF index 180b47c..b6f2c08 100644 --- a/file @@ -63,12 +68,12 @@ index 180b47c..b6f2c08 100644 EOF ' -test_expect_success PERL 'diff works (commit)' ' +test_expect_success 'diff works (commit)' ' (echo d; echo 1) | git add -i >output && sed -ne "/^index/,/content/p" <output >diff && test_cmp expected diff ' -test_expect_success PERL 'revert works (commit)' ' +test_expect_success 'revert works (commit)' ' git add file && (echo r; echo 1) | git add -i && git add -i </dev/null >output && @@ -76,24 +81,24 @@ test_expect_success PERL 'revert works (commit)' ' ' -test_expect_success PERL 'setup expected' ' +test_expect_success 'setup expected' ' cat >expected <<EOF EOF ' -test_expect_success PERL 'setup fake editor' ' +test_expect_success 'setup fake editor' ' >fake_editor.sh && chmod a+x fake_editor.sh && test_set_editor "$(pwd)/fake_editor.sh" ' -test_expect_success PERL 'dummy edit works' ' +test_expect_success 'dummy edit works' ' (echo e; echo a) | git add -p && git diff > diff && test_cmp expected diff ' -test_expect_success PERL 'setup patch' ' +test_expect_success 'setup patch' ' cat >patch <<EOF @@ -1,1 +1,4 @@ this @@ -103,7 +108,7 @@ cat >patch <<EOF EOF ' -test_expect_success PERL 'setup fake editor' ' +test_expect_success 'setup fake editor' ' echo "#!$SHELL_PATH" >fake_editor.sh && cat >>fake_editor.sh <<\EOF && mv -f "$1" oldpatch && @@ -113,26 +118,26 @@ EOF test_set_editor "$(pwd)/fake_editor.sh" ' -test_expect_success PERL 'bad edit rejected' ' +test_expect_success 'bad edit rejected' ' git reset && (echo e; echo n; echo d) | git add -p >output && grep "hunk does not apply" output ' -test_expect_success PERL 'setup patch' ' +test_expect_success 'setup patch' ' cat >patch <<EOF this patch is garbage EOF ' -test_expect_success PERL 'garbage edit rejected' ' +test_expect_success 'garbage edit rejected' ' git reset && (echo e; echo n; echo d) | git add -p >output && grep "hunk does not apply" output ' -test_expect_success PERL 'setup patch' ' +test_expect_success 'setup patch' ' cat >patch <<EOF @@ -1,0 +1,0 @@ baseline @@ -142,7 +147,7 @@ cat >patch <<EOF EOF ' -test_expect_success PERL 'setup expected' ' +test_expect_success 'setup expected' ' cat >expected <<EOF diff --git a/file b/file index b5dd6c9..f910ae9 100644 @@ -157,13 +162,13 @@ index b5dd6c9..f910ae9 100644 EOF ' -test_expect_success PERL 'real edit works' ' +test_expect_success 'real edit works' ' (echo e; echo n; echo d) | git add -p && git diff >output && test_cmp expected output ' -test_expect_success PERL 'skip files similarly as commit -a' ' +test_expect_success 'skip files similarly as commit -a' ' git reset && echo file >.gitignore && echo changed >file && @@ -177,7 +182,7 @@ test_expect_success PERL 'skip files similarly as commit -a' ' ' rm -f .gitignore -test_expect_success PERL,FILEMODE 'patch does not affect mode' ' +test_expect_success FILEMODE 'patch does not affect mode' ' git reset --hard && echo content >>file && chmod +x file && @@ -186,7 +191,7 @@ test_expect_success PERL,FILEMODE 'patch does not affect mode' ' git diff file | grep "new mode" ' -test_expect_success PERL,FILEMODE 'stage mode but not hunk' ' +test_expect_success FILEMODE 'stage mode but not hunk' ' git reset --hard && echo content >>file && chmod +x file && @@ -196,7 +201,7 @@ test_expect_success PERL,FILEMODE 'stage mode but not hunk' ' ' -test_expect_success PERL,FILEMODE 'stage mode and hunk' ' +test_expect_success FILEMODE 'stage mode and hunk' ' git reset --hard && echo content >>file && chmod +x file && @@ -208,14 +213,14 @@ test_expect_success PERL,FILEMODE 'stage mode and hunk' ' # end of tests disabled when filemode is not usable -test_expect_success PERL 'setup again' ' +test_expect_success 'setup again' ' git reset --hard && test_chmod +x file && echo content >>file ' # Write the patch file with a new line at the top and bottom -test_expect_success PERL 'setup patch' ' +test_expect_success 'setup patch' ' cat >patch <<EOF index 180b47c..b6f2c08 100644 --- a/file @@ -229,7 +234,7 @@ EOF ' # Expected output, similar to the patch but w/ diff at the top -test_expect_success PERL 'setup expected' ' +test_expect_success 'setup expected' ' cat >expected <<EOF diff --git a/file b/file index b6f2c08..61b9053 100755 @@ -244,7 +249,7 @@ EOF ' # Test splitting the first patch, then adding both -test_expect_success PERL 'add first line works' ' +test_expect_success 'add first line works' ' git commit -am "clear local changes" && git apply patch && (echo s; echo y; echo y) | git add -p file && @@ -252,7 +257,7 @@ test_expect_success PERL 'add first line works' ' test_cmp expected diff ' -test_expect_success PERL 'setup expected' ' +test_expect_success 'setup expected' ' cat >expected <<EOF diff --git a/non-empty b/non-empty deleted file mode 100644 @@ -264,7 +269,7 @@ index d95f3ad..0000000 EOF ' -test_expect_success PERL 'deleting a non-empty file' ' +test_expect_success 'deleting a non-empty file' ' git reset --hard && echo content >non-empty && git add non-empty && @@ -275,7 +280,7 @@ test_expect_success PERL 'deleting a non-empty file' ' test_cmp expected diff ' -test_expect_success PERL 'setup expected' ' +test_expect_success 'setup expected' ' cat >expected <<EOF diff --git a/empty b/empty deleted file mode 100644 @@ -283,7 +288,7 @@ index e69de29..0000000 EOF ' -test_expect_success PERL 'deleting an empty file' ' +test_expect_success 'deleting an empty file' ' git reset --hard && > empty && git add empty && @@ -294,7 +299,7 @@ test_expect_success PERL 'deleting an empty file' ' test_cmp expected diff ' -test_expect_success PERL 'split hunk setup' ' +test_expect_success 'split hunk setup' ' git reset --hard && for i in 10 20 30 40 50 60 do @@ -310,7 +315,7 @@ test_expect_success PERL 'split hunk setup' ' done >test ' -test_expect_success PERL 'split hunk "add -p (edit)"' ' +test_expect_success 'split hunk "add -p (edit)"' ' # Split, say Edit and do nothing. Then: # # 1. Broken version results in a patch that does not apply and @@ -319,7 +324,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..4bf1dbe9c9 100755 --- a/t/t3900-i18n-commit.sh +++ b/t/t3900-i18n-commit.sh @@ -34,11 +34,47 @@ test_expect_success 'no encoding header for base case' ' test z = "z$E" ' -test_expect_failure 'UTF-16 refused because of NULs' ' +test_expect_success 'UTF-16 refused because of NULs' ' echo UTF-16 >F && - git commit -a -F "$TEST_DIRECTORY"/t3900/UTF-16.txt + test_must_fail 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/t3900/UTF-16.txt b/t/t3900/UTF-16.txt Binary files differnew file mode 100644 index 0000000000..2257f05a99 --- /dev/null +++ b/t/t3900/UTF-16.txt diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index 5dfbda7491..5b79b216e2 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,35 @@ 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 'handle stash specification with spaces' ' + git stash clear && + echo pig >file && + git stash && + stamp=$(git log -g --format="%cd" -1 refs/stash) && + test_tick && + echo cow >file && + git stash && + git stash apply "stash@{$stamp}" && + grep pig file +' + test_done diff --git a/t/t3910-mac-os-precompose.sh b/t/t3910-mac-os-precompose.sh index 5fe57c5438..e4ba6013e4 100755 --- a/t/t3910-mac-os-precompose.sh +++ b/t/t3910-mac-os-precompose.sh @@ -36,7 +36,7 @@ Alongc=$Alongc$AEligatu$AEligatu #254 Byte test_expect_success "detect if nfd needed" ' precomposeunicode=`git config core.precomposeunicode` && - test "$precomposeunicode" = false && + test "$precomposeunicode" = true && git config core.precomposeunicode true ' test_expect_success "setup" ' 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/t4010-diff-pathspec.sh b/t/t4010-diff-pathspec.sh index af5134b70c..2bb973655b 100755 --- a/t/t4010-diff-pathspec.sh +++ b/t/t4010-diff-pathspec.sh @@ -110,4 +110,40 @@ test_expect_success 'diff-tree -r with wildcard' ' test_cmp expected result ' +test_expect_success 'setup submodules' ' + test_tick && + git init submod && + ( cd submod && test_commit first; ) && + git add submod && + git commit -m first && + ( cd submod && test_commit second; ) && + git add submod && + git commit -m second +' + +test_expect_success 'diff-tree ignores trailing slash on submodule path' ' + git diff --name-only HEAD^ HEAD submod >expect && + git diff --name-only HEAD^ HEAD submod/ >actual && + test_cmp expect actual +' + +test_expect_success 'diff multiple wildcard pathspecs' ' + mkdir path2 && + echo rezrov >path2/file1 && + git update-index --add path2/file1 && + tree3=`git write-tree` && + git diff --name-only $tree $tree3 -- "path2*1" "path1*1" >actual && + cat <<-\EOF >expect && + path1/file1 + path2/file1 + EOF + test_cmp expect actual +' + +test_expect_success 'diff-cache ignores trailing slash on submodule path' ' + git diff --name-only HEAD^ submod >expect && + git diff --name-only HEAD^ submod/ >actual && + test_cmp expect actual +' + test_done 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 16a4ca1d60..9c80633146 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,13 +271,29 @@ 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 && (git format-patch --stdout "$@"; echo $? > status.out) | # Prints everything between the Message-ID and In-Reply-To, # and replaces all Message-ID-lookalikes by a sequence number - "$PERL_PATH" -ne ' + perl -ne ' if (/^(message-id|references|in-reply-to)/i) { $printing = 1; } elsif (/^\S/) { @@ -726,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 @@ -748,22 +764,14 @@ test_expect_success 'format-patch --signature="" supresses signatures' ' test_expect_success TTY 'format-patch --stdout paginates' ' rm -f pager_used && - ( - GIT_PAGER="wc >pager_used" && - export GIT_PAGER && - test_terminal git format-patch --stdout --all - ) && + test_terminal env GIT_PAGER="wc >pager_used" git format-patch --stdout --all && test_path_is_file pager_used ' test_expect_success TTY 'format-patch --stdout pagination can be disabled' ' rm -f pager_used && - ( - GIT_PAGER="wc >pager_used" && - export GIT_PAGER && - test_terminal git --no-pager format-patch --stdout --all && - test_terminal git -c "pager.format-patch=false" format-patch --stdout --all - ) && + test_terminal env GIT_PAGER="wc >pager_used" git --no-pager format-patch --stdout --all && + test_terminal env GIT_PAGER="wc >pager_used" git -c "pager.format-patch=false" format-patch --stdout --all && test_path_is_missing pager_used && test_path_is_missing .git/pager_used ' @@ -821,25 +829,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/ && @@ -955,6 +964,321 @@ 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 '--from omits redundant in-body header' ' + git format-patch -1 --stdout --from="A U Thor <author@example.com>" >patch && + cat >expect <<-\EOF && + 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 && @@ -963,4 +1287,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..604a838c1a 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -142,6 +142,352 @@ 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..34591c23da 100755 --- a/t/t4018-diff-funcname.sh +++ b/t/t4018-diff-funcname.sh @@ -7,184 +7,103 @@ test_description='Test custom diff function name patterns' . ./test-lib.sh -LF=' -' -cat >Beer.java <<\EOF -public class Beer -{ - int special; - public static void main(String args[]) - { - String s=" "; - for(int x = 99; x > 0; x--) - { - System.out.print(x + " bottles of beer on the wall " - + x + " bottles of beer\n" - + "Take one down, pass it around, " + (x - 1) - + " bottles of beer on the wall.\n"); - } - System.out.print("Go to the store, buy some more,\n" - + "99 bottles of beer on the wall.\n"); - } -} -EOF -sed 's/beer\\/beer,\\/' <Beer.java >Beer-correct.java -cat >Beer.perl <<\EOT -package Beer; - -use strict; -use warnings; -use parent qw(Exporter); -our @EXPORT_OK = qw(round finalround); - -sub other; # forward declaration - -# hello - -sub round { - my ($n) = @_; - print "$n bottles of beer on the wall "; - print "$n bottles of beer\n"; - print "Take one down, pass it around, "; - $n = $n - 1; - print "$n bottles of beer on the wall.\n"; -} - -sub finalround -{ - print "Go to the store, buy some more\n"; - print "99 bottles of beer on the wall.\n"); -} - -sub withheredocument { - print <<"EOF" -decoy here-doc -EOF - # some lines of context - # to pad it out - print "hello\n"; -} - -__END__ - -=head1 NAME - -Beer - subroutine to output fragment of a drinking song - -=head1 SYNOPSIS - - use Beer qw(round finalround); - - sub song { - for (my $i = 99; $i > 0; $i--) { - round $i; - } - finalround; - } - - song; +test_expect_success 'setup' ' + # a non-trivial custom pattern + git config diff.custom1.funcname "!static +!String +[^ ].*s.*" && -=cut -EOT -sed -e ' - s/hello/goodbye/ - s/beer\\/beer,\\/ - s/more\\/more,\\/ - s/song;/song();/ -' <Beer.perl >Beer-correct.perl + # a custom pattern which matches to end of line + git config diff.custom2.funcname "......Beer\$" && -test_config () { - git config "$1" "$2" && - test_when_finished "git config --unset $1" -} + # alternation in pattern + git config diff.custom3.funcname "Beer$" && + git config diff.custom3.xfuncname "^[ ]*((public|static).*)$" && -test_expect_funcname () { - lang=${2-java} - test_expect_code 1 git diff --no-index -U1 \ - "Beer.$lang" "Beer-correct.$lang" >diff && - grep "^@@.*@@ $1" diff -} + # for regexp compilation tests + echo A >A.java && + echo B >B.java +' -for p in ada bibtex cpp csharp fortran html java matlab objc pascal perl php python ruby tex +diffpatterns=" + ada + bibtex + cpp + csharp + fortran + html + java + matlab + objc + pascal + perl + php + python + ruby + tex + custom1 + custom2 + custom3 +" + +for p in $diffpatterns do test_expect_success "builtin $p pattern compiles" ' echo "*.java diff=$p" >.gitattributes && test_expect_code 1 git diff --no-index \ - Beer.java Beer-correct.java 2>msg && - ! grep fatal msg && - ! grep error msg + A.java B.java 2>msg && + ! test_i18ngrep fatal msg && + ! test_i18ngrep error msg ' test_expect_success "builtin $p wordRegex pattern compiles" ' echo "*.java diff=$p" >.gitattributes && test_expect_code 1 git diff --no-index --word-diff \ - Beer.java Beer-correct.java 2>msg && - ! grep fatal msg && - ! grep error msg + A.java B.java 2>msg && + ! test_i18ngrep fatal msg && + ! test_i18ngrep error msg ' done -test_expect_success 'default behaviour' ' - rm -f .gitattributes && - test_expect_funcname "public class Beer\$" -' - -test_expect_success 'set up .gitattributes declaring drivers to test' ' - cat >.gitattributes <<-\EOF - *.java diff=java - *.perl diff=perl - EOF -' - -test_expect_success 'preset java pattern' ' - test_expect_funcname "public static void main(" -' - -test_expect_success 'preset perl pattern' ' - test_expect_funcname "sub round {\$" perl -' - -test_expect_success 'perl pattern accepts K&R style brace placement, too' ' - test_expect_funcname "sub finalround\$" perl -' - -test_expect_success 'but is not distracted by end of <<here document' ' - test_expect_funcname "sub withheredocument {\$" perl -' - -test_expect_success 'perl pattern is not distracted by sub within POD' ' - test_expect_funcname "=head" perl -' - -test_expect_success 'perl pattern gets full line of POD header' ' - test_expect_funcname "=head1 SYNOPSIS\$" perl -' - -test_expect_success 'perl pattern is not distracted by forward declaration' ' - test_expect_funcname "package Beer;\$" perl -' - -test_expect_success 'custom pattern' ' - test_config diff.java.funcname "!static -!String -[^ ].*s.*" && - test_expect_funcname "int special;\$" -' - test_expect_success 'last regexp must not be negated' ' + echo "*.java diff=java" >.gitattributes && test_config diff.java.funcname "!static" && - test_expect_code 128 git diff --no-index Beer.java Beer-correct.java 2>msg && - grep ": Last expression must not be negated:" msg + test_expect_code 128 git diff --no-index A.java B.java 2>msg && + test_i18ngrep ": Last expression must not be negated:" msg ' -test_expect_success 'pattern which matches to end of line' ' - test_config diff.java.funcname "Beer\$" && - test_expect_funcname "Beer\$" +test_expect_success 'setup hunk header tests' ' + for i in $diffpatterns + do + echo "$i-* diff=$i" + done > .gitattributes && + + # add all test files to the index + ( + cd "$TEST_DIRECTORY"/t4018 && + git --git-dir="$TRASH_DIRECTORY/.git" add . + ) && + + # place modified files in the worktree + for i in $(git ls-files) + do + sed -e "s/ChangeMe/IWasChanged/" <"$TEST_DIRECTORY/t4018/$i" >"$i" || return 1 + done ' -test_expect_success 'alternation in pattern' ' - test_config diff.java.funcname "Beer$" && - test_config diff.java.xfuncname "^[ ]*((public|static).*)$" && - test_expect_funcname "public static void main(" -' +# check each individual file +for i in $(git ls-files) +do + if grep broken "$i" >/dev/null 2>&1 + then + result=failure + else + result=success + fi + test_expect_$result "hunk header: $i" " + test_when_finished 'cat actual' && # for debugging only + git diff -U1 $i >actual && + grep '@@ .* @@.*RIGHT' actual + " +done test_done diff --git a/t/t4018/README b/t/t4018/README new file mode 100644 index 0000000000..283e01cca1 --- /dev/null +++ b/t/t4018/README @@ -0,0 +1,18 @@ +How to write RIGHT test cases +============================= + +Insert the word "ChangeMe" (exactly this form) at a distance of +at least two lines from the line that must appear in the hunk header. + +The text that must appear in the hunk header must contain the word +"right", but in all upper-case, like in the title above. + +To mark a test case that highlights a malfunction, insert the word +BROKEN in all lower-case somewhere in the file. + +This text is a bit twisted and out of order, but it is itself a +test case for the default hunk header pattern. Know what you are doing +if you change it. + +BTW, this tests that the head line goes to the hunk header, not the line +of equal signs. diff --git a/t/t4018/cpp-c++-function b/t/t4018/cpp-c++-function new file mode 100644 index 0000000000..9ee6bbef55 --- /dev/null +++ b/t/t4018/cpp-c++-function @@ -0,0 +1,4 @@ +Item RIGHT::DoSomething( Args with_spaces ) +{ + ChangeMe; +} diff --git a/t/t4018/cpp-class-constructor b/t/t4018/cpp-class-constructor new file mode 100644 index 0000000000..ec4f115c25 --- /dev/null +++ b/t/t4018/cpp-class-constructor @@ -0,0 +1,4 @@ +Item::Item(int RIGHT) +{ + ChangeMe; +} diff --git a/t/t4018/cpp-class-constructor-mem-init b/t/t4018/cpp-class-constructor-mem-init new file mode 100644 index 0000000000..49a69f37e1 --- /dev/null +++ b/t/t4018/cpp-class-constructor-mem-init @@ -0,0 +1,5 @@ +Item::Item(int RIGHT) : + member(0) +{ + ChangeMe; +} diff --git a/t/t4018/cpp-class-definition b/t/t4018/cpp-class-definition new file mode 100644 index 0000000000..11b61da3b7 --- /dev/null +++ b/t/t4018/cpp-class-definition @@ -0,0 +1,4 @@ +class RIGHT +{ + int ChangeMe; +}; diff --git a/t/t4018/cpp-class-definition-derived b/t/t4018/cpp-class-definition-derived new file mode 100644 index 0000000000..3b98cd09ab --- /dev/null +++ b/t/t4018/cpp-class-definition-derived @@ -0,0 +1,5 @@ +class RIGHT : + public Baseclass +{ + int ChangeMe; +}; diff --git a/t/t4018/cpp-class-destructor b/t/t4018/cpp-class-destructor new file mode 100644 index 0000000000..5487665096 --- /dev/null +++ b/t/t4018/cpp-class-destructor @@ -0,0 +1,4 @@ +RIGHT::~RIGHT() +{ + ChangeMe; +} diff --git a/t/t4018/cpp-function-returning-global-type b/t/t4018/cpp-function-returning-global-type new file mode 100644 index 0000000000..1084d5990e --- /dev/null +++ b/t/t4018/cpp-function-returning-global-type @@ -0,0 +1,4 @@ +::Item get::it::RIGHT() +{ + ChangeMe; +} diff --git a/t/t4018/cpp-function-returning-nested b/t/t4018/cpp-function-returning-nested new file mode 100644 index 0000000000..d9750aa61a --- /dev/null +++ b/t/t4018/cpp-function-returning-nested @@ -0,0 +1,5 @@ +get::Item get::it::RIGHT() +{ + ChangeMe; +} + diff --git a/t/t4018/cpp-function-returning-pointer b/t/t4018/cpp-function-returning-pointer new file mode 100644 index 0000000000..ef15657ea8 --- /dev/null +++ b/t/t4018/cpp-function-returning-pointer @@ -0,0 +1,4 @@ +const char *get_it_RIGHT(char *ptr) +{ + ChangeMe; +} diff --git a/t/t4018/cpp-function-returning-reference b/t/t4018/cpp-function-returning-reference new file mode 100644 index 0000000000..01b051df70 --- /dev/null +++ b/t/t4018/cpp-function-returning-reference @@ -0,0 +1,4 @@ +string& get::it::RIGHT(char *ptr) +{ + ChangeMe; +} diff --git a/t/t4018/cpp-gnu-style-function b/t/t4018/cpp-gnu-style-function new file mode 100644 index 0000000000..08c7c7565a --- /dev/null +++ b/t/t4018/cpp-gnu-style-function @@ -0,0 +1,5 @@ +const char * +RIGHT(int arg) +{ + ChangeMe; +} diff --git a/t/t4018/cpp-namespace-definition b/t/t4018/cpp-namespace-definition new file mode 100644 index 0000000000..6749980241 --- /dev/null +++ b/t/t4018/cpp-namespace-definition @@ -0,0 +1,4 @@ +namespace RIGHT +{ + ChangeMe; +} diff --git a/t/t4018/cpp-operator-definition b/t/t4018/cpp-operator-definition new file mode 100644 index 0000000000..1acd827159 --- /dev/null +++ b/t/t4018/cpp-operator-definition @@ -0,0 +1,4 @@ +Value operator+(Value LEFT, Value RIGHT) +{ + ChangeMe; +} diff --git a/t/t4018/cpp-skip-access-specifiers b/t/t4018/cpp-skip-access-specifiers new file mode 100644 index 0000000000..4d4a9dbb9d --- /dev/null +++ b/t/t4018/cpp-skip-access-specifiers @@ -0,0 +1,8 @@ +class RIGHT : public Baseclass +{ +public: +protected: +private: + void DoSomething(); + int ChangeMe; +}; diff --git a/t/t4018/cpp-skip-comment-block b/t/t4018/cpp-skip-comment-block new file mode 100644 index 0000000000..3800b9967a --- /dev/null +++ b/t/t4018/cpp-skip-comment-block @@ -0,0 +1,9 @@ +struct item RIGHT(int i) +// Do not +// pick up +/* these +** comments. +*/ +{ + ChangeMe; +} diff --git a/t/t4018/cpp-skip-labels b/t/t4018/cpp-skip-labels new file mode 100644 index 0000000000..b9c10aba22 --- /dev/null +++ b/t/t4018/cpp-skip-labels @@ -0,0 +1,8 @@ +void RIGHT (void) +{ +repeat: // C++ comment +next: /* C comment */ + do_something(); + + ChangeMe; +} diff --git a/t/t4018/cpp-struct-definition b/t/t4018/cpp-struct-definition new file mode 100644 index 0000000000..521c59fd15 --- /dev/null +++ b/t/t4018/cpp-struct-definition @@ -0,0 +1,9 @@ +struct RIGHT { + unsigned + /* this bit field looks like a label and should not be picked up */ + decoy_bitfield: 2, + more : 1; + int filler; + + int ChangeMe; +}; diff --git a/t/t4018/cpp-struct-single-line b/t/t4018/cpp-struct-single-line new file mode 100644 index 0000000000..a0de5fb800 --- /dev/null +++ b/t/t4018/cpp-struct-single-line @@ -0,0 +1,7 @@ +void wrong() +{ +} + +struct RIGHT_iterator_tag {}; + +int ChangeMe; diff --git a/t/t4018/cpp-template-function-definition b/t/t4018/cpp-template-function-definition new file mode 100644 index 0000000000..0cdf5ba5bd --- /dev/null +++ b/t/t4018/cpp-template-function-definition @@ -0,0 +1,4 @@ +template<class T> int RIGHT(T arg) +{ + ChangeMe; +} diff --git a/t/t4018/cpp-union-definition b/t/t4018/cpp-union-definition new file mode 100644 index 0000000000..7ec94df697 --- /dev/null +++ b/t/t4018/cpp-union-definition @@ -0,0 +1,4 @@ +union RIGHT { + double v; + int ChangeMe; +}; diff --git a/t/t4018/cpp-void-c-function b/t/t4018/cpp-void-c-function new file mode 100644 index 0000000000..153081e872 --- /dev/null +++ b/t/t4018/cpp-void-c-function @@ -0,0 +1,4 @@ +void RIGHT (void) +{ + ChangeMe; +} diff --git a/t/t4018/custom1-pattern b/t/t4018/custom1-pattern new file mode 100644 index 0000000000..e8fd59f884 --- /dev/null +++ b/t/t4018/custom1-pattern @@ -0,0 +1,17 @@ +public class Beer +{ + int special, RIGHT; + public static void main(String args[]) + { + String s=" "; + for(int x = 99; x > 0; x--) + { + System.out.print(x + " bottles of beer on the wall " + + x + " bottles of beer\n" // ChangeMe + + "Take one down, pass it around, " + (x - 1) + + " bottles of beer on the wall.\n"); + } + System.out.print("Go to the store, buy some more,\n" + + "99 bottles of beer on the wall.\n"); + } +} diff --git a/t/t4018/custom2-match-to-end-of-line b/t/t4018/custom2-match-to-end-of-line new file mode 100644 index 0000000000..f88ac318b7 --- /dev/null +++ b/t/t4018/custom2-match-to-end-of-line @@ -0,0 +1,8 @@ +public class RIGHT_Beer +{ + int special; + public static void main(String args[]) + { + System.out.print("ChangeMe"); + } +} diff --git a/t/t4018/custom3-alternation-in-pattern b/t/t4018/custom3-alternation-in-pattern new file mode 100644 index 0000000000..5f3769c64f --- /dev/null +++ b/t/t4018/custom3-alternation-in-pattern @@ -0,0 +1,17 @@ +public class Beer +{ + int special; + public static void main(String RIGHT[]) + { + String s=" "; + for(int x = 99; x > 0; x--) + { + System.out.print(x + " bottles of beer on the wall " + + x + " bottles of beer\n" // ChangeMe + + "Take one down, pass it around, " + (x - 1) + + " bottles of beer on the wall.\n"); + } + System.out.print("Go to the store, buy some more,\n" + + "99 bottles of beer on the wall.\n"); + } +} diff --git a/t/t4018/java-class-member-function b/t/t4018/java-class-member-function new file mode 100644 index 0000000000..298bc7a71b --- /dev/null +++ b/t/t4018/java-class-member-function @@ -0,0 +1,8 @@ +public class Beer +{ + int special; + public static void main(String RIGHT[]) + { + System.out.print("ChangeMe"); + } +} diff --git a/t/t4018/perl-skip-end-of-heredoc b/t/t4018/perl-skip-end-of-heredoc new file mode 100644 index 0000000000..c22d39b256 --- /dev/null +++ b/t/t4018/perl-skip-end-of-heredoc @@ -0,0 +1,8 @@ +sub RIGHTwithheredocument { + print <<"EOF" +decoy here-doc +EOF + # some lines of context + # to pad it out + print "ChangeMe\n"; +} diff --git a/t/t4018/perl-skip-forward-decl b/t/t4018/perl-skip-forward-decl new file mode 100644 index 0000000000..a98cb8bdad --- /dev/null +++ b/t/t4018/perl-skip-forward-decl @@ -0,0 +1,10 @@ +package RIGHT; + +use strict; +use warnings; +use parent qw(Exporter); +our @EXPORT_OK = qw(round finalround); + +sub other; # forward declaration + +# ChangeMe diff --git a/t/t4018/perl-skip-sub-in-pod b/t/t4018/perl-skip-sub-in-pod new file mode 100644 index 0000000000..e39f02462e --- /dev/null +++ b/t/t4018/perl-skip-sub-in-pod @@ -0,0 +1,18 @@ +=head1 NAME + +Beer - subroutine to output fragment of a drinking song + +=head1 SYNOPSIS_RIGHT + + use Beer qw(round finalround); + + sub song { + for (my $i = 99; $i > 0; $i--) { + round $i; + } + finalround; + } + + ChangeMe; + +=cut diff --git a/t/t4018/perl-sub-definition b/t/t4018/perl-sub-definition new file mode 100644 index 0000000000..a507d1f645 --- /dev/null +++ b/t/t4018/perl-sub-definition @@ -0,0 +1,4 @@ +sub RIGHT { + my ($n) = @_; + print "ChangeMe"; +} diff --git a/t/t4018/perl-sub-definition-kr-brace b/t/t4018/perl-sub-definition-kr-brace new file mode 100644 index 0000000000..330b3df114 --- /dev/null +++ b/t/t4018/perl-sub-definition-kr-brace @@ -0,0 +1,4 @@ +sub RIGHT +{ + print "ChangeMe\n"; +} diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh index 2e7d73f090..044620186d 100755 --- a/t/t4020-diff-external.sh +++ b/t/t4020-diff-external.sh @@ -177,7 +177,7 @@ test_expect_success 'no diff with -diff' ' git diff | grep Binary ' -echo NULZbetweenZwords | "$PERL_PATH" -pe 'y/Z/\000/' > file +echo NULZbetweenZwords | perl -pe 'y/Z/\000/' > file test_expect_success 'force diff with "diff"' ' echo >.gitattributes "file diff" && @@ -193,6 +193,19 @@ test_expect_success 'GIT_EXTERNAL_DIFF with more than one changed files' ' GIT_EXTERNAL_DIFF=echo git diff ' +test_expect_success 'GIT_EXTERNAL_DIFF path counter/total' ' + write_script external-diff.sh <<-\EOF && + echo $GIT_DIFF_PATH_COUNTER of $GIT_DIFF_PATH_TOTAL >>counter.txt + EOF + >counter.txt && + cat >expect <<-\EOF && + 1 of 2 + 2 of 2 + EOF + GIT_EXTERNAL_DIFF=./external-diff.sh git diff && + test_cmp expect counter.txt +' + test_expect_success 'GIT_EXTERNAL_DIFF generates pretty paths' ' touch file.ext && git add file.ext && @@ -213,12 +226,13 @@ keep_only_cr () { } test_expect_success 'external diff with autocrlf = true' ' - git config core.autocrlf true && + test_config core.autocrlf true && GIT_EXTERNAL_DIFF=./fake-diff.sh git diff && test $(wc -l < crlfed.txt) = $(cat crlfed.txt | keep_only_cr | wc -c) ' test_expect_success 'diff --cached' ' + test_config core.autocrlf true && git add file && git update-index --assume-unchanged file && echo second >file && @@ -226,4 +240,31 @@ test_expect_success 'diff --cached' ' test_cmp "$TEST_DIRECTORY"/t4020/diff.NUL actual ' +test_expect_success 'clean up crlf leftovers' ' + git update-index --no-assume-unchanged file && + rm -f file* && + git reset --hard +' + +test_expect_success 'submodule diff' ' + git init sub && + ( cd sub && test_commit sub1 ) && + git add sub && + test_tick && + git commit -m "add submodule" && + ( cd sub && test_commit sub2 ) && + write_script gather_pre_post.sh <<-\EOF && + echo "$1 $4" # path, mode + cat "$2" # old file + cat "$5" # new file + EOF + GIT_EXTERNAL_DIFF=./gather_pre_post.sh git diff >actual && + cat >expected <<-EOF && + sub 160000 + Subproject commit $(git rev-parse HEAD:sub) + Subproject commit $(cd sub && git rev-parse HEAD) + EOF + test_cmp expected actual +' + test_done 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/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh index 36e2f075c9..3ccc237a8d 100755 --- a/t/t4029-diff-trailing-space.sh +++ b/t/t4029-diff-trailing-space.sh @@ -27,7 +27,7 @@ test_expect_success \ git config --bool diff.suppressBlankEmpty true && git diff f > actual && test_cmp exp actual && - "$PERL_PATH" -i.bak -p -e "s/^\$/ /" exp && + perl -i.bak -p -e "s/^\$/ /" exp && git config --bool diff.suppressBlankEmpty false && git diff f > actual && test_cmp exp actual && diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh index 461d27ac20..aad6c7f78d 100755 --- a/t/t4030-diff-textconv.sh +++ b/t/t4030-diff-textconv.sh @@ -58,6 +58,12 @@ test_expect_success 'diff produces text' ' test_cmp expect.text actual ' +test_expect_success 'show commit produces text' ' + git show HEAD >diff && + find_diff <diff >actual && + test_cmp expect.text actual +' + test_expect_success 'diff-tree produces binary' ' git diff-tree -p HEAD^ HEAD >diff && find_diff <diff >actual && @@ -84,6 +90,24 @@ test_expect_success 'status -v produces text' ' git reset --soft HEAD@{1} ' +test_expect_success 'show blob produces binary' ' + git show HEAD:file >actual && + printf "\\0\\n\\01\\n" >expect && + test_cmp expect actual +' + +test_expect_success 'show --textconv blob produces text' ' + git show --textconv HEAD:file >actual && + printf "0\\n1\\n" >expect && + test_cmp expect actual +' + +test_expect_success 'show --no-textconv blob produces binary' ' + git show --no-textconv HEAD:file >actual && + printf "\\0\\n\\01\\n" >expect && + test_cmp expect actual +' + test_expect_success 'grep-diff (-G) operates on textconv data (add)' ' echo one >expect && git log --root --format=%s -G0 >actual && @@ -96,6 +120,18 @@ test_expect_success 'grep-diff (-G) operates on textconv data (modification)' ' test_cmp expect actual ' +test_expect_success 'pickaxe (-S) operates on textconv data (add)' ' + echo one >expect && + git log --root --format=%s -S0 >actual && + test_cmp expect actual +' + +test_expect_success 'pickaxe (-S) operates on textconv data (modification)' ' + echo two >expect && + git log --root --format=%s -S1 >actual && + test_cmp expect actual +' + cat >expect.stat <<'EOF' file | Bin 2 -> 4 bytes 1 file changed, 0 insertions(+), 0 deletions(-) @@ -127,12 +163,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/t4034/ada/expect b/t/t4034/ada/expect index be2376e904..a682d288b2 100644 --- a/t/t4034/ada/expect +++ b/t/t4034/ada/expect @@ -4,7 +4,7 @@ <BOLD>+++ b/post<RESET> <CYAN>@@ -1,13 +1,13 @@<RESET> Ada.Text_IO.Put_Line("Hello World<RED>!<RESET><GREEN>?<RESET>"); -1 1e<RED>-<RESET>10 16#FE12#E2 3.141_592 '<RED>x<RESET><GREEN>y<RESET>' +1 <RED>1e-10<RESET><GREEN>1e10<RESET> 16#FE12#E2 3.141_592 '<RED>x<RESET><GREEN>y<RESET>' <RED>a<RESET><GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET> <RED>a<RESET><GREEN>y<RESET> <GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b<RESET> diff --git a/t/t4035-diff-quiet.sh b/t/t4035-diff-quiet.sh index 231412d100..e8ae2a03fd 100755 --- a/t/t4035-diff-quiet.sh +++ b/t/t4035-diff-quiet.sh @@ -148,4 +148,10 @@ test_expect_success 'git diff --ignore-all-space, both files outside repo' ' ) ' +test_expect_success 'git diff --quiet ignores stat-change only entries' ' + test-chmtime +10 a && + echo modified >>b && + test_expect_code 1 git diff --quiet +' + test_done 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 57e8a9dacb..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,43 +38,43 @@ test_create_repo sm1 && add_file . foo >/dev/null head1=$(add_file sm1 foo1 foo2) -fullhead1=$(cd sm1; git rev-list --max-count=1 $head1) +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' " +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 + 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_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..a2c4dab ---- /dev/null -+++ b/sm1 -@@ -0,0 +1 @@ -+Subproject commit $fullhead1 -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 && @@ -77,7 +82,7 @@ test_expect_success 'diff.submodule does not affect plumbing' ' cat >expected <<-EOF && diff --git a/sm1 b/sm1 new file mode 160000 - index 0000000..a2c4dab + index 0000000..$head1 --- /dev/null +++ b/sm1 @@ -0,0 +1 @@ @@ -89,78 +94,77 @@ test_expect_success 'diff.submodule does not affect plumbing' ' 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 -" +' -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 && @@ -170,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 && @@ -494,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/t4049-diff-stat-count.sh b/t/t4049-diff-stat-count.sh index 7b3ef00533..5b594e878f 100755 --- a/t/t4049-diff-stat-count.sh +++ b/t/t4049-diff-stat-count.sh @@ -4,20 +4,62 @@ test_description='diff --stat-count' . ./test-lib.sh -test_expect_success setup ' +test_expect_success 'setup' ' >a && >b && >c && >d && git add a b c d && - chmod +x c d && + git commit -m initial +' + +test_expect_success 'mode-only change show as a 0-line change' ' + git reset --hard && + test_chmod +x b d && + echo a >a && + echo c >c && + cat >expect <<-\EOF + a | 1 + + b | 0 + ... + 4 files changed, 2 insertions(+) + EOF + git diff --stat --stat-count=2 HEAD >actual && + test_i18ncmp expect actual +' + +test_expect_success 'binary changes do not count in lines' ' + git reset --hard && + echo a >a && + echo c >c && + cat "$TEST_DIRECTORY"/test-binary-1.png >d && + cat >expect <<-\EOF + a | 1 + + c | 1 + + ... + 3 files changed, 2 insertions(+) + EOF + git diff --stat --stat-count=2 >actual && + test_i18ncmp expect actual +' + +test_expect_success 'exclude unmerged entries from total file count' ' + git reset --hard && echo a >a && echo b >b && + git ls-files -s a >x && + git rm -f d && + for stage in 1 2 3 + do + sed -e "s/ 0 a/ $stage d/" x + done | + git update-index --index-info && + echo d >d && cat >expect <<-\EOF a | 1 + b | 1 + ... - 4 files changed, 2 insertions(+) + 3 files changed, 3 insertions(+) EOF git diff --stat --stat-count=2 >actual && test_i18ncmp expect actual diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh index 979e98398b..2ab3c48734 100755 --- a/t/t4053-diff-no-index.sh +++ b/t/t4053-diff-no-index.sh @@ -29,4 +29,30 @@ test_expect_success 'git diff --no-index relative path outside repo' ' ) ' +test_expect_success 'git diff --no-index with broken index' ' + ( + cd repo && + echo broken >.git/index && + git diff --no-index a ../non/git/a + ) +' + +test_expect_success 'git diff outside repo with broken index' ' + ( + cd repo && + git diff ../non/git/a ../non/git/b + ) +' + +test_expect_success 'git diff --no-index executed outside repo gives correct error message' ' + ( + GIT_CEILING_DIRECTORIES=$TRASH_DIRECTORY/non && + export GIT_CEILING_DIRECTORIES && + cd non/git && + test_must_fail git diff --no-index a 2>actual.err && + echo "usage: git diff --no-index <path> <path>" >expect.err && + test_cmp expect.err actual.err + ) +' + test_done diff --git a/t/t4055-diff-context.sh b/t/t4055-diff-context.sh index 97172b46b2..cd0454356a 100755 --- a/t/t4055-diff-context.sh +++ b/t/t4055-diff-context.sh @@ -73,7 +73,7 @@ test_expect_success 'plumbing not affected' ' 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_i18ngrep "bad numeric config value" output ' test_expect_success 'negative integer config parsing' ' diff --git a/t/t4056-diff-order.sh b/t/t4056-diff-order.sh new file mode 100755 index 0000000000..c0460bb0e5 --- /dev/null +++ b/t/t4056-diff-order.sh @@ -0,0 +1,121 @@ +#!/bin/sh + +test_description='diff order' + +. ./test-lib.sh + +create_files () { + echo "$1" >a.h && + echo "$1" >b.c && + echo "$1" >c/Makefile && + echo "$1" >d.txt && + git add a.h b.c c/Makefile d.txt && + git commit -m"$1" +} + +test_expect_success 'setup' ' + mkdir c && + create_files 1 && + create_files 2 && + + cat >order_file_1 <<-\EOF && + *Makefile + *.txt + *.h + EOF + + cat >order_file_2 <<-\EOF && + *Makefile + *.h + *.c + EOF + + cat >expect_none <<-\EOF && + a.h + b.c + c/Makefile + d.txt + EOF + + cat >expect_1 <<-\EOF && + c/Makefile + d.txt + a.h + b.c + EOF + + cat >expect_2 <<-\EOF + c/Makefile + a.h + b.c + d.txt + EOF +' + +test_expect_success "no order (=tree object order)" ' + git diff --name-only HEAD^..HEAD >actual && + test_cmp expect_none actual +' + +test_expect_success 'missing orderfile' ' + rm -f bogus_file && + test_must_fail git diff -Obogus_file --name-only HEAD^..HEAD +' + +test_expect_success POSIXPERM,SANITY 'unreadable orderfile' ' + >unreadable_file && + chmod -r unreadable_file && + test_must_fail git diff -Ounreadable_file --name-only HEAD^..HEAD +' + +for i in 1 2 +do + test_expect_success "orderfile using option ($i)" ' + git diff -Oorder_file_$i --name-only HEAD^..HEAD >actual && + test_cmp expect_$i actual + ' + + test_expect_success PIPE "orderfile is fifo ($i)" ' + rm -f order_fifo && + mkfifo order_fifo && + { + cat order_file_$i >order_fifo & + } && + git diff -O order_fifo --name-only HEAD^..HEAD >actual && + wait && + test_cmp expect_$i actual + ' + + test_expect_success "orderfile using config ($i)" ' + git -c diff.orderfile=order_file_$i diff --name-only HEAD^..HEAD >actual && + test_cmp expect_$i actual + ' + + test_expect_success "cancelling configured orderfile ($i)" ' + git -c diff.orderfile=order_file_$i diff -O/dev/null --name-only HEAD^..HEAD >actual && + test_cmp expect_none actual + ' +done + +test_expect_success 'setup for testing combine-diff order' ' + git checkout -b tmp HEAD~ && + create_files 3 && + git checkout master && + git merge --no-commit -s ours tmp && + create_files 5 +' + +test_expect_success "combine-diff: no order (=tree object order)" ' + git diff --name-only HEAD HEAD^ HEAD^2 >actual && + test_cmp expect_none actual +' + +for i in 1 2 +do + test_expect_success "combine-diff: orderfile using option ($i)" ' + git diff -Oorder_file_$i --name-only HEAD HEAD^ HEAD^2 >actual && + test_cmp expect_$i actual + ' +done + +test_done diff --git a/t/t4057-diff-combined-paths.sh b/t/t4057-diff-combined-paths.sh new file mode 100755 index 0000000000..097e63215e --- /dev/null +++ b/t/t4057-diff-combined-paths.sh @@ -0,0 +1,106 @@ +#!/bin/sh + +test_description='combined diff show only paths that are different to all parents' + +. ./test-lib.sh + +# verify that diffc.expect matches output of +# `git diff -c --name-only HEAD HEAD^ HEAD^2` +diffc_verify () { + git diff -c --name-only HEAD HEAD^ HEAD^2 >diffc.actual && + test_cmp diffc.expect diffc.actual +} + +test_expect_success 'trivial merge - combine-diff empty' ' + for i in $(test_seq 1 9) + do + echo $i >$i.txt && + git add $i.txt + done && + git commit -m "init" && + git checkout -b side && + for i in $(test_seq 2 9) + do + echo $i/2 >>$i.txt + done && + git commit -a -m "side 2-9" && + git checkout master && + echo 1/2 >1.txt && + git commit -a -m "master 1" && + git merge side && + >diffc.expect && + diffc_verify +' + + +test_expect_success 'only one trully conflicting path' ' + git checkout side && + for i in $(test_seq 2 9) + do + echo $i/3 >>$i.txt + done && + echo "4side" >>4.txt && + git commit -a -m "side 2-9 +4" && + git checkout master && + for i in $(test_seq 1 9) + do + echo $i/3 >>$i.txt + done && + echo "4master" >>4.txt && + git commit -a -m "master 1-9 +4" && + test_must_fail git merge side && + cat <<-\EOF >4.txt && + 4 + 4/2 + 4/3 + 4master + 4side + EOF + git add 4.txt && + git commit -m "merge side (2)" && + echo 4.txt >diffc.expect && + diffc_verify +' + +test_expect_success 'merge introduces new file' ' + git checkout side && + for i in $(test_seq 5 9) + do + echo $i/4 >>$i.txt + done && + git commit -a -m "side 5-9" && + git checkout master && + for i in $(test_seq 1 3) + do + echo $i/4 >>$i.txt + done && + git commit -a -m "master 1-3 +4hello" && + git merge side && + echo "Hello World" >4hello.txt && + git add 4hello.txt && + git commit --amend && + echo 4hello.txt >diffc.expect && + diffc_verify +' + +test_expect_success 'merge removed a file' ' + git checkout side && + for i in $(test_seq 5 9) + do + echo $i/5 >>$i.txt + done && + git commit -a -m "side 5-9" && + git checkout master && + for i in $(test_seq 1 3) + do + echo $i/4 >>$i.txt + done && + git commit -a -m "master 1-3" && + git merge side && + git rm 4.txt && + git commit --amend && + echo 4.txt >diffc.expect && + diffc_verify +' + +test_done diff --git a/t/t4102-apply-rename.sh b/t/t4102-apply-rename.sh index e3ea3d5114..49e2d6c349 100755 --- a/t/t4102-apply-rename.sh +++ b/t/t4102-apply-rename.sh @@ -7,7 +7,6 @@ test_description='git apply handling copy/rename patch. ' . ./test-lib.sh -. "$TEST_DIRECTORY"/lib-prereq-FILEMODE.sh # setup diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh index b1b906b1bb..1b420e3b5f 100755 --- a/t/t4103-apply-binary.sh +++ b/t/t4103-apply-binary.sh @@ -23,10 +23,10 @@ test_expect_success 'setup' ' git commit -m "Initial Version" 2>/dev/null && git checkout -b binary && - "$PERL_PATH" -pe "y/x/\000/" <file1 >file3 && + perl -pe "y/x/\000/" <file1 >file3 && cat file3 >file4 && git add file2 && - "$PERL_PATH" -pe "y/\000/v/" <file3 >file1 && + perl -pe "y/\000/v/" <file3 >file1 && rm -f file2 && git update-index --add --remove file1 file2 file3 file4 && git commit -m "Second Version" && diff --git a/t/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/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh index fca815392e..1e4d4380bf 100755 --- a/t/t4116-apply-reverse.sh +++ b/t/t4116-apply-reverse.sh @@ -12,14 +12,14 @@ test_description='git apply in reverse test_expect_success setup ' for i in a b c d e f g h i j k l m n; do echo $i; done >file1 && - "$PERL_PATH" -pe "y/ijk/\\000\\001\\002/" <file1 >file2 && + perl -pe "y/ijk/\\000\\001\\002/" <file1 >file2 && git add file1 file2 && git commit -m initial && git tag initial && for i in a b c g h i J K L m o n p q; do echo $i; done >file1 && - "$PERL_PATH" -pe "y/mon/\\000\\001\\002/" <file1 >file2 && + perl -pe "y/mon/\\000\\001\\002/" <file1 >file2 && git commit -a -m second && git tag second && @@ -48,12 +48,12 @@ test_expect_success 'apply in reverse' ' test_expect_success 'setup separate repository lacking postimage' ' - git tar-tree initial initial | $TAR xf - && + git archive --format=tar --prefix=initial/ initial | $TAR xf - && ( cd initial && git init && git add . ) && - git tar-tree second second | $TAR xf - && + git archive --format=tar --prefix=second/ second | $TAR xf - && ( cd second && git init && git add . ) diff --git a/t/t4120-apply-popt.sh b/t/t4120-apply-popt.sh index c5fecdfed4..497b62868d 100755 --- a/t/t4120-apply-popt.sh +++ b/t/t4120-apply-popt.sh @@ -6,7 +6,6 @@ test_description='git apply -p handling.' . ./test-lib.sh -. "$TEST_DIRECTORY"/lib-prereq-FILEMODE.sh test_expect_success setup ' mkdir sub && 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/t4129-apply-samemode.sh b/t/t4129-apply-samemode.sh index 0d36ebdc86..c268298eaf 100755 --- a/t/t4129-apply-samemode.sh +++ b/t/t4129-apply-samemode.sh @@ -3,7 +3,6 @@ test_description='applying patch with mode bits' . ./test-lib.sh -. "$TEST_DIRECTORY"/lib-prereq-FILEMODE.sh test_expect_success setup ' echo original >file && 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/t4200-rerere.sh b/t/t4200-rerere.sh index 7f6666fcd3..ed9c91e25b 100755 --- a/t/t4200-rerere.sh +++ b/t/t4200-rerere.sh @@ -78,7 +78,7 @@ test_expect_success 'activate rerere, old style (conflicting merge)' ' test_might_fail git config --unset rerere.enabled && test_must_fail git merge first && - sha1=$("$PERL_PATH" -pe "s/ .*//" .git/MERGE_RR) && + sha1=$(perl -pe "s/ .*//" .git/MERGE_RR) && rr=.git/rr-cache/$sha1 && grep "^=======\$" $rr/preimage && ! test -f $rr/postimage && @@ -91,7 +91,7 @@ test_expect_success 'rerere.enabled works, too' ' git reset --hard && test_must_fail git merge first && - sha1=$("$PERL_PATH" -pe "s/ .*//" .git/MERGE_RR) && + sha1=$(perl -pe "s/ .*//" .git/MERGE_RR) && rr=.git/rr-cache/$sha1 && grep ^=======$ $rr/preimage ' @@ -101,7 +101,7 @@ test_expect_success 'set up rr-cache' ' git config rerere.enabled true && git reset --hard && test_must_fail git merge first && - sha1=$("$PERL_PATH" -pe "s/ .*//" .git/MERGE_RR) && + sha1=$(perl -pe "s/ .*//" .git/MERGE_RR) && rr=.git/rr-cache/$sha1 ' @@ -172,7 +172,7 @@ test_expect_success 'first postimage wins' ' git show second^:a1 | sed "s/To die: t/To die! T/" >a1 && git commit -q -a -m third && - test_must_fail git pull . first && + test_must_fail git merge first && # rerere kicked in ! grep "^=======\$" a1 && test_cmp expect a1 @@ -185,7 +185,7 @@ test_expect_success 'rerere updates postimage timestamp' ' test_expect_success 'rerere clear' ' rm $rr/postimage && - echo "$sha1 a1" | "$PERL_PATH" -pe "y/\012/\000/" >.git/MERGE_RR && + echo "$sha1 a1" | perl -pe "y/\012/\000/" >.git/MERGE_RR && git rerere clear && ! test -d $rr ' diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh index 6872ba1a42..42866992cf 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 } @@ -148,4 +172,20 @@ test_expect_success 'shortlog encoding' ' git shortlog HEAD~2.. > out && test_cmp expect out' +test_expect_success 'shortlog ignores commits with missing authors' ' + git commit --allow-empty -m normal && + git commit --allow-empty -m soon-to-be-broken && + git cat-file commit HEAD >commit.tmp && + sed "/^author/d" commit.tmp >broken.tmp && + commit=$(git hash-object -w -t commit --stdin <broken.tmp) && + git update-ref HEAD $commit && + cat >expect <<-\EOF && + A U Thor (1): + normal + + EOF + git shortlog HEAD~2.. >actual && + test_cmp expect actual +' + test_done 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..0dd8b65d7c 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,136 @@ 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 + printf "Tricky Guy <author@example.com>" >no-newline && + git add just-bugs both no-newline && + 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 'mailmap.blob can handle blobs without trailing newline' ' + cat >expect <<-\EOF && + Tricky Guy (1): + initial + + nick1 (1): + second + + EOF + git -c mailmap.blob=map:no-newline shortlog 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 +412,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 @@ -255,4 +484,15 @@ test_expect_success 'Blame output (complex mapping)' ' test_cmp expect actual.fuzz ' +cat >expect <<\EOF +Some Dude <some@dude.xx> +EOF + +test_expect_success 'commit --author honors mailmap' ' + test_must_fail git commit --author "nick" --allow-empty -meight && + git commit --author "Some Dude" --allow-empty -meight && + git show --pretty=format:"%an <%ae>%n" >actual && + test_cmp expect actual +' + test_done diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh index 98a43d457a..2a6278bb33 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,203 @@ 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_expect_success 'log decoration properly follows tag chain' ' + git tag -a tag1 -m tag1 && + git tag -a tag2 -m tag2 tag1 && + git tag -d tag1 && + git commit --amend -m shorter && + git log --no-walk --tags --pretty="%H %d" --decorate=full >actual && + cat <<EOF >expected && +6a908c10688b2503073c39c9ba26322c73902bb5 (tag: refs/tags/tag2) +9f716384d92283fb915a4eee5073f030638e05f9 (tag: refs/tags/message-one) +b87e4cccdb77336ea79d89224737be7ea8e95367 (tag: refs/tags/message-two) +EOF + sort actual >actual1 && + test_cmp expected actual1 +' + 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..d8f23f488e 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 @@ -33,4 +46,19 @@ test_expect_success 'git log HEAD -- :/' ' test_cmp expected actual ' +test_expect_success 'command line pathspec parsing for "git log"' ' + git reset --hard && + >a && + git add a && + git commit -m "add an empty a" --allow-empty && + echo 1 >a && + git commit -a -m "update a to 1" && + git checkout HEAD^ && + echo 2 >a && + git commit -a -m "update a to 2" && + test_must_fail git merge master && + git add a && + git log --merge -- a +' + test_done 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..7369d3c517 --- /dev/null +++ b/t/t4211-line-log.sh @@ -0,0 +1,97 @@ +#!/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" + +test_expect_success '-L X (X == nlines)' ' + n=$(wc -l <b.c) && + git log -L $n:b.c +' + +test_expect_success '-L X (X == nlines + 1)' ' + n=$(expr $(wc -l <b.c) + 1) && + test_must_fail git log -L $n:b.c +' + +test_expect_success '-L X (X == nlines + 2)' ' + n=$(expr $(wc -l <b.c) + 2) && + test_must_fail git log -L $n:b.c +' + +test_expect_success '-L ,Y (Y == nlines)' ' + n=$(printf "%d" $(wc -l <b.c)) && + git log -L ,$n:b.c +' + +test_expect_success '-L ,Y (Y == nlines + 1)' ' + n=$(expr $(wc -l <b.c) + 1) && + test_must_fail git log -L ,$n:b.c +' + +test_expect_success '-L ,Y (Y == nlines + 2)' ' + n=$(expr $(wc -l <b.c) + 2) && + test_must_fail 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..3fa171541a --- /dev/null +++ b/t/t4212-log-corrupt.sh @@ -0,0 +1,92 @@ +#!/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 'fsck notices broken commit' ' + git fsck 2>actual && + test_i18ngrep invalid.author actual +' + +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 Apr 7 15:13:13 2005 -0700" + 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+Thu Apr 7 15:13:13 2005 -0700" >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 +' + +munge_author_date () { + git cat-file commit "$1" >commit.orig && + sed "s/^\(author .*>\) [0-9]*/\1 $2/" <commit.orig >commit.munge && + git hash-object -w -t commit commit.munge +} + +test_expect_success 'unparsable dates produce sentinel value' ' + commit=$(munge_author_date HEAD totally_bogus) && + echo "Date: Thu Jan 1 00:00:00 1970 +0000" >expect && + git log -1 $commit >actual.full && + grep Date <actual.full >actual && + test_cmp expect actual +' + +test_expect_success 'unparsable dates produce sentinel value (%ad)' ' + commit=$(munge_author_date HEAD totally_bogus) && + echo >expect && + git log -1 --format=%ad $commit >actual + test_cmp expect actual +' + +# date is 2^64 + 1 +test_expect_success 'date parser recognizes integer overflow' ' + commit=$(munge_author_date HEAD 18446744073709551617) && + echo "Thu Jan 1 00:00:00 1970 +0000" >expect && + git log -1 --format=%ad $commit >actual && + test_cmp expect actual +' + +# date is 2^64 - 2 +test_expect_success 'date parser recognizes time_t overflow' ' + commit=$(munge_author_date HEAD 18446744073709551614) && + echo "Thu Jan 1 00:00:00 1970 +0000" >expect && + git log -1 --format=%ad $commit >actual && + test_cmp expect actual +' + +# date is within 2^63-1, but enough to choke glibc's gmtime +test_expect_success 'absurdly far-in-future dates produce sentinel' ' + commit=$(munge_author_date HEAD 999999999999999999) && + echo "Thu Jan 1 00:00:00 1970 +0000" >expect && + git log -1 --format=%ad $commit >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t4254-am-corrupt.sh b/t/t4254-am-corrupt.sh index b7da95fac5..85716dd6ec 100755 --- a/t/t4254-am-corrupt.sh +++ b/t/t4254-am-corrupt.sh @@ -3,20 +3,19 @@ test_description='git am with corrupt input' . ./test-lib.sh -# Note the missing "+++" line: -cat > bad-patch.diff <<'EOF' -From: A U Thor <au.thor@example.com> -diff --git a/f b/f -index 7898192..6178079 100644 ---- a/f -@@ -1 +1 @@ --a -+b -EOF - test_expect_success setup ' - test $? = 0 && - echo a > f && + # Note the missing "+++" line: + cat >bad-patch.diff <<-\EOF && + From: A U Thor <au.thor@example.com> + diff --git a/f b/f + index 7898192..6178079 100644 + --- a/f + @@ -1 +1 @@ + -a + +b + EOF + + echo a >f && git add f && test_tick && git commit -m initial @@ -26,17 +25,12 @@ test_expect_success setup ' # fatal: unable to write file '(null)' mode 100644: Bad address # Also, it had the unwanted side-effect of deleting f. test_expect_success 'try to apply corrupted patch' ' - git am bad-patch.diff 2> actual - test $? = 1 + test_must_fail git am bad-patch.diff 2>actual ' -cat > expected <<EOF -fatal: git diff header lacks filename information (line 4) -EOF - test_expect_success 'compare diagnostic; ensure file is still here' ' - test $? = 0 && - test -f f && + echo "fatal: git diff header lacks filename information (line 4)" >expected && + test_path_is_file f && test_cmp expected actual ' 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..1cf0a4e103 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -3,7 +3,7 @@ # Copyright (C) 2005 Rene Scharfe # -test_description='git tar-tree and git get-tar-commit-id test +test_description='git archive and git get-tar-commit-id test This test covers the topics of file contents, commit date handling and commit id embedding: @@ -13,11 +13,11 @@ commit id embedding: binary file (/bin/sh). Only paths shorter than 99 characters are used. - git tar-tree applies the commit date to every file in the archive it + git archive applies the commit date to every file in the archive it creates. The test sets the commit date to a specific value and checks if the tar archive contains that value. - When giving git tar-tree a commit id (in contrast to a tree id) it + When giving git archive a commit id (in contrast to a tree id) it embeds this commit id into the tar archive as a comment. The test checks the ability of git get-tar-commit-id to figure it out from the tar file. @@ -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 + ) +' + +test_lazy_prereq GZIP 'gzip --version' + +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,124 +196,12 @@ 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 -' - -$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 archive with --output, override inferred format' ' git archive --format=tar --output=d4.zip HEAD && test_cmp b.tar d4.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_expect_success \ 'git archive --list outside of a git repo' \ 'GIT_DIR=some/non-existing/directory git archive --list' @@ -268,22 +213,20 @@ 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 'upload-archive can allow unreachable commits' ' + test_commit unreachable1 && + sha1=`git rev-parse HEAD` && + git reset --hard HEAD^ && + git archive $sha1 >remote.tar && + test_config uploadarchive.allowUnreachable true && + git archive --remote=. $sha1 >remote.tar ' 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' ' @@ -331,12 +274,6 @@ test_expect_success 'only enabled filters are available remotely' ' test_cmp remote.bar config.bar ' -if $GZIP --version >/dev/null 2>&1; then - test_set_prereq GZIP -else - say "Skipping some tar.gz tests because gzip not found" -fi - test_expect_success GZIP 'git archive --format=tgz' ' git archive --format=tgz HEAD >j.tgz ' @@ -356,14 +293,8 @@ test_expect_success GZIP 'infer tgz from .tar.gz filename' ' test_cmp j.tgz j3.tar.gz ' -if $GUNZIP --version >/dev/null 2>&1; then - test_set_prereq GUNZIP -else - say "Skipping some tar.gz tests because gunzip was not found" -fi - -test_expect_success GZIP,GUNZIP 'extract tgz file' ' - $GUNZIP -c <j.tgz >j.tar && +test_expect_success GZIP 'extract tgz file' ' + gzip -d -c <j.tgz >j.tar && test_cmp b.tar j.tar ' 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/t5001-archive-attr.sh b/t/t5001-archive-attr.sh index f47d8717fd..51dedab29b 100755 --- a/t/t5001-archive-attr.sh +++ b/t/t5001-archive-attr.sh @@ -87,14 +87,4 @@ test_expect_success 'export-subst' ' test_cmp substfile2 archive/substfile2 ' -test_expect_success 'git tar-tree vs. git archive with worktree attributes' ' - git tar-tree HEAD >tar-tree.tar && - test_cmp worktree.tar tar-tree.tar -' - -test_expect_success 'git tar-tree vs. git archive with worktree attrs, bare' ' - (cd bare && git tar-tree HEAD) >bare-tar-tree.tar && - test_cmp bare-worktree.tar bare-tar-tree.tar -' - test_done 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..75d6b3843a 100755 --- a/t/t5150-request-pull.sh +++ b/t/t5150-request-pull.sh @@ -80,13 +80,13 @@ 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|tags/full|BRANCH|g s/mnemonic.txt/FILENAME/g s/^version [0-9]/VERSION/ /^ FILENAME | *[0-9]* [-+]*\$/ b diffstat @@ -127,7 +127,7 @@ test_expect_success 'pull request when forgot to push' ' test_must_fail git request-pull initial "$downstream_url" \ 2>../err ) && - grep "No branch of.*is at:\$" err && + grep "No match for commit .*" err && grep "Are you sure you pushed" err ' @@ -141,7 +141,7 @@ test_expect_success 'pull request after push' ' git checkout initial && git merge --ff-only master && git push origin master:for-upstream && - git request-pull initial origin >../request + git request-pull initial origin master:for-upstream >../request ) && sed -nf read-request.sed <request >digest && cat digest && @@ -160,7 +160,7 @@ test_expect_success 'pull request after push' ' ' -test_expect_success 'request names an appropriate branch' ' +test_expect_success 'request asks HEAD to be pulled' ' rm -fr downstream.git && git init --bare downstream.git && @@ -179,7 +179,7 @@ test_expect_success 'request names an appropriate branch' ' read repository && read branch } <digest && - test "$branch" = tags/full + test -z "$branch" ' @@ -212,12 +212,18 @@ test_expect_success 'pull request format' ' cd local && git checkout initial && git merge --ff-only master && - git push origin master:for-upstream && - git request-pull initial "$downstream_url" >../request + git push origin tags/full && + git request-pull initial "$downstream_url" tags/full >../request ) && <request sed -nf fuzz.sed >request.fuzzy && - test_i18ncmp expect request.fuzzy + test_i18ncmp expect request.fuzzy && + ( + cd local && + git request-pull initial "$downstream_url" tags/full:refs/tags/full + ) >request && + sed -nf fuzz.sed <request >request.fuzzy && + test_i18ncmp expect request.fuzzy ' test_expect_success 'request-pull ignores OPTIONS_KEEPDASHDASH poison' ' @@ -229,7 +235,7 @@ test_expect_success 'request-pull ignores OPTIONS_KEEPDASHDASH poison' ' git checkout initial && git merge --ff-only master && git push origin master:for-upstream && - git request-pull -- initial "$downstream_url" >../request + git request-pull -- initial "$downstream_url" master:for-upstream >../request ) ' diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index a07c871797..20c1961515 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -13,9 +13,9 @@ TRASH=`pwd` test_expect_success \ 'setup' \ 'rm -f .git/index* && - "$PERL_PATH" -e "print \"a\" x 4096;" > a && - "$PERL_PATH" -e "print \"b\" x 4096;" > b && - "$PERL_PATH" -e "print \"c\" x 4096;" > c && + perl -e "print \"a\" x 4096;" > a && + perl -e "print \"b\" x 4096;" > b && + perl -e "print \"c\" x 4096;" > c && test-genrandom "seed a" 2097152 > a_big && test-genrandom "seed b" 2097152 > b_big && git update-index --add a a_big b b_big c && @@ -129,7 +129,7 @@ test_expect_success \ cd "$TRASH" test_expect_success 'compare delta flavors' ' - "$PERL_PATH" -e '\'' + perl -e '\'' defined($_ = -s $_) or die for @ARGV; exit 1 if $ARGV[0] <= $ARGV[1]; '\'' test-2-$packname_2.pack test-3-$packname_3.pack @@ -151,7 +151,7 @@ test_expect_success \ git cat-file $t $object || return 1 done <obj-list } >current && - test_cmp expect current' + cmp expect current' test_expect_success \ 'use packed deltified (REF_DELTA) objects' \ @@ -166,7 +166,7 @@ test_expect_success \ git cat-file $t $object || return 1 done <obj-list } >current && - test_cmp expect current' + cmp expect current' test_expect_success \ 'use packed deltified (OFS_DELTA) objects' \ @@ -181,7 +181,7 @@ test_expect_success \ git cat-file $t $object || return 1 done <obj-list } >current && - test_cmp expect current' + cmp expect current' unset GIT_OBJECT_DIRECTORY @@ -195,9 +195,9 @@ test_expect_success 'survive missing objects/pack directory' ' rm -fr $GOP && git index-pack --stdin --keep=test <../test-3-${packname_3}.pack && test -f $GOP/pack-${packname_3}.pack && - test_cmp $GOP/pack-${packname_3}.pack ../test-3-${packname_3}.pack && + cmp $GOP/pack-${packname_3}.pack ../test-3-${packname_3}.pack && test -f $GOP/pack-${packname_3}.idx && - test_cmp $GOP/pack-${packname_3}.idx ../test-3-${packname_3}.idx && + cmp $GOP/pack-${packname_3}.idx ../test-3-${packname_3}.idx && test -f $GOP/pack-${packname_3}.keep ) ' diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh index fe82025d4a..4bbb718751 100755 --- a/t/t5302-pack-index.sh +++ b/t/t5302-pack-index.sh @@ -174,11 +174,11 @@ test_expect_success \ test_expect_success \ '[index v1] 5) pack-objects happily reuses corrupted data' \ 'pack4=$(git pack-objects test-4 <obj-list) && - test -f "test-4-${pack1}.pack"' + test -f "test-4-${pack4}.pack"' test_expect_success \ '[index v1] 6) newly created pack is BAD !' \ - 'test_must_fail git verify-pack -v "test-4-${pack1}.pack"' + 'test_must_fail git verify-pack -v "test-4-${pack4}.pack"' test_expect_success \ '[index v2] 1) stream pack to repository' \ diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh index 5b1250f0d2..663b02bbb1 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 } @@ -98,7 +98,7 @@ test_expect_success \ 'create_new_pack && git prune-packed && chmod +w ${pack}.pack && - "$PERL_PATH" -i.bak -pe "s/ base /abcdef/" ${pack}.pack && + perl -i.bak -pe "s/ base /abcdef/" ${pack}.pack && test_must_fail git cat-file blob $blob_1 > /dev/null && test_must_fail git cat-file blob $blob_2 > /dev/null && test_must_fail git cat-file blob $blob_3 > /dev/null' @@ -155,7 +155,7 @@ test_expect_success \ 'create_new_pack && git prune-packed && chmod +w ${pack}.pack && - "$PERL_PATH" -i.bak -pe "s/ delta1 /abcdefgh/" ${pack}.pack && + perl -i.bak -pe "s/ delta1 /abcdefgh/" ${pack}.pack && git cat-file blob $blob_1 > /dev/null && test_must_fail git cat-file blob $blob_2 > /dev/null && test_must_fail git cat-file blob $blob_3 > /dev/null' @@ -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..66c9a41739 100755 --- a/t/t5304-prune.sh +++ b/t/t5304-prune.sh @@ -195,4 +195,40 @@ 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_expect_success 'prune .git/shallow' ' + SHA1=`echo hi|git commit-tree HEAD^{tree}` && + echo $SHA1 >.git/shallow && + git prune --dry-run >out && + grep $SHA1 .git/shallow && + grep $SHA1 out && + git prune && + ! test -f .git/shallow +' + test_done diff --git a/t/t5305-include-tag.sh b/t/t5305-include-tag.sh index b061864a87..21517c70cd 100755 --- a/t/t5305-include-tag.sh +++ b/t/t5305-include-tag.sh @@ -45,9 +45,7 @@ test_expect_success 'unpack objects' ' test_expect_success 'check unpacked result (have commit, no tag)' ' git rev-list --objects $commit >list.expect && ( - GIT_DIR=clone.git && - export GIT_DIR && - test_must_fail git cat-file -e $tag && + test_must_fail env GIT_DIR=clone.git git cat-file -e $tag && git rev-list --objects $commit ) >list.actual && test_cmp list.expect list.actual diff --git a/t/t5308-pack-detect-duplicates.sh b/t/t5308-pack-detect-duplicates.sh new file mode 100755 index 0000000000..9c5a8766ab --- /dev/null +++ b/t/t5308-pack-detect-duplicates.sh @@ -0,0 +1,80 @@ +#!/bin/sh + +test_description='handling of duplicate objects in incoming packfiles' +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-pack.sh + +# The sha1s we have in our pack. It's important that these have the same +# starting byte, so that they end up in the same fanout section of the index. +# That lets us make sure we are exercising the binary search with both sets. +LO_SHA1=e68fe8129b546b101aee9510c5328e7f21ca1d18 +HI_SHA1=e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 + +# And here's a "missing sha1" which will produce failed lookups. It must also +# be in the same fanout section, and should be between the two (so that during +# our binary search, we are sure to end up looking at one or the other of the +# duplicate runs). +MISSING_SHA1='e69d000000000000000000000000000000000000' + +# git will never intentionally create packfiles with +# duplicate objects, so we have to construct them by hand. +# +# $1 is the name of the packfile to create +# +# $2 is the number of times to duplicate each object +create_pack () { + pack_header "$((2 * $2))" >"$1" && + for i in $(test_seq 1 "$2"); do + pack_obj $LO_SHA1 && + pack_obj $HI_SHA1 + done >>"$1" && + pack_trailer "$1" +} + +# double-check that create_pack actually works +test_expect_success 'pack with no duplicates' ' + create_pack no-dups.pack 1 && + git index-pack --stdin <no-dups.pack +' + +test_expect_success 'index-pack will allow duplicate objects by default' ' + clear_packs && + create_pack dups.pack 100 && + git index-pack --stdin <dups.pack +' + +test_expect_success 'create batch-check test vectors' ' + cat >input <<-EOF && + $LO_SHA1 + $HI_SHA1 + $MISSING_SHA1 + EOF + cat >expect <<-EOF + $LO_SHA1 blob 2 + $HI_SHA1 blob 0 + $MISSING_SHA1 missing + EOF +' + +test_expect_success 'lookup in duplicated pack (binary search)' ' + git cat-file --batch-check <input >actual && + test_cmp expect actual +' + +test_expect_success 'lookup in duplicated pack (GIT_USE_LOOKUP)' ' + ( + GIT_USE_LOOKUP=1 && + export GIT_USE_LOOKUP && + git cat-file --batch-check <input >actual + ) && + test_cmp expect actual +' + +test_expect_success 'index-pack can reject packs with duplicates' ' + clear_packs && + create_pack dups.pack 2 && + test_must_fail git index-pack --strict --stdin <dups.pack && + test_expect_code 1 git cat-file -e $LO_SHA1 +' + +test_done diff --git a/t/t5309-pack-delta-cycles.sh b/t/t5309-pack-delta-cycles.sh new file mode 100755 index 0000000000..3e7861b075 --- /dev/null +++ b/t/t5309-pack-delta-cycles.sh @@ -0,0 +1,77 @@ +#!/bin/sh + +test_description='test index-pack handling of delta cycles in packfiles' +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-pack.sh + +# Two similar-ish objects that we have computed deltas between. +A=01d7713666f4de822776c7622c10f1b07de280dc +B=e68fe8129b546b101aee9510c5328e7f21ca1d18 + +# double-check our hand-constucted packs +test_expect_success 'index-pack works with a single delta (A->B)' ' + clear_packs && + { + pack_header 2 && + pack_obj $A $B && + pack_obj $B + } >ab.pack && + pack_trailer ab.pack && + git index-pack --stdin <ab.pack && + git cat-file -t $A && + git cat-file -t $B +' + +test_expect_success 'index-pack works with a single delta (B->A)' ' + clear_packs && + { + pack_header 2 && + pack_obj $A && + pack_obj $B $A + } >ba.pack && + pack_trailer ba.pack && + git index-pack --stdin <ba.pack && + git cat-file -t $A && + git cat-file -t $B +' + +test_expect_success 'index-pack detects missing base objects' ' + clear_packs && + { + pack_header 1 && + pack_obj $A $B + } >missing.pack && + pack_trailer missing.pack && + test_must_fail git index-pack --fix-thin --stdin <missing.pack +' + +test_expect_success 'index-pack detects REF_DELTA cycles' ' + clear_packs && + { + pack_header 2 && + pack_obj $A $B && + pack_obj $B $A + } >cycle.pack && + pack_trailer cycle.pack && + test_must_fail git index-pack --fix-thin --stdin <cycle.pack +' + +test_expect_failure 'failover to an object in another pack' ' + clear_packs && + git index-pack --stdin <ab.pack && + git index-pack --stdin --fix-thin <cycle.pack +' + +test_expect_failure 'failover to a duplicate object in the same pack' ' + clear_packs && + { + pack_header 3 && + pack_obj $A $B && + pack_obj $B $A && + pack_obj $A + } >recoverable.pack && + pack_trailer recoverable.pack && + git index-pack --fix-thin --stdin <recoverable.pack +' + +test_done diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh new file mode 100755 index 0000000000..f13525caa3 --- /dev/null +++ b/t/t5310-pack-bitmaps.sh @@ -0,0 +1,142 @@ +#!/bin/sh + +test_description='exercise basic bitmap functionality' +. ./test-lib.sh + +test_expect_success 'setup repo with moderate-sized history' ' + for i in $(test_seq 1 10); do + test_commit $i + done && + git checkout -b other HEAD~5 && + for i in $(test_seq 1 10); do + test_commit side-$i + done && + git checkout master && + blob=$(echo tagged-blob | git hash-object -w --stdin) && + git tag tagged-blob $blob && + git config pack.writebitmaps true && + git config pack.writebitmaphashcache true +' + +test_expect_success 'full repack creates bitmaps' ' + git repack -ad && + ls .git/objects/pack/ | grep bitmap >output && + test_line_count = 1 output +' + +test_expect_success 'rev-list --test-bitmap verifies bitmaps' ' + git rev-list --test-bitmap HEAD +' + +rev_list_tests() { + state=$1 + + test_expect_success "counting commits via bitmap ($state)" ' + git rev-list --count HEAD >expect && + git rev-list --use-bitmap-index --count HEAD >actual && + test_cmp expect actual + ' + + test_expect_success "counting partial commits via bitmap ($state)" ' + git rev-list --count HEAD~5..HEAD >expect && + git rev-list --use-bitmap-index --count HEAD~5..HEAD >actual && + test_cmp expect actual + ' + + test_expect_success "counting non-linear history ($state)" ' + git rev-list --count other...master >expect && + git rev-list --use-bitmap-index --count other...master >actual && + test_cmp expect actual + ' + + test_expect_success "enumerate --objects ($state)" ' + git rev-list --objects --use-bitmap-index HEAD >tmp && + cut -d" " -f1 <tmp >tmp2 && + sort <tmp2 >actual && + git rev-list --objects HEAD >tmp && + cut -d" " -f1 <tmp >tmp2 && + sort <tmp2 >expect && + test_cmp expect actual + ' + + test_expect_success "bitmap --objects handles non-commit objects ($state)" ' + git rev-list --objects --use-bitmap-index HEAD tagged-blob >actual && + grep $blob actual + ' +} + +rev_list_tests 'full bitmap' + +test_expect_success 'clone from bitmapped repository' ' + git clone --no-local --bare . clone.git && + git rev-parse HEAD >expect && + git --git-dir=clone.git rev-parse HEAD >actual && + test_cmp expect actual +' + +test_expect_success 'setup further non-bitmapped commits' ' + for i in $(test_seq 1 10); do + test_commit further-$i + done +' + +rev_list_tests 'partial bitmap' + +test_expect_success 'fetch (partial bitmap)' ' + git --git-dir=clone.git fetch origin master:master && + git rev-parse HEAD >expect && + git --git-dir=clone.git rev-parse HEAD >actual && + test_cmp expect actual +' + +test_expect_success 'incremental repack cannot create bitmaps' ' + test_commit more-1 && + find .git/objects/pack -name "*.bitmap" >expect && + git repack -d && + find .git/objects/pack -name "*.bitmap" >actual && + test_cmp expect actual +' + +test_expect_success 'incremental repack can disable bitmaps' ' + test_commit more-2 && + git repack -d --no-write-bitmap-index +' + +test_expect_success 'full repack, reusing previous bitmaps' ' + git repack -ad && + ls .git/objects/pack/ | grep bitmap >output && + test_line_count = 1 output +' + +test_expect_success 'fetch (full bitmap)' ' + git --git-dir=clone.git fetch origin master:master && + git rev-parse HEAD >expect && + git --git-dir=clone.git rev-parse HEAD >actual && + test_cmp expect actual +' + +test_lazy_prereq JGIT ' + type jgit +' + +test_expect_success JGIT 'we can read jgit bitmaps' ' + git clone . compat-jgit && + ( + cd compat-jgit && + rm -f .git/objects/pack/*.bitmap && + jgit gc && + git rev-list --test-bitmap HEAD + ) +' + +test_expect_success JGIT 'jgit can read our bitmaps' ' + git clone . compat-us && + ( + cd compat-us && + git repack -adb && + # jgit gc will barf if it does not like our bitmaps + jgit gc + ) +' + +test_done diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh index 129fc88bd2..0736bcbcd5 100755 --- a/t/t5400-send-pack.sh +++ b/t/t5400-send-pack.sh @@ -164,6 +164,7 @@ test_expect_success 'receive-pack runs auto-gc in remote repo' ' # Set the child to auto-pack if more than one pack exists cd child && git config gc.autopacklimit 1 && + git config gc.autodetach false && git branch test_auto_gc && # And create a file that follows the temporary object naming # convention for the auto-gc to remove 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..5b2b1c2c13 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,46 @@ 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 'fetch creating new shallow root' ' + ( + git clone "file://$(pwd)/." shallow10 && + git commit --allow-empty -m empty && + cd shallow10 && + git fetch --depth=1 --progress 2>actual && + # This should fetch only the empty commit, no tree or + # blob objects + grep "remote: Total 1" actual + ) +' + test_expect_success 'setup tests for the --stdin parameter' ' for head in C D E F do @@ -442,4 +516,107 @@ test_expect_success 'test --all, --depth, and explicit tag' ' ) >out-adt 2>error-adt ' +test_expect_success 'shallow fetch with tags does not break the repository' ' + mkdir repo1 && + ( + cd repo1 && + git init && + test_commit 1 && + test_commit 2 && + test_commit 3 && + mkdir repo2 && + cd repo2 && + git init && + git fetch --depth=2 ../.git master:branch && + git fsck + ) +' +check_prot_path () { + cat >expected <<-EOF && + Diag: url=$1 + Diag: protocol=$2 + Diag: path=$3 + EOF + git fetch-pack --diag-url "$1" | grep -v hostandport= >actual && + test_cmp expected actual +} + +check_prot_host_path () { + cat >expected <<-EOF && + Diag: url=$1 + Diag: protocol=$2 + Diag: hostandport=$3 + Diag: path=$4 + EOF + git fetch-pack --diag-url "$1" >actual && + test_cmp expected actual +} + +for r in repo re:po re/po +do + # git or ssh with scheme + for p in "ssh+git" "git+ssh" git ssh + do + for h in host host:12 [::1] [::1]:23 + do + case "$p" in + *ssh*) + pp=ssh + ;; + *) + pp=$p + ;; + esac + test_expect_success "fetch-pack --diag-url $p://$h/$r" ' + check_prot_host_path $p://$h/$r $pp "$h" "/$r" + ' + # "/~" -> "~" conversion + test_expect_success "fetch-pack --diag-url $p://$h/~$r" ' + check_prot_host_path $p://$h/~$r $pp "$h" "~$r" + ' + done + done + # file with scheme + for p in file + do + test_expect_success "fetch-pack --diag-url $p://$h/$r" ' + check_prot_path $p://$h/$r $p "/$r" + ' + # No "/~" -> "~" conversion for file + test_expect_success "fetch-pack --diag-url $p://$h/~$r" ' + check_prot_path $p://$h/~$r $p "/~$r" + ' + done + # file without scheme + for h in nohost nohost:12 [::1] [::1]:23 [ [:aa + do + test_expect_success "fetch-pack --diag-url ./$h:$r" ' + check_prot_path ./$h:$r $p "./$h:$r" + ' + # No "/~" -> "~" conversion for file + test_expect_success "fetch-pack --diag-url ./$p:$h/~$r" ' + check_prot_path ./$p:$h/~$r $p "./$p:$h/~$r" + ' + done + #ssh without scheme + p=ssh + for h in host [::1] + do + test_expect_success "fetch-pack --diag-url $h:$r" ' + check_prot_path $h:$r $p "$r" + ' + # Do "/~" -> "~" conversion + test_expect_success "fetch-pack --diag-url $h:/~$r" ' + check_prot_host_path $h:/~$r $p "$h" "~$r" + ' + done +done + +test_expect_success MINGW 'fetch-pack --diag-url file://c:/repo' ' + check_prot_path file://c:/repo file c:/repo +' +test_expect_success MINGW 'fetch-pack --diag-url c:repo' ' + check_prot_path c:repo file c:repo +' + test_done 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..ac79dd915d 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 @@ -163,45 +160,47 @@ cat > test/expect << EOF * remote two Fetch URL: ../two Push URL: ../three - HEAD branch (remote HEAD is ambiguous, may be one of the following): - another - master + HEAD branch: master Local refs configured for 'git push': ahead forces to master (fast-forwardable) master pushes to another (up to date) 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 +218,183 @@ 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 -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) +test_expect_success 'set-head --auto has no problem w/multiple HEADs' ' + ( + cd test && + git fetch two "refs/heads/*:refs/remotes/two/*" && + git remote set-head --auto two >output 2>&1 && + echo "two/HEAD set to master" >expect && + 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 +402,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 +475,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 +503,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 +521,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 +554,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 +575,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 +618,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 +1091,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..5acd753dcf 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -88,7 +88,7 @@ test_expect_success 'fetch --prune on its own works as expected' ' cd "$D" && git clone . prune && cd prune && - git fetch origin refs/heads/master:refs/remotes/origin/extrabranch && + git update-ref refs/remotes/origin/extrabranch master && git fetch --prune origin && test_must_fail git rev-parse origin/extrabranch @@ -98,7 +98,7 @@ test_expect_success 'fetch --prune with a branch name keeps branches' ' cd "$D" && git clone . prune-branch && cd prune-branch && - git fetch origin refs/heads/master:refs/remotes/origin/extrabranch && + git update-ref refs/remotes/origin/extrabranch master && git fetch --prune origin master && git rev-parse origin/extrabranch @@ -113,25 +113,45 @@ test_expect_success 'fetch --prune with a namespace keeps other namespaces' ' git rev-parse origin/master ' -test_expect_success 'fetch --prune --tags does not delete the remote-tracking branches' ' +test_expect_success 'fetch --prune --tags prunes branches but not tags' ' cd "$D" && git clone . prune-tags && cd prune-tags && - git fetch origin refs/heads/master:refs/tags/sometag && + git tag sometag master && + # Create what looks like a remote-tracking branch from an earlier + # fetch that has since been deleted from the remote: + git update-ref refs/remotes/origin/fake-remote master && git fetch --prune --tags origin && git rev-parse origin/master && - test_must_fail git rev-parse somebranch + test_must_fail git rev-parse origin/fake-remote && + git rev-parse sometag ' -test_expect_success 'fetch --prune --tags with branch does not delete other remote-tracking branches' ' +test_expect_success 'fetch --prune --tags with branch does not prune other things' ' cd "$D" && git clone . prune-tags-branch && cd prune-tags-branch && - git fetch origin refs/heads/master:refs/remotes/origin/extrabranch && + git tag sometag master && + git update-ref refs/remotes/origin/extrabranch master && git fetch --prune --tags origin master && - git rev-parse origin/extrabranch + git rev-parse origin/extrabranch && + git rev-parse sometag +' + +test_expect_success 'fetch --prune --tags with refspec prunes based on refspec' ' + cd "$D" && + git clone . prune-tags-refspec && + cd prune-tags-refspec && + git tag sometag master && + git update-ref refs/remotes/origin/foo/otherbranch master && + git update-ref refs/remotes/origin/extrabranch master && + + git fetch --prune --tags origin refs/heads/foo/*:refs/remotes/origin/foo/* && + test_must_fail git rev-parse refs/remotes/origin/foo/otherbranch && + git rev-parse origin/extrabranch && + git rev-parse sometag ' test_expect_success 'fetch tags when there is no tags' ' @@ -281,7 +301,7 @@ test_expect_success 'fetch via rsync' ' mkdir rsynced && (cd rsynced && git init --bare && - git fetch "rsync:$(pwd)/../.git" master:refs/heads/master && + git fetch "rsync:../.git" master:refs/heads/master && git gc --prune && test $(git rev-parse master) = $(cd .. && git rev-parse master) && git fsck --full) @@ -292,7 +312,7 @@ test_expect_success 'push via rsync' ' (cd rsynced2 && git init) && (cd rsynced && - git push "rsync:$(pwd)/../rsynced2/.git" master) && + git push "rsync:../rsynced2/.git" master) && (cd rsynced2 && git gc --prune && test $(git rev-parse master) = $(cd .. && git rev-parse master) && @@ -303,7 +323,7 @@ test_expect_success 'push via rsync' ' mkdir rsynced3 && (cd rsynced3 && git init) && - git push --all "rsync:$(pwd)/rsynced3/.git" && + git push --all "rsync:rsynced3/.git" && (cd rsynced3 && test $(git rev-parse master) = $(cd .. && git rev-parse master) && git fsck --full) @@ -370,30 +390,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 +433,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 +442,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" && @@ -471,6 +517,88 @@ test_expect_success "should be able to fetch with duplicate refspecs" ' ) ' +# configured prune tests + +set_config_tristate () { + # var=$1 val=$2 + case "$2" in + unset) test_unconfig "$1" ;; + *) git config "$1" "$2" ;; + esac +} + +test_configured_prune () { + fetch_prune=$1 remote_origin_prune=$2 cmdline=$3 expected=$4 + + test_expect_success "prune fetch.prune=$1 remote.origin.prune=$2${3:+ $3}; $4" ' + # make sure a newbranch is there in . and also in one + git branch -f newbranch && + ( + cd one && + test_unconfig fetch.prune && + test_unconfig remote.origin.prune && + git fetch && + git rev-parse --verify refs/remotes/origin/newbranch + ) + + # now remove it + git branch -d newbranch && + + # then test + ( + cd one && + set_config_tristate fetch.prune $fetch_prune && + set_config_tristate remote.origin.prune $remote_origin_prune && + + git fetch $cmdline && + case "$expected" in + pruned) + test_must_fail git rev-parse --verify refs/remotes/origin/newbranch + ;; + kept) + git rev-parse --verify refs/remotes/origin/newbranch + ;; + esac + ) + ' +} + +test_configured_prune unset unset "" kept +test_configured_prune unset unset "--no-prune" kept +test_configured_prune unset unset "--prune" pruned + +test_configured_prune false unset "" kept +test_configured_prune false unset "--no-prune" kept +test_configured_prune false unset "--prune" pruned + +test_configured_prune true unset "" pruned +test_configured_prune true unset "--prune" pruned +test_configured_prune true unset "--no-prune" kept + +test_configured_prune unset false "" kept +test_configured_prune unset false "--no-prune" kept +test_configured_prune unset false "--prune" pruned + +test_configured_prune false false "" kept +test_configured_prune false false "--no-prune" kept +test_configured_prune false false "--prune" pruned + +test_configured_prune true false "" kept +test_configured_prune true false "--prune" pruned +test_configured_prune true false "--no-prune" kept + +test_configured_prune unset true "" pruned +test_configured_prune unset true "--no-prune" kept +test_configured_prune unset true "--prune" pruned + +test_configured_prune false true "" pruned +test_configured_prune false true "--no-prune" kept +test_configured_prune false true "--prune" pruned + +test_configured_prune true true "" pruned +test_configured_prune true true "--prune" pruned +test_configured_prune true true "--no-prune" kept + test_expect_success 'all boundary commits are excluded' ' test_commit base && test_commit oneside && @@ -486,4 +614,41 @@ test_expect_success 'all boundary commits are excluded' ' test_bundle_object_count .git/objects/pack/pack-${pack##pack }.pack 3 ' +test_expect_success 'fetch --prune prints the remotes url' ' + git branch goodbye && + git clone . only-prunes && + git branch -D goodbye && + ( + cd only-prunes && + git fetch --prune origin 2>&1 | head -n1 >../actual + ) && + echo "From ${D}/." >expect && + test_cmp expect actual +' + +test_expect_success 'branchname D/F conflict resolved by --prune' ' + git branch dir/file && + git clone . prune-df-conflict && + git branch -D dir/file && + git branch dir && + ( + cd prune-df-conflict && + git fetch --prune && + git rev-parse origin/dir >../actual + ) && + git rev-parse dir >expect && + test_cmp expect actual +' + +test_expect_success 'fetching a one-level ref works' ' + test_commit extra && + git reset --hard HEAD^ && + git update-ref refs/foo extra && + git init one-level && + ( + cd one-level && + git fetch .. HEAD refs/foo + ) +' + test_done 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/t5515/fetch.br-unconfig_--tags_.._.git b/t/t5515/fetch.br-unconfig_--tags_.._.git index 1669cc4af0..0f70f66c70 100644 --- a/t/t5515/fetch.br-unconfig_--tags_.._.git +++ b/t/t5515/fetch.br-unconfig_--tags_.._.git @@ -1,4 +1,5 @@ # br-unconfig --tags ../.git +0567da4d5edd2ff4bb292a465ba9e64dcad9536b ../ 6c9dec2b923228c9ff994c6cfe4ae16c12408dc5 not-for-merge tag 'tag-master' of ../ 8e32a6d901327a23ef831511badce7bf3bf46689 not-for-merge tag 'tag-one' of ../ 22feea448b023a2d864ef94b013735af34d238ba not-for-merge tag 'tag-one-tree' of ../ diff --git a/t/t5515/fetch.master_--tags_.._.git b/t/t5515/fetch.master_--tags_.._.git index 8a7493537b..ab473a6e1f 100644 --- a/t/t5515/fetch.master_--tags_.._.git +++ b/t/t5515/fetch.master_--tags_.._.git @@ -1,4 +1,5 @@ # master --tags ../.git +0567da4d5edd2ff4bb292a465ba9e64dcad9536b ../ 6c9dec2b923228c9ff994c6cfe4ae16c12408dc5 not-for-merge tag 'tag-master' of ../ 8e32a6d901327a23ef831511badce7bf3bf46689 not-for-merge tag 'tag-one' of ../ 22feea448b023a2d864ef94b013735af34d238ba not-for-merge tag 'tag-one-tree' of ../ diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index b5417cc951..67e0ab3462 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,81 @@ 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 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 $the_commit heads/master && - check_push_result $the_first_commit heads/local + 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 +' + +test_expect_success 'branch.*.pushremote config order is irrelevant' ' + mk_test one_repo heads/master && + mk_test two_repo heads/master && + test_config remote.one.url one_repo && + test_config remote.two.url two_repo && + test_config branch.master.pushremote two_repo && + test_config remote.pushdefault one_repo && + test_config push.default matching && + git push && + check_push_result one_repo $the_first_commit heads/master && + check_push_result two_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 +576,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 +592,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 +604,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 +621,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 +629,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 +665,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 +694,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 +726,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 +746,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 +792,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 +808,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 +829,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 +839,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 +851,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 +862,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 +938,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 +964,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 +1021,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 +1036,245 @@ 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 'pushing a specific ref applies remote.$name.push as refmap' ' + mk_test testrepo heads/master && + rm -fr src dst && + git init src && + git init --bare dst && + ( + cd src && + git pull ../testrepo master && + git branch next && + git config remote.dst.url ../dst && + git config remote.dst.push "+refs/heads/*:refs/remotes/src/*" && + git push dst master && + git show-ref refs/heads/master | + sed -e "s|refs/heads/|refs/remotes/src/|" >../dst/expect + ) && + ( + cd dst && + test_must_fail git show-ref refs/heads/next && + test_must_fail git show-ref refs/heads/master && + git show-ref refs/remotes/src/master >actual + ) && + test_cmp dst/expect dst/actual +' + +test_expect_success 'with no remote.$name.push, it is not used as refmap' ' + mk_test testrepo heads/master && + rm -fr src dst && + git init src && + git init --bare dst && + ( + cd src && + git pull ../testrepo master && + git branch next && + git config remote.dst.url ../dst && + git config push.default matching && + git push dst master && + git show-ref refs/heads/master >../dst/expect + ) && + ( + cd dst && + test_must_fail git show-ref refs/heads/next && + git show-ref refs/heads/master >actual + ) && + test_cmp dst/expect dst/actual +' + +test_expect_success 'with no remote.$name.push, upstream mapping is used' ' + mk_test testrepo heads/master && + rm -fr src dst && + git init src && + git init --bare dst && + ( + cd src && + git pull ../testrepo master && + git branch next && + git config remote.dst.url ../dst && + git config remote.dst.fetch "+refs/heads/*:refs/remotes/dst/*" && + git config push.default upstream && + + git config branch.master.merge refs/heads/trunk && + git config branch.master.remote dst && + + git push dst master && + git show-ref refs/heads/master | + sed -e "s|refs/heads/master|refs/heads/trunk|" >../dst/expect + ) && + ( + cd dst && + test_must_fail git show-ref refs/heads/master && + test_must_fail git show-ref refs/heads/next && + git show-ref refs/heads/trunk >actual + ) && + test_cmp dst/expect dst/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_expect_success 'push --no-thin must produce non-thin pack' ' + cat >>path1 <<\EOF && +keep base version of path1 big enough, compared to the new changes +later, in order to pass size heuristics in +builtin/pack-objects.c:try_delta() +EOF + git commit -am initial && + git init no-thin && + git --git-dir=no-thin/.git config receive.unpacklimit 0 && + git push no-thin/.git refs/heads/master:refs/heads/foo && + echo modified >> path1 && + git commit -am modified && + git repack -adf && + rcvpck="git receive-pack --reject-thin-pack-for-testing" && + git push --no-thin --receive-pack="$rcvpck" no-thin/.git refs/heads/master:refs/heads/foo ' 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..227d293350 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,15 +141,102 @@ 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) ' +# add a feature branch, keep-merge, that is merged into master, so the +# test can try preserving the merge commit (or not) with various +# --rebase flags/pull.rebase settings. +test_expect_success 'preserve merge setup' ' + git reset --hard before-rebase && + git checkout -b keep-merge second^ && + test_commit file3 && + git checkout to-rebase && + git merge keep-merge && + git tag before-preserve-rebase +' + +test_expect_success 'pull.rebase=false create a new merge commit' ' + git reset --hard before-preserve-rebase && + test_config pull.rebase false && + git pull . copy && + test $(git rev-parse HEAD^1) = $(git rev-parse before-preserve-rebase) && + test $(git rev-parse HEAD^2) = $(git rev-parse copy) && + test file3 = $(git show HEAD:file3.t) +' + +test_expect_success 'pull.rebase=true flattens keep-merge' ' + git reset --hard before-preserve-rebase && + test_config pull.rebase true && + git pull . copy && + test $(git rev-parse HEAD^^) = $(git rev-parse copy) && + test file3 = $(git show HEAD:file3.t) +' + +test_expect_success 'pull.rebase=1 is treated as true and flattens keep-merge' ' + git reset --hard before-preserve-rebase && + test_config pull.rebase 1 && + git pull . copy && + test $(git rev-parse HEAD^^) = $(git rev-parse copy) && + test file3 = $(git show HEAD:file3.t) +' + +test_expect_success 'pull.rebase=preserve rebases and merges keep-merge' ' + git reset --hard before-preserve-rebase && + test_config pull.rebase preserve && + git pull . copy && + test $(git rev-parse HEAD^^) = $(git rev-parse copy) && + test $(git rev-parse HEAD^2) = $(git rev-parse keep-merge) +' + +test_expect_success 'pull.rebase=invalid fails' ' + git reset --hard before-preserve-rebase && + test_config pull.rebase invalid && + ! git pull . copy +' + +test_expect_success '--rebase=false create a new merge commit' ' + git reset --hard before-preserve-rebase && + test_config pull.rebase true && + git pull --rebase=false . copy && + test $(git rev-parse HEAD^1) = $(git rev-parse before-preserve-rebase) && + test $(git rev-parse HEAD^2) = $(git rev-parse copy) && + test file3 = $(git show HEAD:file3.t) +' + +test_expect_success '--rebase=true rebases and flattens keep-merge' ' + git reset --hard before-preserve-rebase && + test_config pull.rebase preserve && + git pull --rebase=true . copy && + test $(git rev-parse HEAD^^) = $(git rev-parse copy) && + test file3 = $(git show HEAD:file3.t) +' + +test_expect_success '--rebase=preserve rebases and merges keep-merge' ' + git reset --hard before-preserve-rebase && + test_config pull.rebase true && + git pull --rebase=preserve . copy && + test $(git rev-parse HEAD^^) = $(git rev-parse copy) && + test $(git rev-parse HEAD^2) = $(git rev-parse keep-merge) +' + +test_expect_success '--rebase=invalid fails' ' + git reset --hard before-preserve-rebase && + ! git pull --rebase=invalid . copy +' + +test_expect_success '--rebase overrides pull.rebase=preserve and flattens keep-merge' ' + git reset --hard before-preserve-rebase && + test_config pull.rebase preserve && + git pull --rebase . copy && + test $(git rev-parse HEAD^^) = $(git rev-parse copy) && + test file3 = $(git show HEAD:file3.t) +' + test_expect_success '--rebase with rebased upstream' ' git remote add -f me . && @@ -171,9 +285,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/t5525-fetch-tagopt.sh b/t/t5525-fetch-tagopt.sh index 4fbf7a120f..45815f7378 100755 --- a/t/t5525-fetch-tagopt.sh +++ b/t/t5525-fetch-tagopt.sh @@ -8,7 +8,8 @@ setup_clone () { git clone --mirror . $1 && git remote add remote_$1 $1 && (cd $1 && - git tag tag_$1) + git tag tag_$1 && + git branch branch_$1) } test_expect_success setup ' @@ -21,21 +22,33 @@ test_expect_success setup ' test_expect_success "fetch with tagopt=--no-tags does not get tag" ' git fetch remote_one && - test_must_fail git show-ref tag_one + test_must_fail git show-ref tag_one && + git show-ref remote_one/branch_one ' test_expect_success "fetch --tags with tagopt=--no-tags gets tag" ' + ( + cd one && + git branch second_branch_one + ) && git fetch --tags remote_one && - git show-ref tag_one + git show-ref tag_one && + git show-ref remote_one/second_branch_one ' test_expect_success "fetch --no-tags with tagopt=--tags does not get tag" ' git fetch --no-tags remote_two && - test_must_fail git show-ref tag_two + test_must_fail git show-ref tag_two && + git show-ref remote_two/branch_two ' test_expect_success "fetch with tagopt=--tags gets tag" ' + ( + cd two && + git branch second_branch_two + ) && git fetch remote_two && - git show-ref tag_two + git show-ref tag_two && + git show-ref remote_two/second_branch_two ' test_done 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/t5529-push-errors.sh b/t/t5529-push-errors.sh new file mode 100755 index 0000000000..9871307fd4 --- /dev/null +++ b/t/t5529-push-errors.sh @@ -0,0 +1,48 @@ +#!/bin/sh + +test_description='detect some push errors early (before contacting remote)' +. ./test-lib.sh + +test_expect_success 'setup commits' ' + test_commit one +' + +test_expect_success 'setup remote' ' + git init --bare remote.git && + git remote add origin remote.git +' + +test_expect_success 'setup fake receive-pack' ' + FAKE_RP_ROOT=$(pwd) && + export FAKE_RP_ROOT && + write_script fake-rp <<-\EOF && + echo yes >"$FAKE_RP_ROOT"/rp-ran + exit 1 + EOF + git config remote.origin.receivepack "\"\$FAKE_RP_ROOT/fake-rp\"" +' + +test_expect_success 'detect missing branches early' ' + echo no >rp-ran && + echo no >expect && + test_must_fail git push origin missing && + test_cmp expect rp-ran +' + +test_expect_success 'detect missing sha1 expressions early' ' + echo no >rp-ran && + echo no >expect && + test_must_fail git push origin master~2:master && + test_cmp expect rp-ran +' + +test_expect_success 'detect ambiguous refs early' ' + git branch foo && + git tag foo && + echo no >rp-ran && + echo no >expect && + test_must_fail git push origin foo && + test_cmp expect rp-ran +' + +test_done diff --git a/t/t5530-upload-pack-error.sh b/t/t5530-upload-pack-error.sh index c983d3694c..3932e797f7 100755 --- a/t/t5530-upload-pack-error.sh +++ b/t/t5530-upload-pack-error.sh @@ -54,9 +54,6 @@ test_expect_success 'upload-pack fails due to error in rev-list' ' printf "0032want %s\n0034shallow %s00000009done\n0000" \ $(git rev-parse HEAD) $(git rev-parse HEAD^) >input && test_must_fail git upload-pack . <input >/dev/null 2>output.err && - # pack-objects survived - grep "Total.*, reused" output.err && - # but there was an error, which must have been in rev-list grep "bad tree object" output.err ' diff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh index 1947c28c64..445bb5fe26 100755 --- a/t/t5531-deep-submodule-push.sh +++ b/t/t5531-deep-submodule-push.sh @@ -12,10 +12,12 @@ test_expect_success setup ' ( cd work && git init && + git config push.default matching && mkdir -p gar/bage && ( cd gar/bage && git init && + git config push.default matching && >junk && git add junk && git commit -m "Initial junk" diff --git a/t/t5533-push-cas.sh b/t/t5533-push-cas.sh new file mode 100755 index 0000000000..ba20d83333 --- /dev/null +++ b/t/t5533-push-cas.sh @@ -0,0 +1,189 @@ +#!/bin/sh + +test_description='compare & swap push force/delete safety' + +. ./test-lib.sh + +setup_srcdst_basic () { + rm -fr src dst && + git clone --no-local . src && + git clone --no-local src dst && + ( + cd src && git checkout HEAD^0 + ) +} + +test_expect_success setup ' + : create template repository + test_commit A && + test_commit B && + test_commit C +' + +test_expect_success 'push to update (protected)' ' + setup_srcdst_basic && + ( + cd dst && + test_commit D && + test_must_fail git push --force-with-lease=master:master origin master + ) && + git ls-remote . refs/heads/master >expect && + git ls-remote src refs/heads/master >actual && + test_cmp expect actual +' + +test_expect_success 'push to update (protected, forced)' ' + setup_srcdst_basic && + ( + cd dst && + test_commit D && + git push --force --force-with-lease=master:master origin master + ) && + git ls-remote dst refs/heads/master >expect && + git ls-remote src refs/heads/master >actual && + test_cmp expect actual +' + +test_expect_success 'push to update (protected, tracking)' ' + setup_srcdst_basic && + ( + cd src && + git checkout master && + test_commit D && + git checkout HEAD^0 + ) && + git ls-remote src refs/heads/master >expect && + ( + cd dst && + test_commit E && + git ls-remote . refs/remotes/origin/master >expect && + test_must_fail git push --force-with-lease=master origin master && + git ls-remote . refs/remotes/origin/master >actual && + test_cmp expect actual + ) && + git ls-remote src refs/heads/master >actual && + test_cmp expect actual +' + +test_expect_success 'push to update (protected, tracking, forced)' ' + setup_srcdst_basic && + ( + cd src && + git checkout master && + test_commit D && + git checkout HEAD^0 + ) && + ( + cd dst && + test_commit E && + git ls-remote . refs/remotes/origin/master >expect && + git push --force --force-with-lease=master origin master + ) && + git ls-remote dst refs/heads/master >expect && + git ls-remote src refs/heads/master >actual && + test_cmp expect actual +' + +test_expect_success 'push to update (allowed)' ' + setup_srcdst_basic && + ( + cd dst && + test_commit D && + git push --force-with-lease=master:master^ origin master + ) && + git ls-remote dst refs/heads/master >expect && + git ls-remote src refs/heads/master >actual && + test_cmp expect actual +' + +test_expect_success 'push to update (allowed, tracking)' ' + setup_srcdst_basic && + ( + cd dst && + test_commit D && + git push --force-with-lease=master origin master + ) && + git ls-remote dst refs/heads/master >expect && + git ls-remote src refs/heads/master >actual && + test_cmp expect actual +' + +test_expect_success 'push to update (allowed even though no-ff)' ' + setup_srcdst_basic && + ( + cd dst && + git reset --hard HEAD^ && + test_commit D && + git push --force-with-lease=master origin master + ) && + git ls-remote dst refs/heads/master >expect && + git ls-remote src refs/heads/master >actual && + test_cmp expect actual +' + +test_expect_success 'push to delete (protected)' ' + setup_srcdst_basic && + git ls-remote src refs/heads/master >expect && + ( + cd dst && + test_must_fail git push --force-with-lease=master:master^ origin :master + ) && + git ls-remote src refs/heads/master >actual && + test_cmp expect actual +' + +test_expect_success 'push to delete (protected, forced)' ' + setup_srcdst_basic && + ( + cd dst && + git push --force --force-with-lease=master:master^ origin :master + ) && + >expect && + git ls-remote src refs/heads/master >actual && + test_cmp expect actual +' + +test_expect_success 'push to delete (allowed)' ' + setup_srcdst_basic && + ( + cd dst && + git push --force-with-lease=master origin :master + ) && + >expect && + git ls-remote src refs/heads/master >actual && + test_cmp expect actual +' + +test_expect_success 'cover everything with default force-with-lease (protected)' ' + setup_srcdst_basic && + ( + cd src && + git branch naster master^ + ) + git ls-remote src refs/heads/\* >expect && + ( + cd dst && + test_must_fail git push --force-with-lease origin master master:naster + ) && + git ls-remote src refs/heads/\* >actual && + test_cmp expect actual +' + +test_expect_success 'cover everything with default force-with-lease (allowed)' ' + setup_srcdst_basic && + ( + cd src && + git branch naster master^ + ) + ( + cd dst && + git fetch && + git push --force-with-lease origin master master:naster + ) && + git ls-remote dst refs/heads/master | + sed -e "s/master/naster/" >expect && + git ls-remote src refs/heads/naster >actual && + test_cmp expect actual +' + +test_done 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/t5536-fetch-conflicts.sh b/t/t5536-fetch-conflicts.sh new file mode 100755 index 0000000000..6c5d3a4ce0 --- /dev/null +++ b/t/t5536-fetch-conflicts.sh @@ -0,0 +1,100 @@ +#!/bin/sh + +test_description='fetch handles conflicting refspecs correctly' + +. ./test-lib.sh + +D=$(pwd) + +setup_repository () { + git init "$1" && ( + cd "$1" && + git config remote.origin.url "$D" && + shift && + for refspec in "$@" + do + git config --add remote.origin.fetch "$refspec" + done + ) +} + +verify_stderr () { + cat >expected && + # We're not interested in the error + # "fatal: The remote end hung up unexpectedly": + grep -E '^(fatal|warning):' <error | grep -v 'hung up' >actual | sort && + test_cmp expected actual +} + +test_expect_success 'setup' ' + git commit --allow-empty -m "Initial" && + git branch branch1 && + git tag tag1 && + git commit --allow-empty -m "First" && + git branch branch2 && + git tag tag2 +' + +test_expect_success 'fetch with no conflict' ' + setup_repository ok "+refs/heads/*:refs/remotes/origin/*" && ( + cd ok && + git fetch origin + ) +' + +test_expect_success 'fetch conflict: config vs. config' ' + setup_repository ccc \ + "+refs/heads/branch1:refs/remotes/origin/branch1" \ + "+refs/heads/branch2:refs/remotes/origin/branch1" && ( + cd ccc && + test_must_fail git fetch origin 2>error && + verify_stderr <<-\EOF + fatal: Cannot fetch both refs/heads/branch1 and refs/heads/branch2 to refs/remotes/origin/branch1 + EOF + ) +' + +test_expect_success 'fetch duplicate: config vs. config' ' + setup_repository dcc \ + "+refs/heads/*:refs/remotes/origin/*" \ + "+refs/heads/branch1:refs/remotes/origin/branch1" && ( + cd dcc && + git fetch origin + ) +' + +test_expect_success 'fetch conflict: arg overrides config' ' + setup_repository aoc \ + "+refs/heads/*:refs/remotes/origin/*" && ( + cd aoc && + git fetch origin refs/heads/branch2:refs/remotes/origin/branch1 + ) +' + +test_expect_success 'fetch conflict: arg vs. arg' ' + setup_repository caa && ( + cd caa && + test_must_fail git fetch origin \ + refs/heads/*:refs/remotes/origin/* \ + refs/heads/branch2:refs/remotes/origin/branch1 2>error && + verify_stderr <<-\EOF + fatal: Cannot fetch both refs/heads/branch1 and refs/heads/branch2 to refs/remotes/origin/branch1 + EOF + ) +' + +test_expect_success 'fetch conflict: criss-cross args' ' + setup_repository xaa \ + "+refs/heads/*:refs/remotes/origin/*" && ( + cd xaa && + git fetch origin \ + refs/heads/branch1:refs/remotes/origin/branch2 \ + refs/heads/branch2:refs/remotes/origin/branch1 2>error && + verify_stderr <<-\EOF + warning: refs/remotes/origin/branch1 usually tracks refs/heads/branch1, not refs/heads/branch2 + warning: refs/remotes/origin/branch2 usually tracks refs/heads/branch2, not refs/heads/branch1 + EOF + ) +' + +test_done diff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh new file mode 100755 index 0000000000..be951a4679 --- /dev/null +++ b/t/t5537-fetch-shallow.sh @@ -0,0 +1,217 @@ +#!/bin/sh + +test_description='fetch/clone from a shallow clone' + +. ./test-lib.sh + +commit() { + echo "$1" >tracked && + git add tracked && + git commit -m "$1" +} + +test_expect_success 'setup' ' + commit 1 && + commit 2 && + commit 3 && + commit 4 && + git config --global transfer.fsckObjects true +' + +test_expect_success 'setup shallow clone' ' + git clone --no-local --depth=2 .git shallow && + git --git-dir=shallow/.git log --format=%s >actual && + cat <<EOF >expect && +4 +3 +EOF + test_cmp expect actual +' + +test_expect_success 'clone from shallow clone' ' + git clone --no-local shallow shallow2 && + ( + cd shallow2 && + git fsck && + git log --format=%s >actual && + cat <<EOF >expect && +4 +3 +EOF + test_cmp expect actual + ) +' + +test_expect_success 'fetch from shallow clone' ' + ( + cd shallow && + commit 5 + ) && + ( + cd shallow2 && + git fetch && + git fsck && + git log --format=%s origin/master >actual && + cat <<EOF >expect && +5 +4 +3 +EOF + test_cmp expect actual + ) +' + +test_expect_success 'fetch --depth from shallow clone' ' + ( + cd shallow && + commit 6 + ) && + ( + cd shallow2 && + git fetch --depth=2 && + git fsck && + git log --format=%s origin/master >actual && + cat <<EOF >expect && +6 +5 +EOF + test_cmp expect actual + ) +' + +test_expect_success 'fetch --unshallow from shallow clone' ' + ( + cd shallow2 && + git fetch --unshallow && + git fsck && + git log --format=%s origin/master >actual && + cat <<EOF >expect && +6 +5 +4 +3 +EOF + test_cmp expect actual + ) +' + +test_expect_success 'fetch something upstream has but hidden by clients shallow boundaries' ' + # the blob "1" is available in .git but hidden by the + # shallow2/.git/shallow and it should be resent + ! git --git-dir=shallow2/.git cat-file blob `echo 1|git hash-object --stdin` >/dev/null && + echo 1 >1.t && + git add 1.t && + git commit -m add-1-back && + ( + cd shallow2 && + git fetch ../.git +refs/heads/master:refs/remotes/top/master && + git fsck && + git log --format=%s top/master >actual && + cat <<EOF >expect && +add-1-back +4 +3 +EOF + test_cmp expect actual + ) && + git --git-dir=shallow2/.git cat-file blob `echo 1|git hash-object --stdin` >/dev/null + +' + +test_expect_success 'fetch that requires changes in .git/shallow is filtered' ' + ( + cd shallow && + git checkout --orphan no-shallow && + commit no-shallow + ) && + git init notshallow && + ( + cd notshallow && + git fetch ../shallow/.git refs/heads/*:refs/remotes/shallow/*&& + git for-each-ref --format="%(refname)" >actual.refs && + cat <<EOF >expect.refs && +refs/remotes/shallow/no-shallow +EOF + test_cmp expect.refs actual.refs && + git log --format=%s shallow/no-shallow >actual && + cat <<EOF >expect && +no-shallow +EOF + test_cmp expect actual + ) +' + +test_expect_success 'fetch --update-shallow' ' + ( + cd shallow && + git checkout master && + commit 7 && + git tag -m foo heavy-tag HEAD^ && + git tag light-tag HEAD^:tracked + ) && + ( + cd notshallow && + git fetch --update-shallow ../shallow/.git refs/heads/*:refs/remotes/shallow/* && + git fsck && + git for-each-ref --sort=refname --format="%(refname)" >actual.refs && + cat <<EOF >expect.refs && +refs/remotes/shallow/master +refs/remotes/shallow/no-shallow +refs/tags/heavy-tag +refs/tags/light-tag +EOF + test_cmp expect.refs actual.refs && + git log --format=%s shallow/master >actual && + cat <<EOF >expect && +7 +6 +5 +4 +3 +EOF + test_cmp expect actual + ) +' + +if test -n "$NO_CURL" -o -z "$GIT_TEST_HTTPD"; then + say 'skipping remaining tests, git built without http support' + test_done +fi + +LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5537'} +. "$TEST_DIRECTORY"/lib-httpd.sh +start_httpd + +test_expect_success 'clone http repository' ' + git clone --bare --no-local shallow "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + git clone $HTTPD_URL/smart/repo.git clone && + ( + cd clone && + git fsck && + git log --format=%s origin/master >actual && + cat <<EOF >expect && +7 +6 +5 +4 +3 +EOF + test_cmp expect actual + ) +' + +test_expect_success POSIXPERM,SANITY 'shallow fetch from a read-only repo' ' + cp -R .git read-only.git && + find read-only.git -print | xargs chmod -w && + test_when_finished "find read-only.git -type d -print | xargs chmod +w" && + git clone --no-local --depth=2 read-only.git from-read-only && + git --git-dir=from-read-only/.git log --format=%s >actual && + cat >expect <<EOF && +add-1-back +4 +EOF + test_cmp expect actual +' + +stop_httpd +test_done diff --git a/t/t5538-push-shallow.sh b/t/t5538-push-shallow.sh new file mode 100755 index 0000000000..8e54ac5746 --- /dev/null +++ b/t/t5538-push-shallow.sh @@ -0,0 +1,182 @@ +#!/bin/sh + +test_description='push from/to a shallow clone' + +. ./test-lib.sh + +commit() { + echo "$1" >tracked && + git add tracked && + git commit -m "$1" +} + +test_expect_success 'setup' ' + git config --global transfer.fsckObjects true && + commit 1 && + commit 2 && + commit 3 && + commit 4 && + git clone . full && + ( + git init full-abc && + cd full-abc && + commit a && + commit b && + commit c + ) && + git clone --no-local --depth=2 .git shallow && + git --git-dir=shallow/.git log --format=%s >actual && + cat <<EOF >expect && +4 +3 +EOF + test_cmp expect actual && + git clone --no-local --depth=2 full-abc/.git shallow2 && + git --git-dir=shallow2/.git log --format=%s >actual && + cat <<EOF >expect && +c +b +EOF + test_cmp expect actual +' + +test_expect_success 'push from shallow clone' ' + ( + cd shallow && + commit 5 && + git push ../.git +master:refs/remotes/shallow/master + ) && + git log --format=%s shallow/master >actual && + git fsck && + cat <<EOF >expect && +5 +4 +3 +2 +1 +EOF + test_cmp expect actual +' + +test_expect_success 'push from shallow clone, with grafted roots' ' + ( + cd shallow2 && + test_must_fail git push ../.git +master:refs/remotes/shallow2/master 2>err && + grep "shallow2/master.*shallow update not allowed" err + ) && + test_must_fail git rev-parse shallow2/master && + git fsck +' + +test_expect_success 'add new shallow root with receive.updateshallow on' ' + test_config receive.shallowupdate true && + ( + cd shallow2 && + git push ../.git +master:refs/remotes/shallow2/master + ) && + git log --format=%s shallow2/master >actual && + git fsck && + cat <<EOF >expect && +c +b +EOF + test_cmp expect actual +' + +test_expect_success 'push from shallow to shallow' ' + ( + cd shallow && + git --git-dir=../shallow2/.git config receive.shallowupdate true && + git push ../shallow2/.git +master:refs/remotes/shallow/master && + git --git-dir=../shallow2/.git config receive.shallowupdate false + ) && + ( + cd shallow2 && + git log --format=%s shallow/master >actual && + git fsck && + cat <<EOF >expect && +5 +4 +3 +EOF + test_cmp expect actual + ) +' + +test_expect_success 'push from full to shallow' ' + ! git --git-dir=shallow2/.git cat-file blob `echo 1|git hash-object --stdin` && + commit 1 && + git push shallow2/.git +master:refs/remotes/top/master && + ( + cd shallow2 && + git log --format=%s top/master >actual && + git fsck && + cat <<EOF >expect && +1 +4 +3 +EOF + test_cmp expect actual && + git cat-file blob `echo 1|git hash-object --stdin` >/dev/null + ) +' + +if test -n "$NO_CURL" -o -z "$GIT_TEST_HTTPD"; then + say 'skipping remaining tests, git built without http support' + test_done +fi + +. "$TEST_DIRECTORY"/lib-httpd.sh +start_httpd + +test_expect_success 'push to shallow repo via http' ' + git clone --bare --no-local shallow "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + ( + cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + git config http.receivepack true + ) && + ( + cd full && + commit 9 && + git push $HTTPD_URL/smart/repo.git +master:refs/remotes/top/master + ) && + ( + cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + git fsck && + git log --format=%s top/master >actual && + cat <<EOF >expect && +9 +4 +3 +EOF + test_cmp expect actual + ) +' + +test_expect_success 'push from shallow repo via http' ' + mv "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" shallow-upstream.git && + git clone --bare --no-local full "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + ( + cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + git config http.receivepack true + ) && + commit 10 && + git push $HTTPD_URL/smart/repo.git +master:refs/remotes/top/master && + ( + cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + git fsck && + git log --format=%s top/master >actual && + cat <<EOF >expect && +10 +1 +4 +3 +2 +1 +EOF + test_cmp expect actual + ) +' + +stop_httpd +test_done diff --git a/t/t5539-fetch-http-shallow.sh b/t/t5539-fetch-http-shallow.sh new file mode 100755 index 0000000000..94553e1039 --- /dev/null +++ b/t/t5539-fetch-http-shallow.sh @@ -0,0 +1,82 @@ +#!/bin/sh + +test_description='fetch/clone from a shallow clone over http' + +. ./test-lib.sh + +if test -n "$NO_CURL"; then + skip_all='skipping test, git built without http support' + test_done +fi + +. "$TEST_DIRECTORY"/lib-httpd.sh +start_httpd + +commit() { + echo "$1" >tracked && + git add tracked && + git commit -m "$1" +} + +test_expect_success 'setup shallow clone' ' + commit 1 && + commit 2 && + commit 3 && + commit 4 && + commit 5 && + commit 6 && + commit 7 && + git clone --no-local --depth=5 .git shallow && + git config --global transfer.fsckObjects true +' + +test_expect_success 'clone http repository' ' + git clone --bare --no-local shallow "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + git clone $HTTPD_URL/smart/repo.git clone && + ( + cd clone && + git fsck && + git log --format=%s origin/master >actual && + cat <<EOF >expect && +7 +6 +5 +4 +3 +EOF + test_cmp expect actual + ) +' + +# This test is tricky. We need large enough "have"s that fetch-pack +# will put pkt-flush in between. Then we need a "have" the server +# does not have, it'll send "ACK %s ready" +test_expect_success 'no shallow lines after receiving ACK ready' ' + ( + cd shallow && + for i in $(test_seq 15) + do + git checkout --orphan unrelated$i && + test_commit unrelated$i && + git push -q "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \ + refs/heads/unrelated$i:refs/heads/unrelated$i && + git push -q ../clone/.git \ + refs/heads/unrelated$i:refs/heads/unrelated$i || + exit 1 + done && + git checkout master && + test_commit new && + git push "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" master + ) && + ( + cd clone && + git checkout --orphan newnew && + test_commit new-too && + GIT_TRACE_PACKET="$TRASH_DIRECTORY/trace" git fetch --depth=2 && + grep "fetch-pack< ACK .* ready" ../trace && + ! grep "fetch-pack> done" ../trace + ) +' + +stop_httpd +test_done diff --git a/t/t5540-http-push.sh b/t/t5540-http-push-webdav.sh index 01d0d95b4d..8d7b3c57e3 100755 --- a/t/t5540-http-push.sh +++ b/t/t5540-http-push-webdav.sh @@ -16,7 +16,6 @@ then fi LIB_HTTPD_DAV=t -LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5540'} . "$TEST_DIRECTORY"/lib-httpd.sh ROOT_PATH="$PWD" start_httpd @@ -154,7 +153,7 @@ test_http_push_nonff "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git \ test_expect_success 'push to password-protected repository (user in URL)' ' test_commit pw-user && - set_askpass user@host && + set_askpass user@host pass@host && git push "$HTTPD_URL_USER/auth/dumb/test_repo.git" HEAD && git rev-parse --verify HEAD >expect && git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/test_repo.git" \ @@ -168,7 +167,7 @@ test_expect_failure 'user was prompted only once for password' ' test_expect_failure 'push to password-protected repository (no user in URL)' ' test_commit pw-nouser && - set_askpass user@host && + set_askpass user@host pass@host && git push "$HTTPD_URL/auth/dumb/test_repo.git" HEAD && expect_askpass both user@host git rev-parse --verify HEAD >expect && diff --git a/t/t5541-http-push.sh b/t/t5541-http-push-smart.sh index 4b4b4a604f..73af16f481 100755 --- a/t/t5541-http-push.sh +++ b/t/t5541-http-push-smart.sh @@ -12,7 +12,6 @@ if test -n "$NO_CURL"; then fi ROOT_PATH="$PWD" -LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5541'} . "$TEST_DIRECTORY"/lib-httpd.sh . "$TEST_DIRECTORY"/lib-terminal.sh start_httpd @@ -153,7 +152,7 @@ test_expect_success 'used receive-pack service' ' ' test_http_push_nonff "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git \ - "$ROOT_PATH"/test_repo_clone master + "$ROOT_PATH"/test_repo_clone master success test_expect_success 'push fails for non-fast-forward refs unmatched by remote helper' ' # create a dissimilarly-named remote ref so that git is unable to match the @@ -181,8 +180,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 && @@ -275,7 +273,7 @@ test_expect_success 'push over smart http with auth' ' cd "$ROOT_PATH/test_repo_clone" && echo push-auth-test >expect && test_commit push-auth-test && - set_askpass user@host && + set_askpass user@host pass@host && git push "$HTTPD_URL"/auth/smart/test_repo.git && git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \ log -1 --format=%s >actual && @@ -287,7 +285,7 @@ test_expect_success 'push to auth-only-for-push repo' ' cd "$ROOT_PATH/test_repo_clone" && echo push-half-auth >expect && test_commit push-half-auth && - set_askpass user@host && + set_askpass user@host pass@host && git push "$HTTPD_URL"/auth-push/smart/test_repo.git && git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \ log -1 --format=%s >actual && @@ -295,5 +293,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 pass@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-dumb.sh index 80d20c876b..1a3a2b6c1a 100755 --- a/t/t5550-http-fetch.sh +++ b/t/t5550-http-fetch-dumb.sh @@ -8,11 +8,11 @@ if test -n "$NO_CURL"; then test_done fi -LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5550'} . "$TEST_DIRECTORY"/lib-httpd.sh start_httpd test_expect_success 'setup repository' ' + git config push.default matching && echo content1 >file && git add file && git commit -m one @@ -61,13 +61,13 @@ test_expect_success 'http auth can use user/pass in URL' ' ' test_expect_success 'http auth can use just user in URL' ' - set_askpass user@host && + set_askpass wrong pass@host && git clone "$HTTPD_URL_USER/auth/dumb/repo.git" clone-auth-pass && expect_askpass pass user@host ' test_expect_success 'http auth can request both user and pass' ' - set_askpass user@host && + set_askpass user@host pass@host && git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-both && expect_askpass both user@host ' @@ -76,7 +76,7 @@ test_expect_success 'http auth respects credential helper config' ' test_config_global credential.helper "!f() { cat >/dev/null echo username=user@host - echo password=user@host + echo password=pass@host }; f" && set_askpass wrong && git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-helper && @@ -85,14 +85,14 @@ test_expect_success 'http auth respects credential helper config' ' test_expect_success 'http auth can get username from config' ' test_config_global "credential.$HTTPD_URL.username" user@host && - set_askpass user@host && + set_askpass wrong pass@host && git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-user && expect_askpass pass user@host ' test_expect_success 'configured username does not override URL' ' test_config_global "credential.$HTTPD_URL.username" wrong && - set_askpass user@host && + set_askpass wrong pass@host && git clone "$HTTPD_URL_USER/auth/dumb/repo.git" clone-auth-user2 && expect_askpass pass user@host ' diff --git a/t/t5551-http-fetch.sh b/t/t5551-http-fetch-smart.sh index c5cd2e348c..e07eaf35f1 100755 --- a/t/t5551-http-fetch.sh +++ b/t/t5551-http-fetch-smart.sh @@ -8,11 +8,11 @@ if test -n "$NO_CURL"; then test_done fi -LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5551'} . "$TEST_DIRECTORY"/lib-httpd.sh start_httpd test_expect_success 'setup repository' ' + git config push.default matching && echo content >file && git add file && git commit -m one @@ -112,9 +112,13 @@ test_expect_success 'follow redirects (302)' ' git clone $HTTPD_URL/smart-redir-temp/repo.git --quiet repo-t ' +test_expect_success 'redirects re-root further requests' ' + git clone $HTTPD_URL/smart-redir-limited/repo.git repo-redir-limited +' + test_expect_success 'clone from password-protected repository' ' echo two >expect && - set_askpass user@host && + set_askpass user@host pass@host && git clone --bare "$HTTPD_URL/auth/smart/repo.git" smart-auth && expect_askpass both user@host && git --git-dir=smart-auth log -1 --format=%s >actual && @@ -132,7 +136,7 @@ test_expect_success 'clone from auth-only-for-push repository' ' test_expect_success 'clone from auth-only-for-objects repository' ' echo two >expect && - set_askpass user@host && + set_askpass user@host pass@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 && @@ -145,6 +149,13 @@ test_expect_success 'no-op half-auth fetch does not require a password' ' expect_askpass none ' +test_expect_success 'redirects send auth to new location' ' + set_askpass user@host pass@host && + git -c credential.useHttpPath=true \ + clone $HTTPD_URL/smart-redir-auth/repo.git repo-redir-auth && + expect_askpass both user@host auth/smart/repo.git +' + test_expect_success 'disable dumb http on server' ' git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \ config http.getanyfile false @@ -157,6 +168,51 @@ 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 +' + +cat >cookies.txt <<EOF +127.0.0.1 FALSE /smart_cookies/ FALSE 0 othername othervalue +EOF +cat >expect_cookies.txt <<EOF + +127.0.0.1 FALSE /smart_cookies/ FALSE 0 othername othervalue +127.0.0.1 FALSE /smart_cookies/repo.git/info/ FALSE 0 name value +EOF +test_expect_success 'cookies stored in http.cookiefile when http.savecookies set' ' + git config http.cookiefile cookies.txt && + git config http.savecookies true && + git ls-remote $HTTPD_URL/smart_cookies/repo.git master && + tail -3 cookies.txt > cookies_tail.txt + test_cmp expect_cookies.txt cookies_tail.txt +' + test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE test_expect_success EXPENSIVE 'create 50,000 tags in the repo' ' @@ -178,14 +234,18 @@ test_expect_success EXPENSIVE 'create 50,000 tags in the repo' ' done | git fast-import --export-marks=marks && # now assign tags to all the dangling commits we created above - tag=$("$PERL_PATH" -e "print \"bla\" x 30") && - sed -e "s/^:\(.\+\) \(.\+\)$/\2 refs\/tags\/$tag-\1/" <marks >>packed-refs + tag=$(perl -e "print \"bla\" x 30") && + sed -e "s|^:\([^ ]*\) \(.*\)$|\2 refs/tags/$tag-\1|" <marks >>packed-refs ) ' test_expect_success EXPENSIVE 'clone the 50,000 tag repo to check OS command line overflow' ' git clone $HTTPD_URL/smart/repo.git too-many-refs 2>err && - test_line_count = 0 err + 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/t5561-http-backend.sh b/t/t5561-http-backend.sh index b5d7fbc381..d23fb02384 100755 --- a/t/t5561-http-backend.sh +++ b/t/t5561-http-backend.sh @@ -8,7 +8,6 @@ if test -n "$NO_CURL"; then test_done fi -LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5561'} . "$TEST_DIRECTORY"/lib-httpd.sh start_httpd diff --git a/t/t5570-git-daemon.sh b/t/t5570-git-daemon.sh index a3a4e47e1d..6b16379951 100755 --- a/t/t5570-git-daemon.sh +++ b/t/t5570-git-daemon.sh @@ -3,11 +3,11 @@ test_description='test fetching over git protocol' . ./test-lib.sh -LIB_GIT_DAEMON_PORT=${LIB_GIT_DAEMON_PORT-5570} . "$TEST_DIRECTORY"/lib-git-daemon.sh start_git_daemon test_expect_success 'setup repository' ' + git config push.default matching && echo content >file && git add file && git commit -m one @@ -36,7 +36,7 @@ test_expect_success 'fetch changes via git protocol' ' test_cmp file clone/file ' -test_expect_failure 'remote detects correct HEAD' ' +test_expect_success 'remote detects correct HEAD' ' git push public master:other && (cd clone && git remote set-head -d origin && @@ -121,8 +121,7 @@ test_remote_error() fi test_must_fail git "$cmd" "$GIT_DAEMON_URL/$repo" "$@" 2>output && - echo "fatal: remote error: $msg: /$repo" >expect && - test_cmp expect output + test_i18ngrep "fatal: remote error: $msg: /$repo" output && ret=$? chmod +x "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" (exit $ret) 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..5e67035be8 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -36,7 +36,7 @@ test_expect_success 'clone with excess parameters (2)' ' test_expect_success C_LOCALE_OUTPUT 'output from clone' ' rm -fr dst && - git clone -n "file://$(pwd)/src" dst >output && + git clone -n "file://$(pwd)/src" dst >output 2>&1 && test $(grep Clon output | wc -l) = 1 ' @@ -280,4 +280,161 @@ test_expect_success 'clone checking out a tag' ' test_cmp fetch.expected fetch.actual ' +setup_ssh_wrapper () { + test_expect_success 'setup ssh wrapper' ' + write_script "$TRASH_DIRECTORY/ssh-wrapper" <<-\EOF && + echo >>"$TRASH_DIRECTORY/ssh-output" "ssh: $*" && + # throw away all but the last argument, which should be the + # command + while test $# -gt 1; do shift; done + eval "$1" + EOF + GIT_SSH="$TRASH_DIRECTORY/ssh-wrapper" && + export GIT_SSH && + export TRASH_DIRECTORY && + >"$TRASH_DIRECTORY"/ssh-output + ' +} + +expect_ssh () { + test_when_finished ' + (cd "$TRASH_DIRECTORY" && rm -f ssh-expect && >ssh-output) + ' && + { + case "$1" in + none) + ;; + *) + echo "ssh: $1 git-upload-pack '$2'" + esac + } >"$TRASH_DIRECTORY/ssh-expect" && + (cd "$TRASH_DIRECTORY" && test_cmp ssh-expect ssh-output) +} + +setup_ssh_wrapper + +test_expect_success 'clone myhost:src uses ssh' ' + git clone myhost:src ssh-clone && + expect_ssh myhost src +' + +test_expect_success NOT_MINGW,NOT_CYGWIN 'clone local path foo:bar' ' + cp -R src "foo:bar" && + git clone "foo:bar" foobar && + expect_ssh none +' + +test_expect_success 'bracketed hostnames are still ssh' ' + git clone "[myhost:123]:src" ssh-bracket-clone && + expect_ssh myhost:123 src +' + +counter=0 +# $1 url +# $2 none|host +# $3 path +test_clone_url () { + counter=$(($counter + 1)) + test_might_fail git clone "$1" tmp$counter && + expect_ssh "$2" "$3" +} + +test_expect_success NOT_MINGW 'clone c:temp is ssl' ' + test_clone_url c:temp c temp +' + +test_expect_success MINGW 'clone c:temp is dos drive' ' + test_clone_url c:temp none +' + +#ip v4 +for repo in rep rep/home/project 123 +do + test_expect_success "clone host:$repo" ' + test_clone_url host:$repo host $repo + ' +done + +#ipv6 +for repo in rep rep/home/project 123 +do + test_expect_success "clone [::1]:$repo" ' + test_clone_url [::1]:$repo ::1 $repo + ' +done +#home directory +test_expect_success "clone host:/~repo" ' + test_clone_url host:/~repo host "~repo" +' + +test_expect_success "clone [::1]:/~repo" ' + test_clone_url [::1]:/~repo ::1 "~repo" +' + +# Corner cases +for url in foo/bar:baz [foo]bar/baz:qux [foo/bar]:baz +do + test_expect_success "clone $url is not ssh" ' + test_clone_url $url none + ' +done + +#with ssh:// scheme +test_expect_success 'clone ssh://host.xz/home/user/repo' ' + test_clone_url "ssh://host.xz/home/user/repo" host.xz "/home/user/repo" +' + +# from home directory +test_expect_success 'clone ssh://host.xz/~repo' ' + test_clone_url "ssh://host.xz/~repo" host.xz "~repo" +' + +# with port number +test_expect_success 'clone ssh://host.xz:22/home/user/repo' ' + test_clone_url "ssh://host.xz:22/home/user/repo" "-p 22 host.xz" "/home/user/repo" +' + +# from home directory with port number +test_expect_success 'clone ssh://host.xz:22/~repo' ' + test_clone_url "ssh://host.xz:22/~repo" "-p 22 host.xz" "~repo" +' + +#IPv6 +test_expect_success 'clone ssh://[::1]/home/user/repo' ' + test_clone_url "ssh://[::1]/home/user/repo" "::1" "/home/user/repo" +' + +#IPv6 from home directory +test_expect_success 'clone ssh://[::1]/~repo' ' + test_clone_url "ssh://[::1]/~repo" "::1" "~repo" +' + +#IPv6 with port number +test_expect_success 'clone ssh://[::1]:22/home/user/repo' ' + test_clone_url "ssh://[::1]:22/home/user/repo" "-p 22 ::1" "/home/user/repo" +' + +#IPv6 from home directory with port number +test_expect_success 'clone ssh://[::1]:22/~repo' ' + test_clone_url "ssh://[::1]:22/~repo" "-p 22 ::1" "~repo" +' + +test_expect_success 'clone from a repository with two identical branches' ' + + ( + cd src && + git checkout -b another master + ) && + git clone src target-11 && + test "z$( cd target-11 && git symbolic-ref HEAD )" = zrefs/heads/another + +' + +test_expect_success 'shallow clone locally' ' + git clone --depth=1 --no-local src ssrrcc && + git clone ssrrcc ddsstt && + test_cmp ssrrcc/.git/shallow ddsstt/.git/shallow && + ( cd ddsstt && git fsck ) +' + test_done diff --git a/t/t5602-clone-remote-exec.sh b/t/t5602-clone-remote-exec.sh index 3f353d99e8..cbcceab9d5 100755 --- a/t/t5602-clone-remote-exec.sh +++ b/t/t5602-clone-remote-exec.sh @@ -12,21 +12,14 @@ test_expect_success setup ' ' test_expect_success 'clone calls git upload-pack unqualified with no -u option' ' - ( - GIT_SSH=./not_ssh && - export GIT_SSH && - test_must_fail git clone localhost:/path/to/repo junk - ) && + test_must_fail env GIT_SSH=./not_ssh git clone localhost:/path/to/repo junk && echo "localhost git-upload-pack '\''/path/to/repo'\''" >expected && test_cmp expected not_ssh_output ' test_expect_success 'clone calls specified git upload-pack with -u option' ' - ( - GIT_SSH=./not_ssh && - export GIT_SSH && - test_must_fail git clone -u ./something/bin/git-upload-pack localhost:/path/to/repo junk - ) && + test_must_fail env GIT_SSH=./not_ssh \ + git clone -u ./something/bin/git-upload-pack localhost:/path/to/repo junk && echo "localhost ./something/bin/git-upload-pack '\''/path/to/repo'\''" >expected && test_cmp expected not_ssh_output ' 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/t5701-clone-local.sh b/t/t5701-clone-local.sh index 7ff6e0e16c..c4903687fb 100755 --- a/t/t5701-clone-local.sh +++ b/t/t5701-clone-local.sh @@ -134,4 +134,8 @@ test_expect_success 'cloning a local path with --no-local does not hardlink' ' ! repo_is_hardlinked force-nonlocal ' +test_expect_success 'cloning locally respects "-u" for fetching refs' ' + test_must_fail git clone --bare -u false a should_not_work.git +' + test_done diff --git a/t/t5702-clone-options.sh b/t/t5702-clone-options.sh index 02cb024723..9e24ec88e6 100755 --- a/t/t5702-clone-options.sh +++ b/t/t5702-clone-options.sh @@ -19,17 +19,19 @@ test_expect_success 'clone -o' ' ' -test_expect_success 'redirected clone' ' +test_expect_success 'redirected clone does not show progress' ' git clone "file://$(pwd)/parent" clone-redirected >out 2>err && - test ! -s err + ! grep % err && + test_i18ngrep ! "Checking connectivity" err ' -test_expect_success 'redirected clone -v' ' + +test_expect_success 'redirected clone -v does show progress' ' git clone --progress "file://$(pwd)/parent" clone-redirected-progress \ >out 2>err && - test -s err + grep % err ' 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/t5706-clone-branch.sh b/t/t5706-clone-branch.sh index 56be67e07e..6e7a7be052 100755 --- a/t/t5706-clone-branch.sh +++ b/t/t5706-clone-branch.sh @@ -20,7 +20,9 @@ test_expect_success 'setup' ' echo one >file && git add file && git commit -m one && git checkout -b two && echo two >file && git add file && git commit -m two && - git checkout master) + git checkout master) && + mkdir empty && + (cd empty && git init) ' test_expect_success 'vanilla clone chooses HEAD' ' @@ -61,4 +63,8 @@ test_expect_success 'clone -b with bogus branch' ' test_must_fail git clone -b bogus parent clone-bogus ' +test_expect_success 'clone -b not allowed with empty repos' ' + test_must_fail git clone -b branch empty clone-branch-empty +' + 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-helpers.sh deleted file mode 100755 index e7dc668cef..0000000000 --- a/t/t5800-remote-helpers.sh +++ /dev/null @@ -1,148 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2010 Sverre Rabbelier -# - -test_description='Test remote-helper import and export commands' - -. ./test-lib.sh - -if ! test_have_prereq PYTHON ; then - skip_all='skipping git-remote-hg tests, python not available' - test_done -fi - -"$PYTHON_PATH" -c ' -import sys -if sys.hexversion < 0x02040000: - sys.exit(1) -' || { - skip_all='skipping git-remote-hg tests, python version < 2.4' - test_done -} - -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 --bare server/.git && - git clone server public && - (cd public && - echo content >file && - git add file && - git commit -m one && - git push origin master) -' - -test_expect_success 'cloning from local repo' ' - git clone "testgit::${PWD}/server" localclone && - test_cmp public/file localclone/file -' - -test_expect_success 'cloning from remote repo' ' - git clone "testgit::file://${PWD}/server" clone && - test_cmp public/file clone/file -' - -test_expect_success 'create new commit on remote' ' - (cd public && - echo content >>file && - git commit -a -m two && - git push) -' - -test_expect_success 'pulling from local repo' ' - (cd localclone && git pull) && - test_cmp public/file localclone/file -' - -test_expect_success 'pulling from remote remote' ' - (cd clone && git pull) && - test_cmp public/file clone/file -' - -test_expect_success 'pushing to local repo' ' - (cd localclone && - echo content >>file && - git commit -a -m three && - git push) && - compare_refs localclone HEAD server HEAD -' - -# Generally, skip this test. It demonstrates a now-fixed race in -# git-remote-testgit, but is too slow to leave in for general use. -: test_expect_success 'racily pushing to local repo' ' - test_when_finished "rm -rf server2 localclone2" && - cp -R server server2 && - git clone "testgit::${PWD}/server2" localclone2 && - (cd localclone2 && - echo content >>file && - git commit -a -m three && - GIT_REMOTE_TESTGIT_SLEEPY=2 git push) && - compare_refs localclone2 HEAD server2 HEAD -' - -test_expect_success 'synch with changes from localclone' ' - (cd clone && - git pull) -' - -test_expect_success 'pushing remote local repo' ' - (cd clone && - echo content >>file && - git commit -a -m four && - git push) && - compare_refs clone HEAD server HEAD -' - -test_expect_success 'fetch new branch' ' - (cd public && - git checkout -b new && - echo content >>file && - git commit -a -m five && - git push origin new - ) && - (cd localclone && - git fetch origin new - ) && - compare_refs public HEAD localclone FETCH_HEAD -' - -test_expect_success 'fetch multiple branches' ' - (cd localclone && - git fetch - ) && - compare_refs server master localclone refs/remotes/origin/master && - compare_refs server new localclone refs/remotes/origin/new -' - -test_expect_success 'push when remote has extra refs' ' - (cd clone && - echo content >>file && - git commit -a -m six && - git push - ) && - compare_refs clone master server master -' - -test_expect_success 'push new branch by name' ' - (cd clone && - git checkout -b new-name && - echo content >>file && - git commit -a -m seven && - git push origin new-name - ) && - compare_refs clone HEAD server refs/heads/new-name -' - -test_expect_failure 'push new branch with old:new refspec' ' - (cd clone && - git push origin new-name:new-refspec - ) && - compare_refs clone HEAD server refs/heads/new-refspec -' - -test_done diff --git a/t/t5801-remote-helpers.sh b/t/t5801-remote-helpers.sh new file mode 100755 index 0000000000..25fd2e7f46 --- /dev/null +++ b/t/t5801-remote-helpers.sh @@ -0,0 +1,253 @@ +#!/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 'forced push' ' + (cd local && + git checkout -b force-test && + echo content >> file && + git commit -a -m eight && + git push origin force-test && + echo content >> file && + git commit -a --amend -m eight-modified && + git push --force origin force-test + ) && + compare_refs local refs/heads/force-test server refs/heads/force-test +' + +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 disabled by no-private-update' ' + (cd local && + echo more-update >>file && + git commit -a -m more-update && + git rev-parse --verify testgit/origin/heads/update >expect && + GIT_REMOTE_TESTGIT_NO_PRIVATE_UPDATE=t git push origin update && + 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' ' + (cd local && + test_must_fail env GIT_REMOTE_TESTGIT_FAILURE=1 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/t5802-connect-helper.sh b/t/t5802-connect-helper.sh new file mode 100755 index 0000000000..878faf2b63 --- /dev/null +++ b/t/t5802-connect-helper.sh @@ -0,0 +1,72 @@ +#!/bin/sh + +test_description='ext::cmd remote "connect" helper' +. ./test-lib.sh + +test_expect_success setup ' + test_tick && + git commit --allow-empty -m initial && + test_tick && + git commit --allow-empty -m second && + test_tick && + git commit --allow-empty -m third && + test_tick && + git tag -a -m "tip three" three && + + test_tick && + git commit --allow-empty -m fourth +' + +test_expect_success clone ' + cmd=$(echo "echo >&2 ext::sh invoked && %S .." | sed -e "s/ /% /g") && + git clone "ext::sh -c %S% ." dst && + git for-each-ref refs/heads/ refs/tags/ >expect && + ( + cd dst && + git config remote.origin.url "ext::sh -c $cmd" && + git for-each-ref refs/heads/ refs/tags/ + ) >actual && + test_cmp expect actual +' + +test_expect_success 'update following tag' ' + test_tick && + git commit --allow-empty -m fifth && + test_tick && + git tag -a -m "tip five" five && + git for-each-ref refs/heads/ refs/tags/ >expect && + ( + cd dst && + git pull && + git for-each-ref refs/heads/ refs/tags/ >../actual + ) && + test_cmp expect actual +' + +test_expect_success 'update backfilled tag' ' + test_tick && + git commit --allow-empty -m sixth && + test_tick && + git tag -a -m "tip two" two three^1 && + git for-each-ref refs/heads/ refs/tags/ >expect && + ( + cd dst && + git pull && + git for-each-ref refs/heads/ refs/tags/ >../actual + ) && + test_cmp expect actual +' + +test_expect_success 'update backfilled tag without primary transfer' ' + test_tick && + git tag -a -m "tip one " one two^1 && + git for-each-ref refs/heads/ refs/tags/ >expect && + ( + cd dst && + git pull && + git for-each-ref refs/heads/ refs/tags/ >../actual + ) && + test_cmp expect actual +' + +test_done diff --git a/t/t6000-rev-list-misc.sh b/t/t6000-rev-list-misc.sh index b10685af4e..3794e4ceaf 100755 --- a/t/t6000-rev-list-misc.sh +++ b/t/t6000-rev-list-misc.sh @@ -48,4 +48,29 @@ test_expect_success 'rev-list --objects with pathspecs and copied files' ' ! grep one output ' +test_expect_success 'rev-list A..B and rev-list ^A B are the same' ' + git commit --allow-empty -m another && + git tag -a -m "annotated" v1.0 && + git rev-list --objects ^v1.0^ v1.0 >expect && + git rev-list --objects v1.0^..v1.0 >actual && + test_cmp expect actual +' + +test_expect_success 'propagate uninteresting flag down correctly' ' + git rev-list --objects ^HEAD^{tree} HEAD^{tree} >actual && + >expect && + test_cmp expect actual +' + +test_expect_success 'symleft flag bit is propagated down from tag' ' + git log --format="%m %s" --left-right v1.0...master >actual && + cat >expect <<-\EOF && + > two + > one + < another + < that + EOF + test_cmp expect actual +' + 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..9d9d9de08e 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,152 @@ 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)' ' + test_terminal env TERM=vt100 \ + 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 +314,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/t6010-merge-base.sh b/t/t6010-merge-base.sh index f80bba871c..39b3238da2 100755 --- a/t/t6010-merge-base.sh +++ b/t/t6010-merge-base.sh @@ -230,4 +230,71 @@ test_expect_success 'criss-cross merge-base for octopus-step' ' test_cmp expected.sorted actual.sorted ' +test_expect_success 'using reflog to find the fork point' ' + git reset --hard && + git checkout -b base $E && + + ( + for count in 1 2 3 + do + git commit --allow-empty -m "Base commit #$count" && + git rev-parse HEAD >expect$count && + git checkout -B derived && + git commit --allow-empty -m "Derived #$count" && + git rev-parse HEAD >derived$count && + git checkout -B base $E || exit 1 + done + + for count in 1 2 3 + do + git merge-base --fork-point base $(cat derived$count) >actual && + test_cmp expect$count actual || exit 1 + done + + ) && + # check that we correctly default to HEAD + git checkout derived && + git merge-base --fork-point base >actual && + test_cmp expect3 actual +' + +test_expect_success 'merge-base --octopus --all for complex tree' ' + # Best common ancestor for JE, JAA and JDD is JC + # JE + # / | + # / | + # / | + # JAA / | + # |\ / | + # | \ | JDD | + # | \ |/ | | + # | JC JD | + # | | /| | + # | |/ | | + # JA | | | + # |\ /| | | + # X JB | X X + # \ \ | / / + # \__\|/___/ + # J + test_commit J && + test_commit JB && + git reset --hard J && + test_commit JC && + git reset --hard J && + test_commit JTEMP1 && + test_merge JA JB && + test_merge JAA JC && + git reset --hard J && + test_commit JTEMP2 && + test_merge JD JB && + test_merge JDD JC && + git reset --hard J && + test_commit JTEMP3 && + test_merge JE JC && + git rev-parse JC >expected && + git merge-base --all --octopus JAA JDD JE >actual && + test_cmp expected actual +' + test_done diff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh index bbb0581f88..e51eb41f4b 100755 --- a/t/t6011-rev-list-with-bad-commit.sh +++ b/t/t6011-rev-list-with-bad-commit.sh @@ -37,7 +37,7 @@ test_expect_success 'verify number of revisions' \ test_expect_success 'corrupt second commit object' \ ' - "$PERL_PATH" -i.bak -pe "s/second commit/socond commit/" .git/objects/pack/*.pack && + perl -i.bak -pe "s/second commit/socond commit/" .git/objects/pack/*.pack && test_must_fail git fsck --full ' diff --git a/t/t6012-rev-list-simplify.sh b/t/t6012-rev-list-simplify.sh index 839ad97b79..fde5e712eb 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,35 @@ 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_expect_success '--full-diff is not affected by --parents' ' + git log -p --pretty="%H" --full-diff -- file >expected && + git log -p --pretty="%H" --full-diff --parents -- file >actual && + test_cmp expected actual +' + test_done diff --git a/t/t6013-rev-list-reverse-parents.sh b/t/t6013-rev-list-reverse-parents.sh index 892a537989..59fc2f06e0 100755 --- a/t/t6013-rev-list-reverse-parents.sh +++ b/t/t6013-rev-list-reverse-parents.sh @@ -25,7 +25,7 @@ test_expect_success 'set up --reverse example' ' test_expect_success '--reverse --parents --full-history combines correctly' ' git rev-list --parents --full-history master -- foo | - "$PERL_PATH" -e "print reverse <>" > expected && + perl -e "print reverse <>" > expected && git rev-list --reverse --parents --full-history master -- foo \ > actual && test_cmp actual expected @@ -33,7 +33,7 @@ test_expect_success '--reverse --parents --full-history combines correctly' ' test_expect_success '--boundary does too' ' git rev-list --boundary --parents --full-history master ^root -- foo | - "$PERL_PATH" -e "print reverse <>" > expected && + perl -e "print reverse <>" > expected && git rev-list --boundary --reverse --parents --full-history \ master ^root -- foo > actual && test_cmp actual expected diff --git a/t/t6018-rev-list-glob.sh b/t/t6018-rev-list-glob.sh index f00cebff3e..d00f7db868 100755 --- a/t/t6018-rev-list-glob.sh +++ b/t/t6018-rev-list-glob.sh @@ -129,6 +129,18 @@ test_expect_success 'rev-parse --remotes=foo' ' ' +test_expect_success 'rev-parse --exclude with --branches' ' + compare rev-parse "--exclude=*/* --branches" "master someref subspace-x" +' + +test_expect_success 'rev-parse --exclude with --all' ' + compare rev-parse "--exclude=refs/remotes/* --all" "--branches --tags" +' + +test_expect_success 'rev-parse accumulates multiple --exclude' ' + compare rev-parse "--exclude=refs/remotes/* --exclude=refs/tags/* --all" --branches +' + test_expect_success 'rev-list --glob=refs/heads/subspace/*' ' compare rev-list "subspace/one subspace/two" "--glob=refs/heads/subspace/*" @@ -231,6 +243,48 @@ test_expect_success 'rev-list --remotes=foo' ' ' +test_expect_success 'rev-list --exclude with --branches' ' + compare rev-list "--exclude=*/* --branches" "master someref subspace-x" +' + +test_expect_success 'rev-list --exclude with --all' ' + compare rev-list "--exclude=refs/remotes/* --all" "--branches --tags" +' + +test_expect_success 'rev-list accumulates multiple --exclude' ' + compare rev-list "--exclude=refs/remotes/* --exclude=refs/tags/* --all" --branches +' + + +# "git rev-list<ENTER>" is likely to be a bug in the calling script and may +# deserve an error message, but do cases where set of refs programatically +# given using globbing and/or --stdin need to fail with the same error, or +# are we better off reporting a success with no output? The following few +# tests document the current behaviour to remind us that we might want to +# think about this issue. + +test_expect_failure 'rev-list may want to succeed with empty output on no input (1)' ' + >expect && + git rev-list --stdin <expect >actual && + test_cmp expect actual +' + +test_expect_failure 'rev-list may want to succeed with empty output on no input (2)' ' + >expect && + git rev-list --exclude=* --all >actual && + test_cmp expect actual +' + +test_expect_failure 'rev-list may want to succeed with empty output on no input (3)' ' + ( + test_create_repo empty && + cd empty && + >expect && + git rev-list --all >actual && + test_cmp expect actual + ) +' + test_expect_success 'shortlog accepts --glob/--tags/--remotes' ' compare shortlog "subspace/one subspace/two" --branches=subspace && 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/t6022-merge-rename.sh b/t/t6022-merge-rename.sh index c680f789a7..a89dfbef08 100755 --- a/t/t6022-merge-rename.sh +++ b/t/t6022-merge-rename.sh @@ -259,7 +259,7 @@ test_expect_success 'setup for rename + d/f conflicts' ' printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >sub/file && echo foo >dir/file-in-the-way && git add -A && - git commit -m "Common commmit" && + git commit -m "Common commit" && echo 11 >>sub/file && echo more >>dir/file-in-the-way && @@ -439,7 +439,7 @@ test_expect_success 'setup both rename source and destination involved in D/F co mkdir one && echo stuff >one/file && git add -A && - git commit -m "Common commmit" && + git commit -m "Common commit" && git mv one/file destdir && git commit -m "Renamed to destdir" && @@ -479,7 +479,7 @@ test_expect_success 'setup pair rename to parent of other (D/F conflicts)' ' echo stuff >one/file && echo other >two/file && git add -A && - git commit -m "Common commmit" && + git commit -m "Common commit" && git rm -rf one && git mv two/file one && @@ -539,7 +539,7 @@ test_expect_success 'setup rename of one file to two, with directories in the wa echo stuff >original && git add -A && - git commit -m "Common commmit" && + git commit -m "Common commit" && mkdir two && >two/file && @@ -583,7 +583,7 @@ test_expect_success 'setup rename one file to two; directories moving out of the mkdir one two && touch one/file two/file && git add -A && - git commit -m "Common commmit" && + git commit -m "Common commit" && git rm -rf one && git mv original one && @@ -618,7 +618,7 @@ test_expect_success 'setup avoid unnecessary update, normal rename' ' printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >original && git add -A && - git commit -m "Common commmit" && + git commit -m "Common commit" && git mv original rename && echo 11 >>rename && @@ -649,7 +649,7 @@ test_expect_success 'setup to test avoiding unnecessary update, with D/F conflic mkdir df && printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >df/file && git add -A && - git commit -m "Common commmit" && + git commit -m "Common commit" && git mv df/file temp && rm -rf df && 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/t6031-merge-recursive.sh b/t/t6031-merge-recursive.sh index 1cd649e245..a953f1b55c 100755 --- a/t/t6031-merge-recursive.sh +++ b/t/t6031-merge-recursive.sh @@ -2,7 +2,6 @@ test_description='merge-recursive: handle file mode' . ./test-lib.sh -. "$TEST_DIRECTORY"/lib-prereq-FILEMODE.sh test_expect_success 'mode change in one branch: keep changed version' ' : >file1 && 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/t6040-tracking-info.sh b/t/t6040-tracking-info.sh index ec2b516c3f..7ac8fd06c3 100755 --- a/t/t6040-tracking-info.sh +++ b/t/t6040-tracking-info.sh @@ -28,18 +28,25 @@ test_expect_success setup ' git reset --hard HEAD^ && git checkout -b b4 origin && advance e && - advance f + advance f && + git checkout -b brokenbase origin && + git checkout -b b5 --track brokenbase && + advance g && + git branch -d brokenbase && + git checkout -b b6 origin ) && git checkout -b follower --track master && - advance g + advance h ' -script='s/^..\(b.\)[ 0-9a-f]*\[\([^]]*\)\].*/\1 \2/p' +script='s/^..\(b.\) *[0-9a-f]* \(.*\)$/\1 \2/p' cat >expect <<\EOF -b1 ahead 1, behind 1 -b2 ahead 1, behind 1 -b3 behind 1 -b4 ahead 2 +b1 [ahead 1, behind 1] d +b2 [ahead 1, behind 1] d +b3 [behind 1] b +b4 [ahead 2] f +b5 g +b6 c EOF test_expect_success 'branch -v' ' @@ -52,10 +59,12 @@ test_expect_success 'branch -v' ' ' cat >expect <<\EOF -b1 origin/master: ahead 1, behind 1 -b2 origin/master: ahead 1, behind 1 -b3 origin/master: behind 1 -b4 origin/master: ahead 2 +b1 [origin/master: ahead 1, behind 1] d +b2 [origin/master: ahead 1, behind 1] d +b3 [origin/master: behind 1] b +b4 [origin/master: ahead 2] f +b5 [brokenbase: gone] g +b6 [origin/master] c EOF test_expect_success 'branch -vv' ' @@ -67,7 +76,7 @@ test_expect_success 'branch -vv' ' test_i18ncmp expect actual ' -test_expect_success 'checkout' ' +test_expect_success 'checkout (diverged from upstream)' ' ( cd test && git checkout b1 ) >actual && @@ -80,7 +89,22 @@ test_expect_success 'checkout with local tracked branch' ' test_i18ngrep "is ahead of" actual ' -test_expect_success 'status' ' +test_expect_success 'checkout (upstream is gone)' ' + ( + cd test && + git checkout b5 + ) >actual && + test_i18ngrep "is based on .*, but the upstream is gone." actual +' + +test_expect_success 'checkout (up-to-date with upstream)' ' + ( + cd test && git checkout b6 + ) >actual && + test_i18ngrep "Your branch is up-to-date with .origin/master" actual +' + +test_expect_success 'status (diverged from upstream)' ' ( cd test && git checkout b1 >/dev/null && @@ -90,6 +114,65 @@ test_expect_success 'status' ' test_i18ngrep "have 1 and 1 different" actual ' +test_expect_success 'status (upstream is gone)' ' + ( + cd test && + git checkout b5 >/dev/null && + # reports nothing to commit + test_must_fail git commit --dry-run + ) >actual && + test_i18ngrep "is based on .*, but the upstream is gone." actual +' + +test_expect_success 'status (up-to-date with upstream)' ' + ( + cd test && + git checkout b6 >/dev/null && + # reports nothing to commit + test_must_fail git commit --dry-run + ) >actual && + test_i18ngrep "Your branch is up-to-date with .origin/master" actual +' + +cat >expect <<\EOF +## b1...origin/master [ahead 1, behind 1] +EOF + +test_expect_success 'status -s -b (diverged from upstream)' ' + ( + cd test && + git checkout b1 >/dev/null && + git status -s -b | head -1 + ) >actual && + test_i18ncmp expect actual +' + +cat >expect <<\EOF +## b5...brokenbase [gone] +EOF + +test_expect_success 'status -s -b (upstream is gone)' ' + ( + cd test && + git checkout b5 >/dev/null && + git status -s -b | head -1 + ) >actual && + test_i18ncmp expect actual +' + +cat >expect <<\EOF +## b6...origin/master +EOF + +test_expect_success 'status -s -b (up-to-date with upstream)' ' + ( + cd test && + git checkout b6 >/dev/null && + git status -s -b | head -1 + ) >actual && + test_i18ncmp expect actual +' + test_expect_success 'fail to track lightweight tags' ' git checkout master && git tag light && diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh index decdc33c52..719a11673b 100755 --- a/t/t6050-replace.sh +++ b/t/t6050-replace.sh @@ -122,9 +122,9 @@ test_expect_success '"git replace" listing and deleting' ' test "$HASH2" = "$(git replace -l)" && test "$HASH2" = "$(git replace)" && aa=${HASH2%??????????????????????????????????????} && - test "$HASH2" = "$(git replace -l "$aa*")" && + test "$HASH2" = "$(git replace --list "$aa*")" && test_must_fail git replace -d $R && - test_must_fail git replace -d && + test_must_fail git replace --delete && test_must_fail git replace -l -d $HASH2 && git replace -d $HASH2 && git show $HASH2 | grep "A U Thor" && @@ -147,7 +147,7 @@ test_expect_success '"git replace" resolves sha1' ' 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_must_fail git replace --force && test "$HASH2" = "$(git replace)" ' @@ -263,4 +263,65 @@ test_expect_success 'not just commits' ' test_cmp file.replaced file ' +test_expect_success 'replaced and replacement objects must be of the same type' ' + test_must_fail git replace mytag $HASH1 && + test_must_fail git replace HEAD^{tree} HEAD~1 && + BLOB=$(git rev-parse :file) && + test_must_fail git replace HEAD^ $BLOB +' + +test_expect_success '-f option bypasses the type check' ' + git replace -f mytag $HASH1 && + git replace --force HEAD^{tree} HEAD~1 && + git replace -f HEAD^ $BLOB +' + +test_expect_success 'git cat-file --batch works on replace objects' ' + git replace | grep $PARA3 && + echo $PARA3 | git cat-file --batch +' + +test_expect_success 'test --format bogus' ' + test_must_fail git replace --format bogus >/dev/null 2>&1 +' + +test_expect_success 'test --format short' ' + git replace --format=short >actual && + git replace >expected && + test_cmp expected actual +' + +test_expect_success 'test --format medium' ' + H1=$(git --no-replace-objects rev-parse HEAD~1) && + HT=$(git --no-replace-objects rev-parse HEAD^{tree}) && + MYTAG=$(git --no-replace-objects rev-parse mytag) && + { + echo "$H1 -> $BLOB" && + echo "$BLOB -> $REPLACED" && + echo "$HT -> $H1" && + echo "$PARA3 -> $S" && + echo "$MYTAG -> $HASH1" + } | sort >expected && + git replace -l --format medium | sort > actual && + test_cmp expected actual +' + +test_expect_success 'test --format long' ' + { + echo "$H1 (commit) -> $BLOB (blob)" && + echo "$BLOB (blob) -> $REPLACED (blob)" && + echo "$HT (tree) -> $H1 (commit)" && + echo "$PARA3 (commit) -> $S (commit)" && + echo "$MYTAG (tag) -> $HASH1 (commit)" + } | sort >expected && + git replace --format=long | sort > actual && + test_cmp expected actual +' + +test_expect_success 'replace ref cleanup' ' + test -n "$(git replace)" && + git replace -d $(git replace) && + test -z "$(git replace)" +' + test_done diff --git a/t/t6101-rev-parse-parents.sh b/t/t6101-rev-parse-parents.sh index e673c25e94..10b1452766 100755 --- a/t/t6101-rev-parse-parents.sh +++ b/t/t6101-rev-parse-parents.sh @@ -6,39 +6,100 @@ test_description='Test git rev-parse with different parent options' . ./test-lib.sh -. "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions - -date >path0 -git update-index --add path0 -save_tag tree git write-tree -hide_error save_tag start unique_commit "start" tree -save_tag second unique_commit "second" tree -p start -hide_error save_tag start2 unique_commit "start2" tree -save_tag two_parents unique_commit "next" tree -p second -p start2 -save_tag final unique_commit "final" tree -p two_parents - -test_expect_success 'start is valid' 'git rev-parse start | grep "^[0-9a-f]\{40\}$"' -test_expect_success 'start^0' "test $(cat .git/refs/tags/start) = $(git rev-parse start^0)" -test_expect_success 'start^1 not valid' "if git rev-parse --verify start^1; then false; else :; fi" -test_expect_success 'second^1 = second^' "test $(git rev-parse second^1) = $(git rev-parse second^)" -test_expect_success 'final^1^1^1' "test $(git rev-parse start) = $(git rev-parse final^1^1^1)" -test_expect_success 'final^1^1^1 = final^^^' "test $(git rev-parse final^1^1^1) = $(git rev-parse final^^^)" -test_expect_success 'final^1^2' "test $(git rev-parse start2) = $(git rev-parse final^1^2)" -test_expect_success 'final^1^2 != final^1^1' "test $(git rev-parse final^1^2) != $(git rev-parse final^1^1)" -test_expect_success 'final^1^3 not valid' "if git rev-parse --verify final^1^3; then false; else :; fi" -test_expect_success '--verify start2^1' 'test_must_fail git rev-parse --verify start2^1' -test_expect_success '--verify start2^0' 'git rev-parse --verify start2^0' -test_expect_success 'final^1^@ = final^1^1 final^1^2' "test \"$(git rev-parse final^1^@)\" = \"$(git rev-parse final^1^1 final^1^2)\"" -test_expect_success 'final^1^! = final^1 ^final^1^1 ^final^1^2' "test \"$(git rev-parse final^1^\!)\" = \"$(git rev-parse final^1 ^final^1^1 ^final^1^2)\"" - -test_expect_success 'repack for next test' 'git repack -a -d' + +test_cmp_rev_output () { + git rev-parse --verify "$1" >expect && + eval "$2" >actual && + test_cmp expect actual +} + +test_expect_success 'setup' ' + test_commit start && + test_commit second && + git checkout --orphan tmp && + test_commit start2 && + git checkout master && + git merge -m next start2 && + test_commit final && + + test_seq 40 | + while read i + do + git checkout --orphan "b$i" && + test_tick && + git commit --allow-empty -m "$i" && + commit=$(git rev-parse --verify HEAD) && + printf "$commit " >>.git/info/grafts + done +' + +test_expect_success 'start is valid' ' + git rev-parse start | grep "^[0-9a-f]\{40\}$" +' + +test_expect_success 'start^0' ' + test_cmp_rev_output tags/start "git rev-parse start^0" +' + +test_expect_success 'start^1 not valid' ' + test_must_fail git rev-parse --verify start^1 +' + +test_expect_success 'second^1 = second^' ' + test_cmp_rev_output second^ "git rev-parse second^1" +' + +test_expect_success 'final^1^1^1' ' + test_cmp_rev_output start "git rev-parse final^1^1^1" +' + +test_expect_success 'final^1^1^1 = final^^^' ' + test_cmp_rev_output final^^^ "git rev-parse final^1^1^1" +' + +test_expect_success 'final^1^2' ' + test_cmp_rev_output start2 "git rev-parse final^1^2" +' + +test_expect_success 'final^1^2 != final^1^1' ' + test $(git rev-parse final^1^2) != $(git rev-parse final^1^1) +' + +test_expect_success 'final^1^3 not valid' ' + test_must_fail git rev-parse --verify final^1^3 +' + +test_expect_success '--verify start2^1' ' + test_must_fail git rev-parse --verify start2^1 +' + +test_expect_success '--verify start2^0' ' + git rev-parse --verify start2^0 +' + +test_expect_success 'final^1^@ = final^1^1 final^1^2' ' + git rev-parse final^1^1 final^1^2 >expect && + git rev-parse final^1^@ >actual && + test_cmp expect actual +' + +test_expect_success 'final^1^! = final^1 ^final^1^1 ^final^1^2' ' + git rev-parse final^1 ^final^1^1 ^final^1^2 >expect && + git rev-parse final^1^! >actual && + test_cmp expect actual +' + +test_expect_success 'large graft octopus' ' + test_cmp_rev_output b31 "git rev-parse --verify b1^30" +' + +test_expect_success 'repack for next test' ' + git repack -a -d +' + test_expect_success 'short SHA-1 works' ' - start=`git rev-parse --verify start` && - echo $start && - abbrv=`echo $start | sed s/.\$//` && - echo $abbrv && - abbrv=`git rev-parse --verify $abbrv` && - echo $abbrv && - test $start = $abbrv' + start=$(git rev-parse --verify start) && + test_cmp_rev_output start "git rev-parse ${start%?}" +' test_done 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..658353277e --- /dev/null +++ b/t/t6130-pathspec-noglob.sh @@ -0,0 +1,162 @@ +#!/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 'star pathspec globs' ' + cat >expect <<-\EOF && + bracket + star + vanilla + EOF + git log --format=%s -- ":(glob)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 'bracket pathspec globs and matches literal brackets' ' + cat >expect <<-\EOF && + bracket + vanilla + EOF + git log --format=%s -- ":(glob)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 (vanilla)' ' + echo vanilla >expect && + git log --format=%s -- ":(literal)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 (star)' ' + echo star >expect && + git log --format=%s -- ":(literal)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 option matches literally (bracket)' ' + echo bracket >expect && + git log --format=%s -- ":(literal)f[o][o]" >actual && + test_cmp expect actual +' + +test_expect_success 'no-glob option disables :(literal)' ' + : >expect && + git --literal-pathspecs log --format=%s -- ":(literal)foo" >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_expect_success 'blame takes global pathspec flags' ' + git --literal-pathspecs blame -- foo && + git --icase-pathspecs blame -- foo && + git --glob-pathspecs blame -- foo && + git --noglob-pathspecs blame -- foo +' + +test_expect_success 'setup xxx/bar' ' + mkdir xxx && + test_commit xxx xxx/bar +' + +test_expect_success '**/ works with :(glob)' ' + cat >expect <<-\EOF && + xxx + unrelated + EOF + git log --format=%s -- ":(glob)**/bar" >actual && + test_cmp expect actual +' + +test_expect_success '**/ does not work with --noglob-pathspecs' ' + : >expect && + git --noglob-pathspecs log --format=%s -- "**/bar" >actual && + test_cmp expect actual +' + +test_expect_success '**/ works with :(glob) and --noglob-pathspecs' ' + cat >expect <<-\EOF && + xxx + unrelated + EOF + git --noglob-pathspecs log --format=%s -- ":(glob)**/bar" >actual && + test_cmp expect actual +' + +test_expect_success '**/ works with --glob-pathspecs' ' + cat >expect <<-\EOF && + xxx + unrelated + EOF + git --glob-pathspecs log --format=%s -- "**/bar" >actual && + test_cmp expect actual +' + +test_expect_success '**/ does not work with :(literal) and --glob-pathspecs' ' + : >expect && + git --glob-pathspecs log --format=%s -- ":(literal)**/bar" >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t6131-pathspec-icase.sh b/t/t6131-pathspec-icase.sh new file mode 100755 index 0000000000..39fc3f6769 --- /dev/null +++ b/t/t6131-pathspec-icase.sh @@ -0,0 +1,109 @@ +#!/bin/sh + +test_description='test case insensitive pathspec limiting' +. ./test-lib.sh + +if test_have_prereq CASE_INSENSITIVE_FS +then + skip_all='skipping case sensitive tests - case insensitive file system' + test_done +fi + +test_expect_success 'create commits with glob characters' ' + test_commit bar bar && + test_commit bAr bAr && + test_commit BAR BAR && + mkdir foo && + test_commit foo/bar foo/bar && + test_commit foo/bAr foo/bAr && + test_commit foo/BAR foo/BAR && + mkdir fOo && + test_commit fOo/bar fOo/bar && + test_commit fOo/bAr fOo/bAr && + test_commit fOo/BAR fOo/BAR && + mkdir FOO && + test_commit FOO/bar FOO/bar && + test_commit FOO/bAr FOO/bAr && + test_commit FOO/BAR FOO/BAR +' + +test_expect_success 'tree_entry_interesting matches bar' ' + echo bar >expect && + git log --format=%s -- "bar" >actual && + test_cmp expect actual +' + +test_expect_success 'tree_entry_interesting matches :(icase)bar' ' + cat <<-EOF >expect && + BAR + bAr + bar + EOF + git log --format=%s -- ":(icase)bar" >actual && + test_cmp expect actual +' + +test_expect_success 'tree_entry_interesting matches :(icase)bar with prefix' ' + cat <<-EOF >expect && + fOo/BAR + fOo/bAr + fOo/bar + EOF + ( cd fOo && git log --format=%s -- ":(icase)bar" ) >actual && + test_cmp expect actual +' + +test_expect_success 'tree_entry_interesting matches :(icase)bar with empty prefix' ' + cat <<-EOF >expect && + FOO/BAR + FOO/bAr + FOO/bar + fOo/BAR + fOo/bAr + fOo/bar + foo/BAR + foo/bAr + foo/bar + EOF + ( cd fOo && git log --format=%s -- ":(icase)../foo/bar" ) >actual && + test_cmp expect actual +' + +test_expect_success 'match_pathspec matches :(icase)bar' ' + cat <<-EOF >expect && + BAR + bAr + bar + EOF + git ls-files ":(icase)bar" >actual && + test_cmp expect actual +' + +test_expect_success 'match_pathspec matches :(icase)bar with prefix' ' + cat <<-EOF >expect && + fOo/BAR + fOo/bAr + fOo/bar + EOF + ( cd fOo && git ls-files --full-name ":(icase)bar" ) >actual && + test_cmp expect actual +' + +test_expect_success 'match_pathspec matches :(icase)bar with empty prefix' ' + cat <<-EOF >expect && + bar + fOo/BAR + fOo/bAr + fOo/bar + EOF + ( cd fOo && git ls-files --full-name ":(icase)bar" ../bar ) >actual && + test_cmp expect actual +' + +test_expect_success '"git diff" can take magic :(icase) pathspec' ' + echo FOO/BAR >expect && + git diff --name-only HEAD^ HEAD -- ":(icase)foo/bar" >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t6132-pathspec-exclude.sh b/t/t6132-pathspec-exclude.sh new file mode 100755 index 0000000000..62049be0c7 --- /dev/null +++ b/t/t6132-pathspec-exclude.sh @@ -0,0 +1,184 @@ +#!/bin/sh + +test_description='test case exclude pathspec' + +. ./test-lib.sh + +test_expect_success 'setup' ' + for p in file sub/file sub/sub/file sub/file2 sub/sub/sub/file sub2/file; do + if echo $p | grep /; then + mkdir -p `dirname $p` + fi && + : >$p && + git add $p && + git commit -m $p + done && + git log --oneline --format=%s >actual && + cat <<EOF >expect && +sub2/file +sub/sub/sub/file +sub/file2 +sub/sub/file +sub/file +file +EOF + test_cmp expect actual +' + +test_expect_success 'exclude only should error out' ' + test_must_fail git log --oneline --format=%s -- ":(exclude)sub" +' + +test_expect_success 't_e_i() exclude sub' ' + git log --oneline --format=%s -- . ":(exclude)sub" >actual + cat <<EOF >expect && +sub2/file +file +EOF + test_cmp expect actual +' + +test_expect_success 't_e_i() exclude sub/sub/file' ' + git log --oneline --format=%s -- . ":(exclude)sub/sub/file" >actual + cat <<EOF >expect && +sub2/file +sub/sub/sub/file +sub/file2 +sub/file +file +EOF + test_cmp expect actual +' + +test_expect_success 't_e_i() exclude sub using mnemonic' ' + git log --oneline --format=%s -- . ":!sub" >actual + cat <<EOF >expect && +sub2/file +file +EOF + test_cmp expect actual +' + +test_expect_success 't_e_i() exclude :(icase)SUB' ' + git log --oneline --format=%s -- . ":(exclude,icase)SUB" >actual + cat <<EOF >expect && +sub2/file +file +EOF + test_cmp expect actual +' + +test_expect_success 't_e_i() exclude sub2 from sub' ' + ( + cd sub && + git log --oneline --format=%s -- :/ ":/!sub2" >actual + cat <<EOF >expect && +sub/sub/sub/file +sub/file2 +sub/sub/file +sub/file +file +EOF + test_cmp expect actual + ) +' + +test_expect_success 't_e_i() exclude sub/*file' ' + git log --oneline --format=%s -- . ":(exclude)sub/*file" >actual + cat <<EOF >expect && +sub2/file +sub/file2 +file +EOF + test_cmp expect actual +' + +test_expect_success 't_e_i() exclude :(glob)sub/*/file' ' + git log --oneline --format=%s -- . ":(exclude,glob)sub/*/file" >actual + cat <<EOF >expect && +sub2/file +sub/sub/sub/file +sub/file2 +sub/file +file +EOF + test_cmp expect actual +' + +test_expect_success 'm_p_d() exclude sub' ' + git ls-files -- . ":(exclude)sub" >actual + cat <<EOF >expect && +file +sub2/file +EOF + test_cmp expect actual +' + +test_expect_success 'm_p_d() exclude sub/sub/file' ' + git ls-files -- . ":(exclude)sub/sub/file" >actual + cat <<EOF >expect && +file +sub/file +sub/file2 +sub/sub/sub/file +sub2/file +EOF + test_cmp expect actual +' + +test_expect_success 'm_p_d() exclude sub using mnemonic' ' + git ls-files -- . ":!sub" >actual + cat <<EOF >expect && +file +sub2/file +EOF + test_cmp expect actual +' + +test_expect_success 'm_p_d() exclude :(icase)SUB' ' + git ls-files -- . ":(exclude,icase)SUB" >actual + cat <<EOF >expect && +file +sub2/file +EOF + test_cmp expect actual +' + +test_expect_success 'm_p_d() exclude sub2 from sub' ' + ( + cd sub && + git ls-files -- :/ ":/!sub2" >actual + cat <<EOF >expect && +../file +file +file2 +sub/file +sub/sub/file +EOF + test_cmp expect actual + ) +' + +test_expect_success 'm_p_d() exclude sub/*file' ' + git ls-files -- . ":(exclude)sub/*file" >actual + cat <<EOF >expect && +file +sub/file2 +sub2/file +EOF + test_cmp expect actual +' + +test_expect_success 'm_p_d() exclude :(glob)sub/*/file' ' + git ls-files -- . ":(exclude,glob)sub/*/file" >actual + cat <<EOF >expect && +file +sub/file +sub/file2 +sub/sub/sub/file +sub2/file +EOF + 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/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh index 752f5cb7d0..bda354c1c4 100755 --- a/t/t6300-for-each-ref.sh +++ b/t/t6300-for-each-ref.sh @@ -18,16 +18,13 @@ setdate_and_increment () { export GIT_COMMITTER_DATE GIT_AUTHOR_DATE } -test_expect_success 'Create sample commit with known timestamp' ' +test_expect_success setup ' setdate_and_increment && echo "Using $datestamp" > one && git add one && git commit -m "Initial" && setdate_and_increment && - git tag -a -m "Tagging at $datestamp" testtag -' - -test_expect_success 'Create upstream config' ' + git tag -a -m "Tagging at $datestamp" testtag && git update-ref refs/remotes/origin/master master && git remote add origin nowhere && git config branch.master.remote origin && @@ -52,12 +49,14 @@ test_atom head refname refs/heads/master test_atom head upstream refs/remotes/origin/master test_atom head objecttype commit test_atom head objectsize 171 -test_atom head objectname 67a36f10722846e891fbada1ba48ed035de75581 -test_atom head tree 0e51c00fcb93dffc755546f27593d511e1bdb46f +test_atom head objectname $(git rev-parse refs/heads/master) +test_atom head tree $(git rev-parse refs/heads/master^{tree}) test_atom head parent '' test_atom head numparent 0 test_atom head object '' test_atom head type '' +test_atom head '*objectname' '' +test_atom head '*objecttype' '' test_atom head author 'A U Thor <author@example.com> 1151939924 +0200' test_atom head authorname 'A U Thor' test_atom head authoremail '<author@example.com>' @@ -80,17 +79,20 @@ test_atom head contents:body '' test_atom head contents:signature '' test_atom head contents 'Initial ' +test_atom head HEAD '*' test_atom tag refname refs/tags/testtag test_atom tag upstream '' test_atom tag objecttype tag test_atom tag objectsize 154 -test_atom tag objectname 98b46b1d36e5b07909de1b3886224e3e81e87322 +test_atom tag objectname $(git rev-parse refs/tags/testtag) test_atom tag tree '' test_atom tag parent '' test_atom tag numparent '' -test_atom tag object '67a36f10722846e891fbada1ba48ed035de75581' +test_atom tag object $(git rev-parse refs/tags/testtag^0) test_atom tag type 'commit' +test_atom tag '*objectname' '67a36f10722846e891fbada1ba48ed035de75581' +test_atom tag '*objecttype' 'commit' test_atom tag author '' test_atom tag authorname '' test_atom tag authoremail '' @@ -113,6 +115,7 @@ test_atom tag contents:body '' test_atom tag contents:signature '' test_atom tag contents 'Tagging at 1151939927 ' +test_atom tag HEAD ' ' test_expect_success 'Check invalid atoms names are errors' ' test_must_fail git for-each-ref --format="%(INVALID)" refs/heads @@ -304,8 +307,35 @@ test_expect_success 'Check short upstream format' ' test_cmp expected actual ' +test_expect_success 'setup for upstream:track[short]' ' + test_commit two +' + +cat >expected <<EOF +[ahead 1] +EOF + +test_expect_success 'Check upstream:track format' ' + git for-each-ref --format="%(upstream:track)" refs/heads >actual && + test_cmp expected actual +' + +cat >expected <<EOF +> +EOF + +test_expect_success 'Check upstream:trackshort format' ' + git for-each-ref --format="%(upstream:trackshort)" refs/heads >actual && + test_cmp expected actual +' + +test_expect_success 'Check that :track[short] cannot be used with other atoms' ' + test_must_fail git for-each-ref --format="%(refname:track)" 2>/dev/null && + test_must_fail git for-each-ref --format="%(refname:trackshort)" 2>/dev/null +' + cat >expected <<EOF -67a36f1 +$(git rev-parse --short HEAD) EOF test_expect_success 'Check short objectname format' ' @@ -317,6 +347,23 @@ test_expect_success 'Check for invalid refname format' ' test_must_fail git for-each-ref --format="%(refname:INVALID)" ' +get_color () +{ + git config --get-color no.such.slot "$1" +} + +cat >expected <<EOF +$(git rev-parse --short refs/heads/master) $(get_color green)master$(get_color reset) +$(git rev-parse --short refs/remotes/origin/master) $(get_color green)origin/master$(get_color reset) +$(git rev-parse --short refs/tags/testtag) $(get_color green)testtag$(get_color reset) +$(git rev-parse --short refs/tags/two) $(get_color green)two$(get_color reset) +EOF + +test_expect_success 'Check %(color:...) ' ' + git for-each-ref --format="%(objectname:short) %(color:green)%(refname:short)" >actual && + test_cmp expected actual +' + cat >expected <<\EOF heads/master tags/master @@ -456,9 +503,9 @@ test_atom refs/tags/signed-long contents "subject line body contents $sig" -cat >expected <<\EOF -408fe76d02a785a006c2e9c669b7be5589ede96d <committer@example.com> refs/tags/master -90b5ebede4899eda64893bc2a4c8f1d6fb6dfc40 <committer@example.com> refs/tags/bogo +cat >expected <<EOF +$(git rev-parse refs/tags/master) <committer@example.com> refs/tags/master +$(git rev-parse refs/tags/bogo) <committer@example.com> refs/tags/bogo EOF test_expect_success 'Verify sort with multiple keys' ' diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh index b1a63655f9..63194d819e 100755 --- a/t/t6500-gc.sh +++ b/t/t6500-gc.sh @@ -9,6 +9,11 @@ test_expect_success 'gc empty repository' ' git gc ' +test_expect_success 'gc does not leave behind pid file' ' + git gc && + test_path_is_missing .git/gc.pid +' + test_expect_success 'gc --gobbledegook' ' test_expect_code 129 git gc --nonsense 2>err && test_i18ngrep "[Uu]sage: git gc" err diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh index a845b154e4..215d43d6a6 100755 --- a/t/t7001-mv.sh +++ b/t/t7001-mv.sh @@ -70,6 +70,35 @@ test_expect_success \ rm -f idontexist untracked1 untracked2 \ path0/idontexist path0/untracked1 path0/untracked2 \ .git/index.lock +rmdir path1 + +test_expect_success \ + 'moving to absent target with trailing slash' \ + 'test_must_fail git mv path0/COPYING no-such-dir/ && + test_must_fail git mv path0/COPYING no-such-dir// && + git mv path0/ no-such-dir/ && + test_path_is_dir no-such-dir' + +test_expect_success \ + 'clean up' \ + 'git reset --hard' + +test_expect_success \ + 'moving to existing untracked target with trailing slash' \ + 'mkdir path1 && + git mv path0/ path1/ && + test_path_is_dir path1/path0/' + +test_expect_success \ + 'moving to existing tracked target with trailing slash' \ + 'mkdir path2 && + >path2/file && git add path2/file && + git mv path1/path0/ path2/ && + test_path_is_dir path2/path0/' + +test_expect_success \ + 'clean up' \ + 'git reset --hard' test_expect_success \ 'adding another file' \ @@ -218,13 +247,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 +266,212 @@ 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_expect_success 'setup submodule' ' + git commit -m initial && + git reset --hard && + git submodule add ./. sub && + echo content >file && + git add file && + git commit -m "added sub and file" && + git branch submodule +' + +test_expect_success 'git mv cannot move a submodule in a file' ' + test_must_fail git mv sub file +' + +test_expect_success 'git mv moves a submodule with a .git directory and no .gitmodules' ' + entry="$(git ls-files --stage sub | cut -f 1)" && + git rm .gitmodules && + ( + cd sub && + rm -f .git && + cp -a ../.git/modules/sub .git && + GIT_WORK_TREE=. git config --unset core.worktree + ) && + mkdir mod && + git mv sub mod/sub && + ! test -e sub && + [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] && + ( + cd mod/sub && + git status + ) && + git update-index --refresh && + git diff-files --quiet +' + +test_expect_success 'git mv moves a submodule with a .git directory and .gitmodules' ' + rm -rf mod && + git reset --hard && + git submodule update && + entry="$(git ls-files --stage sub | cut -f 1)" && + ( + cd sub && + rm -f .git && + cp -a ../.git/modules/sub .git && + GIT_WORK_TREE=. git config --unset core.worktree + ) && + mkdir mod && + git mv sub mod/sub && + ! test -e sub && + [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] && + ( + cd mod/sub && + git status + ) && + echo mod/sub >expected && + git config -f .gitmodules submodule.sub.path >actual && + test_cmp expected actual && + git update-index --refresh && + git diff-files --quiet +' + +test_expect_success 'git mv moves a submodule with gitfile' ' + rm -rf mod/sub && + git reset --hard && + git submodule update && + entry="$(git ls-files --stage sub | cut -f 1)" && + ( + cd mod && + git mv ../sub/ . + ) && + ! test -e sub && + [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] && + ( + cd mod/sub && + git status + ) && + echo mod/sub >expected && + git config -f .gitmodules submodule.sub.path >actual && + test_cmp expected actual && + git update-index --refresh && + git diff-files --quiet +' + +test_expect_success 'mv does not complain when no .gitmodules file is found' ' + rm -rf mod/sub && + git reset --hard && + git submodule update && + git rm .gitmodules && + entry="$(git ls-files --stage sub | cut -f 1)" && + git mv sub mod/sub 2>actual.err && + ! test -s actual.err && + ! test -e sub && + [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] && + ( + cd mod/sub && + git status + ) && + git update-index --refresh && + git diff-files --quiet +' + +test_expect_success 'mv will error out on a modified .gitmodules file unless staged' ' + rm -rf mod/sub && + git reset --hard && + git submodule update && + git config -f .gitmodules foo.bar true && + entry="$(git ls-files --stage sub | cut -f 1)" && + test_must_fail git mv sub mod/sub 2>actual.err && + test -s actual.err && + test -e sub && + git diff-files --quiet -- sub && + git add .gitmodules && + git mv sub mod/sub 2>actual.err && + ! test -s actual.err && + ! test -e sub && + [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] && + ( + cd mod/sub && + git status + ) && + git update-index --refresh && + git diff-files --quiet +' + +test_expect_success 'mv issues a warning when section is not found in .gitmodules' ' + rm -rf mod/sub && + git reset --hard && + git submodule update && + git config -f .gitmodules --remove-section submodule.sub && + git add .gitmodules && + entry="$(git ls-files --stage sub | cut -f 1)" && + echo "warning: Could not find section in .gitmodules where path=sub" >expect.err && + git mv sub mod/sub 2>actual.err && + test_i18ncmp expect.err actual.err && + ! test -e sub && + [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] && + ( + cd mod/sub && + git status + ) && + git update-index --refresh && + git diff-files --quiet +' + +test_expect_success 'mv --dry-run does not touch the submodule or .gitmodules' ' + rm -rf mod/sub && + git reset --hard && + git submodule update && + git mv -n sub mod/sub 2>actual.err && + test -f sub/.git && + git diff-index --exit-code HEAD && + git update-index --refresh && + git diff-files --quiet -- sub .gitmodules +' + +test_expect_success 'checking out a commit before submodule moved needs manual updates' ' + git mv sub sub2 && + git commit -m "moved sub to sub2" && + git checkout -q HEAD^ 2>actual && + echo "warning: unable to rmdir sub2: Directory not empty" >expected && + test_i18ncmp expected actual && + git status -s sub2 >actual && + echo "?? sub2/" >expected && + test_cmp expected actual && + ! test -f sub/.git && + test -f sub2/.git && + git submodule update && + test -f sub/.git && + rm -rf sub2 && + git diff-index --exit-code HEAD && + git update-index --refresh && + git diff-files --quiet -- sub .gitmodules && + git status -s sub2 >actual && + ! test -s actual +' + +test_expect_success 'mv -k does not accidentally destroy submodules' ' + git checkout submodule && + mkdir dummy dest && + git mv -k dummy sub dest && + git status --porcelain >actual && + grep "^R sub -> dest/sub" actual && + git reset --hard && + git checkout . +' + test_done diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh index 1e7a209efa..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 ' diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 5189446534..143a8ea605 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' ' @@ -1066,12 +1078,12 @@ test_expect_success GPG \ ' # usage with rfc1991 signatures -echo "rfc1991" > gpghome/gpg.conf get_tag_header rfc1991-signed-tag $commit commit $time >expect echo "RFC1991 signed tag" >>expect echo '-----BEGIN PGP MESSAGE-----' >>expect test_expect_success GPG \ 'creating a signed tag with rfc1991' ' + echo "rfc1991" >gpghome/gpg.conf && git tag -s -m "RFC1991 signed tag" rfc1991-signed-tag $commit && get_tag_msg rfc1991-signed-tag >actual && test_cmp expect actual @@ -1085,6 +1097,7 @@ chmod +x fakeeditor test_expect_success GPG \ 'reediting a signed tag body omits signature' ' + echo "rfc1991" >gpghome/gpg.conf && echo "RFC1991 signed tag" >expect && GIT_EDITOR=./fakeeditor git tag -f -s rfc1991-signed-tag $commit && test_cmp expect actual @@ -1092,11 +1105,13 @@ test_expect_success GPG \ test_expect_success GPG \ 'verifying rfc1991 signature' ' + echo "rfc1991" >gpghome/gpg.conf && git tag -v rfc1991-signed-tag ' test_expect_success GPG \ 'list tag with rfc1991 signature' ' + echo "rfc1991" >gpghome/gpg.conf && echo "rfc1991-signed-tag RFC1991 signed tag" >expect && git tag -l -n1 rfc1991-signed-tag >actual && test_cmp expect actual && @@ -1365,4 +1380,47 @@ test_expect_success 'multiple --points-at are OR-ed together' ' test_cmp expect actual ' +test_expect_success 'lexical sort' ' + git tag foo1.3 && + git tag foo1.6 && + git tag foo1.10 && + git tag -l --sort=refname "foo*" >actual && + cat >expect <<EOF && +foo1.10 +foo1.3 +foo1.6 +EOF + test_cmp expect actual +' + +test_expect_success 'version sort' ' + git tag -l --sort=version:refname "foo*" >actual && + cat >expect <<EOF && +foo1.3 +foo1.6 +foo1.10 +EOF + test_cmp expect actual +' + +test_expect_success 'reverse version sort' ' + git tag -l --sort=-version:refname "foo*" >actual && + cat >expect <<EOF && +foo1.10 +foo1.6 +foo1.3 +EOF + test_cmp expect actual +' + +test_expect_success 'reverse lexical sort' ' + git tag -l --sort=-refname "foo*" >actual && + cat >expect <<EOF && +foo1.6 +foo1.3 +foo1.10 +EOF + test_cmp expect actual +' + test_done diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh index ff2590849d..da958a8b56 100755 --- a/t/t7006-pager.sh +++ b/t/t7006-pager.sh @@ -37,6 +37,18 @@ test_expect_failure TTY 'pager runs from subdir' ' test_cmp expected actual ' +test_expect_success TTY 'LESS and LV envvars are set for pagination' ' + ( + sane_unset LESS LV && + PAGER="env >pager-env.out; wc" && + export PAGER && + + test_terminal git log + ) && + grep ^LESS= pager-env.out && + grep ^LV= pager-env.out +' + test_expect_success TTY 'some commands do not use a pager' ' rm -f paginated.out && test_terminal git rev-list HEAD && @@ -134,11 +146,7 @@ test_expect_success 'no color when stdout is a regular file' ' test_expect_success TTY 'color when writing to a pager' ' rm -f paginated.out && test_config color.ui auto && - ( - TERM=vt100 && - export TERM && - test_terminal git log - ) && + test_terminal env TERM=vt100 git log && colorful paginated.out ' @@ -146,11 +154,7 @@ test_expect_success TTY 'colors are suppressed by color.pager' ' rm -f paginated.out && test_config color.ui auto && test_config color.pager false && - ( - TERM=vt100 && - export TERM && - test_terminal git log - ) && + test_terminal env TERM=vt100 git log && ! colorful paginated.out ' @@ -169,11 +173,7 @@ test_expect_success 'color when writing to a file intended for a pager' ' test_expect_success TTY 'colors are sent to pager for external commands' ' test_config alias.externallog "!git log" && test_config color.ui auto && - ( - TERM=vt100 && - export TERM && - test_terminal git -p externallog - ) && + test_terminal env TERM=vt100 git -p externallog && colorful paginated.out ' diff --git a/t/t7008-grep-binary.sh b/t/t7008-grep-binary.sh index 26f831984d..b146406e9c 100755 --- a/t/t7008-grep-binary.sh +++ b/t/t7008-grep-binary.sh @@ -145,4 +145,35 @@ test_expect_success 'grep respects not-binary diff attribute' ' test_cmp expect actual ' +cat >nul_to_q_textconv <<'EOF' +#!/bin/sh +"$PERL_PATH" -pe 'y/\000/Q/' < "$1" +EOF +chmod +x nul_to_q_textconv + +test_expect_success 'setup textconv filters' ' + echo a diff=foo >.gitattributes && + git config diff.foo.textconv "\"$(pwd)\""/nul_to_q_textconv +' + +test_expect_success 'grep does not honor textconv' ' + test_must_fail git grep Qfile +' + +test_expect_success 'grep --textconv honors textconv' ' + echo "a:binaryQfile" >expect && + git grep --textconv Qfile >actual && + test_cmp expect actual +' + +test_expect_success 'grep --no-textconv does not honor textconv' ' + test_must_fail git grep --no-textconv Qfile +' + +test_expect_success 'grep --textconv blob honors textconv' ' + echo "HEAD:a:binaryQfile" >expect && + git grep --textconv Qfile HEAD:a >actual && + test_cmp expect actual +' + test_done diff --git a/t/t7009-filter-branch-null-sha1.sh b/t/t7009-filter-branch-null-sha1.sh new file mode 100755 index 0000000000..a997f7ac3a --- /dev/null +++ b/t/t7009-filter-branch-null-sha1.sh @@ -0,0 +1,49 @@ +#!/bin/sh + +test_description='filter-branch removal of trees with null sha1' +. ./test-lib.sh + +test_expect_success 'setup: base commits' ' + test_commit one && + test_commit two && + test_commit three +' + +test_expect_success 'setup: a commit with a bogus null sha1 in the tree' ' + { + git ls-tree HEAD && + printf "160000 commit $_z40\\tbroken\\n" + } >broken-tree + echo "add broken entry" >msg && + + tree=$(git mktree <broken-tree) && + test_tick && + commit=$(git commit-tree $tree -p HEAD <msg) && + git update-ref HEAD "$commit" +' + +# we have to make one more commit on top removing the broken +# entry, since otherwise our index does not match HEAD (and filter-branch will +# complain). We could make the index match HEAD, but doing so would involve +# writing a null sha1 into the index. +test_expect_success 'setup: bring HEAD and index in sync' ' + test_tick && + git commit -a -m "back to normal" +' + +test_expect_success 'filter commands are still checked' ' + test_must_fail git filter-branch \ + --force --prune-empty \ + --index-filter "git rm --cached --ignore-unmatch three.t" +' + +test_expect_success 'removing the broken entry works' ' + echo three >expect && + git filter-branch \ + --force --prune-empty \ + --index-filter "git rm --cached --ignore-unmatch broken" && + git log -1 --format=%s >actual && + test_cmp expect actual +' + +test_done 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..741ec08576 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 && @@ -28,20 +29,19 @@ test_expect_success 'Report new path with conflict' ' test_cmp expect actual ' -cat >expect <<EOF -# On branch side -# You have unmerged paths. -# (fix conflicts and run "git commit") -# -# Unmerged paths: -# (use "git add/rm <file>..." as appropriate to mark resolution) -# -# deleted by us: foo -# +test_expect_success 'M/D conflict does not segfault' ' + cat >expect <<EOF && +On branch side +You have unmerged paths. + (fix conflicts and run "git commit") + +Unmerged paths: + (use "git add/rm <file>..." as appropriate to mark resolution) + + deleted by us: foo + no changes added to commit (use "git add" and/or "git commit -a") EOF - -test_expect_success 'M/D conflict does not segfault' ' mkdir mdconflict && ( cd mdconflict && @@ -134,19 +134,19 @@ test_expect_success 'status when conflicts with add and rm advice (deleted by th test_commit on_second main.txt on_second && test_commit master conflict.txt master && test_must_fail git merge second_branch && - cat >expected <<-\EOF && - # On branch master - # You have unmerged paths. - # (fix conflicts and run "git commit") - # - # Unmerged paths: - # (use "git add/rm <file>..." as appropriate to mark resolution) - # - # both added: conflict.txt - # deleted by them: main.txt - # - no changes added to commit (use "git add" and/or "git commit -a") - EOF + cat >expected <<\EOF && +On branch master +You have unmerged paths. + (fix conflicts and run "git commit") + +Unmerged paths: + (use "git add/rm <file>..." as appropriate to mark resolution) + + both added: conflict.txt + deleted by them: main.txt + +no changes added to commit (use "git add" and/or "git commit -a") +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -167,20 +167,20 @@ test_expect_success 'prepare for conflicts' ' test_expect_success 'status when conflicts with add and rm advice (both deleted)' ' test_must_fail git merge conflict && - cat >expected <<-\EOF && - # On branch conflict_second - # You have unmerged paths. - # (fix conflicts and run "git commit") - # - # Unmerged paths: - # (use "git add/rm <file>..." as appropriate to mark resolution) - # - # both deleted: main.txt - # added by them: sub_master.txt - # added by us: sub_second.txt - # - no changes added to commit (use "git add" and/or "git commit -a") - EOF + cat >expected <<\EOF && +On branch conflict_second +You have unmerged paths. + (fix conflicts and run "git commit") + +Unmerged paths: + (use "git add/rm <file>..." as appropriate to mark resolution) + + both deleted: main.txt + added by them: sub_master.txt + added by us: sub_second.txt + +no changes added to commit (use "git add" and/or "git commit -a") +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -191,22 +191,22 @@ test_expect_success 'status when conflicts with only rm advice (both deleted)' ' test_must_fail git merge conflict && git add sub_master.txt && git add sub_second.txt && - cat >expected <<-\EOF && - # On branch conflict_second - # You have unmerged paths. - # (fix conflicts and run "git commit") - # - # Changes to be committed: - # - # new file: sub_master.txt - # - # Unmerged paths: - # (use "git rm <file>..." to mark resolution) - # - # both deleted: main.txt - # - # Untracked files not listed (use -u option to show untracked files) - EOF + cat >expected <<\EOF && +On branch conflict_second +You have unmerged paths. + (fix conflicts and run "git commit") + +Changes to be committed: + + new file: sub_master.txt + +Unmerged paths: + (use "git rm <file>..." to mark resolution) + + both deleted: main.txt + +Untracked files not listed (use -u option to show untracked files) +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual && git reset --hard && 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/t7101-reset.sh b/t/t7101-reset-empty-subdirs.sh index 96e163f084..96e163f084 100755 --- a/t/t7101-reset.sh +++ b/t/t7101-reset-empty-subdirs.sh diff --git a/t/t7102-reset.sh b/t/t7102-reset.sh index b096dc88c2..450529404c 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,44 @@ 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_expect_success 'reset -N keeps removed files as intent-to-add' ' + echo new-file >new-file && + git add new-file && + git reset -N HEAD && + + tree=$(git write-tree) && + git ls-tree $tree new-file >actual && + >expect && + test_cmp expect actual && + + git diff --name-only >actual && + echo new-file >expect && + test_cmp expect actual +' + +test_expect_success 'reset --mixed sets up work tree' ' + git init mixed_worktree && + ( + cd mixed_worktree && + test_commit dummy + ) && + : >expect && + git --git-dir=mixed_worktree/.git --work-tree=mixed_worktree reset >actual && + test_cmp expect actual +' + test_done diff --git a/t/t7104-reset.sh b/t/t7104-reset-hard.sh index f136ee7bb5..f136ee7bb5 100755 --- a/t/t7104-reset.sh +++ b/t/t7104-reset-hard.sh diff --git a/t/t7105-reset-patch.sh b/t/t7105-reset-patch.sh index 95fab20361..98b7d7b969 100755 --- a/t/t7105-reset-patch.sh +++ b/t/t7105-reset-patch.sh @@ -25,15 +25,17 @@ test_expect_success PERL 'saying "n" does nothing' ' ' test_expect_success PERL 'git reset -p' ' - (echo n; echo y) | git reset -p && + (echo n; echo y) | git reset -p >output && verify_state dir/foo work head && - verify_saved_state bar + verify_saved_state bar && + test_i18ngrep "Unstage" output ' test_expect_success PERL 'git reset -p HEAD^' ' - (echo n; echo y) | git reset -p HEAD^ && + (echo n; echo y) | git reset -p HEAD^ >output && verify_state dir/foo work parent && - verify_saved_state bar + verify_saved_state bar && + test_i18ngrep "Apply" output ' # The idea in the rest is that bar sorts first, so we always say 'y' diff --git a/t/t7106-reset-unborn-branch.sh b/t/t7106-reset-unborn-branch.sh new file mode 100755 index 0000000000..0f95f00477 --- /dev/null +++ b/t/t7106-reset-unborn-branch.sh @@ -0,0 +1,70 @@ +#!/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 && + + >expect && + git ls-files >actual && + test_cmp expect actual +' + +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 && + + echo b >expect && + git ls-files >actual && + test_cmp expect actual +' + +test_expect_success PERL 'reset -p' ' + rm .git/index && + git add a && + echo y >yes && + git reset -p <yes >output && + + >expect && + git ls-files >actual && + test_cmp expect actual && + test_i18ngrep "Unstage" output +' + +test_expect_success 'reset --soft is a no-op' ' + rm .git/index && + git add a && + git reset --soft && + + echo a >expect && + git ls-files >actual && + test_cmp expect actual +' + +test_expect_success 'reset --hard' ' + rm .git/index && + git add a && + test_when_finished "echo a >a" && + git reset --hard && + + >expect && + git ls-files >actual && + test_cmp expect actual && + 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..74de814aec 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 && @@ -477,4 +511,20 @@ test_expect_success SANITY 'git clean -d with an unreadable empty directory' ' ! test -d foo ' +test_expect_success 'git clean -d respects pathspecs (dir is prefix of pathspec)' ' + mkdir -p foo && + mkdir -p foobar && + git clean -df foobar && + test_path_is_dir foo && + test_path_is_missing foobar +' + +test_expect_success 'git clean -d respects pathspecs (pathspec is prefix of dir)' ' + mkdir -p foo && + mkdir -p foobar && + git clean -df foo && + test_path_is_missing foo && + test_path_is_dir foobar +' + test_done diff --git a/t/t7301-clean-interactive.sh b/t/t7301-clean-interactive.sh new file mode 100755 index 0000000000..3ae394e934 --- /dev/null +++ b/t/t7301-clean-interactive.sh @@ -0,0 +1,475 @@ +#!/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 (c: clean hotkey)' ' + + 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 (cl: clean prefix)' ' + + 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 cl | 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 quit | 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 - filenames)' ' + + mkdir -p build docs && + touch a.out foo.txt bar.txt baz.txt && + (echo s; echo a.out fo ba bar; echo; echo c) | \ + git clean -id && + test -f Makefile && + test ! -f a.out && + test ! -f foo.txt && + test ! -f bar.txt && + test -f baz.txt && + rm baz.txt + +' + +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 2683cba7e3..c28e8d8ada 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -18,6 +18,16 @@ test_expect_success 'setup - initial commit' ' git branch initial ' +test_expect_success 'configuration parsing' ' + test_when_finished "rm -f .gitmodules" && + cat >.gitmodules <<-\EOF && + [submodule "s"] + path + ignore + EOF + test_must_fail git status +' + test_expect_success 'setup - repository in init subdirectory' ' mkdir init && ( @@ -78,7 +88,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 && ( @@ -212,6 +222,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 @@ -308,7 +344,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 @@ -319,6 +355,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 && @@ -399,6 +455,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 && @@ -406,7 +481,7 @@ test_expect_success 'do not add files from a submodule' ' ' -test_expect_success 'gracefully add submodule with a trailing slash' ' +test_expect_success 'gracefully add/reset submodule with a trailing slash' ' git reset --hard && git commit -m "commit subproject" init && @@ -420,7 +495,9 @@ test_expect_success 'gracefully add submodule with a trailing slash' ' git add init/ && test_must_fail git diff --exit-code --cached init && test $commit = $(git ls-files --stage | - sed -n "s/^160000 \([^ ]*\).*/\1/p") + sed -n "s/^160000 \([^ ]*\).*/\1/p") && + git reset init/ && + git diff --exit-code --cached init ' @@ -696,7 +773,7 @@ test_expect_success 'submodule add --name allows to replace a submodule with ano rm -rf repo && git rm repo && git submodule add -q --name repo_new "$submodurl/bare.git" repo >actual && - test ! -s actual && + test_must_be_empty actual && echo "gitdir: ../.git/modules/submod" >expect && test_cmp expect submod/.git && ( @@ -708,13 +785,11 @@ test_expect_success 'submodule add --name allows to replace a submodule with ano test_cmp expect .git ) && echo "repo" >expect && - git config -f .gitmodules submodule.repo.path >actual && - test_cmp expect actual && + test_must_fail git config -f .gitmodules submodule.repo.path && 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 && + test_must_fail git config -f .gitmodules submodule.repo.url && echo "$submodurl/bare.git" >expect && git config -f .gitmodules submodule.repo_new.url >actual && test_cmp expect actual && @@ -734,12 +809,8 @@ test_expect_success 'submodule add with an existing name fails unless forced' ' 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 && + test_must_fail git config -f .gitmodules submodule.repo_new.path && + test_must_fail git config -f .gitmodules submodule.repo_new.url && echo "$submodurl/bare.git" >expect && git config submodule.repo_new.url >actual && test_cmp expect actual && @@ -757,4 +828,160 @@ test_expect_success 'submodule add with an existing name fails unless forced' ' ) ' +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" + ) && + 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..366746f0d4 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) @@ -68,6 +104,24 @@ EOF test_cmp expected actual " +test_expect_success 'no ignore=all setting has any effect' " + git config -f .gitmodules submodule.sm1.path sm1 && + git config -f .gitmodules submodule.sm1.ignore all && + git config submodule.sm1.ignore all && + git config diff.ignoreSubmodules all && + git submodule summary >actual && + cat >expected <<-EOF && +* sm1 $head1...$head2 (1): + > Add foo3 + +EOF + test_cmp expected actual && + git config --unset diff.ignoreSubmodules && + git config --remove-section submodule.sm1 && + git config -f .gitmodules --remove-section submodule.sm1 +" + + commit_file sm1 && head3=$( cd sm1 && @@ -76,8 +130,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 +143,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 +156,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 +176,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 +186,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,62 +246,60 @@ 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 -# Submodule changes to be committed: -# -# * sm1 $head6...0000000: -# -# * sm2 0000000...$head7 (2): -# > Add foo9 -# + git submodule summary --for-status HEAD^ >actual && + test_i18ncmp actual - <<EOF +* sm1 $head6...0000000: + +* sm2 0000000...$head7 (2): + > Add foo9 + 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 94e26c47ea..79bc135bf6 100755 --- a/t/t7403-submodule-sync.sh +++ b/t/t7403-submodule-sync.sh @@ -11,216 +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 submodule && - git submodule add ../submodule sub-submodule && - test_tick && - git commit -m "sub-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" + ( + 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 --recursive) && + ( + 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 --recursive) && + ( + cd relative-clone && + git submodule update --init --recursive + ) && git clone super recursive-clone && - (cd recursive-clone && git submodule update --init --recursive) + ( + 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 moved-submodule && - git config -f .gitmodules submodule.sub-submodule.url ../moved-submodule && - test_tick && - git commit -a -m moved-sub-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 + ( + 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 + 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 + ( + 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 ) && - test -d "$(cd super-clone/submodule && - git config remote.origin.url + 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 + test -d "$( + cd super-clone/submodule/sub-submodule && + git config remote.origin.url )" && - (cd super-clone/submodule/sub-submodule && - git checkout master && - git pull + ( + 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 submodule/sub-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" - ) + ( + 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 4975ec07ce..28ca76384f 100755 --- a/t/t7406-submodule-update.sh +++ b/t/t7406-submodule-update.sh @@ -58,11 +58,14 @@ test_expect_success 'setup a submodule tree' ' git submodule add ../merging merging && test_tick && git commit -m "rebasing" - ) + ) && (cd super && git submodule add ../none none && test_tick && git commit -m "none" + ) && + (cd super && + git tag initial-setup ) ' @@ -80,6 +83,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 && @@ -279,6 +297,50 @@ 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 does not copy command into .git/config' ' + (cd super && + H=$(git ls-files -s submodule | cut -d" " -f2) && + mkdir submodule1 && + git update-index --add --cacheinfo 160000 $H submodule1 && + git config -f .gitmodules submodule.submodule1.path submodule1 && + git config -f .gitmodules submodule.submodule1.url ../submodule && + git config -f .gitmodules submodule.submodule1.update !false && + git submodule init submodule1 && + echo "none" >expect && + git config submodule.submodule1.update >actual && + test_cmp expect actual + ) +' + test_expect_success 'submodule init picks up rebase' ' (cd super && git config -f .gitmodules submodule.rebasing.update rebase && @@ -596,14 +658,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 ) ' @@ -643,7 +705,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.: .git reset --hard -q" actual && (cd submodule/subsubmodule && git log > ../../expected ) && @@ -664,8 +727,10 @@ test_expect_success 'submodule add properly re-creates deeper level submodules' 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 && @@ -674,7 +739,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 ) ' @@ -682,14 +747,68 @@ 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_expect_success 'submodule update --recursive drops module name before recursing' ' + (cd super2 && + (cd deeper/submodule/subsubmodule && + git checkout HEAD^ + ) && + git submodule update --recursive deeper/submodule >actual && + test_i18ngrep "Submodule path .deeper/submodule/subsubmodule.: checked out" actual ) ' +test_expect_success 'submodule update --checkout clones detached HEAD' ' + git clone super super4 && + echo "detached HEAD" >expected && + (cd super4 && + git reset --hard initial-setup && + git submodule init submodule && + git submodule update >> /tmp/log 2>&1 && + (cd submodule && + git symbolic-ref HEAD > ../../actual || + echo "detached HEAD" > ../../actual + ) + ) && + test_cmp actual expected && + rm -rf super4 +' + +test_expect_success 'submodule update --merge clones attached HEAD' ' + git clone super super4 && + echo "refs/heads/master" >expected && + (cd super4 && + git reset --hard initial-setup && + git submodule init submodule && + git config submodule.submodule.update merge && + git submodule update --merge && + (cd submodule && + git symbolic-ref HEAD > ../../actual || + echo "detached HEAD" > ../../actual + ) + ) && + test_cmp actual expected && + rm -rf super4 +' + test_done diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index 107b4b7c45..7ca10b8606 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 && @@ -129,7 +145,7 @@ test_expect_success 'use "submodule foreach" to checkout 2nd level submodule' ' git rev-parse --resolve-git-dir nested1/.git && test_must_fail git rev-parse --resolve-git-dir nested1/nested2/.git && git submodule foreach "git submodule update --init" && - git rev-parse --resolve-git-dir nested1/nested1/nested2/.git + git rev-parse --resolve-git-dir nested1/nested2/.git && test_must_fail git rev-parse --resolve-git-dir nested1/nested2/nested3/.git ) ' @@ -238,10 +254,6 @@ test_expect_success 'ensure "status --cached --recursive" preserves the --cached ) && git submodule status --cached --recursive -- nested1 > ../actual ) && - if test_have_prereq MINGW - then - dos2unix actual - fi && test_cmp expect actual ' @@ -313,4 +325,13 @@ test_expect_success 'command passed to foreach --recursive retains notion of std test_cmp expected actual ' +test_expect_success 'multi-argument command passed to foreach is not shell-evaluated twice' ' + ( + cd super && + git submodule foreach "echo \\\"quoted\\\"" > ../expected && + git submodule foreach echo \"quoted\" > ../actual + ) && + test_cmp expected actual +' + test_done 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..d58b097ff3 100755 --- a/t/t7501-commit.sh +++ b/t/t7501-commit.sh @@ -53,18 +53,55 @@ test_expect_success PERL 'can use paths with --interactive' ' ' test_expect_success 'using invalid commit with -C' ' - test_must_fail git commit -C bogus + test_must_fail git commit --allow-empty -C bogus ' test_expect_success 'nothing to commit' ' + git reset --hard && test_must_fail git commit -m initial ' +test_expect_success '--dry-run fails with nothing to commit' ' + test_must_fail git commit -m initial --dry-run +' + +test_expect_success '--short fails with nothing to commit' ' + test_must_fail git commit -m initial --short +' + +test_expect_success '--porcelain fails with nothing to commit' ' + test_must_fail git commit -m initial --porcelain +' + +test_expect_success '--long fails with nothing to commit' ' + test_must_fail git commit -m initial --long +' + test_expect_success 'setup: non-initial commit' ' echo bongo bongo bongo >file && git commit -m next -a ' +test_expect_success '--dry-run with stuff to commit returns ok' ' + echo bongo bongo bongo >>file && + git commit -m next -a --dry-run +' + +test_expect_failure '--short with stuff to commit returns ok' ' + echo bongo bongo bongo >>file && + git commit -m next -a --short +' + +test_expect_failure '--porcelain with stuff to commit returns ok' ' + echo bongo bongo bongo >>file && + git commit -m next -a --porcelain +' + +test_expect_success '--long with stuff to commit returns ok' ' + echo bongo bongo bongo >>file && + git commit -m next -a --long +' + test_expect_success 'commit message from non-existing file' ' echo more bongo: bongo bongo bongo bongo >file && test_must_fail git commit -F gah -a @@ -524,4 +561,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..9a3f3a1b41 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 ' -test_expect_success 'cleanup commit messages (verbatim,-t)' ' +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 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,23 @@ test_expect_success 'cleanup commit messages (whitespace,-F)' ' ' -test_expect_success 'cleanup commit messages (strip,-F)' ' +test_expect_success 'cleanup commit messages (scissors option,-F,-e)' ' + + echo >>negative && + cat >text <<EOF && + +# to be kept +# ------------------------ >8 ------------------------ +to be removed +EOF + echo "# to be kept" >expect && + git commit --cleanup=scissors -e -F text -a && + git cat-file -p HEAD |sed -e "1,/^\$/d">actual && + test_cmp expect actual + +' + +test_expect_success 'cleanup commit messages (strip option,-F)' ' echo >>negative && { echo;echo "# text";echo sample;echo; } >text && @@ -218,7 +250,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 +263,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 +344,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 +362,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 +377,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 +457,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 +479,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 +494,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 +557,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..03dce09cfe 100755 --- a/t/t7505-prepare-commit-msg-hook.sh +++ b/t/t7505-prepare-commit-msg-hook.sh @@ -134,14 +134,26 @@ test_expect_success 'with hook (-c)' ' test_expect_success 'with hook (merge)' ' - head=`git rev-parse HEAD` && - git checkout -b other HEAD@{1} && - echo "more" >> file && + test_when_finished "git checkout -f master" && + git checkout -B other HEAD@{1} && + echo "more" >>file && + git add file && + git commit -m other && + git checkout - && + git merge --no-ff other && + test "`git log -1 --pretty=format:%s`" = "merge (no editor)" +' + +test_expect_success 'with hook and editor (merge)' ' + + test_when_finished "git checkout -f master" && + git checkout -B other HEAD@{1} && + echo "more" >>file && git add file && git commit -m other && git checkout - && - git merge other && - test "`git log -1 --pretty=format:%s`" = merge + env GIT_EDITOR="\"\$FAKE_EDITOR\"" git merge --no-ff -e other && + test "`git log -1 --pretty=format:%s`" = "merge" ' cat > "$HOOK" <<'EOF' @@ -151,21 +163,38 @@ EOF test_expect_success 'with failing hook' ' + test_when_finished "git checkout -f master" && head=`git rev-parse HEAD` && echo "more" >> file && git add file && - ! GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -c $head + test_must_fail env GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -c $head ' test_expect_success 'with failing hook (--no-verify)' ' + test_when_finished "git checkout -f master" && head=`git rev-parse HEAD` && echo "more" >> file && git add file && - ! GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify -c $head + test_must_fail env GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify -c $head ' +test_expect_success 'with failing hook (merge)' ' + + test_when_finished "git checkout -f master" && + 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 --no-ff other + +' test_done diff --git a/t/t7507-commit-verbose.sh b/t/t7507-commit-verbose.sh index da5bd3b5a5..2ddf28c984 100755 --- a/t/t7507-commit-verbose.sh +++ b/t/t7507-commit-verbose.sh @@ -65,9 +65,35 @@ test_expect_success 'diff in message is retained without -v' ' check_message diff ' -test_expect_failure 'diff in message is retained with -v' ' +test_expect_success 'diff in message is retained with -v' ' git commit --amend -F diff -v && check_message diff ' +test_expect_success 'submodule log is stripped out too with -v' ' + git config diff.submodule log && + git submodule add ./. sub && + git commit -m "sub added" && + ( + cd sub && + echo "more" >>file && + git commit -a -m "submodule commit" + ) && + ( + GIT_EDITOR=cat && + export GIT_EDITOR && + test_must_fail git commit -a -v 2>err + ) && + test_i18ngrep "Aborting commit due to empty commit message." err +' + +test_expect_success 'verbose diff is stripped out with set core.commentChar' ' + ( + GIT_EDITOR=cat && + export GIT_EDITOR && + test_must_fail git -c core.commentchar=";" commit -a -v 2>err + ) && + test_i18ngrep "Aborting commit due to empty commit message." err +' + test_done diff --git a/t/t7508-status.sh b/t/t7508-status.sh index e313ef196e..c987b5ed65 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" && ( @@ -59,8 +60,13 @@ test_expect_success 'status (1)' ' test_i18ngrep "use \"git rm --cached <file>\.\.\.\" to unstage" output ' +strip_comments () { + tab=' ' + sed "s/^\# //; s/^\#$//; s/^#$tab/$tab/" <"$1" >"$1".tmp && + rm "$1" && mv "$1".tmp "$1" +} + test_expect_success 'status --column' ' - COLUMNS=50 git status --column="column dense" >output && cat >expect <<\EOF && # On branch master # Changes to be committed: @@ -77,9 +83,17 @@ test_expect_success 'status --column' ' # Untracked files: # (use "git add <file>..." to include in what will be committed) # -# dir1/untracked dir2/untracked untracked -# dir2/modified output +# dir1/untracked dir2/untracked output +# dir2/modified expect untracked +# EOF + COLUMNS=50 git -c status.displayCommentPrefix=true status --column="column dense" >output && + test_i18ncmp expect output +' + +test_expect_success 'status --column status.displayCommentPrefix=false' ' + strip_comments expect && + COLUMNS=49 git -c status.displayCommentPrefix=false status --column="column dense" >output && test_i18ncmp expect output ' @@ -105,33 +119,62 @@ cat >expect <<\EOF # expect # output # untracked +# EOF -test_expect_success 'status (2)' ' - git status >output && +test_expect_success 'status with status.displayCommentPrefix=true' ' + git -c status.displayCommentPrefix=true status >output && test_i18ncmp expect output ' +test_expect_success 'status with status.displayCommentPrefix=false' ' + strip_comments expect && + git -c status.displayCommentPrefix=false status >output && + test_i18ncmp expect output +' + +test_expect_success 'setup fake editor' ' + cat >.git/editor <<-\EOF && + #! /bin/sh + cp "$1" output +EOF + chmod 755 .git/editor +' + +commit_template_commented () { + ( + EDITOR=.git/editor && + export EDITOR && + # Fails due to empty message + test_must_fail git commit + ) && + ! grep '^[^#]' output +} + +test_expect_success 'commit ignores status.displayCommentPrefix=false in COMMIT_EDITMSG' ' + commit_template_commented +' + cat >expect <<\EOF -# On branch master -# Changes to be committed: -# new file: dir2/added -# -# Changes not staged for commit: -# modified: dir1/modified -# -# Untracked files: -# dir1/untracked -# dir2/modified -# dir2/untracked -# expect -# output -# untracked +On branch master +Changes to be committed: + new file: dir2/added + +Changes not staged for commit: + modified: dir1/modified + +Untracked files: + dir1/untracked + dir2/modified + dir2/untracked + expect + output + untracked + 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 @@ -185,33 +228,35 @@ test_expect_success 'status with gitignore' ' git status -s --ignored >output && test_cmp expect output && - cat >expect <<-\EOF && - # On branch master - # Changes to be committed: - # (use "git reset HEAD <file>..." to unstage) - # - # new file: dir2/added - # - # Changes not staged for commit: - # (use "git add <file>..." to update what will be committed) - # (use "git checkout -- <file>..." to discard changes in working directory) - # - # modified: dir1/modified - # - # Untracked files: - # (use "git add <file>..." to include in what will be committed) - # - # dir2/modified - # Ignored files: - # (use "git add -f <file>..." to include in what will be committed) - # - # .gitignore - # dir1/untracked - # dir2/untracked - # expect - # output - # untracked - EOF + cat >expect <<\EOF && +On branch master +Changes to be committed: + (use "git reset HEAD <file>..." to unstage) + + new file: dir2/added + +Changes not staged for commit: + (use "git add <file>..." to update what will be committed) + (use "git checkout -- <file>..." to discard changes in working directory) + + modified: dir1/modified + +Untracked files: + (use "git add <file>..." to include in what will be committed) + + dir2/modified + +Ignored files: + (use "git add -f <file>..." to include in what will be committed) + + .gitignore + dir1/untracked + dir2/untracked + expect + output + untracked + +EOF git status --ignored >output && test_i18ncmp expect output ' @@ -246,30 +291,31 @@ test_expect_success 'status with gitignore (nothing untracked)' ' git status -s --ignored >output && test_cmp expect output && - cat >expect <<-\EOF && - # On branch master - # Changes to be committed: - # (use "git reset HEAD <file>..." to unstage) - # - # new file: dir2/added - # - # Changes not staged for commit: - # (use "git add <file>..." to update what will be committed) - # (use "git checkout -- <file>..." to discard changes in working directory) - # - # modified: dir1/modified - # - # Ignored files: - # (use "git add -f <file>..." to include in what will be committed) - # - # .gitignore - # dir1/untracked - # dir2/modified - # dir2/untracked - # expect - # output - # untracked - EOF + cat >expect <<\EOF && +On branch master +Changes to be committed: + (use "git reset HEAD <file>..." to unstage) + + new file: dir2/added + +Changes not staged for commit: + (use "git add <file>..." to update what will be committed) + (use "git checkout -- <file>..." to discard changes in working directory) + + modified: dir1/modified + +Ignored files: + (use "git add -f <file>..." to include in what will be committed) + + .gitignore + dir1/untracked + dir2/modified + dir2/untracked + expect + output + untracked + +EOF git status --ignored >output && test_i18ncmp expect output ' @@ -310,49 +356,47 @@ test_expect_success 'setup dir3' ' : >dir3/untracked2 ' -cat >expect <<EOF -# On branch master -# Changes to be committed: -# (use "git reset HEAD <file>..." to unstage) -# -# new file: dir2/added -# -# Changes not staged for commit: -# (use "git add <file>..." to update what will be committed) -# (use "git checkout -- <file>..." to discard changes in working directory) -# -# modified: dir1/modified -# -# Untracked files not listed (use -u option to show untracked files) -EOF test_expect_success 'status -uno' ' + cat >expect <<EOF && +On branch master +Changes to be committed: + (use "git reset HEAD <file>..." to unstage) + + new file: dir2/added + +Changes not staged for commit: + (use "git add <file>..." to update what will be committed) + (use "git checkout -- <file>..." to discard changes in working directory) + + modified: dir1/modified + +Untracked files not listed (use -u option to show untracked files) +EOF git status -uno >output && test_i18ncmp expect output ' 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 ' -cat >expect <<EOF -# On branch master -# Changes to be committed: -# new file: dir2/added -# -# Changes not staged for commit: -# modified: dir1/modified -# -# Untracked files not listed -EOF -git config advice.statusHints false test_expect_success 'status -uno (advice.statusHints false)' ' + cat >expect <<EOF && +On branch master +Changes to be committed: + new file: dir2/added + +Changes not staged for commit: + modified: dir1/modified + +Untracked files not listed +EOF + test_config advice.statusHints false && git status -uno >output && test_i18ncmp expect output ' -git config --unset advice.statusHints cat >expect << EOF M dir1/modified @@ -369,38 +413,38 @@ test_expect_success 'status -s (status.showUntrackedFiles no)' ' test_cmp expect output ' -cat >expect <<EOF -# On branch master -# Changes to be committed: -# (use "git reset HEAD <file>..." to unstage) -# -# new file: dir2/added -# -# Changes not staged for commit: -# (use "git add <file>..." to update what will be committed) -# (use "git checkout -- <file>..." to discard changes in working directory) -# -# modified: dir1/modified -# -# Untracked files: -# (use "git add <file>..." to include in what will be committed) -# -# dir1/untracked -# dir2/modified -# dir2/untracked -# dir3/ -# expect -# output -# untracked -EOF test_expect_success 'status -unormal' ' + cat >expect <<EOF && +On branch master +Changes to be committed: + (use "git reset HEAD <file>..." to unstage) + + new file: dir2/added + +Changes not staged for commit: + (use "git add <file>..." to update what will be committed) + (use "git checkout -- <file>..." to discard changes in working directory) + + modified: dir1/modified + +Untracked files: + (use "git add <file>..." to include in what will be committed) + + dir1/untracked + dir2/modified + dir2/untracked + dir3/ + expect + output + untracked + +EOF git status -unormal >output && test_i18ncmp expect output ' 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 ' @@ -427,39 +471,39 @@ test_expect_success 'status -s (status.showUntrackedFiles normal)' ' test_cmp expect output ' -cat >expect <<EOF -# On branch master -# Changes to be committed: -# (use "git reset HEAD <file>..." to unstage) -# -# new file: dir2/added -# -# Changes not staged for commit: -# (use "git add <file>..." to update what will be committed) -# (use "git checkout -- <file>..." to discard changes in working directory) -# -# modified: dir1/modified -# -# Untracked files: -# (use "git add <file>..." to include in what will be committed) -# -# dir1/untracked -# dir2/modified -# dir2/untracked -# dir3/untracked1 -# dir3/untracked2 -# expect -# output -# untracked -EOF test_expect_success 'status -uall' ' + cat >expect <<EOF && +On branch master +Changes to be committed: + (use "git reset HEAD <file>..." to unstage) + + new file: dir2/added + +Changes not staged for commit: + (use "git add <file>..." to update what will be committed) + (use "git checkout -- <file>..." to discard changes in working directory) + + modified: dir1/modified + +Untracked files: + (use "git add <file>..." to include in what will be committed) + + dir1/untracked + dir2/modified + dir2/untracked + dir3/untracked1 + dir3/untracked2 + expect + output + untracked + +EOF git status -uall >output && test_i18ncmp expect output ' 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,38 +528,37 @@ 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 ' -cat >expect <<\EOF -# On branch master -# Changes to be committed: -# (use "git reset HEAD <file>..." to unstage) -# -# new file: ../dir2/added -# -# Changes not staged for commit: -# (use "git add <file>..." to update what will be committed) -# (use "git checkout -- <file>..." to discard changes in working directory) -# -# modified: modified -# -# Untracked files: -# (use "git add <file>..." to include in what will be committed) -# -# untracked -# ../dir2/modified -# ../dir2/untracked -# ../expect -# ../output -# ../untracked -EOF - test_expect_success 'status with relative paths' ' + cat >expect <<\EOF && +On branch master +Changes to be committed: + (use "git reset HEAD <file>..." to unstage) + + new file: ../dir2/added + +Changes not staged for commit: + (use "git add <file>..." to update what will be committed) + (use "git checkout -- <file>..." to discard changes in working directory) + + modified: modified + +Untracked files: + (use "git add <file>..." to include in what will be committed) + + untracked + ../dir2/modified + ../dir2/untracked + ../expect + ../output + ../untracked + +EOF (cd dir1 && git status) >output && test_i18ncmp expect output ' @@ -562,40 +605,38 @@ test_expect_success 'setup unique colors' ' ' -cat >expect <<\EOF -# On branch <GREEN>master<RESET> -# Changes to be committed: -# (use "git reset HEAD <file>..." to unstage) -# -# <GREEN>new file: dir2/added<RESET> -# -# 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) -# -# <RED>modified: dir1/modified<RESET> -# -# Untracked files: -# (use "git add <file>..." to include in what will be committed) -# -# <BLUE>dir1/untracked<RESET> -# <BLUE>dir2/modified<RESET> -# <BLUE>dir2/untracked<RESET> -# <BLUE>expect<RESET> -# <BLUE>output<RESET> -# <BLUE>untracked<RESET> -EOF - test_expect_success 'status with color.ui' ' - git config color.ui always && - test_when_finished "git config --unset color.ui" && + cat >expect <<\EOF && +On branch <GREEN>master<RESET> +Changes to be committed: + (use "git reset HEAD <file>..." to unstage) + + <GREEN>new file: dir2/added<RESET> + +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) + + <RED>modified: dir1/modified<RESET> + +Untracked files: + (use "git add <file>..." to include in what will be committed) + + <BLUE>dir1/untracked<RESET> + <BLUE>dir2/modified<RESET> + <BLUE>dir2/untracked<RESET> + <BLUE>expect<RESET> + <BLUE>output<RESET> + <BLUE>untracked<RESET> + +EOF + 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 ' @@ -692,35 +733,34 @@ test_expect_success 'status --porcelain respects -b' ' ' -cat >expect <<\EOF -# On branch master -# Changes to be committed: -# (use "git reset HEAD <file>..." to unstage) -# -# new file: dir2/added -# -# Changes not staged for commit: -# (use "git add <file>..." to update what will be committed) -# (use "git checkout -- <file>..." to discard changes in working directory) -# -# modified: dir1/modified -# -# Untracked files: -# (use "git add <file>..." to include in what will be committed) -# -# dir1/untracked -# dir2/modified -# dir2/untracked -# expect -# output -# untracked -EOF test_expect_success 'status without relative paths' ' + cat >expect <<\EOF && +On branch master +Changes to be committed: + (use "git reset HEAD <file>..." to unstage) + + new file: dir2/added + +Changes not staged for commit: + (use "git add <file>..." to update what will be committed) + (use "git checkout -- <file>..." to discard changes in working directory) + + modified: dir1/modified - git config status.relativePaths false && - test_when_finished "git config --unset status.relativePaths" && +Untracked files: + (use "git add <file>..." to include in what will be committed) + + dir1/untracked + dir2/modified + dir2/untracked + expect + output + untracked + +EOF + test_config status.relativePaths false && (cd dir1 && git status) >output && test_i18ncmp expect output @@ -739,30 +779,30 @@ 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 ' -cat <<EOF >expect -# On branch master -# Changes to be committed: -# (use "git reset HEAD <file>..." to unstage) -# -# modified: dir1/modified -# -# Untracked files: -# (use "git add <file>..." to include in what will be committed) -# -# dir1/untracked -# dir2/ -# expect -# output -# untracked -EOF test_expect_success 'dry-run of partial commit excluding new file in index' ' + cat >expect <<EOF && +On branch master +Changes to be committed: + (use "git reset HEAD <file>..." to unstage) + + modified: dir1/modified + +Untracked files: + (use "git add <file>..." to include in what will be committed) + + dir1/untracked + dir2/ + expect + output + untracked + +EOF git commit --dry-run dir1/modified >output && test_i18ncmp expect output ' @@ -787,31 +827,32 @@ test_expect_success 'setup status submodule summary' ' git add sm ' -cat >expect <<EOF -# On branch master -# Changes to be committed: -# (use "git reset HEAD <file>..." to unstage) -# -# new file: dir2/added -# new file: 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 -# -# Untracked files: -# (use "git add <file>..." to include in what will be committed) -# -# dir1/untracked -# dir2/modified -# dir2/untracked -# expect -# output -# untracked -EOF test_expect_success 'status submodule summary is disabled by default' ' + cat >expect <<EOF && +On branch master +Changes to be committed: + (use "git reset HEAD <file>..." to unstage) + + new file: dir2/added + new file: 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 + +Untracked files: + (use "git add <file>..." to include in what will be committed) + + dir1/untracked + dir2/modified + dir2/untracked + expect + output + untracked + +EOF git status >output && test_i18ncmp expect output ' @@ -846,41 +887,52 @@ test_expect_success 'status -s --untracked-files=all does not show submodule' ' head=$(cd sm && git rev-parse --short=7 --verify HEAD) -cat >expect <<EOF -# On branch master -# Changes to be committed: -# (use "git reset HEAD <file>..." to unstage) -# -# new file: dir2/added -# new file: 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 -# -# Submodule changes to be committed: -# -# * sm 0000000...$head (1): -# > Add foo -# -# Untracked files: -# (use "git add <file>..." to include in what will be committed) -# -# dir1/untracked -# dir2/modified -# dir2/untracked -# expect -# output -# untracked -EOF test_expect_success 'status submodule summary' ' + cat >expect <<EOF && +On branch master +Changes to be committed: + (use "git reset HEAD <file>..." to unstage) + + new file: dir2/added + new file: 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 + +Submodule changes to be committed: + +* sm 0000000...$head (1): + > Add foo + +Untracked files: + (use "git add <file>..." to include in what will be committed) + + dir1/untracked + dir2/modified + dir2/untracked + expect + output + untracked + +EOF git config status.submodulesummary 10 && git status >output && test_i18ncmp expect output ' +test_expect_success 'status submodule summary with status.displayCommentPrefix=false' ' + strip_comments expect && + git -c status.displayCommentPrefix=false status >output && + test_i18ncmp expect output +' + +test_expect_success 'commit with submodule summary ignores status.displayCommentPrefix' ' + commit_template_commented +' + cat >expect <<EOF M dir1/modified A dir2/added @@ -897,26 +949,27 @@ test_expect_success 'status -s submodule summary' ' test_cmp expect output ' -cat >expect <<EOF -# On branch master -# Changes not staged for commit: -# (use "git add <file>..." to update what will be committed) -# (use "git checkout -- <file>..." to discard changes in working directory) -# -# modified: dir1/modified -# -# Untracked files: -# (use "git add <file>..." to include in what will be committed) -# -# dir1/untracked -# dir2/modified -# dir2/untracked -# expect -# output -# untracked +test_expect_success 'status submodule summary (clean submodule): commit' ' + cat >expect <<EOF && +On branch master +Changes not staged for commit: + (use "git add <file>..." to update what will be committed) + (use "git checkout -- <file>..." to discard changes in working directory) + + modified: dir1/modified + +Untracked files: + (use "git add <file>..." to include in what will be committed) + + dir1/untracked + dir2/modified + dir2/untracked + expect + output + untracked + no changes added to commit (use "git add" and/or "git commit -a") EOF -test_expect_success 'status submodule summary (clean submodule): commit' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && @@ -941,41 +994,42 @@ test_expect_success 'status -s submodule summary (clean submodule)' ' test_expect_success 'status -z implies porcelain' ' git status --porcelain | - "$PERL_PATH" -pe "s/\012/\000/g" >expect && + perl -pe "s/\012/\000/g" >expect && git status -z >output && test_cmp expect output ' -cat >expect <<EOF -# On branch master -# Changes to be committed: -# (use "git reset HEAD^1 <file>..." to unstage) -# -# new file: dir2/added -# new file: 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 -# -# Submodule changes to be committed: -# -# * sm 0000000...$head (1): -# > Add foo -# -# Untracked files: -# (use "git add <file>..." to include in what will be committed) -# -# dir1/untracked -# dir2/modified -# dir2/untracked -# expect -# output -# untracked -EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' + cat >expect <<EOF && +On branch master +Changes to be committed: + (use "git reset HEAD^1 <file>..." to unstage) + + new file: dir2/added + new file: 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 + +Submodule changes to be committed: + +* sm 0000000...$head (1): + > Add foo + +Untracked files: + (use "git add <file>..." to include in what will be committed) + + dir1/untracked + dir2/modified + dir2/untracked + expect + output + untracked + +EOF git config status.submodulesummary 10 && git commit --dry-run --amend >output && test_i18ncmp expect output @@ -1000,52 +1054,51 @@ test_expect_success POSIXPERM,SANITY 'status succeeds in a read-only repository' new_head=$(cd sm && git rev-parse --short=7 --verify HEAD) touch .gitmodules -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 -# -# Submodule changes to be committed: -# -# * sm $head...$new_head (1): -# > Add bar -# -# 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 '--ignore-submodules=untracked suppresses submodules with untracked content' ' + 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 + +Submodule changes to be committed: + +* sm $head...$new_head (1): + > Add bar + +Untracked files: + (use "git add <file>..." to include in what will be committed) + + .gitmodules + dir1/untracked + dir2/modified + dir2/untracked + expect + output + untracked + +EOF echo modified sm/untracked && git status --ignore-submodules=untracked >output && test_i18ncmp expect output ' 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 +1118,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' ' @@ -1112,39 +1164,39 @@ test_expect_success '.git/config ignore=dirty suppresses submodules with modifie git config -f .gitmodules --remove-section submodule.subname ' -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) -# (commit or discard the untracked or modified content in submodules) -# -# modified: dir1/modified -# modified: sm (modified content) -# -# Submodule changes to be committed: -# -# * sm $head...$new_head (1): -# > Add bar -# -# 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 "--ignore-submodules=untracked doesn't suppress submodules with modified content" ' + 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) + (commit or discard the untracked or modified content in submodules) + + modified: dir1/modified + modified: sm (modified content) + +Submodule changes to be committed: + +* sm $head...$new_head (1): + > Add bar + +Untracked files: + (use "git add <file>..." to include in what will be committed) + + .gitmodules + dir1/untracked + dir2/modified + dir2/untracked + expect + output + untracked + +EOF git status --ignore-submodules=untracked > output && test_i18ncmp expect output ' @@ -1170,43 +1222,43 @@ test_expect_success ".git/config ignore=untracked doesn't suppress submodules wi head2=$(cd sm && git commit -q -m "2nd commit" foo && git rev-parse --short=7 --verify HEAD) -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 "--ignore-submodules=untracked 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 git status --ignore-submodules=untracked > output && test_i18ncmp expect output ' @@ -1254,32 +1306,81 @@ test_expect_success ".git/config ignore=dirty doesn't suppress submodule summary ' cat > expect << EOF -# On branch master -# Changes not staged for commit: -# (use "git add <file>..." to update what will be committed) -# (use "git checkout -- <file>..." to discard changes in working directory) -# -# modified: dir1/modified -# -# Untracked files: -# (use "git add <file>..." to include in what will be committed) -# -# .gitmodules -# dir1/untracked -# dir2/modified -# dir2/untracked -# expect -# output -# untracked -no changes added to commit (use "git add" and/or "git commit -a") +; 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 -c status.displayCommentPrefix=true status >output && + test_i18ncmp expect output +' + +test_expect_success "status (core.commentchar with two chars with submodule summary)" ' + test_config core.commentchar ";;" && + git -c status.displayCommentPrefix=true status >output && + test_i18ncmp expect output +' + test_expect_success "--ignore-submodules=all suppresses submodule summary" ' + cat > expect << EOF && +On branch master +Changes not staged for commit: + (use "git add <file>..." to update what will be committed) + (use "git checkout -- <file>..." to discard changes in working directory) + + modified: dir1/modified + +Untracked files: + (use "git add <file>..." to include in what will be committed) + + .gitmodules + dir1/untracked + dir2/modified + dir2/untracked + expect + output + untracked + +no changes added to commit (use "git add" and/or "git commit -a") +EOF git status --ignore-submodules=all > output && test_i18ncmp expect output ' -test_expect_failure '.gitmodules ignore=all suppresses submodule summary' ' +test_expect_success '.gitmodules ignore=all suppresses submodule summary' ' git config --add -f .gitmodules submodule.subname.ignore all && git config --add -f .gitmodules submodule.subname.path sm && git status > output && @@ -1287,7 +1388,7 @@ test_expect_failure '.gitmodules ignore=all suppresses submodule summary' ' git config -f .gitmodules --remove-section submodule.subname ' -test_expect_failure '.git/config ignore=all suppresses submodule summary' ' +test_expect_success '.git/config ignore=all suppresses submodule summary' ' git config --add -f .gitmodules submodule.subname.ignore none && git config --add -f .gitmodules submodule.subname.path sm && git config --add submodule.subname.ignore all && @@ -1298,4 +1399,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/t7510-signed-commit.sh b/t/t7510-signed-commit.sh index 1d3c56fe61..5ddac1a9f7 100755 --- a/t/t7510-signed-commit.sh +++ b/t/t7510-signed-commit.sh @@ -5,6 +5,8 @@ test_description='signed commit tests' . "$TEST_DIRECTORY/lib-gpg.sh" test_expect_success GPG 'create signed commits' ' + test_when_finished "test_unconfig commit.gpgsign" && + echo 1 >file && git add file && test_tick && git commit -S -m initial && git tag initial && @@ -25,12 +27,27 @@ test_expect_success GPG 'create signed commits' ' git tag fourth-unsigned && test_tick && git commit --amend -S -m "fourth signed" && - git tag fourth-signed + git tag fourth-signed && + + git config commit.gpgsign true && + echo 5 >file && test_tick && git commit -a -m "fifth signed" && + git tag fifth-signed && + + git config commit.gpgsign false && + echo 6 >file && test_tick && git commit -a -m "sixth" && + git tag sixth-unsigned && + + git config commit.gpgsign true && + echo 7 >file && test_tick && git commit -a -m "seventh" --no-gpg-sign && + git tag seventh-unsigned && + + test_tick && git rebase -f HEAD^^ && git tag sixth-signed HEAD^ && + git tag seventh-signed ' test_expect_success GPG 'show signatures' ' ( - for commit in initial second merge master + for commit in initial second merge fourth-signed fifth-signed sixth-signed master do git show --pretty=short --show-signature $commit >actual && grep "Good signature from" actual || exit 1 @@ -39,7 +56,7 @@ test_expect_success GPG 'show signatures' ' done ) && ( - for commit in merge^2 fourth-unsigned + for commit in merge^2 fourth-unsigned sixth-unsigned seventh-unsigned do git show --pretty=short --show-signature $commit >actual && grep "Good signature from" actual && exit 1 @@ -52,7 +69,7 @@ test_expect_success GPG 'show signatures' ' test_expect_success GPG 'detect fudged signature' ' git cat-file commit master >raw && - sed -e "s/fourth signed/4th forged/" raw >forged1 && + sed -e "s/seventh/7th forged/" raw >forged1 && git hash-object -w -t commit forged1 >forged1.commit && git show --pretty=short --show-signature $(cat forged1.commit) >actual1 && grep "BAD signature from" actual1 && diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh index b3f6eb9c68..68ad2d7454 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 && @@ -24,18 +25,18 @@ test_expect_success 'prepare for conflicts' ' test_expect_success 'status when conflicts unresolved' ' test_must_fail git merge master && - cat >expected <<-\EOF && - # On branch conflicts - # You have unmerged paths. - # (fix conflicts and run "git commit") - # - # Unmerged paths: - # (use "git add <file>..." to mark resolution) - # - # both modified: main.txt - # - no changes added to commit (use "git add" and/or "git commit -a") - EOF + cat >expected <<\EOF && +On branch conflicts +You have unmerged paths. + (fix conflicts and run "git commit") + +Unmerged paths: + (use "git add <file>..." to mark resolution) + + both modified: main.txt + +no changes added to commit (use "git add" and/or "git commit -a") +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -46,17 +47,17 @@ test_expect_success 'status when conflicts resolved before commit' ' test_must_fail git merge master && echo one >main.txt && git add main.txt && - cat >expected <<-\EOF && - # On branch conflicts - # All conflicts fixed but you are still merging. - # (use "git commit" to conclude merge) - # - # Changes to be committed: - # - # modified: main.txt - # - # Untracked files not listed (use -u option to show untracked files) - EOF + cat >expected <<\EOF && +On branch conflicts +All conflicts fixed but you are still merging. + (use "git commit" to conclude merge) + +Changes to be committed: + + modified: main.txt + +Untracked files not listed (use -u option to show untracked files) +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -73,22 +74,23 @@ 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. - # (fix conflicts and then run "git rebase --continue") - # (use "git rebase --skip" to skip this patch) - # (use "git rebase --abort" to check out the original branch) - # - # Unmerged paths: - # (use "git reset HEAD <file>..." to unstage) - # (use "git add <file>..." to mark resolution) - # - # both modified: main.txt - # - no changes added to commit (use "git add" and/or "git commit -a") - EOF + 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) + +Unmerged paths: + (use "git reset HEAD <file>..." to unstage) + (use "git add <file>..." to mark resolution) + + both modified: main.txt + +no changes added to commit (use "git add" and/or "git commit -a") +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -97,21 +99,22 @@ 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. - # (all conflicts fixed: run "git rebase --continue") - # - # Changes to be committed: - # (use "git reset HEAD <file>..." to unstage) - # - # modified: main.txt - # - # Untracked files not listed (use -u option to show untracked files) - EOF + 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: + (use "git reset HEAD <file>..." to unstage) + + modified: main.txt + +Untracked files not listed (use -u option to show untracked files) +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -130,22 +133,23 @@ 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. - # (fix conflicts and then run "git rebase --continue") - # (use "git rebase --skip" to skip this patch) - # (use "git rebase --abort" to check out the original branch) - # - # Unmerged paths: - # (use "git reset HEAD <file>..." to unstage) - # (use "git add <file>..." to mark resolution) - # - # both modified: main.txt - # - no changes added to commit (use "git add" and/or "git commit -a") - EOF + 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) + +Unmerged paths: + (use "git reset HEAD <file>..." to unstage) + (use "git add <file>..." to mark resolution) + + both modified: main.txt + +no changes added to commit (use "git add" and/or "git commit -a") +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -154,20 +158,21 @@ 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. - # (all conflicts fixed: run "git rebase --continue") - # - # Changes to be committed: - # (use "git reset HEAD <file>..." to unstage) - # - # modified: main.txt - # - # Untracked files not listed (use -u option to show untracked files) - EOF + 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: + (use "git reset HEAD <file>..." to unstage) + + modified: main.txt + +Untracked files not listed (use -u option to show untracked files) +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -182,15 +187,16 @@ 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. - # (use "git commit --amend" to amend the current commit) - # (use "git rebase --continue" once you are satisfied with your changes) - # - nothing to commit (use -u to show untracked files) - EOF + 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) + +nothing to commit (use -u to show untracked files) +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -206,21 +212,22 @@ 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. - # (Once your working directory is clean, run "git rebase --continue") - # - # Changes not staged for commit: - # (use "git add <file>..." to update what will be committed) - # (use "git checkout -- <file>..." to discard changes in working directory) - # - # modified: main.txt - # - no changes added to commit (use "git add" and/or "git commit -a") - EOF + 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: + (use "git add <file>..." to update what will be committed) + (use "git checkout -- <file>..." to discard changes in working directory) + + modified: main.txt + +no changes added to commit (use "git add" and/or "git commit -a") +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -236,16 +243,17 @@ 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. - # (use "git commit --amend" to amend the current commit) - # (use "git rebase --continue" once you are satisfied with your changes) - # - nothing to commit (use -u to show untracked files) - EOF + 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) + +nothing to commit (use -u to show untracked files) +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -265,16 +273,17 @@ 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. - # (use "git commit --amend" to amend the current commit) - # (use "git rebase --continue" once you are satisfied with your changes) - # - nothing to commit (use -u to show untracked files) - EOF + 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) + +nothing to commit (use -u to show untracked files) +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -285,22 +294,23 @@ 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. - # (Once your working directory is clean, run "git rebase --continue") - # - # Changes not staged for commit: - # (use "git add <file>..." to update what will be committed) - # (use "git checkout -- <file>..." to discard changes in working directory) - # - # modified: main.txt - # - no changes added to commit (use "git add" and/or "git commit -a") - EOF + 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: + (use "git add <file>..." to update what will be committed) + (use "git checkout -- <file>..." to discard changes in working directory) + + modified: main.txt + +no changes added to commit (use "git add" and/or "git commit -a") +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -311,17 +321,18 @@ 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. - # (use "git commit --amend" to amend the current commit) - # (use "git rebase --continue" once you are satisfied with your changes) - # - nothing to commit (use -u to show untracked files) - EOF + 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) + +nothing to commit (use -u to show untracked files) +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -332,17 +343,18 @@ 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. - # (use "git commit --amend" to amend the current commit) - # (use "git rebase --continue" once you are satisfied with your changes) - # - nothing to commit (use -u to show untracked files) - EOF + 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) + +nothing to commit (use -u to show untracked files) +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -353,23 +365,24 @@ 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. - # (Once your working directory is clean, run "git rebase --continue") - # - # Changes not staged for commit: - # (use "git add <file>..." to update what will be committed) - # (use "git checkout -- <file>..." to discard changes in working directory) - # - # modified: main.txt - # - no changes added to commit (use "git add" and/or "git commit -a") - EOF + 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: + (use "git add <file>..." to update what will be committed) + (use "git checkout -- <file>..." to discard changes in working directory) + + modified: main.txt + +no changes added to commit (use "git add" and/or "git commit -a") +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -380,18 +393,19 @@ 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. - # (use "git commit --amend" to amend the current commit) - # (use "git rebase --continue" once you are satisfied with your changes) - # - nothing to commit (use -u to show untracked files) - EOF + 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) + +nothing to commit (use -u to show untracked files) +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -402,19 +416,20 @@ 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. - # (use "git commit --amend" to amend the current commit) - # (use "git rebase --continue" once you are satisfied with your changes) - # - nothing to commit (use -u to show untracked files) - EOF + 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) + +nothing to commit (use -u to show untracked files) +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -425,25 +440,26 @@ 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. - # (Once your working directory is clean, run "git rebase --continue") - # - # Changes not staged for commit: - # (use "git add <file>..." to update what will be committed) - # (use "git checkout -- <file>..." to discard changes in working directory) - # - # modified: main.txt - # - no changes added to commit (use "git add" and/or "git commit -a") - EOF + 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: + (use "git add <file>..." to update what will be committed) + (use "git checkout -- <file>..." to discard changes in working directory) + + modified: main.txt + +no changes added to commit (use "git add" and/or "git commit -a") +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -454,20 +470,21 @@ 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. - # (use "git commit --amend" to amend the current commit) - # (use "git rebase --continue" once you are satisfied with your changes) - # - nothing to commit (use -u to show untracked files) - EOF + 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) + +nothing to commit (use -u to show untracked files) +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -487,15 +504,15 @@ test_expect_success 'status in an am session: file already exists' ' test_when_finished "rm Maildir/* && git am --abort" && git format-patch -1 -oMaildir && test_must_fail git am Maildir/*.patch && - cat >expected <<-\EOF && - # On branch am_already_exists - # You are in the middle of an am session. - # (fix conflicts and then run "git am --resolved") - # (use "git am --skip" to skip this patch) - # (use "git am --abort" to restore the original branch) - # - nothing to commit (use -u to show untracked files) - EOF + cat >expected <<\EOF && +On branch am_already_exists +You are in the middle of an am session. + (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) + +nothing to commit (use -u to show untracked files) +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -509,15 +526,15 @@ test_expect_success 'status in an am session: file does not exist' ' test_when_finished "rm Maildir/* && git am --abort" && git format-patch -1 -oMaildir && test_must_fail git am Maildir/*.patch && - cat >expected <<-\EOF && - # On branch am_not_exists - # You are in the middle of an am session. - # (fix conflicts and then run "git am --resolved") - # (use "git am --skip" to skip this patch) - # (use "git am --abort" to restore the original branch) - # - nothing to commit (use -u to show untracked files) - EOF + cat >expected <<\EOF && +On branch am_not_exists +You are in the middle of an am session. + (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) + +nothing to commit (use -u to show untracked files) +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -532,15 +549,15 @@ test_expect_success 'status in an am session: empty patch' ' git commit -m "delete all am_empty" && echo error >Maildir/0002-two_am.patch && test_must_fail git am Maildir/*.patch && - cat >expected <<-\EOF && - # On branch am_empty - # You are in the middle of an am session. - # The current patch is empty. - # (use "git am --skip" to skip this patch) - # (use "git am --abort" to restore the original branch) - # - nothing to commit (use -u to show untracked files) - EOF + cat >expected <<\EOF && +On branch am_empty +You are in the middle of an am session. +The current patch is empty. + (use "git am --skip" to skip this patch) + (use "git am --abort" to restore the original branch) + +nothing to commit (use -u to show untracked files) +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -556,13 +573,14 @@ 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. - # (use "git bisect reset" to get back to the original branch) - # - nothing to commit (use -u to show untracked files) - EOF + 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) +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -577,16 +595,17 @@ 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. - # - # Unmerged paths: - # both modified: main.txt - # - no changes added to commit - EOF + cat >expected <<EOF && +rebase in progress; onto $ONTO +You are currently rebasing branch '\''statushints_disabled'\'' on '\''$ONTO'\''. + +Unmerged paths: + both modified: main.txt + +no changes added to commit +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -607,18 +626,20 @@ test_expect_success 'prepare for cherry-pick conflicts' ' test_expect_success 'status when cherry-picking before resolving conflicts' ' test_when_finished "git cherry-pick --abort" && test_must_fail git cherry-pick cherry_branch_second && - cat >expected <<-\EOF && - # On branch cherry_branch - # You are currently cherry-picking. - # (fix conflicts and run "git commit") - # - # Unmerged paths: - # (use "git add <file>..." to mark resolution) - # - # both modified: main.txt - # - no changes added to commit (use "git add" and/or "git commit -a") - EOF + TO_CHERRY_PICK=$(git rev-parse --short CHERRY_PICK_HEAD) && + cat >expected <<EOF && +On branch cherry_branch +You are currently cherry-picking commit $TO_CHERRY_PICK. + (fix conflicts and run "git cherry-pick --continue") + (use "git cherry-pick --abort" to cancel the cherry-pick operation) + +Unmerged paths: + (use "git add <file>..." to mark resolution) + + both modified: main.txt + +no changes added to commit (use "git add" and/or "git commit -a") +EOF git status --untracked-files=no >actual && test_i18ncmp expected actual ' @@ -628,22 +649,100 @@ test_expect_success 'status when cherry-picking after resolving conflicts' ' git reset --hard cherry_branch && test_when_finished "git cherry-pick --abort" && test_must_fail git cherry-pick cherry_branch_second && + TO_CHERRY_PICK=$(git rev-parse --short CHERRY_PICK_HEAD) && echo end >main.txt && git add main.txt && - cat >expected <<-\EOF && - # On branch cherry_branch - # You are currently cherry-picking. - # (all conflicts fixed: run "git commit") - # - # Changes to be committed: - # - # modified: main.txt - # - # Untracked files not listed (use -u option to show untracked files) - EOF + cat >expected <<EOF && +On branch cherry_branch +You are currently cherry-picking commit $TO_CHERRY_PICK. + (all conflicts fixed: run "git cherry-pick --continue") + (use "git cherry-pick --abort" to cancel the cherry-pick operation) + +Changes to be committed: + + modified: main.txt + +Untracked files not listed (use -u option to show untracked files) +EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + +test_expect_success '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/t7514-commit-patch.sh b/t/t7514-commit-patch.sh new file mode 100755 index 0000000000..998a2103c7 --- /dev/null +++ b/t/t7514-commit-patch.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +test_description='hunk edit with "commit -p -m"' +. ./test-lib.sh + +if ! test_have_prereq PERL +then + skip_all="skipping '$test_description' tests, perl not available" + test_done +fi + +test_expect_success 'setup (initial)' ' + echo line1 >file && + git add file && + git commit -m commit1 +' + +test_expect_success 'edit hunk "commit -p -m message"' ' + test_when_finished "rm -f editor_was_started" && + rm -f editor_was_started && + echo more >>file && + echo e | env GIT_EDITOR=": >editor_was_started" git commit -p -m commit2 file && + test -r editor_was_started +' + +test_expect_success 'edit hunk "commit --dry-run -p -m message"' ' + test_when_finished "rm -f editor_was_started" && + rm -f editor_was_started && + echo more >>file && + echo e | env GIT_EDITOR=": >editor_was_started" git commit -p -m commit3 file && + test -r editor_was_started +' + +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..f768c900ab 100755 --- a/t/t7601-merge-pull-config.sh +++ b/t/t7601-merge-pull-config.sh @@ -38,6 +38,27 @@ test_expect_success 'merge c1 with c2' ' test -f c2.c ' +test_expect_success 'fast-forward pull succeeds with "true" in pull.ff' ' + git reset --hard c0 && + test_config pull.ff true && + git pull . c1 && + test "$(git rev-parse HEAD)" = "$(git rev-parse c1)" +' + +test_expect_success 'fast-forward pull creates merge with "false" in pull.ff' ' + git reset --hard c0 && + test_config pull.ff false && + git pull . c1 && + test "$(git rev-parse HEAD^1)" = "$(git rev-parse c0)" && + test "$(git rev-parse HEAD^2)" = "$(git rev-parse c1)" +' + +test_expect_success 'pull prevents non-fast-forward with "only" in pull.ff' ' + git reset --hard c1 && + test_config pull.ff only && + test_must_fail git pull . c3 +' + test_expect_success 'merge c1 with c2 (ours in pull.twohead)' ' git reset --hard c1 && git config pull.twohead ours && @@ -109,7 +130,7 @@ test_expect_success 'setup conflicted merge' ' ' # First do the merge with resolve and recursive then verify that -# recusive is choosen. +# recursive 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..05d9db090d 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 ) && @@ -253,7 +253,7 @@ test_expect_success 'deleted vs modified submodule' ' git checkout -b test6 branch1 && git submodule update -N && mv submod submod-movedaside && - git rm submod && + git rm --cached submod && git commit -m "Submodule deleted from branch" && git checkout -b test6.a test6 && test_must_fail git merge master && @@ -322,7 +322,7 @@ test_expect_success 'file vs modified submodule' ' git checkout -b test7 branch1 && git submodule update -N && mv submod submod-movedaside && - git rm submod && + git rm --cached submod && echo not a submodule >submod && git add submod && git commit -m "Submodule path becomes file" && @@ -453,7 +453,7 @@ test_expect_success 'submodule in subdirectory' ' test_expect_success 'directory vs modified submodule' ' git checkout -b test11 branch1 && mv submod submod-movedaside && - git rm submod && + git rm --cached submod && mkdir submod && echo not a submodule >submod/file16 && git add submod/file16 && 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/t7700-repack.sh b/t/t7700-repack.sh index d954b846a1..284018e3cd 100755 --- a/t/t7700-repack.sh +++ b/t/t7700-repack.sh @@ -17,11 +17,11 @@ test_expect_success 'objects in packs marked .keep are not repacked' ' # The second pack will contain the excluded object packsha1=$(git rev-list --objects --all | grep file2 | git pack-objects pack) && - touch -r pack-$packsha1.pack pack-$packsha1.keep && + >pack-$packsha1.keep && objsha1=$(git verify-pack -v pack-$packsha1.idx | head -n 1 | sed -e "s/^\([0-9a-f]\{40\}\).*/\1/") && mv pack-* .git/objects/pack/ && - git repack -A -d -l && + git repack --no-pack-kept-objects -A -d -l && git prune-packed && for p in .git/objects/pack/*.idx; do idx=$(basename $p) @@ -35,6 +35,22 @@ test_expect_success 'objects in packs marked .keep are not repacked' ' test -z "$found_duplicate_object" ' +test_expect_success 'writing bitmaps can duplicate .keep objects' ' + # build on $objsha1, $packsha1, and .keep state from previous + git repack -Adl && + test_when_finished "found_duplicate_object=" && + for p in .git/objects/pack/*.idx; do + idx=$(basename $p) + test "pack-$packsha1.idx" = "$idx" && continue + if git verify-pack -v $p | egrep "^$objsha1"; then + found_duplicate_object=1 + echo "DUPLICATE OBJECT FOUND" + break + fi + done && + test "$found_duplicate_object" = 1 +' + test_expect_success 'loose objects in alternate ODB are not repacked' ' mkdir alt_objects && echo `pwd`/alt_objects > .git/objects/info/alternates && diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh index eb1d3f85b5..5a193c500d 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" && - - diff=$(git difftool --no-prompt branch) && - test "$diff" = "master" && + difftool_test_setup && + test_config difftool.test-tool.cmd "cat \"\$REMOTE\"" && + echo master >expect && + git difftool --no-prompt branch >actual && + test_cmp expect actual && - 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 && - - diff=$(git difftool --no-prompt --gui branch) && - test "$diff" = "branch" && + difftool_test_setup && + test_config merge.tool bogus-tool && + test_config diff.tool bogus-tool && + test_config diff.guitool test-tool && - 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 && + difftool_test_setup && + : >expect && + git difftool --no-prompt --gui --no-gui >actual && + test_cmp expect actual && - git config merge.tool bogus-tool && - git config diff.tool bogus-tool && - git config diff.guitool test-tool && - diff=$(git difftool --no-prompt --no-gui --gui branch) && - test "$diff" = "branch" && - - restore_test_defaults + test_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 && - - GIT_DIFF_TOOL=test-tool && - export GIT_DIFF_TOOL && - - diff=$(git difftool --no-prompt branch) && - test "$diff" = "branch" && + difftool_test_setup && + test_config diff.tool bogus-tool && + test_config merge.tool bogus-tool && - GIT_DIFF_TOOL=bogus-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 --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,137 @@ 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" + ) +' + +test_expect_success PERL 'difftool properly honors gitlink and core.worktree' ' + git submodule add ./. submod/ule && + ( + cd submod/ule && + test_config diff.tool checktrees && + test_config difftool.checktrees.cmd '\'' + test -d "$LOCAL" && test -d "$REMOTE" && echo good + '\'' && + echo good >expect && + git difftool --tool=checktrees --dir-diff HEAD~ >actual && + test_cmp expect actual ) ' diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index f698001c99..63b3039243 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -105,7 +105,7 @@ do test_expect_success "grep -w $L (w)" ' : >expected && - test_must_fail git grep -n -w -e "^w" >actual && + test_must_fail git grep -n -w -e "^w" $H >actual && test_cmp expected actual ' @@ -240,92 +240,104 @@ do test_cmp expected actual ' test_expect_success "grep $L with grep.extendedRegexp=false" ' - echo "ab:a+bc" >expected && - git -c grep.extendedRegexp=false grep "a+b*c" ab >actual && + echo "${HC}ab:a+bc" >expected && + git -c grep.extendedRegexp=false grep "a+b*c" $H ab >actual && test_cmp expected actual ' test_expect_success "grep $L with grep.extendedRegexp=true" ' - echo "ab:abc" >expected && - git -c grep.extendedRegexp=true grep "a+b*c" ab >actual && + echo "${HC}ab:abc" >expected && + git -c grep.extendedRegexp=true grep "a+b*c" $H ab >actual && test_cmp expected actual ' test_expect_success "grep $L with grep.patterntype=basic" ' - echo "ab:a+bc" >expected && - git -c grep.patterntype=basic grep "a+b*c" ab >actual && + echo "${HC}ab:a+bc" >expected && + git -c grep.patterntype=basic grep "a+b*c" $H ab >actual && test_cmp expected actual ' test_expect_success "grep $L with grep.patterntype=extended" ' - echo "ab:abc" >expected && - git -c grep.patterntype=extended grep "a+b*c" ab >actual && + echo "${HC}ab:abc" >expected && + git -c grep.patterntype=extended grep "a+b*c" $H ab >actual && test_cmp expected actual ' test_expect_success "grep $L with grep.patterntype=fixed" ' - echo "ab:a+b*c" >expected && - git -c grep.patterntype=fixed grep "a+b*c" ab >actual && + echo "${HC}ab:a+b*c" >expected && + git -c grep.patterntype=fixed grep "a+b*c" $H ab >actual && test_cmp expected actual ' test_expect_success LIBPCRE "grep $L with grep.patterntype=perl" ' - echo "ab:a+b*c" >expected && - git -c grep.patterntype=perl grep "a\x{2b}b\x{2a}c" ab >actual && + echo "${HC}ab:a+b*c" >expected && + git -c grep.patterntype=perl grep "a\x{2b}b\x{2a}c" $H ab >actual && test_cmp expected actual ' test_expect_success "grep $L with grep.patternType=default and grep.extendedRegexp=true" ' - echo "ab:abc" >expected && + echo "${HC}ab:abc" >expected && git \ -c grep.patternType=default \ -c grep.extendedRegexp=true \ - grep "a+b*c" ab >actual && + grep "a+b*c" $H ab >actual && test_cmp expected actual ' test_expect_success "grep $L with grep.extendedRegexp=true and grep.patternType=default" ' - echo "ab:abc" >expected && + echo "${HC}ab:abc" >expected && git \ -c grep.extendedRegexp=true \ -c grep.patternType=default \ - grep "a+b*c" ab >actual && + grep "a+b*c" $H ab >actual && test_cmp expected actual ' - test_expect_success 'grep $L with grep.patternType=extended and grep.extendedRegexp=false' ' - echo "ab:abc" >expected && + test_expect_success "grep $L with grep.patternType=extended and grep.extendedRegexp=false" ' + echo "${HC}ab:abc" >expected && git \ -c grep.patternType=extended \ -c grep.extendedRegexp=false \ - grep "a+b*c" ab >actual && + grep "a+b*c" $H ab >actual && test_cmp expected actual ' - test_expect_success 'grep $L with grep.patternType=basic and grep.extendedRegexp=true' ' - echo "ab:a+bc" >expected && + test_expect_success "grep $L with grep.patternType=basic and grep.extendedRegexp=true" ' + echo "${HC}ab:a+bc" >expected && git \ -c grep.patternType=basic \ -c grep.extendedRegexp=true \ - grep "a+b*c" ab >actual && + grep "a+b*c" $H ab >actual && test_cmp expected actual ' - test_expect_success 'grep $L with grep.extendedRegexp=false and grep.patternType=extended' ' - echo "ab:abc" >expected && + test_expect_success "grep $L with grep.extendedRegexp=false and grep.patternType=extended" ' + echo "${HC}ab:abc" >expected && git \ -c grep.extendedRegexp=false \ -c grep.patternType=extended \ - grep "a+b*c" ab >actual && + grep "a+b*c" $H ab >actual && test_cmp expected actual ' - test_expect_success 'grep $L with grep.extendedRegexp=true and grep.patternType=basic' ' - echo "ab:a+bc" >expected && + test_expect_success "grep $L with grep.extendedRegexp=true and grep.patternType=basic" ' + echo "${HC}ab:a+bc" >expected && git \ -c grep.extendedRegexp=true \ -c grep.patternType=basic \ - grep "a+b*c" ab >actual && + grep "a+b*c" $H ab >actual && + test_cmp expected actual + ' + + test_expect_success "grep --count $L" ' + echo ${HC}ab:3 >expected && + git grep --count -e b $H -- ab >actual && + test_cmp expected actual + ' + + test_expect_success "grep --count -h $L" ' + echo 3 >expected && + git grep --count -h -e b $H -- ab >actual && test_cmp expected actual ' done 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..eacd49ade6 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 && @@ -22,11 +20,11 @@ test_expect_success 'setup ' ' ' cat >expected <<EOF -fatal: git cat-file --textconv: unable to run textconv on :one.bin +bin: test version 2 EOF test_expect_success 'no filter specified' ' - git cat-file --textconv :one.bin 2>result + git cat-file --textconv :one.bin >result && test_cmp expected result ' @@ -36,10 +34,6 @@ test_expect_success 'setup textconv filters' ' git config diff.test.cachetextconv false ' -cat >expected <<EOF -bin: test version 2 -EOF - test_expect_success 'cat-file without --textconv' ' git cat-file blob :one.bin >result && test_cmp expected result @@ -72,26 +66,20 @@ 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)' ' + printf "%s" "one.bin" >expected && 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)' ' - ! git cat-file --textconv :symlink.bin 2>result && - cat >expected <<\EOF && -fatal: git cat-file --textconv: unable to run textconv on :symlink.bin -EOF +test_expect_success 'cat-file --textconv on index (symlink)' ' + git cat-file --textconv :symlink.bin >result && test_cmp expected result ' -test_expect_success SYMLINKS '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 -EOF +test_expect_success 'cat-file --textconv on HEAD (symlink)' ' + git cat-file --textconv HEAD:symlink.bin >result && test_cmp expected result ' diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 6c6af7d13f..1ecdacb6fd 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -23,7 +23,6 @@ test_expect_success $PREREQ \ echo do echo " echo \"!\$a!\"" echo "done >commandline\$output" - test_have_prereq MINGW && echo "dos2unix commandline\$output" echo "cat > msgtxt\$output" ) >fake.sendmail && chmod +x ./fake.sendmail && @@ -101,7 +100,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 +170,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 +265,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 && @@ -308,7 +409,7 @@ test_expect_success $PREREQ 'Valid In-Reply-To when prompting' ' (echo "From Example <from@example.com>" echo "To Example <to@example.com>" echo "" - ) | env GIT_SEND_EMAIL_NOTTY=1 git send-email \ + ) | GIT_SEND_EMAIL_NOTTY=1 git send-email \ --smtp-server="$(pwd)/fake.sendmail" \ $patches 2>errors && ! grep "^In-Reply-To: < *>" msgtxt1 @@ -760,7 +861,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 +955,20 @@ 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 && @@ -976,55 +1091,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 \ 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 index 4f2dfe0e3d..4d81ba1c2c 100755 --- a/t/t9020-remote-svn.sh +++ b/t/t9020-remote-svn.sh @@ -12,15 +12,19 @@ then test_done fi -# We override svnrdump by placing a symlink to the svnrdump-emulator in . -export PATH="$HOME:$PATH" -ln -sf $GIT_BUILD_DIR/contrib/svn-fe/svnrdump_sim.py "$HOME/svnrdump" +# 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!? + # let's reuse an existing dump file!? git remote add svnsim testsvn::sim://$TEST_DIRECTORY/t9154/svn.dump git remote add svnfile testsvn::file://$TEST_DIRECTORY/t9154/svn.dump } @@ -32,8 +36,8 @@ fi test_debug ' git --version - which git - which svnrdump + type git + type svnrdump ' test_expect_success REMOTE_SVN 'simple fetch' ' @@ -70,7 +74,8 @@ test_expect_success REMOTE_SVN 'mark-file regeneration' ' ' test_expect_success REMOTE_SVN 'incremental imports must lead to the same head' ' - export SVNRMAX=3 && + SVNRMAX=3 && + export SVNRMAX && init_git && git fetch svnsim && test_cmp .git/refs/svn/svnsim/master .git/refs/remotes/svnsim/master && 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/t9112-git-svn-md5less-file.sh b/t/t9112-git-svn-md5less-file.sh index a61d6716d2..9861c719f8 100755 --- a/t/t9112-git-svn-md5less-file.sh +++ b/t/t9112-git-svn-md5less-file.sh @@ -7,7 +7,7 @@ test_description='test that git handles an svn repository with missing md5sums' # Loading a node from a svn dumpfile without a Text-Content-Length # field causes svn to neglect to store or report an md5sum. (it will # calculate one if you had put Text-Content-Length: 0). This showed -# up in a repository creted with cvs2svn. +# up in a repository created with cvs2svn. cat > dumpfile.svn <<EOF SVN-fs-dump-format-version: 1 diff --git a/t/t9114-git-svn-dcommit-merge.sh b/t/t9114-git-svn-dcommit-merge.sh index 3077851015..d33d714006 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 && @@ -62,7 +62,7 @@ test_expect_success 'setup git mirror and merge' ' echo friend > README && cat tmp >> README && git commit -a -m "friend" && - git pull . merge + git merge merge ' test_debug 'gitk --all & sleep 1' diff --git a/t/t9117-git-svn-init-clone.sh b/t/t9117-git-svn-init-clone.sh index b7ef9e2589..69e9c0db5d 100755 --- a/t/t9117-git-svn-init-clone.sh +++ b/t/t9117-git-svn-init-clone.sh @@ -52,4 +52,71 @@ test_expect_success 'clone to target directory with --stdlayout' ' rm -rf target ' +test_expect_success 'init without -s/-T/-b/-t does not warn' ' + test ! -d trunk && + git svn init "$svnrepo"/project/trunk trunk 2>warning && + test_must_fail grep -q prefix warning && + rm -rf trunk && + rm -f warning + ' + +test_expect_success 'clone without -s/-T/-b/-t does not warn' ' + test ! -d trunk && + git svn clone "$svnrepo"/project/trunk 2>warning && + test_must_fail grep -q prefix warning && + rm -rf trunk && + rm -f warning + ' + +test_svn_configured_prefix () { + prefix=$1 && + cat >expect <<EOF && +project/trunk:refs/remotes/${prefix}trunk +project/branches/*:refs/remotes/${prefix}* +project/tags/*:refs/remotes/${prefix}tags/* +EOF + test ! -f actual && + git --git-dir=project/.git config svn-remote.svn.fetch >>actual && + git --git-dir=project/.git config svn-remote.svn.branches >>actual && + git --git-dir=project/.git config svn-remote.svn.tags >>actual && + test_cmp expect actual && + rm -f expect actual +} + +test_expect_success 'init with -s/-T/-b/-t without --prefix warns' ' + test ! -d project && + git svn init -s "$svnrepo"/project project 2>warning && + grep -q prefix warning && + test_svn_configured_prefix "" && + rm -rf project && + rm -f warning + ' + +test_expect_success 'clone with -s/-T/-b/-t without --prefix warns' ' + test ! -d project && + git svn clone -s "$svnrepo"/project 2>warning && + grep -q prefix warning && + test_svn_configured_prefix "" && + rm -rf project && + rm -f warning + ' + +test_expect_success 'init with -s/-T/-b/-t and --prefix does not warn' ' + test ! -d project && + git svn init -s "$svnrepo"/project project --prefix="" 2>warning && + test_must_fail grep -q prefix warning && + test_svn_configured_prefix "" && + rm -rf project && + rm -f warning + ' + +test_expect_success 'clone with -s/-T/-b/-t and --prefix does not warn' ' + test ! -d project && + git svn clone -s "$svnrepo"/project --prefix="" 2>warning && + test_must_fail grep -q prefix warning && + test_svn_configured_prefix "" && + rm -rf project && + rm -f warning + ' + test_done diff --git a/t/t9129-git-svn-i18n-commitencoding.sh b/t/t9129-git-svn-i18n-commitencoding.sh index 9a40f1e199..8cfdfe790f 100755 --- a/t/t9129-git-svn-i18n-commitencoding.sh +++ b/t/t9129-git-svn-i18n-commitencoding.sh @@ -29,7 +29,7 @@ fi compare_svn_head_with () { # extract just the log message and strip out committer info. # don't use --limit here since svn 1.1.x doesn't have it, - LC_ALL="$a_utf8_locale" svn log `git svn info --url` | "$PERL_PATH" -w -e ' + LC_ALL="$a_utf8_locale" svn log `git svn info --url` | perl -w -e ' use bytes; $/ = ("-"x72) . "\n"; my @x = <STDIN>; diff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh index c17aa3186f..d60da63f7a 100755 --- a/t/t9137-git-svn-dcommit-clobber-series.sh +++ b/t/t9137-git-svn-dcommit-clobber-series.sh @@ -20,8 +20,8 @@ test_expect_success '(supposedly) non-conflicting change from SVN' ' test x"`sed -n -e 61p < file`" = x61 && svn_cmd co "$svnrepo" tmp && (cd tmp && - "$PERL_PATH" -i.bak -p -e "s/^58$/5588/" file && - "$PERL_PATH" -i.bak -p -e "s/^61$/6611/" file && + perl -i.bak -p -e "s/^58$/5588/" file && + perl -i.bak -p -e "s/^61$/6611/" file && poke file && test x"`sed -n -e 58p < file`" = x5588 && test x"`sed -n -e 61p < file`" = x6611 && @@ -40,8 +40,8 @@ test_expect_success 'some unrelated changes to git' " test_expect_success 'change file but in unrelated area' " test x\"\`sed -n -e 4p < file\`\" = x4 && test x\"\`sed -n -e 7p < file\`\" = x7 && - "$PERL_PATH" -i.bak -p -e 's/^4\$/4444/' file && - "$PERL_PATH" -i.bak -p -e 's/^7\$/7777/' file && + perl -i.bak -p -e 's/^4\$/4444/' file && + perl -i.bak -p -e 's/^7\$/7777/' file && test x\"\`sed -n -e 4p < file\`\" = x4444 && test x\"\`sed -n -e 7p < file\`\" = x7777 && git commit -m '4 => 4444, 7 => 7777' file && diff --git a/t/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/t9150/make-svk-dump b/t/t9150/make-svk-dump index 2242f14ebe..2242f14ebe 100644..100755 --- a/t/t9150/make-svk-dump +++ b/t/t9150/make-svk-dump diff --git a/t/t9151/make-svnmerge-dump b/t/t9151/make-svnmerge-dump index e1e138cb1a..e1e138cb1a 100644..100755 --- a/t/t9151/make-svnmerge-dump +++ b/t/t9151/make-svnmerge-dump 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 69934b2e77..812c9cd462 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -5,7 +5,6 @@ test_description='Test export of commits to CVS' . ./test-lib.sh -. "$TEST_DIRECTORY"/lib-prereq-FILEMODE.sh if ! test_have_prereq PERL; then skip_all='skipping git cvsexportcommit tests, perl not available' @@ -25,8 +24,9 @@ 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..27263dfb80 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -12,7 +12,7 @@ test_description='test git fast-import utility' # This could be written as "head -c $1", but IRIX "head" does not # support the -c option. head_c () { - "$PERL_PATH" -e ' + perl -e ' my $len = $ARGV[1]; while ($len > 0) { my $s; @@ -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 ### @@ -1039,6 +1031,32 @@ test_expect_success \ git diff-tree -M -r M3^ M3 >actual && compare_diff_raw expect actual' +cat >input <<INPUT_END +commit refs/heads/M4 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE +data <<COMMIT +rename root +COMMIT + +from refs/heads/M2^0 +R "" sub + +INPUT_END + +cat >expect <<EOF +:100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 R100 file2/oldf sub/file2/oldf +:100755 100755 85df50785d62d3b05ab03d9cbf7e4a0b49449730 85df50785d62d3b05ab03d9cbf7e4a0b49449730 R100 file4 sub/file4 +:100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc R100 i/am/new/to/you sub/i/am/new/to/you +:100755 100755 e74b7d465e52746be2b4bae983670711e6e66657 e74b7d465e52746be2b4bae983670711e6e66657 R100 newdir/exec.sh sub/newdir/exec.sh +:100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 R100 newdir/interesting sub/newdir/interesting +EOF +test_expect_success \ + 'M: rename root to subdirectory' \ + 'git fast-import <input && + git diff-tree -M -r M4^ M4 >actual && + cat actual && + compare_diff_raw expect actual' + ### ### series N ### @@ -1236,6 +1254,29 @@ test_expect_success \ compare_diff_raw expect actual' test_expect_success \ + 'N: copy root by path' \ + 'cat >expect <<-\EOF && + :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100 file2/newf oldroot/file2/newf + :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 C100 file2/oldf oldroot/file2/oldf + :100755 100755 85df50785d62d3b05ab03d9cbf7e4a0b49449730 85df50785d62d3b05ab03d9cbf7e4a0b49449730 C100 file4 oldroot/file4 + :100755 100755 e74b7d465e52746be2b4bae983670711e6e66657 e74b7d465e52746be2b4bae983670711e6e66657 C100 newdir/exec.sh oldroot/newdir/exec.sh + :100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 C100 newdir/interesting oldroot/newdir/interesting + EOF + cat >input <<-INPUT_END && + commit refs/heads/N-copy-root-path + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + copy root directory by (empty) path + COMMIT + + from refs/heads/branch^0 + C "" oldroot + INPUT_END + git fast-import <input && + git diff-tree -C --find-copies-harder -r branch N-copy-root-path >actual && + compare_diff_raw expect actual' + +test_expect_success \ 'N: delete directory by copying' \ 'cat >expect <<-\EOF && OBJID @@ -2823,14 +2864,14 @@ test_expect_success 'S: notemodify with garbage after sha1 dataref must fail' ' ' # -# notemodify, mark in committish +# notemodify, mark in commit-ish # -test_expect_success 'S: notemodify with garbarge after mark committish must fail' ' +test_expect_success 'S: notemodify with garbarge after mark commit-ish must fail' ' test_must_fail git fast-import --import-marks=marks <<-EOF 2>err && commit refs/heads/Snotes committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT - commit S note committish + commit S note commit-ish COMMIT N :202 :302x EOF @@ -2942,4 +2983,20 @@ test_expect_success 'S: ls with garbage after sha1 must fail' ' test_i18ngrep "space after tree-ish" err ' +### +### series T (ls) +### +# Setup is carried over from series S. + +test_expect_success 'T: ls root tree' ' + sed -e "s/Z\$//" >expect <<-EOF && + 040000 tree $(git rev-parse S^{tree}) Z + EOF + sha1=$(git rev-parse --verify S) && + git fast-import --import-marks=marks <<-EOF >actual && + ls $sha1 "" + EOF + test_cmp expect actual +' + test_done diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh index 3e821f958b..2312dec8f0 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 ) && ( @@ -424,7 +429,7 @@ test_expect_success 'fast-export quotes pathnames' ' --cacheinfo 100644 $blob "path with \\backslash" \ --cacheinfo 100644 $blob "path with space" && git commit -m addition && - git ls-files -z -s | "$PERL_PATH" -0pe "s{\\t}{$&subdir/}" >index && + git ls-files -z -s | perl -0pe "s{\\t}{$&subdir/}" >index && git read-tree --empty && git update-index -z --index-info <index && git commit -m rename && @@ -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 9502f2438a..3edc4086d8 100755 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@ -20,7 +20,7 @@ then skip_all='skipping git-cvsserver tests, cvs not found' test_done fi -"$PERL_PATH" -e 'use DBI; use DBD::SQLite' >/dev/null 2>&1 || { +perl -e 'use DBI; use DBD::SQLite' >/dev/null 2>&1 || { skip_all='skipping git-cvsserver tests, Perl SQLite interface unavailable' test_done } @@ -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" && diff --git a/t/t9401-git-cvsserver-crlf.sh b/t/t9401-git-cvsserver-crlf.sh index 1c5bc84fa7..5a4ed28e49 100755 --- a/t/t9401-git-cvsserver-crlf.sh +++ b/t/t9401-git-cvsserver-crlf.sh @@ -68,7 +68,7 @@ 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 || { +perl -e 'use DBI; use DBD::SQLite' >/dev/null 2>&1 || { skip_all='skipping git-cvsserver tests, Perl SQLite interface unavailable' test_done } @@ -84,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 && diff --git a/t/t9402-git-cvsserver-refs.sh b/t/t9402-git-cvsserver-refs.sh new file mode 100755 index 0000000000..1e266effff --- /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 -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..e74b9ab1e1 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 && @@ -329,7 +328,7 @@ test_expect_success \ git add b && git commit -a -m "On branch" && git checkout master && - git pull . b && + git merge b && git tag merge_commit' test_expect_success \ @@ -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"' @@ -689,9 +683,11 @@ test_expect_success \ # syntax highlighting -highlight --version >/dev/null 2>&1 +highlight_version=$(highlight --version </dev/null 2>/dev/null) if [ $? -eq 127 ]; then - say "Skipping syntax highlighting test, because 'highlight' was not found" + say "Skipping syntax highlighting tests: 'highlight' not found" +elif test -z "$highlight_version"; then + say "Skipping syntax highlighting tests: incorrect 'highlight' found" else test_set_prereq HIGHLIGHT cat >>gitweb_config.perl <<-\EOF 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/t9700-perl-git.sh b/t/t9700-perl-git.sh index 435d896476..102c133112 100755 --- a/t/t9700-perl-git.sh +++ b/t/t9700-perl-git.sh @@ -11,7 +11,7 @@ if ! test_have_prereq PERL; then test_done fi -"$PERL_PATH" -MTest::More -e 0 2>/dev/null || { +perl -MTest::More -e 0 2>/dev/null || { skip_all="Perl Test::More unavailable, skipping test" test_done } @@ -55,6 +55,6 @@ test_external_has_tap=1 test_external_without_stderr \ 'Perl API' \ - "$PERL_PATH" "$TEST_DIRECTORY"/t9700/test.pl + perl "$TEST_DIRECTORY"/t9700/test.pl test_done diff --git a/t/t9700/test.pl b/t/t9700/test.pl index 0d4e366232..1140767b50 100755 --- a/t/t9700/test.pl +++ b/t/t9700/test.pl @@ -45,7 +45,8 @@ 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; +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"); 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..66d3fc91a7 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-appended 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 } @@ -132,6 +250,89 @@ test_expect_success 'ignore apple' ' ) ' +test_expect_success SYMLINKS 'create p4 symlink' ' + cd "$cli" && + ln -s symlink-target symlink && + p4 add symlink && + p4 submit -d "add symlink" +' + +test_expect_success SYMLINKS 'ensure p4 symlink parsed correctly' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot@all && + ( + cd "$git" && + test -L symlink && + test $(readlink symlink) = symlink-target + ) +' + +test_expect_success SYMLINKS 'empty symlink target' ' + ( + # first create the file as a file + cd "$cli" && + >empty-symlink && + p4 add empty-symlink && + p4 submit -d "add empty-symlink as a file" + ) && + ( + # now change it to be a symlink to "target1" + cd "$cli" && + p4 edit empty-symlink && + p4 reopen -t symlink empty-symlink && + rm empty-symlink && + ln -s target1 empty-symlink && + p4 add empty-symlink && + p4 submit -d "make empty-symlink point to target1" + ) && + ( + # Hack the p4 depot to make the symlink point to nothing; + # this should not happen in reality, but shows up + # in p4 repos in the wild. + # + # The sed expression changes this: + # @@ + # text + # @target1 + # @ + # to this: + # @@ + # text + # @@ + # + cd "$db/depot" && + sed "/@target1/{; s/target1/@/; n; d; }" \ + empty-symlink,v >empty-symlink,v.tmp && + mv empty-symlink,v.tmp empty-symlink,v + ) && + ( + # Make sure symlink really is empty. Asking + # p4 to sync here will make it generate errors. + cd "$cli" && + p4 print -q //depot/empty-symlink#2 >out && + test ! -s out + ) && + test_when_finished cleanup_git && + + # make sure git p4 handles it without error + git p4 clone --dest="$git" //depot@all && + + # fix the symlink, make it point to "target2" + ( + cd "$cli" && + p4 open empty-symlink && + rm empty-symlink && + ln -s target2 empty-symlink && + p4 submit -d "make empty-symlink point to target2" + ) && + cleanup_git && + git p4 clone --dest="$git" //depot@all && + ( + cd "$git" && + test $(readlink empty-symlink) = target2 + ) +' + test_expect_success 'kill p4d' ' kill_p4d ' diff --git a/t/t9805-git-p4-skip-submit-edit.sh b/t/t9805-git-p4-skip-submit-edit.sh index ff2cc79701..89311886db 100755 --- a/t/t9805-git-p4-skip-submit-edit.sh +++ b/t/t9805-git-p4-skip-submit-edit.sh @@ -17,7 +17,7 @@ test_expect_success 'init depot' ' ) ' -# this works because EDITOR is set to : +# this works because P4EDITOR is set to true test_expect_success 'no config, unedited, say yes' ' git p4 clone --dest="$git" //depot && test_when_finished cleanup_git && @@ -90,7 +90,9 @@ test_expect_success 'no config, edited' ' cd "$git" && echo line >>file1 && git commit -a -m "change 5" && - P4EDITOR="" EDITOR="\"$TRASH_DIRECTORY/ed.sh\"" git p4 submit && + P4EDITOR="$TRASH_DIRECTORY/ed.sh" && + export P4EDITOR && + git p4 submit && p4 changes //depot/... >wc && test_line_count = 5 wc ) diff --git a/t/t9806-git-p4-options.sh b/t/t9806-git-p4-options.sh index 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..4caf36e006 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_success '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..23a827fa77 100755 --- a/t/t9809-git-p4-client-view.sh +++ b/t/t9809-git-p4-client-view.sh @@ -76,28 +76,28 @@ test_expect_success 'init depot' ' ' # double % for printf -test_expect_success 'unsupported view wildcard %%n' ' +test_expect_success 'view wildcard %%n' ' client_view "//depot/%%%%1/sub/... //client/sub/%%%%1/..." && test_when_finished cleanup_git && - test_must_fail git p4 clone --use-client-spec --dest="$git" //depot + git p4 clone --use-client-spec --dest="$git" //depot ' -test_expect_success 'unsupported view wildcard *' ' +test_expect_success 'view wildcard *' ' client_view "//depot/*/bar/... //client/*/bar/..." && test_when_finished cleanup_git && - test_must_fail git p4 clone --use-client-spec --dest="$git" //depot + git p4 clone --use-client-spec --dest="$git" //depot ' -test_expect_success 'wildcard ... only supported at end of spec 1' ' +test_expect_success 'wildcard ... in the middle' ' client_view "//depot/.../file11 //client/.../file11" && test_when_finished cleanup_git && - test_must_fail git p4 clone --use-client-spec --dest="$git" //depot + git p4 clone --use-client-spec --dest="$git" //depot ' -test_expect_success 'wildcard ... only supported at end of spec 2' ' +test_expect_success 'wildcard ... in the middle and at the end' ' client_view "//depot/.../a/... //client/.../a/..." && test_when_finished cleanup_git && - test_must_fail git p4 clone --use-client-spec --dest="$git" //depot + git p4 clone --use-client-spec --dest="$git" //depot ' test_expect_success 'basic map' ' @@ -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..8134ab439b 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 && @@ -259,7 +263,7 @@ test_expect_success 'cope with rcs keyword expansion damage' ' git config git-p4.attemptRCSCleanup true && (cd "$cli" && p4_append_to_file kwfile1.c) && old_lines=$(wc -l <kwfile1.c) && - "$PERL_PATH" -n -i -e "print unless m/Revision:/" kwfile1.c && + perl -n -i -e "print unless m/Revision:/" kwfile1.c && new_lines=$(wc -l <kwfile1.c) && test $new_lines = $(($old_lines - 1)) && diff --git a/t/t9812-git-p4-wildcards.sh b/t/t9812-git-p4-wildcards.sh index 143d413057..c7472cbf54 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,12 +152,65 @@ 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 ) ' +test_expect_success 'p4 deleted a wildcard file' ' + ( + cd "$cli" && + echo "wild delete test" >wild@delete && + p4 add -f wild@delete && + p4 submit -d "add wild@delete" + ) && + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + test_path_is_file wild@delete + ) && + ( + cd "$cli" && + # must use its encoded name + p4 delete wild%40delete && + p4 submit -d "delete wild@delete" + ) && + ( + cd "$git" && + git p4 sync && + git merge --ff-only p4/master && + test_path_is_missing wild@delete + ) +' + +test_expect_success 'wildcard files requiring keyword scrub' ' + ( + cd "$cli" && + cat <<-\EOF >scrub@wild && + $Id$ + line2 + EOF + p4 add -t text+k -f scrub@wild && + p4 submit -d "scrub at wild" + ) && + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + git config git-p4.attemptRCSCleanup true && + sed "s/^line2/line2 edit/" <scrub@wild >scrub@wild.tmp && + mv -f scrub@wild.tmp scrub@wild && + git commit -m "scrub at wild line2 edit" scrub@wild && + git p4 submit + ) +' + test_expect_success 'kill p4d' ' kill_p4d ' diff --git a/t/t9813-git-p4-preserve-users.sh b/t/t9813-git-p4-preserve-users.sh index f2e85e518b..166b840bfa 100755 --- a/t/t9813-git-p4-preserve-users.sh +++ b/t/t9813-git-p4-preserve-users.sh @@ -19,16 +19,6 @@ test_expect_success 'create files' ' ) ' -p4_add_user() { - name=$1 fullname=$2 && - p4 user -f -i <<-EOF && - User: $name - Email: $name@localhost - FullName: $fullname - EOF - p4 passwd -P secret $name -} - p4_grant_admin() { name=$1 && { @@ -51,8 +41,8 @@ make_change_by_user() { # Test username support, submitting as user 'alice' test_expect_success 'preserve users' ' - p4_add_user alice Alice && - p4_add_user bob Bob && + p4_add_user alice && + p4_add_user bob && p4_grant_admin alice && git p4 clone --dest="$git" //depot && test_when_finished cleanup_git && @@ -60,8 +50,8 @@ test_expect_success 'preserve users' ' cd "$git" && echo "username: a change by alice" >>file1 && echo "username: a change by bob" >>file2 && - git commit --author "Alice <alice@localhost>" -m "a change by alice" file1 && - git commit --author "Bob <bob@localhost>" -m "a change by bob" file2 && + git commit --author "Alice <alice@example.com>" -m "a change by alice" file1 && + git commit --author "Bob <bob@example.com>" -m "a change by bob" file2 && git config git-p4.skipSubmitEditCheck true && P4EDITOR=touch P4USER=alice P4PASSWD=secret git p4 commit --preserve-user && p4_check_commit_author file1 alice && @@ -78,7 +68,7 @@ test_expect_success 'refuse to preserve users without perms' ' cd "$git" && git config git-p4.skipSubmitEditCheck true && echo "username-noperms: a change by alice" >>file1 && - git commit --author "Alice <alice@localhost>" -m "perms: a change by alice" file1 && + git commit --author "Alice <alice@example.com>" -m "perms: a change by alice" file1 && P4EDITOR=touch P4USER=bob P4PASSWD=secret && export P4EDITOR P4USER P4PASSWD && test_must_fail git p4 commit --preserve-user && @@ -94,9 +84,9 @@ test_expect_success 'preserve user where author is unknown to p4' ' cd "$git" && git config git-p4.skipSubmitEditCheck true && echo "username-bob: a change by bob" >>file1 && - git commit --author "Bob <bob@localhost>" -m "preserve: a change by bob" file1 && + git commit --author "Bob <bob@example.com>" -m "preserve: a change by bob" file1 && echo "username-unknown: a change by charlie" >>file1 && - git commit --author "Charlie <charlie@localhost>" -m "preserve: a change by charlie" file1 && + git commit --author "Charlie <charlie@example.com>" -m "preserve: a change by charlie" file1 && P4EDITOR=touch P4USER=alice P4PASSWD=secret && export P4EDITOR P4USER P4PASSWD && test_must_fail git p4 commit --preserve-user && @@ -121,24 +111,24 @@ test_expect_success 'not preserving user with mixed authorship' ' ( cd "$git" && git config git-p4.skipSubmitEditCheck true && - p4_add_user derek Derek && + p4_add_user derek && - make_change_by_user usernamefile3 Derek derek@localhost && + make_change_by_user usernamefile3 Derek derek@example.com && P4EDITOR=cat P4USER=alice P4PASSWD=secret && export P4EDITOR P4USER P4PASSWD && git p4 commit |\ - grep "git author derek@localhost does not match" && + grep "git author derek@example.com does not match" && - make_change_by_user usernamefile3 Charlie charlie@localhost && + make_change_by_user usernamefile3 Charlie charlie@example.com && git p4 commit |\ - grep "git author charlie@localhost does not match" && + grep "git author charlie@example.com does not match" && - make_change_by_user usernamefile3 alice alice@localhost && + make_change_by_user usernamefile3 alice alice@example.com && git p4 commit |\ test_must_fail grep "git author.*does not match" && git config git-p4.skipUserNameCheck true && - make_change_by_user usernamefile3 Charlie charlie@localhost && + make_change_by_user usernamefile3 Charlie charlie@example.com && git p4 commit |\ test_must_fail grep "git author.*does not match" && 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/t9816-git-p4-locked.sh b/t/t9816-git-p4-locked.sh new file mode 100755 index 0000000000..e71e543343 --- /dev/null +++ b/t/t9816-git-p4-locked.sh @@ -0,0 +1,145 @@ +#!/bin/sh + +test_description='git p4 locked file behavior' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +# See +# http://www.perforce.com/perforce/doc.current/manuals/p4sag/03_superuser.html#1088563 +# for suggestions on how to configure "sitewide pessimistic locking" +# where only one person can have a file open for edit at a time. +test_expect_success 'init depot' ' + ( + cd "$cli" && + echo "TypeMap: +l //depot/..." | p4 typemap -i && + echo file1 >file1 && + p4 add file1 && + p4 submit -d "add file1" + ) +' + +test_expect_success 'edit with lock not taken' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo line2 >>file1 && + git add file1 && + git commit -m "line2 in file1" && + git config git-p4.skipSubmitEdit true && + git p4 submit + ) +' + +test_expect_failure 'add with lock not taken' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo line1 >>add-lock-not-taken && + git add file2 && + git commit -m "add add-lock-not-taken" && + git config git-p4.skipSubmitEdit true && + git p4 submit --verbose + ) +' + +lock_in_another_client() { + # build a different client + cli2="$TRASH_DIRECTORY/cli2" && + mkdir -p "$cli2" && + test_when_finished "p4 client -f -d client2 && rm -rf \"$cli2\"" && + ( + cd "$cli2" && + P4CLIENT=client2 && + cli="$cli2" && + client_view "//depot/... //client2/..." && + p4 sync && + p4 open file1 + ) +} + +test_expect_failure 'edit with lock taken' ' + lock_in_another_client && + test_when_finished cleanup_git && + test_when_finished "cd \"$cli\" && p4 sync -f file1" && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo line3 >>file1 && + git add file1 && + git commit -m "line3 in file1" && + git config git-p4.skipSubmitEdit true && + git p4 submit --verbose + ) +' + +test_expect_failure 'delete with lock taken' ' + lock_in_another_client && + test_when_finished cleanup_git && + test_when_finished "cd \"$cli\" && p4 sync -f file1" && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git rm file1 && + git commit -m "delete file1" && + git config git-p4.skipSubmitEdit true && + git p4 submit --verbose + ) +' + +test_expect_failure 'chmod with lock taken' ' + lock_in_another_client && + test_when_finished cleanup_git && + test_when_finished "cd \"$cli\" && p4 sync -f file1" && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + chmod +x file1 && + git add file1 && + git commit -m "chmod +x file1" && + git config git-p4.skipSubmitEdit true && + git p4 submit --verbose + ) +' + +test_expect_failure 'copy with lock taken' ' + lock_in_another_client && + test_when_finished cleanup_git && + test_when_finished "cd \"$cli\" && p4 revert file2 && rm -f file2" && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + cp file1 file2 && + git add file2 && + git commit -m "cp file1 to file2" && + git config git-p4.skipSubmitEdit true && + git config git-p4.detectCopies true && + git p4 submit --verbose + ) +' + +test_expect_failure 'move with lock taken' ' + lock_in_another_client && + test_when_finished cleanup_git && + test_when_finished "cd \"$cli\" && p4 sync file1 && rm -f file2" && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git mv file1 file2 && + git commit -m "mv file1 to file2" && + git config git-p4.skipSubmitEdit true && + git config git-p4.detectRenames true && + git p4 submit --verbose + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 8fa025f9d4..2d4beb5e50 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[${#_words[@]}+1]='' (( _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,18 +462,18 @@ 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 ' @@ -293,4 +482,81 @@ test_expect_success 'send-email' ' 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..59f875e830 100755 --- a/t/t9903-bash-prompt.sh +++ b/t/t9903-bash-prompt.sh @@ -10,446 +10,581 @@ 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_expect_success 'prompt - branch name' ' + printf " (master)" >expected && + __git_ps1 >"$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_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 - $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_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 '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" -' +repo_with_newline='repo +with +newline' -test_expect_success 'gitdir - gitfile in parent' ' - echo "$TRASH_DIRECTORY/otherrepo/.git" > expected && - echo "gitdir: $TRASH_DIRECTORY/otherrepo/.git" > subdir/.git && - test_when_finished "rm -f subdir/.git" && - ( - cd subdir/subsubdir && - __gitdir > "$actual" - ) && - test_cmp expected "$actual" -' +if mkdir "$repo_with_newline" 2>/dev/null +then + test_set_prereq FUNNYNAMES +else + say 'Your filesystem does not allow newlines in filenames.' +fi -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" && +test_expect_success FUNNYNAMES 'prompt - with newline in path' ' + printf " (master)" >expected && + git init "$repo_with_newline" && + test_when_finished "rm -rf \"$repo_with_newline\"" && + mkdir "$repo_with_newline"/subdir && ( - cd link && - __gitdir > "$actual" + cd "$repo_with_newline/subdir" && + __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_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 - disabled by config' ' - printf " (master)" > expected && - echo "dirty" > file && +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 - 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" + __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" + ) && + 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..158e10a67e 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -1,4 +1,5 @@ -#!/bin/sh +# Library of functions shared by all tests scripts, included by +# test-lib.sh. # # Copyright (c) 2005 Junio C Hamano # @@ -31,6 +32,11 @@ test_set_editor () { export EDITOR } +test_set_index_version () { + GIT_INDEX_VERSION="$1" + export GIT_INDEX_VERSION +} + test_decode_color () { awk ' function name(n) { @@ -76,11 +82,11 @@ test_decode_color () { } nul_to_q () { - "$PERL_PATH" -pe 'y/\000/Q/' + perl -pe 'y/\000/Q/' } q_to_nul () { - "$PERL_PATH" -pe 'y/Q/\000/' + perl -pe 'y/Q/\000/' } q_to_cr () { @@ -91,6 +97,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 +145,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 +178,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 +285,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 +313,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 +349,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 +364,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 +383,7 @@ test_expect_success () { test_failure_ "$@" fi fi - echo >&3 "" + test_finish_ } # test_external runs external test scripts that provide continuous @@ -517,6 +548,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 +617,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: @@ -601,7 +654,7 @@ test_seq () { 2) ;; *) error "bug in the test script: not 1 or 2 parameters to test_seq" ;; esac - "$PERL_PATH" -le 'print for $ARGV[0]..$ARGV[1]' -- "$@" + perl -le 'print for $ARGV[0]..$ARGV[1]' -- "$@" } # This function can be used to schedule some commands to be run @@ -646,3 +699,148 @@ 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 +} + +perl () { + command "$PERL_PATH" "$@" +} + +# Is the value one of the various ways to spell a boolean true/false? +test_normalize_bool () { + git -c magic.variable="$1" config --bool magic.variable 2>/dev/null +} + +# Given a variable $1, normalize the value of it to one of "true", +# "false", or "auto" and store the result to it. +# +# test_tristate GIT_TEST_HTTPD +# +# A variable set to an empty string is set to 'false'. +# A variable set to 'false' or 'auto' keeps its value. +# Anything else is set to 'true'. +# An unset variable defaults to 'auto'. +# +# The last rule is to allow people to set the variable to an empty +# string and export it to decline testing the particular feature +# for versions both before and after this change. We used to treat +# both unset and empty variable as a signal for "do not test" and +# took any non-empty string as "please test". + +test_tristate () { + if eval "test x\"\${$1+isset}\" = xisset" + then + # explicitly set + eval " + case \"\$$1\" in + '') $1=false ;; + auto) ;; + *) $1=\$(test_normalize_bool \$$1 || echo true) ;; + esac + " + else + eval "$1=auto" + fi +} + +# Exit the test suite, either by skipping all remaining tests or by +# exiting with an error. If "$1" is "auto", we then we assume we were +# opportunistically trying to set up some tests and we skip. If it is +# "true", then we report a failure. +# +# The error/skip message should be given by $2. +# +test_skip_or_die () { + case "$1" in + auto) + skip_all=$2 + test_done + ;; + true) + error "$2" + ;; + *) + error "BUG: test tristate is '$1' (real error: $2)" + esac +} + +# The following mingw_* functions obey POSIX shell syntax, but are actually +# bash scripts, and are meant to be used only with bash on Windows. + +# A test_cmp function that treats LF and CRLF equal and avoids to fork +# diff when possible. +mingw_test_cmp () { + # Read text into shell variables and compare them. If the results + # are different, use regular diff to report the difference. + local test_cmp_a= test_cmp_b= + + # When text came from stdin (one argument is '-') we must feed it + # to diff. + local stdin_for_diff= + + # Since it is difficult to detect the difference between an + # empty input file and a failure to read the files, we go straight + # to diff if one of the inputs is empty. + if test -s "$1" && test -s "$2" + then + # regular case: both files non-empty + mingw_read_file_strip_cr_ test_cmp_a <"$1" + mingw_read_file_strip_cr_ test_cmp_b <"$2" + elif test -s "$1" && test "$2" = - + then + # read 2nd file from stdin + mingw_read_file_strip_cr_ test_cmp_a <"$1" + mingw_read_file_strip_cr_ test_cmp_b + stdin_for_diff='<<<"$test_cmp_b"' + elif test "$1" = - && test -s "$2" + then + # read 1st file from stdin + mingw_read_file_strip_cr_ test_cmp_a + mingw_read_file_strip_cr_ test_cmp_b <"$2" + stdin_for_diff='<<<"$test_cmp_a"' + fi + test -n "$test_cmp_a" && + test -n "$test_cmp_b" && + test "$test_cmp_a" = "$test_cmp_b" || + eval "diff -u \"\$@\" $stdin_for_diff" +} + +# $1 is the name of the shell variable to fill in +mingw_read_file_strip_cr_ () { + # Read line-wise using LF as the line separator + # and use IFS to strip CR. + local line + while : + do + if IFS=$'\r' read -r -d $'\n' line + then + # good + line=$line$'\n' + else + # we get here at EOF, but also if the last line + # was not terminated by LF; in the latter case, + # some text was read + if test -z "$line" + then + # EOF, really + break + fi + fi + eval "$1=\$$1\$line" + done +} diff --git a/t/test-lib.sh b/t/test-lib.sh index 489bc80fc1..87f327ff8b 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -1,4 +1,4 @@ -#!/bin/sh +# Test framework for git. See t/README for usage. # # Copyright (c) 2005 Junio C Hamano # @@ -26,6 +26,10 @@ then # outside of t/, e.g. for running tests on the test library # itself. TEST_DIRECTORY=$(pwd) +else + # ensure that TEST_DIRECTORY is an absolute path so that it + # is valid even if the current working directory is changed + TEST_DIRECTORY=$(cd "$TEST_DIRECTORY" && pwd) || exit 1 fi if test -z "$TEST_OUTPUT_DIRECTORY" then @@ -54,8 +58,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 +89,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 @@ -102,6 +108,12 @@ export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME export EDITOR +if test -n "${TEST_GIT_INDEX_VERSION:+isset}" +then + GIT_INDEX_VERSION="$TEST_GIT_INDEX_VERSION" + export GIT_INDEX_VERSION +fi + # Add libc MALLOC and MALLOC_PERTURB test # only if we are not executing the test with valgrind if expr " $GIT_TEST_OPTS " : ".* --valgrind " >/dev/null || @@ -128,6 +140,7 @@ fi unset CDPATH unset GREP_OPTIONS +unset UNZIP case $(echo $GIT_TRACE |tr "[A-Z]" "[a-z]") in 1|2|true) @@ -182,6 +195,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,7 +207,14 @@ 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 ;; --tee) shift ;; # was handled already --root=*) @@ -202,6 +225,15 @@ do esac done +if test -n "$valgrind_only" +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 +244,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 @@ -249,7 +283,7 @@ error "Test script did not set test_description." if test "$help" = "t" then - echo "$test_description" + printf '%s\n' "$test_description" exit 0 fi @@ -289,7 +323,7 @@ trap 'die' EXIT . "$TEST_DIRECTORY/test-lib-functions.sh" # You are not expected to call test_ok_ and test_failure_ directly, use -# the text_expect_* functions instead. +# the test_expect_* functions instead. test_ok_ () { test_success=$(($test_success + 1)) @@ -298,26 +332,85 @@ test_ok_ () { test_failure_ () { test_failure=$(($test_failure + 1)) - say_color error "not ok - $test_count $1" + say_color error "not ok $test_count - $1" shift - echo "$@" | sed -e 's/^/# /' + printf '%s\n' "$*" | sed -e 's/^/# /' test "$immediate" = "" || { GIT_EXIT_OK=t; exit 1; } } test_known_broken_ok_ () { test_fixed=$(($test_fixed+1)) - say_color "" "ok $test_count - $@ # TODO known breakage" + say_color error "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 "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 + 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" + then + GIT_VALGRIND_ENABLED=t + return + fi + GIT_VALGRIND_ENABLED= + if match_pattern_list $test_count $valgrind_only + 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 +420,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 +438,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 @@ -389,7 +491,8 @@ test_done () { 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 +506,18 @@ test_done () { if test "$test_fixed" != 0 then - say_color pass "# fixed $test_fixed known breakage(s)" + say_color error "# $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 "# 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,7 +531,7 @@ 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" fi @@ -473,11 +581,9 @@ then make_valgrind_symlink () { # handle only executables, unless they are shell libraries that - # need to be in the exec-path. We will just use "#!" as a - # guess for a shell-script, since we have no idea what the user - # may have configured as the shell path. + # need to be in the exec-path. test -x "$1" || - test "#!" = "$(head -c 2 <"$1")" || + test "# " = "$(head -c 2 <"$1")" || return; base=$(basename "$1") @@ -520,6 +626,11 @@ then 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 + test -n "$valgrind_only" && GIT_VALGRIND_ENABLED= + export GIT_VALGRIND_ENABLED elif test -n "$GIT_TEST_INSTALLED" then GIT_EXEC_PATH=$($GIT_TEST_INSTALLED/git --exec-path) || @@ -565,15 +676,6 @@ test -d "$GIT_BUILD_DIR"/templates/blt || { error "You haven't built things yet, have you?" } -if test -z "$GIT_TEST_INSTALLED" && test -z "$NO_PYTHON" -then - GITPYTHONLIB="$GIT_BUILD_DIR/git_remote_helpers/build/lib" - export GITPYTHONLIB - test -d "$GIT_BUILD_DIR"/git_remote_helpers/build || { - error "You haven't built git_remote_helpers yet, have you?" - } -fi - if ! test -x "$GIT_BUILD_DIR"/test-chmtime then echo >&2 'You need to build test-chmtime:' @@ -582,14 +684,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 +702,22 @@ 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 # 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 +755,25 @@ 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 + GIT_TEST_CMP=mingw_test_cmp ;; *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,11 +819,27 @@ 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 ' +test_lazy_prereq FILEMODE ' + test "$(git config --bool core.filemode)" = true +' + test_lazy_prereq CASE_INSENSITIVE_FS ' echo good >CamelCase && echo bad >camelcase && @@ -738,6 +859,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 \ |